optimus-ep 0.5
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/Rakefile +9 -0
- data/bin/eprime2tabfile +165 -0
- data/bin/stim.times +5 -0
- data/bin/stim1.times +5 -0
- data/bin/stim1_b.times +5 -0
- data/bin/stim1_c.times +5 -0
- data/bin/stim1_d.times +5 -0
- data/bin/test_data.txt +278 -0
- data/bin/test_data2.txt +277 -0
- data/bin/test_eprime_stimfile.rb +20 -0
- data/lib/calculator.rb +49 -0
- data/lib/column_calculator.rb +308 -0
- data/lib/eprime.rb +23 -0
- data/lib/eprime_data.rb +154 -0
- data/lib/eprime_reader.rb +105 -0
- data/lib/eprimetab_parser.rb +21 -0
- data/lib/excel_parser.rb +21 -0
- data/lib/log_file_parser.rb +208 -0
- data/lib/row_filter.rb +40 -0
- data/lib/tabfile_parser.rb +55 -0
- data/lib/tabfile_writer.rb +44 -0
- data/lib/writers/stimtimes_writer.rb +97 -0
- data/spec/calculator_spec.rb +56 -0
- data/spec/column_calculator_spec.rb +368 -0
- data/spec/eprime_data_spec.rb +202 -0
- data/spec/eprime_reader_spec.rb +115 -0
- data/spec/eprimetab_parser_spec.rb +23 -0
- data/spec/excel_parser_spec.rb +26 -0
- data/spec/log_file_parser_spec.rb +156 -0
- data/spec/row_filter_spec.rb +32 -0
- data/spec/samples/bad_excel_tsv.txt +4 -0
- data/spec/samples/corrupt_log_file.txt +116 -0
- data/spec/samples/eprime_tsv.txt +7 -0
- data/spec/samples/excel_tsv.txt +5 -0
- data/spec/samples/optimus_log.txt +110 -0
- data/spec/samples/short_columns.txt +1 -0
- data/spec/samples/sorted_columns.txt +1 -0
- data/spec/samples/std_columns.txt +1 -0
- data/spec/samples/unknown_type.txt +2 -0
- data/spec/samples/unreadable_file +1 -0
- data/spec/spec_helper.rb +98 -0
- data/spec/tabfile_parser_spec.rb +62 -0
- data/spec/tabfile_writer_spec.rb +91 -0
- data/spec/writers/stimtimes_writer_spec.rb +16 -0
- metadata +106 -0
@@ -0,0 +1,368 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
4
|
+
#
|
5
|
+
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
|
+
# Imaging and Behavior, University of Wisconsin - Madison
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
9
|
+
require File.join(File.dirname(__FILE__), '../lib/eprime')
|
10
|
+
|
11
|
+
require 'column_calculator'
|
12
|
+
|
13
|
+
include EprimeTestHelper
|
14
|
+
|
15
|
+
NEW_COLUMN = 'NEW_COLUMN'
|
16
|
+
|
17
|
+
shared_examples_for "Eprime::ColumnCalculator with edata" do
|
18
|
+
it "should have the proper size" do
|
19
|
+
@calc.size.should == @edata.size
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow accessing rows" do
|
23
|
+
@calc[0].should be_an_instance_of(Eprime::ColumnCalculator::Row)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return data" do
|
27
|
+
@calc[0]['stim_time'].should == @edata[0]['stim_time']
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should compute column indexes for data column names" do
|
31
|
+
@calc.column_index('stim_time').should == 0
|
32
|
+
@calc.column_index('run_start').should == 1
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should find column indexes for data columns" do
|
36
|
+
@calc.column_index(0).should == 0
|
37
|
+
@calc.column_index(1).should == 1
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return nil when searching for out-of-bound named indexes" do
|
41
|
+
@calc.column_index('not_present').should be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return nil when searching for out-of-bound numeric indexes" do
|
45
|
+
@calc.column_index(@calc.columns.size).should be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should allow setting a computed column" do
|
49
|
+
lambda {
|
50
|
+
@calc.computed_column NEW_COLUMN, "1"
|
51
|
+
}.should_not raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should allow setting a copydown column" do
|
55
|
+
lambda {
|
56
|
+
@calc.copydown_column 'sparse_copy', 'sparse'
|
57
|
+
}.should_not raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should contain new name when setting computed column" do
|
61
|
+
@calc.computed_column NEW_COLUMN, "1"
|
62
|
+
@calc.columns.should include(NEW_COLUMN)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should contain the new name when setting copydown column" do
|
66
|
+
@calc.copydown_column 'sparse_copy', 'sparse'
|
67
|
+
@calc.columns.should include('sparse_copy')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should increse in column size when setting computed column" do
|
71
|
+
s1 = @calc.columns.size
|
72
|
+
@calc.computed_column NEW_COLUMN, "1"
|
73
|
+
s2 = @calc.columns.size
|
74
|
+
s2.should == s1+1
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should compute the proper column index for computed columns" do
|
78
|
+
prev_max_index = @calc.columns.size-1
|
79
|
+
@calc.computed_column NEW_COLUMN, "1"
|
80
|
+
@calc.column_index(NEW_COLUMN).should == prev_max_index+1
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should find numeric indexes for computed columns" do
|
84
|
+
get_index = @calc.columns.size
|
85
|
+
@calc.computed_column NEW_COLUMN, '1'
|
86
|
+
@calc.column_index(get_index).should == get_index
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should allow named indexing for computed columns" do
|
90
|
+
@calc.computed_column NEW_COLUMN, "1"
|
91
|
+
lambda {
|
92
|
+
@calc[0][NEW_COLUMN]
|
93
|
+
}.should_not raise_error
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should allow numeric indexing for computed columns" do
|
97
|
+
@calc.computed_column NEW_COLUMN, "1"
|
98
|
+
lambda {
|
99
|
+
@calc[0][NEW_COLUMN]
|
100
|
+
}.should_not raise_error
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should raise when name-indexing nonexistent column" do
|
104
|
+
lambda {
|
105
|
+
@calc[0][NEW_COLUMN]
|
106
|
+
}.should raise_error(IndexError)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should raise when numerically indexing nonexistent column" do
|
110
|
+
lambda {
|
111
|
+
@calc[0][@calc.columns.size]
|
112
|
+
}.should raise_error(IndexError)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should raise when adding computed column with existing column name" do
|
116
|
+
lambda {
|
117
|
+
@calc.computed_column @edata.columns[0], '1'
|
118
|
+
}.should raise_error(Eprime::ColumnCalculator::ComputationError)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
describe Eprime::ColumnCalculator do
|
124
|
+
before :each do
|
125
|
+
@edata = mock_edata
|
126
|
+
@calc = Eprime::ColumnCalculator.new
|
127
|
+
@calc.data = @edata
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "(with no computed columns)" do
|
131
|
+
it "should should have only static columns" do
|
132
|
+
@calc.columns.should == @edata.columns
|
133
|
+
end
|
134
|
+
|
135
|
+
it_should_behave_like "Eprime::ColumnCalculator with edata"
|
136
|
+
end
|
137
|
+
|
138
|
+
describe "(statically computing columns)" do
|
139
|
+
|
140
|
+
it "should return data for data columns" do
|
141
|
+
@edata[0]['stim_time'].should_not be_nil
|
142
|
+
@calc[0].compute('stim_time').should == @edata[0]['stim_time']
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should compute static columns on single rows" do
|
146
|
+
@calc.computed_column "always_1", "1"
|
147
|
+
@calc[0].compute("always_1").should == "1"
|
148
|
+
end
|
149
|
+
|
150
|
+
it "should compute on single rows with some math" do
|
151
|
+
@calc.computed_column "test", "(3+2)*4"
|
152
|
+
@calc[0].compute("test").should == ((3+2)*4).to_s
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should allow adding two columns" do
|
156
|
+
@calc.computed_column "always_1", "1"
|
157
|
+
@calc.computed_column "test", "(3+2)*4"
|
158
|
+
@calc[0].compute("always_1").should == "1"
|
159
|
+
@calc[0].compute("test").should == ((3+2)*4).to_s
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should raise when computing nonexistent column" do
|
163
|
+
lambda {
|
164
|
+
@calc[0].compute('nonexistent')
|
165
|
+
}.should raise_error(IndexError)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should compute constants via indexing" do
|
169
|
+
@calc.computed_column "always_1", "1"
|
170
|
+
@calc[0]["always_1"].should == "1"
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should compute with add, mul, and grouping via indexing" do
|
174
|
+
# See calculator_spec.rb for exhaustive testing of the parser
|
175
|
+
@calc.computed_column "add_mul", "5*(6+2)"
|
176
|
+
@calc.each do |row|
|
177
|
+
row["add_mul"].should == (5*(6+2)).to_s
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should work with multiple computed columns via indexing" do
|
182
|
+
@calc.computed_column "always_1", "1"
|
183
|
+
@calc.computed_column "add_mul", "5*(6+2)"
|
184
|
+
|
185
|
+
@calc.each do |row|
|
186
|
+
row["always_1"].should == "1"
|
187
|
+
row["add_mul"].should == (5*(6+2)).to_s
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "(with computed columns)" do
|
193
|
+
|
194
|
+
it "should compute based on data columns" do
|
195
|
+
@calc.computed_column "stim_time_s", "{stim_time}/1000"
|
196
|
+
@calc.each do |row|
|
197
|
+
row["stim_time_s"].should == (row["stim_time"].to_f/1000.0).to_s
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
it "should allow math between two columns" do
|
202
|
+
@calc.computed_column "stim_from_run", "{stim_time}-{run_start}"
|
203
|
+
@calc.each do |row|
|
204
|
+
row['stim_from_run'].should == (row['stim_time'].to_i - row['run_start'].to_i).to_s
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should allow columns based on other computed columns" do
|
209
|
+
@calc.computed_column "stim_from_run", "{stim_time}-{run_start}"
|
210
|
+
@calc.computed_column "stim_run_s", "{stim_from_run} / 1000"
|
211
|
+
@calc.each do |row|
|
212
|
+
row['stim_run_s'].should == ((row['stim_time'].to_f - row['run_start'].to_f)/1000.0).to_s
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should fail to compute with nonexistent columns" do
|
217
|
+
@calc.computed_column "borked", "{stim_time} - {not_there}"
|
218
|
+
lambda {
|
219
|
+
@calc[0]["borked"]
|
220
|
+
}.should raise_error(IndexError)
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should assume zero when a column has blank values" do
|
224
|
+
@calc.computed_column "sparse_plus_0", "{sparse} + 0"
|
225
|
+
@calc.each do |row|
|
226
|
+
row["sparse"].to_f.should == row["sparse_plus_0"].to_f
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should detect loops in column computation" do
|
231
|
+
@calc.computed_column "loop1", "{stim_time} - {run_start} - {loop3}"
|
232
|
+
@calc.computed_column "loop2", "{loop1}"
|
233
|
+
@calc.computed_column "loop3", "{loop2}"
|
234
|
+
@calc.computed_column "loop4", "{loop3}"
|
235
|
+
lambda {
|
236
|
+
@calc[0]['loop4']
|
237
|
+
}.should raise_error(Eprime::ColumnCalculator::ComputationError)
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should compute columns when there are two paths to a node" do
|
241
|
+
@calc.computed_column "c1", "{stim_time} - {run_start}"
|
242
|
+
@calc.computed_column "c2", "{c1}"
|
243
|
+
@calc.computed_column "c3", "{c1} - {c2}"
|
244
|
+
lambda {
|
245
|
+
@calc[0]["c3"]
|
246
|
+
}.should_not raise_error
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
describe "(with copydown columns)" do
|
252
|
+
before :each do
|
253
|
+
@calc.copydown_column 'sparse_copy', 'sparse'
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should work" do
|
257
|
+
last_val = ''
|
258
|
+
@calc.each do |row|
|
259
|
+
if !row['sparse'].to_s.empty?
|
260
|
+
last_val = row['sparse'].to_s
|
261
|
+
end
|
262
|
+
row['sparse_copy'].should == last_val
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe "(with counter columns)" do
|
268
|
+
it "should count up with no options" do
|
269
|
+
@calc.counter_column "count_up"
|
270
|
+
i = 0;
|
271
|
+
@calc.each do |row|
|
272
|
+
i += 1
|
273
|
+
row["count_up"].should == i
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should count from 1 when :start_value is set" do
|
278
|
+
@calc.counter_column "count_up", :start_value => 1
|
279
|
+
i = 1
|
280
|
+
@calc.each do |row|
|
281
|
+
i += 1
|
282
|
+
row["count_up"].should == i
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
it "should count down when :count_by is -1" do
|
287
|
+
@calc.counter_column "count_down", :count_by => -1
|
288
|
+
i = 0
|
289
|
+
@calc.each do |row|
|
290
|
+
i -= 1
|
291
|
+
row['count_down'].should == i
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should count by a proc when specified" do
|
296
|
+
@calc.counter_column "count_succ", :count_by => lambda {|val| val.succ}
|
297
|
+
i = 0
|
298
|
+
@calc.each do |row|
|
299
|
+
i = i.succ
|
300
|
+
row["count_succ"].should == i
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
it "should count by a symbol when specified" do
|
305
|
+
@calc.counter_column "count_succ", :count_by => :succ
|
306
|
+
i = 0
|
307
|
+
@calc.each do |row|
|
308
|
+
i = i.succ
|
309
|
+
row['count_succ'].should == i
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
it "count by a string when specified" do
|
314
|
+
@calc.counter_column "count_succ", :count_by => 'succ'
|
315
|
+
i = 0
|
316
|
+
@calc.each do |row|
|
317
|
+
i = i.succ
|
318
|
+
row['count_succ'].should == i
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should count only when :count_when is true" do
|
323
|
+
@calc.counter_column "count_on_sparse", :count_when => lambda {|row| !row['sparse'].to_s.empty? }
|
324
|
+
|
325
|
+
i = 0
|
326
|
+
@calc.each do |row|
|
327
|
+
i += 1 if !row['sparse'].to_s.empty?
|
328
|
+
row['count_on_sparse'].should == i
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should reset when :reset_when is true" do
|
333
|
+
@calc.counter_column "reset_on_sparse", :reset_when => lambda {|row| !row['sparse'].to_s.empty? }
|
334
|
+
i = 0
|
335
|
+
@calc.each do |row|
|
336
|
+
i = 0 if !row['sparse'].to_s.empty?
|
337
|
+
i += 1
|
338
|
+
row['reset_on_sparse'].should == i
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
describe Eprime::ColumnCalculator::Expression do
|
345
|
+
before :each do
|
346
|
+
@expr_str = "({stim_time}-{run_start}) / 1000"
|
347
|
+
@expr = Eprime::ColumnCalculator::Expression.new(@expr_str)
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should find two columns" do
|
351
|
+
@expr.columns.size.should == 2
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should split into stim_time and run_start" do
|
355
|
+
@expr.columns.sort.should == %w(stim_time run_start).sort
|
356
|
+
end
|
357
|
+
|
358
|
+
it "should not allow changing columns" do
|
359
|
+
lambda {
|
360
|
+
@expr.columns << 'wakka'
|
361
|
+
}.should raise_error(TypeError)
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should convert to a string" do
|
365
|
+
@expr.to_s.should == @expr_str
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
@@ -0,0 +1,202 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
4
|
+
#
|
5
|
+
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
|
+
# Imaging and Behavior, University of Wisconsin - Madison
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
9
|
+
require File.join(File.dirname(__FILE__), '../lib/eprime')
|
10
|
+
include EprimeTestHelper
|
11
|
+
|
12
|
+
INITIAL_COLUMNS = %w(col1 col2 col3 col4)
|
13
|
+
NEW_COL_1 = "new_column_1"
|
14
|
+
NEW_COL_2 = "new_column_2"
|
15
|
+
|
16
|
+
shared_examples_for "empty Eprime::Data" do
|
17
|
+
it "should have no rows" do
|
18
|
+
@data.length.should == 0
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should allow new rows" do
|
22
|
+
@data.add_row.should_not be_nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
shared_examples_for "Eprime::Data with one row" do
|
27
|
+
it "should be row-indexable" do
|
28
|
+
@data[0].should === @row # Test for identicality
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should store column values by name" do
|
32
|
+
@row[INITIAL_COLUMNS[0]] = "kitten"
|
33
|
+
@row[INITIAL_COLUMNS[0]].should == "kitten"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should reset column values" do
|
37
|
+
@row[INITIAL_COLUMNS[0]] = "kitten"
|
38
|
+
@row[INITIAL_COLUMNS[0]] = "bitten"
|
39
|
+
@row[INITIAL_COLUMNS[0]].should == "bitten"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should allow setting column values by numeric index" do
|
43
|
+
@row[INITIAL_COLUMNS[0]] = "kitten"
|
44
|
+
index = @data.find_column_index(INITIAL_COLUMNS[0])
|
45
|
+
@row[index] = "bitten"
|
46
|
+
@row[index].should == "bitten"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise when setting out-of-bound column value" do
|
50
|
+
lambda {
|
51
|
+
@row[@data.columns.length] = "kitten"
|
52
|
+
}.should raise_error(IndexError)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise IndexError when querying for nonexistent column names" do
|
56
|
+
lambda {
|
57
|
+
@row[NEW_COL_1]
|
58
|
+
}.should raise_error(IndexError)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should raise IndexError when querying for nonexistent column index" do
|
62
|
+
lambda {
|
63
|
+
@row[@data.columns.length]
|
64
|
+
}.should raise_error(IndexError)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should return nil when querying columns set in other rows" do
|
68
|
+
@row[INITIAL_COLUMNS[0]] = "kitteh"
|
69
|
+
new_row = @data.add_row
|
70
|
+
new_row[INITIAL_COLUMNS[0]].should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should get values" do
|
74
|
+
@row[INITIAL_COLUMNS[0]] = "kitten"
|
75
|
+
@row.values.should include("kitten")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe Eprime::Data do
|
80
|
+
describe "without initial columns" do
|
81
|
+
before :each do
|
82
|
+
@data = Eprime::Data.new
|
83
|
+
@d2 = mock_eprime(2,3)
|
84
|
+
@d3 = mock_eprime(2,4)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should have return an Eprime::Data object on merge" do
|
88
|
+
@data.merge(@d2).should be_an_instance_of(Eprime::Data)
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "(empty)" do
|
92
|
+
it_should_behave_like "empty Eprime::Data"
|
93
|
+
|
94
|
+
it "should have no columns at creation" do
|
95
|
+
@data.columns.length.should == 0
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should add rows on merge" do
|
99
|
+
d = @data.merge(@d2)
|
100
|
+
d.size.should == (@data.size + @d2.size)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should add rows to the original object on merge!" do
|
104
|
+
lambda {
|
105
|
+
@data.merge!(@d2, @d3)
|
106
|
+
}.should change(@data, :size).by(@d2.size + @d3.size)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should not change the original object's size on merge" do
|
110
|
+
lambda {
|
111
|
+
@data.merge(@d2, @d3)
|
112
|
+
}.should_not change(@data, :size)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "(with one row)" do
|
117
|
+
before :each do
|
118
|
+
@row = @data.add_row
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should should add rows on merge" do
|
122
|
+
d = @data.merge(@d2, @d3)
|
123
|
+
d.size.should == (@data.size + @d2.size + @d3.size)
|
124
|
+
end
|
125
|
+
|
126
|
+
it_should_behave_like "Eprime::Data with one row"
|
127
|
+
|
128
|
+
it "should add a column when setting a value in row" do
|
129
|
+
@row[NEW_COL_1] = "test_value"
|
130
|
+
@data.columns.should satisfy do |c|
|
131
|
+
c.include?(NEW_COL_1)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should not add the same column name twice" do
|
136
|
+
@row[NEW_COL_1] = "value1"
|
137
|
+
lambda {
|
138
|
+
@row[NEW_COL_1] = "value2"
|
139
|
+
}.should_not change(@data.columns, :length)
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should add a second column" do
|
143
|
+
@row[NEW_COL_1] = "value"
|
144
|
+
lambda {
|
145
|
+
@row[NEW_COL_2] = "value"
|
146
|
+
}.should change(@data.columns, :length)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe "Eprime::Data with initial columns" do
|
154
|
+
describe "without setting ignore" do
|
155
|
+
before :each do
|
156
|
+
@data = Eprime::Data.new(INITIAL_COLUMNS)
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "(empty)" do
|
160
|
+
it_should_behave_like "empty Eprime::Data"
|
161
|
+
|
162
|
+
it "should have the same number of columns as INITIAL_COLUMNS" do
|
163
|
+
@data.columns.length.should == INITIAL_COLUMNS.length
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "(with one row)" do
|
169
|
+
it_should_behave_like "Eprime::Data with one row"
|
170
|
+
|
171
|
+
before :each do
|
172
|
+
@row = @data.add_row
|
173
|
+
end
|
174
|
+
|
175
|
+
it "should raise a warning when adding a new column" do
|
176
|
+
lambda {
|
177
|
+
@row[NEW_COL_1] = "kitteh"
|
178
|
+
}.should raise_error(Eprime::ColumnAddedWarning)
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "with ignore set" do
|
185
|
+
before :each do
|
186
|
+
@data = Eprime::Data.new(INITIAL_COLUMNS, :ignore_warnings => true)
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should not raise a warning when adding a new column" do
|
190
|
+
row = @data.add_row
|
191
|
+
lambda {
|
192
|
+
row[NEW_COL_1] = "kitteh"
|
193
|
+
}.should_not raise_error
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should add new columns" do
|
197
|
+
row = @data.add_row
|
198
|
+
row[NEW_COL_1] = "kitteh"
|
199
|
+
row[NEW_COL_1].should == "kitteh"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
4
|
+
#
|
5
|
+
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
|
+
# Imaging and Behavior, University of Wisconsin - Madison
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
9
|
+
require File.join(File.dirname(__FILE__), '../lib/eprime')
|
10
|
+
include EprimeTestHelper
|
11
|
+
|
12
|
+
describe Eprime::Reader do
|
13
|
+
before(:each) do
|
14
|
+
@reader = Eprime::Reader.new
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
it "should raise error when reading nil" do
|
19
|
+
lambda {
|
20
|
+
@reader.input = (nil)
|
21
|
+
}.should raise_error
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should raise when filetype is unknown" do
|
25
|
+
File.open(UNKNOWN_FILE) do |file|
|
26
|
+
lambda { @reader.input = (file) }.should raise_error(Eprime::UnknownTypeError)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "with log files" do
|
31
|
+
before :each do
|
32
|
+
@file = File.open(LOG_FILE, 'r')
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should not raise errors on reading" do
|
36
|
+
lambda {
|
37
|
+
@reader.input = @file
|
38
|
+
}.should_not raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should detect log files" do
|
42
|
+
@reader.input = (@file)
|
43
|
+
@reader.type.should == :log
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return the Eprime::Reader::LogfileParser" do
|
47
|
+
@reader.input = @file
|
48
|
+
@reader.parser.should be_an_instance_of(Eprime::Reader::LogfileParser)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should make a non-empty Eprime::Data object" do
|
52
|
+
@reader.input = @file
|
53
|
+
data = @reader.eprime_data
|
54
|
+
data.length.should > 0
|
55
|
+
data.columns.sort.should == SORTED_COLUMNS
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should respect options" do
|
59
|
+
@reader.input = @file
|
60
|
+
@reader.options = {:columns => SHORT_COLUMNS}
|
61
|
+
lambda {
|
62
|
+
@reader.parser.options.should == {:columns => SHORT_COLUMNS}
|
63
|
+
}.should raise_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "with excel tsv files" do
|
68
|
+
|
69
|
+
before :each do
|
70
|
+
@file = File.open(EXCEL_FILE)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should detect excel csv files" do
|
74
|
+
@reader.input = @file
|
75
|
+
@reader.type.should == :excel
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should resutn the Eprime::Reader::ExcelParser" do
|
79
|
+
@reader.input = @file
|
80
|
+
@reader.parser.should be_an_instance_of(Eprime::Reader::ExcelParser)
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should make a non-empty Eprime::Data object" do
|
84
|
+
@reader.input = @file
|
85
|
+
data = @reader.eprime_data
|
86
|
+
data.length.should > 0
|
87
|
+
data.columns.sort.should == SORTED_COLUMNS
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "with eprime tsv files" do
|
93
|
+
before :each do
|
94
|
+
@file = File.open(EPRIME_FILE)
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should detect eprime csv files" do
|
98
|
+
@reader.input = @file
|
99
|
+
@reader.type.should == :eprime
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should return the Eprime::Reader::EprimetabParser" do
|
103
|
+
@reader.input = @file
|
104
|
+
@reader.parser.should be_an_instance_of(Eprime::Reader::EprimetabParser)
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should make a non-empty Eprime::Data object" do
|
108
|
+
@reader.input = @file
|
109
|
+
data = @reader.eprime_data
|
110
|
+
data.length.should > 0
|
111
|
+
data.columns.sort.should == SORTED_COLUMNS
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008 Board of Regents of the University of Wisconsin System
|
4
|
+
#
|
5
|
+
# Written by Nathan Vack <njvack@wisc.edu>, at the Waisman Laborotory for Brain
|
6
|
+
# Imaging and Behavior, University of Wisconsin - Madison
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__),'spec_helper')
|
9
|
+
require File.join(File.dirname(__FILE__), '../lib/eprime')
|
10
|
+
include EprimeTestHelper
|
11
|
+
|
12
|
+
describe Eprime::Reader::EprimetabParser do
|
13
|
+
before :each do
|
14
|
+
@file = File.open(EPRIME_FILE, 'r')
|
15
|
+
@reader = Eprime::Reader::EprimetabParser.new(@file)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should read the sample eprime file" do
|
19
|
+
lambda {
|
20
|
+
@reader.to_eprime
|
21
|
+
}.should_not raise_error
|
22
|
+
end
|
23
|
+
end
|