optimus-ep 0.6.91 → 0.8.0
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 +13 -0
- data/{License.txt → LICENSE} +1 -1
- data/{Manifest.txt → Manifest} +23 -11
- data/{README.txt → README} +1 -1
- data/Rakefile +9 -10
- data/autotest/discover.rb +1 -0
- data/bin/eprime2tabfile +10 -10
- data/bin/extract_timings +4 -4
- data/lib/eprimetab_parser.rb +3 -3
- data/lib/excel_parser.rb +2 -2
- data/lib/expression_parser/evaluators.rb +188 -0
- data/lib/expression_parser/expressions.rb +173 -0
- data/lib/log_file_parser.rb +9 -9
- data/lib/optimus.rb +30 -0
- data/lib/{eprime_data.rb → optimus_data.rb} +12 -29
- data/lib/{eprime_reader.rb → optimus_reader.rb} +27 -13
- data/lib/parsed_calculator.rb +92 -0
- data/lib/raw_tab_parser.rb +3 -3
- data/lib/runners/generic_runner.rb +7 -7
- data/lib/runners/yaml_template/option_parser.rb +33 -0
- data/lib/runners/yaml_template/runner.rb +19 -0
- data/lib/tabfile_parser.rb +6 -6
- data/lib/tabfile_writer.rb +7 -7
- data/lib/transformers/basic_transformer.rb +35 -24
- data/lib/transformers/column_calculator.rb +131 -326
- data/lib/transformers/multipasser.rb +10 -6
- data/lib/transformers/row_filter.rb +7 -12
- data/lib/transformers/timing_extractor.rb +3 -3
- data/lib/version.rb +3 -3
- data/lib/writers/stimtimes_writer.rb +6 -6
- data/optimus-ep.gemspec +37 -0
- data/spec/eprimetab_parser_spec.rb +7 -7
- data/spec/excel_parser_spec.rb +6 -6
- data/spec/expression_parser/evaluators_spec.rb +241 -0
- data/spec/expression_parser/expressions_spec.rb +119 -0
- data/spec/log_file_parser_spec.rb +30 -30
- data/spec/{eprime_data_spec.rb → optimus_data_spec.rb} +20 -20
- data/spec/{eprime_reader_spec.rb → optimus_reader_spec.rb} +36 -24
- data/spec/parsed_calculator_spec.rb +112 -0
- data/spec/raw_tab_parser_spec.rb +26 -0
- data/spec/runners/generic_runner_spec.rb +5 -12
- data/spec/runners/yaml_template/option_parser_spec.rb +25 -0
- data/spec/runners/yaml_template/runner_spec.rb +20 -0
- data/spec/samples/optimus_log.txt +103 -103
- data/spec/samples/optimus_log_utf16le.txt +0 -0
- data/spec/samples/raw_tsv.txt +4 -0
- data/spec/spec_helper.rb +75 -12
- data/spec/tabfile_parser_spec.rb +18 -18
- data/spec/tabfile_writer_spec.rb +12 -12
- data/spec/transformers/basic_transformer_spec.rb +18 -8
- data/spec/transformers/column_calculator_spec.rb +109 -364
- data/spec/transformers/multipasser_spec.rb +14 -7
- data/spec/transformers/row_filter_spec.rb +11 -6
- data/spec/transformers/timing_extractor_spec.rb +8 -8
- data/spec/writers/stimtimes_writer_spec.rb +3 -3
- metadata +103 -50
- data/History.txt +0 -45
- data/lib/calculator.rb +0 -51
- data/lib/eprime.rb +0 -24
- data/spec/calculator_spec.rb +0 -70
@@ -1,381 +1,186 @@
|
|
1
1
|
# Part of the Optimus package for managing E-Prime data
|
2
2
|
#
|
3
|
-
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
3
|
+
# Copyright (C) 2008-09 Board of Regents of the University of Wisconsin System
|
4
4
|
#
|
5
5
|
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
6
|
# Imaging and Behavior, University of Wisconsin - Madison
|
7
7
|
|
8
|
-
require '
|
9
|
-
|
10
|
-
module Eprime
|
8
|
+
require 'parsed_calculator'
|
9
|
+
module Optimus
|
11
10
|
module Transformers
|
12
11
|
|
13
|
-
# This implements columnwise
|
14
|
-
|
12
|
+
# This implements columnwise operations with a new shiny parser
|
13
|
+
|
14
|
+
# Column types:
|
15
15
|
# 1: Data columns -- columns backed directly by data
|
16
16
|
# 2: Computed columns -- columns computed by numerical operations of other columns in the same row
|
17
|
-
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# Currently, counter columns may behave strangely when used in and using computed columns -- a parser
|
22
|
-
# like the computed columns' parser is really needed.
|
17
|
+
|
18
|
+
# note: to determine if number: ^(((\d{1,3})(,\d{3})*)|(\d+))(.\d+)?$
|
19
|
+
# Better: If you've got funny numbers, coerce into numericness. Make
|
20
|
+
# coercion very robust.
|
23
21
|
|
24
22
|
class ColumnCalculator
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
COLUMN_TYPES = %w(data_cols computed_cols copydown_cols counter_cols)
|
23
|
+
attr_accessor :data
|
24
|
+
attr_accessor :sort_expression
|
25
|
+
|
29
26
|
include Enumerable
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
@
|
42
|
-
end
|
43
|
-
|
44
|
-
# Makes this into a static Eprime::Data object
|
45
|
-
def to_eprime_data
|
46
|
-
computed
|
27
|
+
|
28
|
+
DEFAULT_COL_OPTS = {
|
29
|
+
:reset_when => true,
|
30
|
+
:count_when => false,
|
31
|
+
:count_by => :next
|
32
|
+
}
|
33
|
+
def initialize(parser = Optimus::ParsedCalculator::ExpressionParser.new)
|
34
|
+
@computed_column_names = []
|
35
|
+
@computed_columns = {}
|
36
|
+
@computed_data = nil
|
37
|
+
@parser = parser
|
38
|
+
@sort_expression = nil
|
47
39
|
end
|
48
|
-
|
40
|
+
|
49
41
|
def data=(data)
|
50
42
|
@data = data
|
51
|
-
|
52
|
-
@data.columns.each do |col_name|
|
53
|
-
@data_cols << DataColumn.new(col_name, @data)
|
54
|
-
end
|
55
|
-
set_columns!
|
43
|
+
reset!
|
56
44
|
end
|
57
|
-
|
58
|
-
def
|
59
|
-
|
45
|
+
|
46
|
+
def sort_expression=(value)
|
47
|
+
@sort_expression = Evaluatable.new(value, @parser)
|
60
48
|
end
|
61
|
-
|
62
|
-
def
|
63
|
-
|
49
|
+
|
50
|
+
def computed_column(name, start_val, options = {})
|
51
|
+
if columns.include?(name)
|
52
|
+
raise DuplicateColumnError.new("Can't add duplicate column name #{name}")
|
53
|
+
end
|
54
|
+
sve = Evaluatable.new(start_val, @parser)
|
55
|
+
@computed_column_names << name
|
56
|
+
new_opts = DEFAULT_COL_OPTS.merge(options)
|
57
|
+
DEFAULT_COL_OPTS.keys.each do |key|
|
58
|
+
new_opts[key] = Evaluatable.new(new_opts[key], @parser)
|
59
|
+
end
|
60
|
+
@computed_columns[name] = ComputedColumn.new(
|
61
|
+
name, sve, new_opts
|
62
|
+
)
|
63
|
+
reset!
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
def column(col_id)
|
69
|
-
index = column_index(col_id)
|
70
|
-
raise IndexError.new("#{col_id} does not exist") if index.nil?
|
71
|
-
return @columns_intern[index]
|
66
|
+
def copydown_column(new_name, old_name)
|
67
|
+
computed_column(new_name, "{#{old_name}}", :reset_when => "{#{old_name}}")
|
72
68
|
end
|
73
69
|
|
74
|
-
def
|
75
|
-
|
70
|
+
def counter_column(name, start_val = 1, options = {})
|
71
|
+
computed_column(name, start_val, options = {})
|
76
72
|
end
|
77
73
|
|
78
74
|
def columns
|
79
|
-
@columns
|
80
|
-
end
|
81
|
-
|
82
|
-
def computed_column(name, expression)
|
83
|
-
@computed_cols << ComputedColumn.new(name, Expression.new(expression))
|
84
|
-
set_columns!
|
85
|
-
end
|
86
|
-
|
87
|
-
def copydown_column(name, copied_name)
|
88
|
-
@copydown_cols << CopydownColumn.new(name, copied_name)
|
89
|
-
set_columns!
|
90
|
-
end
|
91
|
-
|
92
|
-
def counter_column(name, options = {})
|
93
|
-
@counter_cols << CounterColumn.new(name, options)
|
94
|
-
set_columns!
|
95
|
-
end
|
96
|
-
|
97
|
-
def sort_expression=(expr)
|
98
|
-
# The name 'sorter' is utterly arbitrary and never used
|
99
|
-
@sorter = ComputedColumn.new('sorter', Expression.new(expr))
|
100
|
-
@computed = nil
|
101
|
-
end
|
102
|
-
|
103
|
-
def sort_expression
|
104
|
-
@sorter.to_s
|
105
|
-
end
|
106
|
-
|
107
|
-
def each(&block)
|
108
|
-
computed.each(&block)
|
109
|
-
end
|
110
|
-
|
111
|
-
def self.compute(numeric_expression)
|
112
|
-
@@calculator.compute(numeric_expression)
|
75
|
+
@data.columns + @computed_column_names
|
113
76
|
end
|
114
|
-
|
115
|
-
private
|
116
77
|
|
117
|
-
def
|
118
|
-
|
78
|
+
def each(&block)
|
79
|
+
computed_data.each(&block)
|
119
80
|
end
|
120
81
|
|
121
|
-
def
|
122
|
-
|
123
|
-
if @column_indexes[column.name]
|
124
|
-
raise ComputationError.new("#{column.name} already exists!")
|
125
|
-
end
|
126
|
-
# Save the index
|
127
|
-
@column_indexes[@columns_intern.size] = @columns_intern.size
|
128
|
-
@column_indexes[column.name] = @columns_intern.size
|
129
|
-
@columns_intern << column
|
130
|
-
@columns << column.name
|
82
|
+
def [](index)
|
83
|
+
computed_data[index]
|
131
84
|
end
|
132
85
|
|
133
|
-
|
134
|
-
@columns = []
|
135
|
-
@columns_intern = []
|
136
|
-
@column_indexes = {}
|
137
|
-
COLUMN_TYPES.each do |type|
|
138
|
-
ar = instance_variable_get("@#{type}")
|
139
|
-
ar.each do |col|
|
140
|
-
add_column(col)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
@computed = nil
|
144
|
-
end
|
86
|
+
private
|
145
87
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
#
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
# we go over each column type specifically. When counter columns
|
162
|
-
# work better, we can rearchitect this a bit.
|
163
|
-
COLUMN_TYPES.each do |type|
|
164
|
-
ar = instance_variable_get("@#{type}")
|
165
|
-
ar.each do |col|
|
166
|
-
row.compute(col.name)
|
167
|
-
end
|
88
|
+
def reset!
|
89
|
+
@computed_data = nil
|
90
|
+
end
|
91
|
+
|
92
|
+
# Strategy: Compute everything and return it. No lazy-evaluation stuff
|
93
|
+
# to worry about -- we just return a vanilla Optimus::Data object.
|
94
|
+
def computed_data
|
95
|
+
return @computed_data if @computed_data
|
96
|
+
@computed_data = Optimus::Data.new(columns)
|
97
|
+
@computed_data.merge!(@data)
|
98
|
+
@computed_data.each do |row|
|
99
|
+
@computed_column_names.each do |col|
|
100
|
+
row[col] = @computed_columns[col].evaluate(
|
101
|
+
:row => row, :computed_columns => @computed_columns
|
102
|
+
)
|
168
103
|
end
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
# make it a float, so we don't need to
|
174
|
-
# sort on strings like "-31" (which doesn't work)
|
175
|
-
begin
|
176
|
-
sv = Kernel.Float(sv)
|
177
|
-
rescue ArgumentError
|
178
|
-
# If this fails, it's OK -- we just won't convert.
|
104
|
+
if @sort_expression.respond_to? :evaluate
|
105
|
+
row.sort_value = @sort_expression.evaluate(
|
106
|
+
:row => row, :computed_columns => @computed_columns
|
107
|
+
)
|
179
108
|
end
|
180
|
-
new_row = @computed.add_row
|
181
|
-
new_row.sort_value = sv
|
182
|
-
new_row.values = row.values
|
183
109
|
end
|
184
|
-
@computed
|
185
110
|
end
|
186
111
|
|
187
|
-
class
|
188
|
-
|
189
|
-
|
190
|
-
|
112
|
+
class ComputedColumn
|
113
|
+
COUNTERS = {
|
114
|
+
:next => lambda {|val|
|
115
|
+
return val.succ if val.respond_to? :succ
|
116
|
+
return val + 1
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
def initialize(name, reset_exp, options = {})
|
191
121
|
@name = name
|
122
|
+
@reset_exp = reset_exp
|
123
|
+
@reset_when = options[:reset_when]
|
124
|
+
@count_when = options[:count_when]
|
125
|
+
@count_by = options[:count_by]
|
126
|
+
@current_value = nil
|
192
127
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
class DataColumn < Column
|
201
|
-
def initialize(name, data)
|
202
|
-
@data_index = data.find_column_index(name)
|
203
|
-
@data = data
|
204
|
-
super(name)
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
class CopydownColumn < Column
|
209
|
-
def initialize(name, copied_name)
|
210
|
-
super(name)
|
211
|
-
@last_val = ''
|
212
|
-
@copied_name = copied_name
|
213
|
-
end
|
214
|
-
|
215
|
-
def compute(row, path = [])
|
216
|
-
if !row[@copied_name].to_s.empty?
|
217
|
-
@last_val = row[@copied_name].to_s
|
128
|
+
|
129
|
+
def evaluate(*args)
|
130
|
+
if @reset_when.bool_eval(*args)
|
131
|
+
@current_value = @reset_exp.evaluate(*args)
|
218
132
|
end
|
219
|
-
|
220
|
-
|
221
|
-
end
|
222
|
-
|
223
|
-
class ComputedColumn < Column
|
224
|
-
|
225
|
-
def initialize(name, expression)
|
226
|
-
@expression = expression
|
227
|
-
super(name)
|
133
|
+
next_val! if @count_when.bool_eval(*args)
|
134
|
+
return @current_value
|
228
135
|
end
|
229
|
-
|
230
|
-
def compute(row, path = [])
|
231
|
-
return super(row) if super(row)
|
232
136
|
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
if
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
# Allow defining the column computation as a lambda
|
243
|
-
return @expression.expr.call(row) if @expression.expr.respond_to? :call
|
244
|
-
|
245
|
-
|
246
|
-
column_names = @expression.columns
|
247
|
-
column_names.each do |col_name|
|
248
|
-
col = row.find_column(col_name)
|
249
|
-
val = col.compute(row, path+[@name])
|
250
|
-
if val.to_s.empty?
|
251
|
-
val = "0"
|
252
|
-
end
|
253
|
-
compute_str.gsub!("{#{col_name}}", val)
|
137
|
+
private
|
138
|
+
def next_val!(*args)
|
139
|
+
return if @current_value.nil?
|
140
|
+
cval = @count_by.evaluate(*args)
|
141
|
+
counter = COUNTERS[cval] || cval
|
142
|
+
if counter.respond_to?(:call)
|
143
|
+
@current_value = counter.call(@current_value)
|
144
|
+
else
|
145
|
+
@current_value += counter
|
254
146
|
end
|
255
|
-
return ColumnCalculator.compute(compute_str)
|
256
147
|
end
|
148
|
+
end # class ComputedColumn
|
257
149
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
:count_when => lambda {|row| true},
|
265
|
-
:reset_when => lambda {|row| false}
|
266
|
-
}
|
267
|
-
def initialize(name, options)
|
268
|
-
@options = STANDARD_OPTS.merge(options)
|
269
|
-
@start_value = @options[:start_value]
|
270
|
-
@count_by = @options[:count_by]
|
271
|
-
@count_when = @options[:count_when]
|
272
|
-
@reset_when = @options[:reset_when]
|
273
|
-
@current_value = @start_value
|
274
|
-
super(name)
|
275
|
-
end
|
276
|
-
|
277
|
-
def compute(row, path = [])
|
278
|
-
if @reset_when.call(row)
|
279
|
-
@current_value = @start_value
|
280
|
-
end
|
281
|
-
if @current_value.respond_to? :call
|
282
|
-
@current_value = @current_value.call(row)
|
150
|
+
class Evaluatable
|
151
|
+
def initialize(target, parser = nil)
|
152
|
+
if target.is_a? String
|
153
|
+
@target = parser.parse(target)
|
154
|
+
else
|
155
|
+
@target = target
|
283
156
|
end
|
157
|
+
end
|
284
158
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
else
|
291
|
-
@current_value = @current_value + @count_by
|
292
|
-
end
|
159
|
+
def evaluate(*args)
|
160
|
+
# Check for magicality
|
161
|
+
if @target == :once
|
162
|
+
@target = false
|
163
|
+
return true
|
293
164
|
end
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
class Row
|
300
|
-
attr_reader :values
|
301
|
-
attr_accessor :sort_value
|
302
|
-
|
303
|
-
def initialize(parent, rowdata)
|
304
|
-
@parent = parent
|
305
|
-
@rowdata = rowdata
|
306
|
-
@values = []
|
307
|
-
# Add all the data columns to @values
|
308
|
-
rowdata.columns.each do |dcol_name|
|
309
|
-
index = @parent.column_index(dcol_name)
|
310
|
-
rd = rowdata[dcol_name]
|
311
|
-
begin
|
312
|
-
ci = values[index]
|
313
|
-
rescue Exception => e
|
314
|
-
raise e
|
315
|
-
end
|
316
|
-
@values[index] = rowdata[dcol_name]
|
165
|
+
# If we don't have a call method or an evaluate method, just
|
166
|
+
# this as our own default method.
|
167
|
+
if not [:call, :evaluate].any? {|msg| @target.respond_to? msg}
|
168
|
+
return @target
|
317
169
|
end
|
318
|
-
@
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
raise IndexError.new("#{col_id} does not exist")
|
170
|
+
if @target.respond_to? :call
|
171
|
+
row = (args.last || {})[:row] || []
|
172
|
+
return @target.call(row)
|
173
|
+
else
|
174
|
+
return @target.evaluate(*args)
|
324
175
|
end
|
325
|
-
return @values[@parent.column_index(col_id)]
|
326
|
-
end
|
327
|
-
|
328
|
-
def find_column(column_name)
|
329
|
-
@parent.column(column_name)
|
330
176
|
end
|
331
|
-
|
332
|
-
def columns
|
333
|
-
@parent.columns
|
334
|
-
end
|
335
|
-
|
336
|
-
|
337
|
-
# Recursively compute this column name and every column on which it depends
|
338
|
-
def compute(col_name)
|
339
|
-
raise ArgumentError.new("compute requires a column name") unless col_name.is_a? String
|
340
177
|
|
341
|
-
|
342
|
-
|
343
|
-
val
|
344
|
-
@values[index] = val
|
178
|
+
def bool_eval(*args)
|
179
|
+
val = self.evaluate(*args)
|
180
|
+
return false if val == ''
|
345
181
|
return val
|
346
182
|
end
|
347
|
-
|
348
|
-
|
349
|
-
@sort_value <=> other_row.sort_value
|
350
|
-
end
|
351
|
-
end
|
352
|
-
|
353
|
-
|
354
|
-
class Expression
|
355
|
-
attr_reader :columns
|
356
|
-
attr_reader :expr
|
357
|
-
|
358
|
-
COLUMN_FINDER = /\{([^}]*)\}/ # Finds strings like {foo} and {bar}
|
359
|
-
def initialize(expr_string)
|
360
|
-
@expr = expr_string
|
361
|
-
unless expr_string.is_a? Proc
|
362
|
-
@columns = find_columns(expr_string).freeze
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
def to_s
|
367
|
-
@expr.to_s.dup
|
368
|
-
end
|
369
|
-
|
370
|
-
private
|
371
|
-
def find_columns(str)
|
372
|
-
return str.scan(COLUMN_FINDER).flatten
|
373
|
-
end
|
374
|
-
end
|
375
|
-
|
376
|
-
class ComputationError < Exception
|
377
|
-
|
378
|
-
end
|
379
|
-
end
|
183
|
+
end# class Evaluatable
|
184
|
+
end # class ColumnCalculator
|
380
185
|
end
|
381
|
-
end
|
186
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Part of the Optimus package for managing E-Prime data
|
2
2
|
#
|
3
|
-
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
3
|
+
# Copyright (C) 2008-09 Board of Regents of the University of Wisconsin System
|
4
4
|
#
|
5
5
|
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
6
|
# Imaging and Behavior, University of Wisconsin - Madison
|
@@ -20,14 +20,18 @@
|
|
20
20
|
|
21
21
|
require 'transformers/column_calculator'
|
22
22
|
require 'transformers/row_filter'
|
23
|
+
require 'parsed_calculator'
|
23
24
|
|
24
|
-
module
|
25
|
+
module Optimus
|
25
26
|
module Transformers
|
26
27
|
class Multipasser
|
27
28
|
|
28
29
|
class Pass
|
29
30
|
attr_accessor :sort_expression, :row_filter, :computed_columns
|
30
|
-
def initialize(
|
31
|
+
def initialize(
|
32
|
+
sort_expression = "1",
|
33
|
+
row_filter = lambda{|r| true},
|
34
|
+
computed_columns = [])
|
31
35
|
@sort_expression = sort_expression
|
32
36
|
@row_filter = row_filter
|
33
37
|
@computed_columns = computed_columns
|
@@ -56,7 +60,7 @@ module Eprime
|
|
56
60
|
end
|
57
61
|
|
58
62
|
def add_pass(*args)
|
59
|
-
|
63
|
+
reset!
|
60
64
|
if args[0].instance_of? Pass
|
61
65
|
p = args[0]
|
62
66
|
else
|
@@ -80,13 +84,13 @@ module Eprime
|
|
80
84
|
@computed = @data
|
81
85
|
return @computed
|
82
86
|
end
|
83
|
-
@computed =
|
87
|
+
@computed = Optimus::Data.new
|
84
88
|
# Just add a simple pass if we don't have any...
|
85
89
|
@passes.each do |pass|
|
86
90
|
# We want to duplicate the data, add a sort expression to it, add
|
87
91
|
# computed columns, filter it, and then merge it into the complete
|
88
92
|
# dataset.
|
89
|
-
#cur_data = @data.
|
93
|
+
#cur_data = @data.to_optimus_data
|
90
94
|
comp_data = ColumnCalculator.new
|
91
95
|
comp_data.data = @data
|
92
96
|
comp_data.sort_expression = pass.sort_expression
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# Part of the Optimus package for managing E-Prime data
|
2
2
|
#
|
3
|
-
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
3
|
+
# Copyright (C) 2008-09 Board of Regents of the University of Wisconsin System
|
4
4
|
#
|
5
5
|
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
6
|
# Imaging and Behavior, University of Wisconsin - Madison
|
7
7
|
|
8
|
-
module
|
8
|
+
module Optimus
|
9
9
|
module Transformers
|
10
10
|
|
11
|
-
# Implements a row-wise filter for
|
11
|
+
# Implements a row-wise filter for optimus data.
|
12
12
|
# Right now it requires a proc; I'll do something better with a little
|
13
13
|
# DSL later.
|
14
14
|
class RowFilter
|
@@ -20,7 +20,7 @@ module Eprime
|
|
20
20
|
@computed = nil
|
21
21
|
end
|
22
22
|
|
23
|
-
def
|
23
|
+
def to_optimus_data
|
24
24
|
computed
|
25
25
|
end
|
26
26
|
|
@@ -32,7 +32,7 @@ module Eprime
|
|
32
32
|
|
33
33
|
def computed
|
34
34
|
return @computed if @computed
|
35
|
-
@computed =
|
35
|
+
@computed = Optimus::Data.new(@data.columns)
|
36
36
|
@data.find_all{ |row|
|
37
37
|
match?(row)
|
38
38
|
}.each { |row|
|
@@ -46,13 +46,8 @@ module Eprime
|
|
46
46
|
def match?(row)
|
47
47
|
if @filter.is_a? Proc
|
48
48
|
return @filter.call(row)
|
49
|
-
elsif @filter.
|
50
|
-
|
51
|
-
# only 'equals' is supported for comparators
|
52
|
-
if @filter[1].downcase != 'equals'
|
53
|
-
raise ArgumentError.new('Only equals is supported in filtering')
|
54
|
-
end
|
55
|
-
return row[@filter[0]].to_s == @filter[2].to_s
|
49
|
+
elsif @filter.respond_to? :to_bool
|
50
|
+
return @filter.to_bool(:row => row)
|
56
51
|
end
|
57
52
|
end
|
58
53
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Part of the Optimus package for managing E-Prime data
|
2
2
|
#
|
3
|
-
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
3
|
+
# Copyright (C) 2008-09 Board of Regents of the University of Wisconsin System
|
4
4
|
#
|
5
5
|
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
6
|
# Imaging and Behavior, University of Wisconsin - Madison
|
@@ -18,7 +18,7 @@
|
|
18
18
|
# the guts of the logic to extract stimuli.
|
19
19
|
require 'transformers/basic_transformer'
|
20
20
|
|
21
|
-
module
|
21
|
+
module Optimus
|
22
22
|
module Transformers
|
23
23
|
class TimingExtractor < BasicTransformer
|
24
24
|
def initialize(data)
|
@@ -54,7 +54,7 @@ module Eprime
|
|
54
54
|
|
55
55
|
def extract!
|
56
56
|
return if @extracted_data
|
57
|
-
@extracted_data =
|
57
|
+
@extracted_data = Optimus::Data.new
|
58
58
|
@stim_schemas.each do |ss|
|
59
59
|
matches = processed.find_all(&ss['row_filter'])
|
60
60
|
matches.each do |row|
|