Class: SciYAG::Backends::Backend
- Inherits:
-
Object
- Object
- SciYAG::Backends::Backend
- Extended by:
- MetaBuilder::DescriptionExtend
- Includes:
- MetaBuilder::DescriptionInclude
- Defined in:
- lib/SciYAG/Backends/backend.rb
Overview
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.
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 bu 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 ;-) !
Direct Known Subclasses
BinnerBackend, GnuplotBackend, MDBBackend, MathBackend, TextBackend
Constant Summary collapse
- @@log =
nil
Class Method Summary collapse
-
.default_state(name) ⇒ Object
Returns the default state of the named backend, or nil if it wasn’t found.
-
.describe(name, longname, desc, register = true) ⇒ Object
Creates a description object with the given texts and associates it with the class.
-
.list_backends ⇒ Object
Returns a hash containing the description of all available backends.
- .list_descriptions ⇒ Object
-
.logger=(logger) ⇒ Object
Set the logger for Backends.
Instance Method Summary collapse
- #base_line=(str) ⇒ Object
-
#clear_xy_filters ⇒ Object
Removes all filters on the list.
-
#expand_sets(spec) ⇒ Object
When converting a user input into a set, a program should always use this function, unless it has really good reasons for that.
-
#get_cached_entry(name, exclude = [], supp_info = {}, &code) ⇒ Object
Gets a cached entry or generate it and cache it.
-
#has_set?(set) ⇒ Boolean
(also: #set?)
Returns true if the backend can provide data for the given set.
-
#initialize ⇒ Backend
constructor
Sets up a few things, such as the filters.
-
#meta_data(set) ⇒ Object
This function should return a hash containing all meta-information available about the given set.
-
#pop_xy_filter ⇒ Object
Removes a filter from the top.
- #push_xy_filter(f) ⇒ Object
-
#query_xy_data(set) ⇒ Object
This function must be redefined by children who provide 2D datasets.
-
#set_type(set) ⇒ Object
Returns :xy or :xyz depending on the kind of the given set.
-
#sets_available ⇒ Object
Some backends have a pretty good idea of the sets available for use.
-
#xy_data(set) ⇒ Object
Used by other classes to query for the Backends data.
-
#xyz_data(set) ⇒ Object
Returns the XYZ data for the given set.
Methods included from MetaBuilder::DescriptionExtend
base_description, create_factory, describe, description, factory_class, factory_description, factory_description_hash, factory_description_list, group, has_factory?, inherit_parameters, param, param_accessor, param_reader, param_writer, register_class, set_description
Methods included from MetaBuilder::DescriptionInclude
#description, #get_param, #get_param_raw, #long_name, #option_parser_banner, #option_parser_fill, #option_parser_options, #parameter, #restore_state, #save_state, #set_param, #set_param_raw
Constructor Details
#initialize ⇒ Backend
Sets up a few things, such as the filters.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/SciYAG/Backends/backend.rb', line 84 def initialize() @xy_filters = [] @xy_filters_apply = false @xyz_filters = [] @xyz_filters_apply = false # If set, uses this set as a baseline for all the others. @base_line = "" @base_line_cache = false # Filters are classes that have one method apply, which takes a # pair/triplet of vectors and return the same number of stuff, # modified or not. # We create a cache by default. Doesn't take up much space anyway: @cache = Cache.new end |
Class Method Details
.default_state(name) ⇒ Object
Returns the default state of the named backend, or nil if it wasn’t found.
344 345 346 347 348 349 350 351 |
# File 'lib/SciYAG/Backends/backend.rb', line 344 def self.default_state(name) desc = factory_description_hash[name] if desc return desc.default_state else return nil end end |
.describe(name, longname, desc, register = true) ⇒ Object
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"
129 130 131 132 |
# File 'lib/SciYAG/Backends/backend.rb', line 129 def Backend.describe(name, longname, desc, register = true) d = BackendDescription.new(self, name, longname, desc, register) set_description(d) end |
.list_backends ⇒ Object
Returns a hash containing the description of all available backends
135 136 137 |
# File 'lib/SciYAG/Backends/backend.rb', line 135 def Backend.list_backends return factory_description_hash end |
.list_descriptions ⇒ Object
139 140 141 142 |
# File 'lib/SciYAG/Backends/backend.rb', line 139 def Backend.list_descriptions warn "Backend.list_descriptions should not be used, use Backend.list_backends instead" list_backends end |
.logger=(logger) ⇒ Object
Set the logger for Backends
356 357 358 |
# File 'lib/SciYAG/Backends/backend.rb', line 356 def self.logger= (logger) @@log = logger end |
Instance Method Details
#base_line=(str) ⇒ Object
153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/SciYAG/Backends/backend.rb', line 153 def base_line=(str) if str =~ /^no$/ or str.empty? @base_line = "" else @base_line = (str)[0] # Fill the cache. ary = query_xy_data(@base_line) @base_line_cache = if ary.is_a?(Array) ary[0] else ary end end end |
#clear_xy_filters ⇒ Object
Removes all filters on the list.
115 116 117 118 |
# File 'lib/SciYAG/Backends/backend.rb', line 115 def clear_xy_filters @xy_filters = [] @xy_filters_apply = false end |
#expand_sets(spec) ⇒ Object
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.
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/SciYAG/Backends/backend.rb', line 271 def (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.}" debug "Error backtrace: #{ex.backtrace.join "\n"}" warn "Ignoring, but you're nearly garanteed something will "+ "fail later on" return [spec] end |
#get_cached_entry(name, exclude = [], supp_info = {}, &code) ⇒ Object
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
333 334 335 336 337 338 339 340 |
# File 'lib/SciYAG/Backends/backend.rb', line 333 def get_cached_entry(name, exclude = [], supp_info = {}, &code) state = save_state for k in exclude state.delete(k) end state.merge!(supp_info) return @cache.get_cache(name, state, &code) end |
#has_set?(set) ⇒ Boolean Also known as: set?
Returns true if the backend can provide data for the given set.
186 187 188 |
# File 'lib/SciYAG/Backends/backend.rb', line 186 def has_set?(set) return false end |
#meta_data(set) ⇒ Object
This function should return a hash containing all meta-information available about the given set. The hash can contain elements such as:
:date
-
the date at which the set was recorded
:x_legend
-
legend of the X axis
:x_unit
-
unit of the X axis
(and the same kind for Y and Z axis)
Of course, this list is not limitative; you are encouraged at any rate to add as much metadata as possible. Later on, I’ll provide a method to register metadata types.
180 181 182 183 |
# File 'lib/SciYAG/Backends/backend.rb', line 180 def (set) warn "No metadata implementation for backend " + "#{description.name}" end |
#pop_xy_filter ⇒ Object
Removes a filter from the top
110 111 112 |
# File 'lib/SciYAG/Backends/backend.rb', line 110 def pop_xy_filter return @xy_filters.pop end |
#push_xy_filter(f) ⇒ Object
104 105 106 107 |
# File 'lib/SciYAG/Backends/backend.rb', line 104 def push_xy_filter(f) @xy_filters << f @xy_filters_apply = true end |
#query_xy_data(set) ⇒ Object
This function must be redefined by children who provide 2D datasets. This function must return either:
-
a Function alone, representing the 2D data of the set
-
or an Array, whose first element is a Function and whose second element is an array containing metadata about the dataset.
203 204 205 |
# File 'lib/SciYAG/Backends/backend.rb', line 203 def query_xy_data(set) raise "query_xy_data must be redefined by children !" end |
#set_type(set) ⇒ Object
Returns :xy or :xyz depending on the kind of the given set.
193 194 195 |
# File 'lib/SciYAG/Backends/backend.rb', line 193 def set_type(set) raise "Shouldn't be called for the base class" end |
#sets_available ⇒ Object
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.
324 325 326 |
# File 'lib/SciYAG/Backends/backend.rb', line 324 def sets_available return [] end |
#xy_data(set) ⇒ Object
Used by other classes to query for the Backends data. This may include processing with data filters. Please note that the query_xy_data functions must return a Dobjects::Function. The return value must be modifiable without consequences to the backend.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/SciYAG/Backends/backend.rb', line 212 def xy_data(set) retval = query_xy_data(set) if retval.is_a?(Array) ary,errors, = *retval else ary = retval errors = {} = {} end if (not @base_line.empty?) and @base_line_cache ary.y.sub!(@base_line_cache.y) end # Now, this is the fun part: we create the Dataset object dataset = DataSet2D.new(self, ary, errors, ) # apply the filters if necessary if @xy_filters_apply for filter in @xy_filters filter.apply!(dataset) end end return dataset end |
#xyz_data(set) ⇒ Object
Returns the XYZ data for the given set
236 237 238 239 240 241 242 243 244 245 |
# File 'lib/SciYAG/Backends/backend.rb', line 236 def xyz_data(set) ary = query_xyz_data(set) # apply the filters if necessary if @xyz_filters_apply for filter in @xyz_filters ary = filter.apply(ary) end end return ary end |