1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
|
#
# = bio/sequence/adapter.rb - Bio::Sequence adapter helper module
#
# Copyright:: Copyright (C) 2008
# Naohisa Goto <ng@bioruby.org>,
# License:: The Ruby License
#
module Bio
require 'bio/sequence' unless const_defined?(:Sequence)
# Internal use only. Normal users should not use this module.
#
# Helper methods for defining adapters used when converting data classes to
# Bio::Sequence class, with pseudo lazy evaluation and pseudo memoization.
#
# This module is used by using "extend", not "include".
#
module Sequence::Adapter
autoload :GenBank, 'bio/db/genbank/genbank_to_biosequence'
autoload :EMBL, 'bio/db/embl/embl_to_biosequence'
autoload :FastaFormat, 'bio/db/fasta/fasta_to_biosequence'
autoload :FastaNumericFormat, 'bio/db/fasta/qual_to_biosequence'
autoload :BioSQL, 'bio/db/biosql/biosql_to_biosequence'
autoload :SangerChromatogram,
'bio/db/sanger_chromatogram/chromatogram_to_biosequence'
autoload :Fastq, 'bio/db/fastq/fastq_to_biosequence'
private
# Defines a reader attribute method with psudo lazy evaluation/memoization.
#
# It defines a method <i>name</i> like attr_reader, but at the first time
# when the method <i>name</i> is called, it acts as follows:
# When instance variable @<i>name</i> is not defined,
# calls <tt>__get__<i>name</i>(@source_data)</tt> and stores the returned
# value to @<i>name</i>, and changes its behavior to the same as
# <tt>attr_reader </tt><i>:name</i>.
# When instance variable @name is already defined,
# its behavior is changed to the same as
# <tt>attr_reader </tt><i>:name</i>.
# When the object is frozen, storing to the instance variable and
# changing methods behavior do not occur, and the value of
# <tt>__get__<i>name</i>(@source_data)</tt> is returned.
#
# Note that it assumes that the source data object is stored in
# @source_data instance variable.
def attr_reader_lazy(name)
#$stderr.puts "attr_reader_lazy :#{name}"
varname = "@#{name}".intern
methodname = "__get__#{name}".intern
# module to reset method's behavior to normal attr_reader
reset = "Attr_#{name}".intern
const_set(reset, Module.new { attr_reader name })
reset_module_name = "#{self}::#{reset}"
# define attr method
module_eval <<__END_OF_DEF__
def #{name}
unless defined? #{varname} then
#$stderr.puts "LAZY #{name}: calling #{methodname}"
val = #{methodname}(@source_data)
#{varname} = val unless frozen?
else
val = #{varname}
end
unless frozen? then
#$stderr.puts "LAZY #{name}: finalize: attr_reader :#{name}"
self.extend(#{reset_module_name})
end
val
end
__END_OF_DEF__
end
# Defines a Bio::Sequence to Bio::* adapter method with
# psudo lazy evaluation and psudo memoization.
#
# Without block, defines a private method <tt>__get__<i>name</i>(orig)</tt>
# which calls <i>source_method</i> for @source_data.
#
# def__get__(name, source_method) is the same as:
# def __get__name(orig); orig.source_method; end
# attr_reader_lazy name
#
# If block is given, <tt>__get__<i>name</i>(orig)</tt> is defined
# with the block. The @source_data is given as an argument of the block,
# i.e. the block must get an argument.
#
def def_biosequence_adapter(name, source_method = name, &block)
methodname = "__get__#{name}".intern
if block then
define_method(methodname, block)
else
module_eval <<__END_OF_DEF__
def #{methodname}(orig)
orig.#{source_method}
end
__END_OF_DEF__
end
private methodname
attr_reader_lazy name
true
end
end #module Sequence::Adapter
end #module Bio
|