Version 3 (modified by ngoto, 15 years ago)

--

Day-1

Day0

Day1

Day2

Designing a mechanism to output object using the ERb template engine for writing data in RDF

  • Mitsuteru Nakao
  • Naohisa Goto
  • Toshiaki Katayama
  • Raoul Jean Pierre Bonnal

Basic idea

medline = Bio::MEDLINE.new(medline_flatfile)
puts medline.output_rdf # => print a medline abstract in RDF format.
  • Writing a Bio::DB object data in RDF format
  • Using the Erb template system
  • Template replaceablity

Proposed architecture

Adding a module Bio::OutputErb?

module Bio
  module OutputErb
    require 'erb'
    def output_method_erb(m, t)
      erb = ERB.new(File.read(t))
      erb.def_method(self, m, t)
    end
  end
end

Extending the Bio::MEDLINE

class MEDLINE
  extend OutputErb
  def_output_method_erb("output_ttl", 'bio/bio/db/medline/medline.ttl.erb')

  def output(t)
    send("output_#{t.to_s}")
  end
end

An Erb template file medline.ttl.erb for RDF/Turtle (partial)

<%
require 'date'
# http://www.nlm.nih.gov/bsd/mms/medlineelements.html
# A generic RDF subject URI at the TogoWS REST
@prefix = "http://togows.dbcls.jp/entry/ncbi-pubmed"

def uri
  "<#{@prefix}/#{c(pubmed['PMID'])}>"
end

# Generate a generic RDF predicate URI at the TogoWS REST.
def predicate(field_name)
  "<http://togows.dbcls.jp/nezu/1.0/ncbi-pubmed##{field_name}>"
end

def ndate(str)
  str.strip
  case str
  when /^\d+$/
    str.gsub(/(\d{4})(\d{2})(\d{2})/) { "#{$1}-#{$2}-#{$3}"}
  else
    str.gsub("/", '-')
  end
end

def ndatetime(str)
  d,t = str.split(" ")
  [ndate(d), t].join(" ")
end
%><%= uri %>    <%= predicate('pmid') %>        "<%=c pubmed['PMID'] %>" .
<%= uri %>      <http://www.w3.org/2000/01/rdf-schema#label>    "pmid:<%=c pubmed['PMID'] %>" .
<%= uri %>      <http://purl.org/dc/elements/1.1/title> "pmid:<%=c pubmed['PMID'] %>" .
<%= uri %>      <http://purl.org/dc/elements/1.1/identifier>    <http://pubmed.org/<%=c pubmed['PMID'] %>> .
<%= uri %>      <%= predicate('own') %> "<%=c pubmed['OWN'] %>" .
<%= uri %>      <%= predicate('stat') %>        "<%=c pubmed['STAT'] %>" .
<%= uri %>      <%= predicate('da') %>  "<%= ndate(c pubmed['DA']) %>" .
<%= uri %>      <%= predicate('dcom') %>        "<%=ndate(c pubmed['DCOM']) %>" .
<%= uri %>      <%= predicate('lr') %>  "<%=ndate(c pubmed['LR']) %>" .
<% pubmed['IS'].scan(/(\d+-\d+ \(\S+\))/).flatten.each do |is| %>
<%= uri %>      <%= predicate('is') %>  "<%=c "#{is}" %>" .
<% end %>
<%= uri %>      <%= predicate('vi') %>  "<%=c pubmed['VI'] %>" .
<%= uri %>      <http://prismstandard.org/namespaces/2.0/basic/volume>  "<%=c pubmed['VI'] %>" .
<%= uri %>      <%= predicate('dp') %>  "<%=c pubmed['DP'] %>" .
...

On using

medline = Bio::MEDLINE.new(medline_flatfile)

mdeline.output_ttl # .ttl == RDF/Turtle
mdeline.output(:ttl) # alias 
medline.to_ttl # alias 
medline.to(:ttl) # alias 

Use user template

class MEDLINE
  def_output_method_erb("output_rdfxml", 'bio/bio/db/medline/medline.rdfxml.erb')
end

medline = Bio::MEDLINE.new(medline_flatfile)
mdeline.output_rdfxml

File arrangement

  • lib/bio/db/
    • medline.rb
    • medline/medline.ttl.erb

Issues

Naming issue

  • Choice: Bio::Renderer / Bio::Render / Bio::Template / Bio::Output / Bio::Export / Bio::Exporter / Bio::Writer / Bio::OutputErb?
  • Choice: medline.output_ttl / medline.output(:ttl) / medline.to_ttl / medline.to(:ttl)
    • Pros: the to_ttl naming is easy for beginner.
    • Cons: to_ttl style name is for converting class. The to_s method is to convert a object to String expression. And to_json may be confusional.

Method namespace

  • Functions defined at the template file contaminates the namespace of the Bio::MEDLINE class.

Performance issue

  • Reading template file every time may be heavy because it uses eval.
    • ERB#def_method (or def_class or def_module) may help, but another problem: it always reads the template when the method (or class/module) is defined even if the output is not needed.