ctioga2 0.0 → 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog +25 -1
- data/lib/ctioga2/commands/commands.rb +13 -2
- data/lib/ctioga2/commands/doc/doc.rb +13 -17
- data/lib/ctioga2/commands/doc/documentation-commands.rb +14 -1
- data/lib/ctioga2/commands/doc/help.rb +136 -25
- data/lib/ctioga2/commands/doc/html.rb +56 -4
- data/lib/ctioga2/commands/doc/introspection.rb +45 -9
- data/lib/ctioga2/commands/doc/man.rb +7 -5
- data/lib/ctioga2/commands/doc/markup.rb +39 -12
- data/lib/ctioga2/commands/doc/wordwrap.rb +70 -0
- data/lib/ctioga2/commands/general-commands.rb +7 -4
- data/lib/ctioga2/commands/general-types.rb +27 -12
- data/lib/ctioga2/commands/interpreter.rb +2 -2
- data/lib/ctioga2/commands/parsers/command-line.rb +9 -5
- data/lib/ctioga2/commands/parsers/file.rb +5 -3
- data/lib/ctioga2/commands/type.rb +10 -3
- data/lib/ctioga2/commands/variables.rb +2 -2
- data/lib/ctioga2/data/backends/backend.rb +17 -15
- data/lib/ctioga2/data/backends/backends.rb +2 -2
- data/lib/ctioga2/data/backends/backends/gnuplot.rb +20 -5
- data/lib/ctioga2/data/backends/backends/math.rb +2 -2
- data/lib/ctioga2/data/backends/backends/text.rb +112 -17
- data/lib/ctioga2/data/backends/description.rb +10 -11
- data/lib/ctioga2/data/datacolumn.rb +73 -14
- data/lib/ctioga2/data/dataset.rb +305 -9
- data/lib/ctioga2/data/filters.rb +49 -1
- data/lib/ctioga2/data/indexed-dtable.rb +137 -0
- data/lib/ctioga2/data/point.rb +98 -7
- data/lib/ctioga2/data/stack.rb +98 -21
- data/lib/ctioga2/graphics/coordinates.rb +19 -2
- data/lib/ctioga2/graphics/elements.rb +12 -2
- data/lib/ctioga2/graphics/elements/containers.rb +14 -2
- data/lib/ctioga2/graphics/elements/contour.rb +67 -0
- data/lib/ctioga2/graphics/elements/curve2d.rb +103 -42
- data/lib/ctioga2/graphics/elements/element.rb +12 -2
- data/lib/ctioga2/graphics/elements/gradient-region.rb +94 -0
- data/lib/ctioga2/graphics/elements/parametric2d.rb +172 -0
- data/lib/ctioga2/graphics/elements/primitive.rb +37 -21
- data/lib/ctioga2/graphics/elements/region.rb +143 -0
- data/lib/ctioga2/graphics/elements/subplot.rb +92 -32
- data/lib/ctioga2/graphics/elements/tangent.rb +99 -0
- data/lib/ctioga2/graphics/elements/xyz-map.rb +126 -0
- data/lib/ctioga2/graphics/generator.rb +91 -6
- data/lib/ctioga2/graphics/legends.rb +26 -21
- data/lib/ctioga2/graphics/legends/area.rb +8 -8
- data/lib/ctioga2/graphics/legends/items.rb +5 -5
- data/lib/ctioga2/graphics/legends/storage.rb +4 -2
- data/lib/ctioga2/graphics/root.rb +24 -2
- data/lib/ctioga2/graphics/styles.rb +8 -0
- data/lib/ctioga2/graphics/styles/axes.rb +49 -23
- data/lib/ctioga2/graphics/styles/base.rb +2 -2
- data/lib/ctioga2/graphics/styles/carrays.rb +9 -2
- data/lib/ctioga2/graphics/styles/colormap.rb +272 -0
- data/lib/ctioga2/graphics/styles/curve.rb +64 -4
- data/lib/ctioga2/graphics/styles/drawable.rb +68 -9
- data/lib/ctioga2/graphics/styles/errorbar.rb +73 -0
- data/lib/ctioga2/graphics/styles/factory.rb +133 -17
- data/lib/ctioga2/graphics/styles/gradients.rb +60 -0
- data/lib/ctioga2/graphics/styles/location.rb +64 -0
- data/lib/ctioga2/graphics/styles/map-axes.rb +164 -0
- data/lib/ctioga2/graphics/styles/plot.rb +165 -62
- data/lib/ctioga2/graphics/styles/sets.rb +14 -1
- data/lib/ctioga2/graphics/styles/texts.rb +44 -34
- data/lib/ctioga2/graphics/subplot-commands.rb +94 -6
- data/lib/ctioga2/graphics/types.rb +113 -35
- data/lib/ctioga2/graphics/types/bijection.rb +3 -3
- data/lib/ctioga2/graphics/types/boundaries.rb +120 -1
- data/lib/ctioga2/graphics/types/dimensions.rb +8 -1
- data/lib/ctioga2/graphics/types/grid.rb +196 -0
- data/lib/ctioga2/graphics/types/location.rb +228 -0
- data/lib/ctioga2/graphics/types/point.rb +2 -2
- data/lib/ctioga2/log.rb +18 -18
- data/lib/ctioga2/metabuilder/type.rb +15 -3
- data/lib/ctioga2/metabuilder/types.rb +2 -2
- data/lib/ctioga2/metabuilder/types/coordinates.rb +13 -1
- data/lib/ctioga2/metabuilder/types/data.rb +50 -0
- data/lib/ctioga2/metabuilder/types/generic.rb +60 -0
- data/lib/ctioga2/metabuilder/types/lists.rb +53 -16
- data/lib/ctioga2/metabuilder/types/styles.rb +26 -45
- data/lib/ctioga2/plotmaker.rb +91 -20
- data/lib/ctioga2/postprocess.rb +8 -8
- data/lib/ctioga2/utils.rb +23 -4
- metadata +107 -75
- 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:
|
|
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
|
|
99
|
+
if o =~ /^\s*\/?([\w-]+)\s*=(.*)/
|
|
100
100
|
if cmd.has_option? $1
|
|
101
101
|
options[$1] = $2
|
|
102
102
|
else
|
|
103
|
-
error
|
|
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:
|
|
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
|
|
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
|
-
#
|
|
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:
|
|
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
|
-
#
|
|
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:
|
|
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
|
-
#
|
|
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
|
-
#
|
|
58
|
+
# \todo adapt to the new structure.
|
|
59
59
|
#
|
|
60
|
-
#
|
|
60
|
+
# \todo add back filters (with time)
|
|
61
61
|
#
|
|
62
|
-
#
|
|
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
|
-
#
|
|
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
|
|
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
|
-
#
|
|
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:
|
|
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
|
|
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
|
|
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
|
|
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:
|
|
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
|
-
#
|
|
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:
|
|
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
|
-
|
|
81
|
-
|
|
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
|
-
#
|
|
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
|
|
281
|
-
|
|
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)
|