class CTioga2::Data::Backends::Backend
This class provides the infrastructure for accessing data sets. It shouldn't be used directly, but rather subclassed and reimplemented. The aim of this class is to provide any software which is interested to retrive data from some source with a consistent way to do so, independent the kind of source accessed.
todo update documentation.
Subclasses should:
-
provide a consistent method for creating themselves, with as much information as necessary, including options and default parameters. Actually, their initialize function should take no value but on the other side, the
BackendDescription
associated with it should make it easy to set all the parameters necessary to get one set of data. -
provide a way to fill an OptionParser with their own parameters
-
provide a way to retrieve the data via named 'sets' (either 2D or 3D data, depending on the subclass)
-
provide a way to obtain all meta-informations on one dataset, such as the date, the meaning of the columns (if any), and so on.
-
provide a way to know which named sets are available, or at least a subset (or nothing if we don't know a thing).
-
wether the actual reading of the data is done at initialization time or at query time is left to the implementor ;-) !
todo adapt to the new structure.
todo add back filters (with time)
todo add a Cache ?
Public Class Methods
Creates a description object with the given texts and associates it with the class. It is necessary to have this statement before any parameter declaration. If you don't set any description, you will not be able to benefit from the plugin system. To be used in Backend
subclasses, simply this way:
describe "biniou", "Biniou backend", "A backend to deal with Binious"
# File lib/ctioga2/data/backends/backend.rb, line 90 def Backend.describe(name, longname, desc, register = true) d = BackendDescription.new(self, name, longname, desc, register) set_description(d) end
Returns a hash containing the description of all available backends
# File lib/ctioga2/data/backends/backend.rb, line 97 def Backend.list_backends return factory_description_hash end
Sets up a few things, such as the filters.
# File lib/ctioga2/data/backends/backend.rb, line 73 def initialize end
Public Instance Methods
Public interface to query DataSet from a Backend
. Children must redefine query_dataset
rather than this function. This function also applies filters and does othe kinds of transformations
# File lib/ctioga2/data/backends/backend.rb, line 129 def dataset(set) return query_dataset(set) end
Returns the BackendDescription
associated with this Backend
.
# File lib/ctioga2/data/backends/backend.rb, line 77 def description return self.class.description end
When converting a user input into a set, a program should always use this function, unless it has really good reasons for that.
The default implementation is to expand 2##4 to 2, 3, 4. Can be useful even for mathematical stuff.
Another thing is recognised and expanded: #<2<i*2>,5> runs the code i*2 with the values from 2 to 5 and returns the result. The code in the middle is a Ruby
block, and therefore should be valid !
A third expansion is now available: #<a = 2<a * sin(x)>10> will expand into 2*sin(x) , 3*sin(x) … 10*sin(x) it is different than the previous in the sense that the code in the middle is not a Ruby
code, but a mere string, which means there won't be compilation problems.
Unless your backend can't accomodate for that, all redefinitions of this function should check for their specific signatures first and call this function if they fail. This way, they will profit from improvements in this code while keeping old stuff working.
# File lib/ctioga2/data/backends/backend.rb, line 157 def expand_sets(spec) if m = /(\d+)##(\d+)/.match(spec) debug { "Using expansion rule #1" } a = m[1].to_i b = m[2].to_i ret = [] a.upto(b) do |i| ret << m.pre_match + i.to_s + m.post_match end return ret elsif m = /\#<(\d+)<(.*?)>(\d+)>/.match(spec) debug { "Using expansion rule #2" } from = m[1].to_i to = m[3].to_i debug { "Ruby code used for expansion: {|i| #{m[2]} }" } code = eval "proc {|i| #{m[2]} }" ret = [] from.upto(to) do |i| ret << m.pre_match + code.call(i).to_s + m.post_match end return ret elsif m = /\#<\s*(\w+)\s*=\s*(\d+)\s*<(.*?)>\s*(\d+)\s*>/.match(spec) debug { "Using expansion rule #3" } var = m[1] from = m[2].to_i to = m[4].to_i # Then we replace all occurences of the variable literal = '"' + m[3].gsub(/\b#{var}\b/, '#{' + var + '}') + '"' debug { "Ruby code used for expansion: {|#{var}| #{literal} }" } code = eval "proc {|#{var}| #{literal} }" ret = [] from.upto(to) do |i| ret << m.pre_match + code.call(i).to_s + m.post_match end return ret end # Fallback return [spec] rescue Exception => ex # In case something went wrong in the eval. warn { "An error occured during expansion of '#{spec}': #{ex.message}" } debug { "Error backtrace: #{ex.backtrace.join "\n"}" } warn { "Ignoring, but you're nearly garanteed something will "+ "fail later on" } return [spec] end
Returns true if the backend can provide data for the given set.
# File lib/ctioga2/data/backends/backend.rb, line 118 def has_set?(set) return false end
Directly set a named parameter
# File lib/ctioga2/data/backends/backend.rb, line 220 def set_param_from_string(param, string) description.param_hash[param].set_from_string(self, string) end
Some backends have a pretty good idea of the sets available for use. Some really don't. You can choose to reimplement this function if you can provide a useful list of sets for your backend. This list doesn't need to be exhaustive (and is most unlikely to be). It can also return something that would need further expansion using expand_sets.
# File lib/ctioga2/data/backends/backend.rb, line 212 def sets_available return [] end
Protected Instance Methods
Gets a cached entry or generate it and cache it. See Cache#cache for more details. The cache's meta_data is constructed as following:
-
the current state of the backend is taken
-
keys inside exclude are removed.
-
supp_info is added
todo get the implementation back again.
# File lib/ctioga2/data/backends/backend.rb, line 245 def get_cached_entry(name, exclude = [], supp_info = {}, &code) raise YetUnimplemented state = save_state for k in exclude state.delete(k) end state.merge!(supp_info) return @cache.get_cache(name, state, &code) end
Returns a DataSet object for the given set. Must be reimplemented by children. The public interface is dataset
.
It is strongly recommended to use Dataset.dataset_from_spec
to create the Dataset
return values in reimplementations.
# File lib/ctioga2/data/backends/backend.rb, line 232 def query_dataset(set) raise "query_dataset must be redefined by children !" end