ctioga2 0.0 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/Changelog +25 -1
  2. data/lib/ctioga2/commands/commands.rb +13 -2
  3. data/lib/ctioga2/commands/doc/doc.rb +13 -17
  4. data/lib/ctioga2/commands/doc/documentation-commands.rb +14 -1
  5. data/lib/ctioga2/commands/doc/help.rb +136 -25
  6. data/lib/ctioga2/commands/doc/html.rb +56 -4
  7. data/lib/ctioga2/commands/doc/introspection.rb +45 -9
  8. data/lib/ctioga2/commands/doc/man.rb +7 -5
  9. data/lib/ctioga2/commands/doc/markup.rb +39 -12
  10. data/lib/ctioga2/commands/doc/wordwrap.rb +70 -0
  11. data/lib/ctioga2/commands/general-commands.rb +7 -4
  12. data/lib/ctioga2/commands/general-types.rb +27 -12
  13. data/lib/ctioga2/commands/interpreter.rb +2 -2
  14. data/lib/ctioga2/commands/parsers/command-line.rb +9 -5
  15. data/lib/ctioga2/commands/parsers/file.rb +5 -3
  16. data/lib/ctioga2/commands/type.rb +10 -3
  17. data/lib/ctioga2/commands/variables.rb +2 -2
  18. data/lib/ctioga2/data/backends/backend.rb +17 -15
  19. data/lib/ctioga2/data/backends/backends.rb +2 -2
  20. data/lib/ctioga2/data/backends/backends/gnuplot.rb +20 -5
  21. data/lib/ctioga2/data/backends/backends/math.rb +2 -2
  22. data/lib/ctioga2/data/backends/backends/text.rb +112 -17
  23. data/lib/ctioga2/data/backends/description.rb +10 -11
  24. data/lib/ctioga2/data/datacolumn.rb +73 -14
  25. data/lib/ctioga2/data/dataset.rb +305 -9
  26. data/lib/ctioga2/data/filters.rb +49 -1
  27. data/lib/ctioga2/data/indexed-dtable.rb +137 -0
  28. data/lib/ctioga2/data/point.rb +98 -7
  29. data/lib/ctioga2/data/stack.rb +98 -21
  30. data/lib/ctioga2/graphics/coordinates.rb +19 -2
  31. data/lib/ctioga2/graphics/elements.rb +12 -2
  32. data/lib/ctioga2/graphics/elements/containers.rb +14 -2
  33. data/lib/ctioga2/graphics/elements/contour.rb +67 -0
  34. data/lib/ctioga2/graphics/elements/curve2d.rb +103 -42
  35. data/lib/ctioga2/graphics/elements/element.rb +12 -2
  36. data/lib/ctioga2/graphics/elements/gradient-region.rb +94 -0
  37. data/lib/ctioga2/graphics/elements/parametric2d.rb +172 -0
  38. data/lib/ctioga2/graphics/elements/primitive.rb +37 -21
  39. data/lib/ctioga2/graphics/elements/region.rb +143 -0
  40. data/lib/ctioga2/graphics/elements/subplot.rb +92 -32
  41. data/lib/ctioga2/graphics/elements/tangent.rb +99 -0
  42. data/lib/ctioga2/graphics/elements/xyz-map.rb +126 -0
  43. data/lib/ctioga2/graphics/generator.rb +91 -6
  44. data/lib/ctioga2/graphics/legends.rb +26 -21
  45. data/lib/ctioga2/graphics/legends/area.rb +8 -8
  46. data/lib/ctioga2/graphics/legends/items.rb +5 -5
  47. data/lib/ctioga2/graphics/legends/storage.rb +4 -2
  48. data/lib/ctioga2/graphics/root.rb +24 -2
  49. data/lib/ctioga2/graphics/styles.rb +8 -0
  50. data/lib/ctioga2/graphics/styles/axes.rb +49 -23
  51. data/lib/ctioga2/graphics/styles/base.rb +2 -2
  52. data/lib/ctioga2/graphics/styles/carrays.rb +9 -2
  53. data/lib/ctioga2/graphics/styles/colormap.rb +272 -0
  54. data/lib/ctioga2/graphics/styles/curve.rb +64 -4
  55. data/lib/ctioga2/graphics/styles/drawable.rb +68 -9
  56. data/lib/ctioga2/graphics/styles/errorbar.rb +73 -0
  57. data/lib/ctioga2/graphics/styles/factory.rb +133 -17
  58. data/lib/ctioga2/graphics/styles/gradients.rb +60 -0
  59. data/lib/ctioga2/graphics/styles/location.rb +64 -0
  60. data/lib/ctioga2/graphics/styles/map-axes.rb +164 -0
  61. data/lib/ctioga2/graphics/styles/plot.rb +165 -62
  62. data/lib/ctioga2/graphics/styles/sets.rb +14 -1
  63. data/lib/ctioga2/graphics/styles/texts.rb +44 -34
  64. data/lib/ctioga2/graphics/subplot-commands.rb +94 -6
  65. data/lib/ctioga2/graphics/types.rb +113 -35
  66. data/lib/ctioga2/graphics/types/bijection.rb +3 -3
  67. data/lib/ctioga2/graphics/types/boundaries.rb +120 -1
  68. data/lib/ctioga2/graphics/types/dimensions.rb +8 -1
  69. data/lib/ctioga2/graphics/types/grid.rb +196 -0
  70. data/lib/ctioga2/graphics/types/location.rb +228 -0
  71. data/lib/ctioga2/graphics/types/point.rb +2 -2
  72. data/lib/ctioga2/log.rb +18 -18
  73. data/lib/ctioga2/metabuilder/type.rb +15 -3
  74. data/lib/ctioga2/metabuilder/types.rb +2 -2
  75. data/lib/ctioga2/metabuilder/types/coordinates.rb +13 -1
  76. data/lib/ctioga2/metabuilder/types/data.rb +50 -0
  77. data/lib/ctioga2/metabuilder/types/generic.rb +60 -0
  78. data/lib/ctioga2/metabuilder/types/lists.rb +53 -16
  79. data/lib/ctioga2/metabuilder/types/styles.rb +26 -45
  80. data/lib/ctioga2/plotmaker.rb +91 -20
  81. data/lib/ctioga2/postprocess.rb +8 -8
  82. data/lib/ctioga2/utils.rb +23 -4
  83. metadata +107 -75
  84. data/lib/ctioga2/data/merge.rb +0 -43
@@ -19,7 +19,7 @@ require 'ctioga2/commands/strings'
19
19
 
20
20
  module CTioga2
21
21
 
22
- Version::register_svn_info('$Revision: 2 $', '$Date: 2009-04-25 14:03:30 +0200 (Sat, 25 Apr 2009) $')
22
+ Version::register_svn_info('$Revision: 151 $', '$Date: 2010-06-19 23:45:20 +0200 (Sat, 19 Jun 2010) $')
23
23
 
24
24
  module Commands
25
25
 
@@ -96,11 +96,13 @@ module CTioga2
96
96
  # Problem: the space on the right of the = sign is
97
97
  # *significant*.
98
98
  for o in args
99
- if o =~ /^\s*([\w-]+)\s*=(.*)/
99
+ if o =~ /^\s*\/?([\w-]+)\s*=(.*)/
100
100
  if cmd.has_option? $1
101
101
  options[$1] = $2
102
102
  else
103
- error "Command #{cmd.name} does not take option #{$1}"
103
+ error {
104
+ "Command #{cmd.name} does not take option #{$1}"
105
+ }
104
106
  end
105
107
  end
106
108
  end
@@ -16,11 +16,16 @@ require 'ctioga2/metabuilder/types'
16
16
 
17
17
  module CTioga2
18
18
 
19
- Version::register_svn_info('$Revision: 18 $', '$Date: 2009-04-28 23:43:54 +0200 (Tue, 28 Apr 2009) $')
19
+ Version::register_svn_info('$Revision: 173 $', '$Date: 2010-10-22 21:41:39 +0200 (Fri, 22 Oct 2010) $')
20
20
 
21
21
  module Commands
22
22
 
23
23
  # A named type, based on CTioga2::MetaBuilder::Type
24
+ #
25
+ # @todo *Structural* in real, I don't think it is necessary
26
+ # anymore to rely on MetaBuilder, as most types in CTioga2 already
27
+ # provide a from_text class function that does a nice job. I
28
+ # should convert as many things as possible to using that.
24
29
  class CommandType
25
30
 
26
31
  # The underlying CTioga2::MetaBuilder::Type object.
@@ -43,7 +48,9 @@ module CTioga2
43
48
  return obj
44
49
  else
45
50
  if obj.is_a? Symbol
46
- warn "Converting type specifcation #{obj.inspect} to string at #{caller[1]}"
51
+ warn {
52
+ "Converting type specification #{obj.inspect} to string at #{caller[1]}"
53
+ }
47
54
  obj = obj.to_s
48
55
  end
49
56
  type = Interpreter::type(obj)
@@ -87,7 +94,7 @@ module CTioga2
87
94
 
88
95
  # Returns the long option for the option parser.
89
96
  #
90
- # TODO: maybe this should be rethought a bit ?
97
+ # \todo maybe this should be rethought a bit ?
91
98
  def option_parser_long_option(name, param = nil)
92
99
  return @type.option_parser_long_option(name, param)
93
100
  end
@@ -16,7 +16,7 @@ require 'ctioga2/commands/strings'
16
16
 
17
17
  module CTioga2
18
18
 
19
- Version::register_svn_info('$Revision: 2 $', '$Date: 2009-04-25 14:03:30 +0200 (Sat, 25 Apr 2009) $')
19
+ Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
20
20
 
21
21
  module Commands
22
22
 
@@ -43,7 +43,7 @@ module CTioga2
43
43
  # variable = value
44
44
  # They are stored in the form on an InterpreterString
45
45
  #
46
- # TODO: The variables system should automatically transform
46
+ # \todo The variables system should automatically transform
47
47
  # recursive variables into immediate ones when there is no
48
48
  # variables replacement text.
49
49
  class Variables
@@ -21,7 +21,7 @@ require 'ctioga2/data/backends/description'
21
21
 
22
22
  module CTioga2
23
23
 
24
- Version::register_svn_info('$Revision: 59 $', '$Date: 2009-05-28 23:15:50 +0200 (Thu, 28 May 2009) $')
24
+ Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
25
25
 
26
26
 
27
27
  module Data
@@ -36,7 +36,7 @@ module CTioga2
36
36
  # to retrive data from some source with a consistent way to do so,
37
37
  # independent the kind of source accessed.
38
38
  #
39
- # TODO: update documentation.
39
+ # \todo update documentation.
40
40
  #
41
41
  # Subclasses should:
42
42
  # * provide a consistent method for creating themselves,
@@ -55,11 +55,11 @@ module CTioga2
55
55
  # * wether the actual reading of the data is done at initialization time
56
56
  # or at query time is left to the implementor ;-) !
57
57
  #
58
- # TODO: adapt to the new structure.
58
+ # \todo adapt to the new structure.
59
59
  #
60
- # TODO: add back filters (with time)
60
+ # \todo add back filters (with time)
61
61
  #
62
- # TODO: add a Cache ?
62
+ # \todo add a Cache ?
63
63
  class Backend
64
64
 
65
65
  # Include logging facilities...
@@ -106,7 +106,7 @@ This is the base class for backends. It should never be used directly.
106
106
  EOD
107
107
 
108
108
 
109
- # TODO: the baseline should not be implemented.
109
+ # \todo the baseline should not be implemented.
110
110
  # It is much more efficient to ;
111
111
  # * implement a dataset subtraction command;
112
112
  # * use the add-dataset hook to automatically subtract a given
@@ -159,7 +159,7 @@ EOD
159
159
  # code while keeping old stuff working.
160
160
  def expand_sets(spec)
161
161
  if m = /(\d+)##(\d+)/.match(spec)
162
- debug "Using expansion rule #1"
162
+ debug { "Using expansion rule #1" }
163
163
  a = m[1].to_i
164
164
  b = m[2].to_i
165
165
  ret = []
@@ -168,10 +168,10 @@ EOD
168
168
  end
169
169
  return ret
170
170
  elsif m = /\#<(\d+)<(.*?)>(\d+)>/.match(spec)
171
- debug "Using expansion rule #2"
171
+ debug { "Using expansion rule #2" }
172
172
  from = m[1].to_i
173
173
  to = m[3].to_i
174
- debug "Ruby code used for expansion: {|i| #{m[2]} }"
174
+ debug { "Ruby code used for expansion: {|i| #{m[2]} }" }
175
175
  code = eval "proc {|i| #{m[2]} }"
176
176
  ret = []
177
177
  from.upto(to) do |i|
@@ -179,13 +179,13 @@ EOD
179
179
  end
180
180
  return ret
181
181
  elsif m = /\#<\s*(\w+)\s*=\s*(\d+)\s*<(.*?)>\s*(\d+)\s*>/.match(spec)
182
- debug "Using expansion rule #3"
182
+ debug { "Using expansion rule #3" }
183
183
  var = m[1]
184
184
  from = m[2].to_i
185
185
  to = m[4].to_i
186
186
  # Then we replace all occurences of the variable
187
187
  literal = '"' + m[3].gsub(/\b#{var}\b/, '#{' + var + '}') + '"'
188
- debug "Ruby code used for expansion: {|#{var}| #{literal} }"
188
+ debug { "Ruby code used for expansion: {|#{var}| #{literal} }" }
189
189
  code = eval "proc {|#{var}| #{literal} }"
190
190
  ret = []
191
191
  from.upto(to) do |i|
@@ -197,10 +197,12 @@ EOD
197
197
  return [spec]
198
198
  rescue Exception => ex
199
199
  # In case something went wrong in the eval.
200
- warn "An error occured during expansion of '#{spec}': #{ex.message}"
201
- debug "Error backtrace: #{ex.backtrace.join "\n"}"
202
- warn "Ignoring, but you're nearly garanteed something will "+
200
+ warn { "An error occured during expansion of '#{spec}': #{ex.message}" }
201
+ debug { "Error backtrace: #{ex.backtrace.join "\n"}" }
202
+ warn {
203
+ "Ignoring, but you're nearly garanteed something will "+
203
204
  "fail later on"
205
+ }
204
206
  return [spec]
205
207
  end
206
208
 
@@ -242,7 +244,7 @@ EOD
242
244
  # * keys inside _exclude_ are removed.
243
245
  # * _supp_info_ is added
244
246
  #
245
- # TODO: get the implementation back again.
247
+ # \todo get the implementation back again.
246
248
  def get_cached_entry(name, exclude = [], supp_info = {}, &code)
247
249
  raise YetUnimplemented
248
250
  state = save_state
@@ -33,7 +33,7 @@ for file in files.uniq
33
33
  begin
34
34
  require "ctioga2/data/backends/backends/#{file}"
35
35
  rescue Exception => e
36
- warn "There was a problem trying to load 'ctioga2/data/backends/backends/#{file}': "
37
- warn "#{e.inspect}"
36
+ warn { "There was a problem trying to load 'ctioga2/data/backends/backends/#{file}': " }
37
+ warn { "#{e.inspect}" }
38
38
  end
39
39
  end
@@ -25,7 +25,7 @@ require 'stringio'
25
25
 
26
26
  module CTioga2
27
27
 
28
- Version::register_svn_info('$Revision: 61 $', '$Date: 2009-05-29 01:00:56 +0200 (Fri, 29 May 2009) $')
28
+ Version::register_svn_info('$Revision: 151 $', '$Date: 2010-06-19 23:45:20 +0200 (Sat, 19 Jun 2010) $')
29
29
 
30
30
 
31
31
  module Data
@@ -50,6 +50,10 @@ EOD
50
50
  param_accessor :range, 'range',
51
51
  "Plotting X range", 'float-range',
52
52
  "The plotting X range, such as 0:2"
53
+
54
+ param_accessor :samples, 'samples',
55
+ "The number of samples", 'text',
56
+ "The number of samples"
53
57
 
54
58
  # This is called by the architecture to get the data. It splits
55
59
  # the set name into filename@cols, reads the file if necessary and
@@ -76,20 +80,31 @@ EOD
76
80
  def run_gnuplot(filename, overrides = @variables_overrides)
77
81
  date = File::mtime(filename)
78
82
  # Get it from the cache !
79
- debug "Running gnuplot on file #{filename}"
83
+ debug { "Running gnuplot on file #{filename}" }
80
84
  f = File.open(filename)
81
85
  # We open a bidirectionnal connection to gnuplot:
82
86
  gnuplot = IO.popen("gnuplot", "r+")
83
87
  output = ""
84
- gnuplot.puts "set term table"
88
+ ## \todo determine gnuplot version for choosing which one we
89
+ ## want to use.
90
+ # gnuplot.puts "set term table"
91
+ gnuplot.puts "set table"
92
+ if @samples
93
+ overrides ||= ""
94
+ overrides += ";set samples #{@samples}"
95
+ end
85
96
  for line in f
86
97
  next if line =~ /set\s+term/
87
98
  if overrides and line =~ /plot\s+/
88
- debug "Found a plot, inserting variable overrides: #{overrides}"
99
+ debug {
100
+ "Found a plot, inserting variable overrides: #{overrides}"
101
+ }
89
102
  line.gsub!(/plot\s+/, "#{overrides};plot ")
90
103
  end
91
104
  if @range and line =~ /plot\s+/
92
- debug "Found a plot, inserting range: #{@range}"
105
+ debug {
106
+ "Found a plot, inserting range: #{@range}"
107
+ }
93
108
  line.gsub!(/plot\s+(\[[^\]]+\])?/,
94
109
  "plot [#{@range}]")
95
110
  end
@@ -21,7 +21,7 @@ require 'Dobjects/Function'
21
21
 
22
22
  module CTioga2
23
23
 
24
- Version::register_svn_info('$Revision: 17 $', '$Date: 2009-04-28 22:22:22 +0200 (Tue, 28 Apr 2009) $')
24
+ Version::register_svn_info('$Revision: 155 $', '$Date: 2010-06-21 21:41:32 +0200 (Mon, 21 Jun 2010) $')
25
25
 
26
26
  module Data
27
27
 
@@ -36,7 +36,7 @@ module CTioga2
36
36
  This backend returns computations of mathematical formulas.
37
37
  EOD
38
38
 
39
- # TODO: make provisions for 3-D datasets. Ideas: x(t):y(t):z(t)
39
+ # \todo make provisions for 3-D datasets. Ideas: x(t):y(t):z(t)
40
40
  # for parametric plots ? (possibly x(t):y1(t):y2(t):...:yn(t)) ?
41
41
 
42
42
  param_accessor :samples, 'samples', "Samples", 'integer',
@@ -25,7 +25,7 @@ require 'stringio'
25
25
 
26
26
  module CTioga2
27
27
 
28
- Version::register_svn_info('$Revision: 17 $', '$Date: 2009-04-28 22:22:22 +0200 (Tue, 28 Apr 2009) $')
28
+ Version::register_svn_info('$Revision: 191 $', '$Date: 2010-11-07 15:53:08 +0100 (Sun, 07 Nov 2010) $')
29
29
 
30
30
 
31
31
  module Data
@@ -49,6 +49,7 @@ module CTioga2
49
49
  ".bz2" => "bunzip2 -c %s",
50
50
  ".lzma" => "unlzma -c %s",
51
51
  ".lz" => "unlzma -c %s",
52
+ ".xz" => "unxz -c %s",
52
53
  }
53
54
 
54
55
  include Dobjects
@@ -76,9 +77,14 @@ EOD
76
77
  'regexp',
77
78
  "The columns separator. Defaults to /\s+/"
78
79
 
80
+ param_accessor :param_regex, 'parameters', "Parameters parsing",
81
+ 'regexp',
82
+ "Regular expression for extracting parameters from a file. Defaults to nil (ie nothing)"
79
83
 
80
- # param_accessor :select, 'select', "Select lines", {:type => :string},
81
- # "Skips line where the code returns false"
84
+ param_accessor :header_line_regex, 'header-line',
85
+ 'Header line regular expression',
86
+ 'regexp',
87
+ "Regular expression indicating the header line (containing column names) (default /^##/"
82
88
 
83
89
  def initialize
84
90
  @dummy = nil
@@ -95,11 +101,20 @@ EOD
95
101
  # We don't split data by default.
96
102
  @split = false
97
103
 
104
+ @param_regex = nil
105
+
106
+ @header_line_regex = /^\#\#\s*/
107
+
98
108
  super()
99
109
 
100
110
  # Override Backend's cache - for now.
101
111
  @cache = {} # A cache file_name -> data
102
112
 
113
+ @param_cache = {} # Same thing as cache, but for parameters
114
+
115
+ @headers_cache = {} # Same thing as cache, but for header
116
+ # lines.
117
+
103
118
  end
104
119
 
105
120
  def extend(mod)
@@ -147,20 +162,20 @@ EOD
147
162
  # Try to find a compressed version
148
163
  for ext,method in UNCOMPRESSORS
149
164
  if File.readable? "#{file}#{ext}"
150
- info "Using compressed file #{file}#{ext} in stead of #{file}"
165
+ info { "Using compressed file #{file}#{ext} in stead of #{file}" }
151
166
  return IO.popen(method % "#{file}#{ext}")
152
167
  end
153
168
  end
154
169
  else
155
170
  for ext, method in UNCOMPRESSORS
156
171
  if file =~ /#{ext}$/
157
- info "Taking file #{file} as a compressed file"
172
+ info { "Taking file #{file} as a compressed file" }
158
173
  return IO.popen(method % file)
159
174
  end
160
175
  end
161
176
  return File::open(file)
162
177
  end
163
- error "Could not open #{file}"
178
+ error { "Could not open #{file}" }
164
179
  return nil
165
180
  end
166
181
 
@@ -182,11 +197,11 @@ EOD
182
197
  while line = io.gets
183
198
  line_number += 1
184
199
  if line =~ InvalidLineRE
185
- debug "Found invalid line at #{line_number}"
200
+ debug { "Found invalid line at #{line_number}" }
186
201
  if ! last_line_is_invalid
187
202
  # We begin a new set.
188
203
  cur_set += 1
189
- debug "Found set #{cur_set} at line #{line_number}"
204
+ debug { "Found set #{cur_set} at line #{line_number}" }
190
205
  if(cur_set > set)
191
206
  return str
192
207
  end
@@ -214,32 +229,99 @@ EOD
214
229
  else
215
230
  set = 1
216
231
  end
217
- debug "Trying to get set #{set} from file '#{filename}'"
232
+ debug { "Trying to get set #{set} from file '#{filename}'" }
218
233
  str = get_set_string(get_io_object(filename), set)
219
234
  return StringIO.new(str)
220
235
  end
221
236
  end
222
237
 
238
+ undef :param_regex=
239
+ # A proper writer for @param_regex
240
+ def param_regex=(val)
241
+ if val.is_a? Regexp
242
+ @param_regex = val
243
+ elsif val =~ /([^\\]|^)\(/ # Has capturing groups
244
+ @param_regex = /#{val}/
245
+ else # Treat as separator
246
+ @param_regex = /(\S+)\s*#{val}\s*(\S+)/
247
+ end
248
+ end
249
+
250
+ # Turns an array of comments into a hash[param] -> value
251
+ def parse_parameters(comments)
252
+ ret = {}
253
+ for line in comments
254
+ if line =~ @param_regex
255
+ ret[$1] = $2.to_f
256
+ end
257
+ end
258
+ return ret
259
+ end
260
+
261
+ # Turns an array of comments into a hash column name -> column
262
+ # number (1-based)
263
+ def parse_header_line(comments)
264
+ for line in comments
265
+ if line =~ @header_line_regex
266
+ colnames = line.gsub(@header_line_regex,'').split(@separator)
267
+ i = 1
268
+ ret = {}
269
+ for n in colnames
270
+ ret[n] = i
271
+ i += 1
272
+ end
273
+ return ret
274
+ end
275
+ end
276
+ return {}
277
+ end
278
+
223
279
  # Reads data from a file. If needed, extract the file from the
224
280
  # columns specification.
225
281
  #
226
- # TODO: the cache really should include things such as time of
282
+ # \todo the cache really should include things such as time of
227
283
  # last modification and various parameters that influence the
228
- # reading of the file.
284
+ # reading of the file, and the parameters read from the file
285
+ # using #parse_parameters
286
+ #
287
+ # \todo There should be a real global handling of meta-data
288
+ # extracted from files, so that they could be included for
289
+ # instance in the automatic labels ? (and we could have fun
290
+ # improving this one ?)
291
+ #
292
+ # \warning This needs Tioga r561
229
293
  def read_file(file)
230
294
  if file =~ /(.*)@.*/
231
295
  file = $1
232
296
  end
233
297
  name = file # As file will be modified.
234
298
  if ! @cache.key?(file) # Read the file if it is not cached.
299
+ comments = []
235
300
  fancy_read_options = {'index_col' => true,
236
301
  'skip_first' => @skip,
237
- 'sep' => @separator
302
+ 'sep' => @separator,
303
+ 'comment_out' => comments
238
304
  }
239
305
  io_set = get_io_set(file)
240
- debug "Fancy read '#{file}', options #{fancy_read_options.inspect}"
306
+ debug { "Fancy read '#{file}', options #{fancy_read_options.inspect}" }
241
307
  @cache[name] = Dvector.fancy_read(io_set, nil, fancy_read_options)
308
+ if @param_regex
309
+ # Now parsing params
310
+ @param_cache[name] = parse_parameters(comments)
311
+ info { "Read #{@param_cache[name].size} parameters from #{name}" }
312
+ debug { "Parameters read: #{@param_cache[name].inspect}" }
313
+ end
314
+ if @header_line_regex
315
+ @headers_cache[name] = parse_header_line(comments)
316
+ info { "Read #{@headers_cache[name].size} column names from #{name}" }
317
+ debug { "Got: #{@headers_cache[name].inspect}" }
318
+ end
242
319
  end
320
+ ## @todo These are not very satisfying; ideally, the data
321
+ ## information should be embedded into @cache[name] rather
322
+ ## than as external variables. Well...
323
+ @current_parameters = @param_cache[name]
324
+ @current_header = @headers_cache[name]
243
325
  return @cache[name]
244
326
  end
245
327
 
@@ -268,17 +350,30 @@ EOD
268
350
  end
269
351
 
270
352
  return Dataset.dataset_from_spec(set, col_spec) do |col|
271
- get_data_column(col, compute_formulas)
353
+ get_data_column(col, compute_formulas,
354
+ @current_parameters, @current_header)
272
355
  end
273
356
  end
274
357
 
275
358
  # Gets the data corresponding to the given column. If
276
359
  # _compute_formulas_ is true, the column specification is
277
360
  # taken to be a formula (in the spirit of gnuplot's)
278
- def get_data_column(column, compute_formulas = false)
361
+ def get_data_column(column, compute_formulas = false,
362
+ parameters = nil, header = nil)
279
363
  if compute_formulas
280
- formula = column.gsub(/\$(\d+)/, 'column[\1]')
281
- debug "Using formula #{formula} for column spec: #{column}"
364
+ formula = column
365
+ if parameters
366
+ for k,v in parameters
367
+ formula.gsub!(/\b#{k}\b/, v.to_s)
368
+ end
369
+ end
370
+ formula.gsub!(/\$(\d+)/, 'column[\1]')
371
+ if header
372
+ for k,v in header
373
+ formula.gsub!("$#{k}$", "column[#{v}]")
374
+ end
375
+ end
376
+ debug { "Using formula #{formula} for column spec: #{column}" }
282
377
  return Dvector.compute_formula(formula,
283
378
  @current_data,
284
379
  @included_modules)