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
data/lib/optimus.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008-09 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
|
+
# Add our lib to the search path
|
9
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
10
|
+
|
11
|
+
require 'optimus_data'
|
12
|
+
require 'version'
|
13
|
+
require 'tabfile_writer'
|
14
|
+
require 'optimus_reader'
|
15
|
+
|
16
|
+
module Optimus
|
17
|
+
|
18
|
+
class Error < RuntimeError; end
|
19
|
+
|
20
|
+
# Raised whenever an input file's type can't be detemined by Optimus::Reader
|
21
|
+
class UnknownTypeError < Error; end
|
22
|
+
|
23
|
+
# Raised whenever an input file seems to be damaged
|
24
|
+
class DamagedFileError < Error; end
|
25
|
+
|
26
|
+
# Raised when a parse fails due to loops
|
27
|
+
class EvaluationLoopError < Error; end
|
28
|
+
|
29
|
+
class DuplicateColumnError < Error; end
|
30
|
+
end
|
@@ -1,27 +1,16 @@
|
|
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
|
|
10
|
-
#
|
11
|
-
# column is added. Generally, this is an indication that Something is Funny.
|
12
|
-
class ColumnAddedWarning < Exception
|
13
|
-
# We want to be able to get the index out of this
|
14
|
-
attr_reader :index
|
15
|
-
def initialize(message, index)
|
16
|
-
@index = index
|
17
|
-
super(message)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# A generalized data structure for eprime files -- essentially just
|
10
|
+
# A generalized data structure for optimus files -- essentially just
|
22
11
|
# a table structure.
|
23
12
|
# I should be able to say:
|
24
|
-
# e_data =
|
13
|
+
# e_data = Optimus::Data.new
|
25
14
|
# e_data[0][0] for the first row / col
|
26
15
|
# e_data[0]['ExperimentName'] for the experiment name
|
27
16
|
# e_data[0][0] = "foo"
|
@@ -39,7 +28,7 @@ module Eprime
|
|
39
28
|
# One last thing: if you care about column ordering, but may be adding
|
40
29
|
# data in an arbitrary order (example: reading E-Prime log files),
|
41
30
|
# you can force a column order by passing an array of strings to
|
42
|
-
#
|
31
|
+
# Optimus::Data.new
|
43
32
|
|
44
33
|
class Data
|
45
34
|
|
@@ -57,15 +46,15 @@ module Eprime
|
|
57
46
|
end
|
58
47
|
end
|
59
48
|
|
60
|
-
# Returns a new
|
49
|
+
# Returns a new Optimus::Data object containing the data from this
|
61
50
|
# and all other data sets
|
62
51
|
def merge(*datasets)
|
63
52
|
cols = [self, *datasets].map { |d| d.columns }.flatten.uniq
|
64
|
-
d =
|
53
|
+
d = Optimus::Data.new(cols)
|
65
54
|
return d.merge!(self, *datasets)
|
66
55
|
end
|
67
56
|
|
68
|
-
# Combine more
|
57
|
+
# Combine more Optimus::Data objects into this one, in-place
|
69
58
|
def merge!(*datasets)
|
70
59
|
datasets.each do |source|
|
71
60
|
add_columns!(source.columns)
|
@@ -99,10 +88,10 @@ module Eprime
|
|
99
88
|
end
|
100
89
|
|
101
90
|
def dup
|
102
|
-
|
91
|
+
Optimus::Data.new().merge!(self)
|
103
92
|
end
|
104
93
|
|
105
|
-
alias :
|
94
|
+
alias :to_optimus_data :dup
|
106
95
|
|
107
96
|
# We mostly delegate to our rows array
|
108
97
|
def method_missing(method, *args, &block)
|
@@ -130,13 +119,7 @@ module Eprime
|
|
130
119
|
@columns << col_id
|
131
120
|
@column_hash[col_id] = index
|
132
121
|
@column_hash[index] = index
|
133
|
-
|
134
|
-
raise ColumnAddedWarning.new(
|
135
|
-
"Error: Added column #{col_id} after specifying columns at init",
|
136
|
-
index
|
137
|
-
)
|
138
|
-
end
|
139
|
-
return index
|
122
|
+
index
|
140
123
|
end
|
141
124
|
|
142
125
|
private
|
@@ -159,7 +142,7 @@ module Eprime
|
|
159
142
|
def [](index)
|
160
143
|
num_index = @parent.find_column_index(index)
|
161
144
|
unless (num_index.is_a?(Fixnum) and @parent.columns.length>num_index)
|
162
|
-
raise IndexError.new("Column #{
|
145
|
+
raise IndexError.new("Column #{index} does not exist")
|
163
146
|
end
|
164
147
|
return @data[num_index]
|
165
148
|
end
|
@@ -1,26 +1,28 @@
|
|
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 'stringio'
|
9
|
+
require 'iconv'
|
10
|
+
|
8
11
|
require 'log_file_parser'
|
9
12
|
require 'excel_parser'
|
10
13
|
require 'eprimetab_parser'
|
11
14
|
require 'raw_tab_parser'
|
12
15
|
|
13
|
-
module
|
16
|
+
module Optimus
|
14
17
|
|
15
18
|
# A class that should open any type of E-Prime text file and read it into
|
16
19
|
# an E-Prime data structure.
|
17
|
-
# This class isn't yet used anywhere.
|
18
20
|
class Reader
|
19
21
|
|
20
22
|
attr_reader :type, :parser, :input
|
21
23
|
attr_accessor :options
|
22
24
|
|
23
|
-
PARSERS = [LogfileParser, ExcelParser,
|
25
|
+
PARSERS = [LogfileParser, ExcelParser, OptimustabParser, RawTabParser]
|
24
26
|
|
25
27
|
def initialize(input = nil, options = {})
|
26
28
|
@options = options || {}
|
@@ -31,9 +33,9 @@ module Eprime
|
|
31
33
|
set_input(input)
|
32
34
|
end
|
33
35
|
|
34
|
-
def
|
35
|
-
@
|
36
|
-
return @
|
36
|
+
def optimus_data
|
37
|
+
@optimus_data ||= @parser.to_optimus
|
38
|
+
return @optimus_data
|
37
39
|
end
|
38
40
|
|
39
41
|
def options=(options)
|
@@ -55,11 +57,23 @@ module Eprime
|
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
60
|
+
def set_file_with_encoding(file)
|
61
|
+
file.rewind
|
62
|
+
datas = file.read(2)
|
63
|
+
if datas == "\377\376"
|
64
|
+
converted = Iconv.conv("ASCII//TRANSLIT", "UTF-16LE", file.read)
|
65
|
+
converted_f = StringIO.new(converted)
|
66
|
+
else
|
67
|
+
converted_f = file
|
68
|
+
converted_f.rewind
|
69
|
+
end
|
70
|
+
return converted_f
|
71
|
+
end
|
58
72
|
|
59
|
-
# Sets @type to one of
|
60
|
-
# Does not change file position.
|
73
|
+
# Sets @type to one of Optimus::Reader::TYPES or raises an
|
74
|
+
# Optimus::UnknownTypeError. Does not change file position.
|
61
75
|
def set_type(file)
|
62
|
-
@file = file
|
76
|
+
@file = set_file_with_encoding(file)
|
63
77
|
original_pos = @file.pos
|
64
78
|
@file.rewind
|
65
79
|
first_lines = Array.new
|
@@ -73,11 +87,11 @@ module Eprime
|
|
73
87
|
if @type.nil?
|
74
88
|
raise UnknownTypeError.new("Can't determine the type of #{file.path}")
|
75
89
|
end
|
76
|
-
@
|
90
|
+
@optimus_data = nil
|
77
91
|
@parser = @type.new(@file, @options)
|
78
92
|
end
|
79
93
|
|
80
|
-
# Determines the type of an
|
94
|
+
# Determines the type of an optimus file, based on its first two lines.
|
81
95
|
# Returns one of the elements of PARSERS or nil
|
82
96
|
def determine_file_type(first_lines)
|
83
97
|
# Log files start with *** Header Start ***
|
@@ -85,7 +99,7 @@ module Eprime
|
|
85
99
|
# Excel files have a filename on the first line (no tabs); the second line
|
86
100
|
# contains at least three elements, tab-delimted
|
87
101
|
#
|
88
|
-
#
|
102
|
+
# optimus CSV files will have at least three tab-delimited elements on the first line
|
89
103
|
|
90
104
|
return PARSERS.detect { |parser_class|
|
91
105
|
parser_class.can_parse?(first_lines)
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008-09 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
|
+
# A two-stage parser that should be both faster and more flexible than the
|
9
|
+
# one-stage regex hack currently in use.
|
10
|
+
# Major difference: this will return parse trees that need to be evaluated
|
11
|
+
# by passing in a row's worth of data, instead of directly evaluating a string
|
12
|
+
# after substituting row data.
|
13
|
+
|
14
|
+
require 'rubygems'
|
15
|
+
require 'rparsec'
|
16
|
+
require 'pp'
|
17
|
+
require 'expression_parser/expressions'
|
18
|
+
|
19
|
+
module Optimus
|
20
|
+
module ParsedCalculator
|
21
|
+
include RParsec
|
22
|
+
class ExpressionParser
|
23
|
+
extend RParsec::Parsers
|
24
|
+
include RParsec::Parsers
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@operators = RParsec::Operators.new(
|
28
|
+
%w{+ - * / % & ( ) not and or = != > >= < <=}
|
29
|
+
)
|
30
|
+
expr = nil
|
31
|
+
lazy_expr = lazy { expr }
|
32
|
+
atom = (
|
33
|
+
token(:str) { |lex| StringLiteral.new(lex) } |
|
34
|
+
token(:number) { |lex| NumberLiteral.new(lex) } |
|
35
|
+
token(:column) { |lex| ColumnReference.new(lex) } )
|
36
|
+
|
37
|
+
lit = atom | (@operators['('] >> lazy_expr << @operators[')'])
|
38
|
+
|
39
|
+
# Follows hte standard C
|
40
|
+
table = RParsec::OperatorTable.new.
|
41
|
+
prefix(@operators['-'] >> lambda {|a| -a}, 50).
|
42
|
+
prefix(@operators['not'] >> lambda {|a| a.logical_not}, 50).
|
43
|
+
infixl(@operators['*'] >> lambda {|a, b| a*b}, 30).
|
44
|
+
infixl(@operators['/'] >> lambda {|a, b| a/b}, 30).
|
45
|
+
infixl(@operators['%'] >> lambda {|a, b| a%b}, 30).
|
46
|
+
infixl(@operators['+'] >> lambda {|a, b| a+b}, 27).
|
47
|
+
infixl(@operators['-'] >> lambda {|a, b| a-b}, 27).
|
48
|
+
infixl(@operators['&'] >> lambda {|a, b| a&b}, 25).
|
49
|
+
infixl(@operators['>'] >> lambda {|a, b| a>b}, 17).
|
50
|
+
infixl(@operators['>='] >> lambda {|a, b| a>=b}, 17).
|
51
|
+
infixl(@operators['<'] >> lambda {|a, b| a<b}, 17).
|
52
|
+
infixl(@operators['<='] >> lambda {|a, b| a<=b}, 17).
|
53
|
+
infixl(@operators['='] >> lambda {|a, b| a.eq(b)}, 15).
|
54
|
+
infixl(@operators['!='] >> lambda {|a, b| a.neq(b)}, 15).
|
55
|
+
infixl(@operators['and'] >> lambda {|a, b| a.logical_and(b)}, 5).
|
56
|
+
infixl(@operators['or'] >> lambda {|a, b| a.logical_or(b)}, 4)
|
57
|
+
|
58
|
+
expr = RParsec::Expressions.build(lit, table)
|
59
|
+
|
60
|
+
lexeme = tokenizer.lexeme(whitespaces) << eof
|
61
|
+
@parser = lexeme.nested(expr << eof)
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse(str)
|
65
|
+
begin
|
66
|
+
@parser.parse(str)
|
67
|
+
rescue Exception
|
68
|
+
raise
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def tokenizer
|
75
|
+
return (
|
76
|
+
string_literal.token(:str) |
|
77
|
+
number.token(:number) |
|
78
|
+
column_reference.token(:column) |
|
79
|
+
@operators.lexer
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
def string_literal
|
84
|
+
(char("'") >> (not_char("'")|str("''")).many.fragment << char("'"))
|
85
|
+
end
|
86
|
+
|
87
|
+
def column_reference
|
88
|
+
(char('{') >> (string('\}')|not_char('}')).many_.fragment << char('}'))
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/raw_tab_parser.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
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
8
|
# This almost completely delegates to TabfileParser
|
9
|
-
# It differs from
|
9
|
+
# It differs from OptimustabParser only in that it doesn't skip any lines.
|
10
10
|
|
11
11
|
require 'tabfile_parser'
|
12
12
|
|
13
|
-
module
|
13
|
+
module Optimus
|
14
14
|
class Reader
|
15
15
|
class RawTabParser < TabfileParser
|
16
16
|
def initialize(file, options = {})
|
@@ -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
|
@@ -9,17 +9,17 @@
|
|
9
9
|
# This class should handle argument processing, file I/O, and such.
|
10
10
|
|
11
11
|
|
12
|
-
require '
|
13
|
-
require '
|
12
|
+
require 'optimus'
|
13
|
+
require 'optimus_reader'
|
14
14
|
require 'tabfile_writer'
|
15
15
|
require 'transformers/timing_extractor'
|
16
16
|
require 'optparse'
|
17
17
|
require 'ostruct'
|
18
18
|
|
19
|
-
module
|
19
|
+
module Optimus
|
20
20
|
module Runners
|
21
21
|
class GenericRunner
|
22
|
-
include ::
|
22
|
+
include ::Optimus::Transformers
|
23
23
|
|
24
24
|
attr_accessor :out, :err
|
25
25
|
def initialize(extractor_class, *args)
|
@@ -43,10 +43,10 @@ module Eprime
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def read_data
|
46
|
-
data =
|
46
|
+
data = Optimus::Data.new()
|
47
47
|
@options.input_files.each do |infile|
|
48
48
|
File.open(infile) do |f|
|
49
|
-
data.merge!(
|
49
|
+
data.merge!(Optimus::Reader.new(f).optimus_data)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
@data = data
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008-09 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
|
+
# OptionParser for the yaml_template_runner
|
9
|
+
|
10
|
+
|
11
|
+
require 'optimus'
|
12
|
+
require 'optparse'
|
13
|
+
|
14
|
+
module Optimus
|
15
|
+
module Runners
|
16
|
+
module YamlTemplate
|
17
|
+
class OptimusOptionParser
|
18
|
+
attr_reader :errors
|
19
|
+
def initialize
|
20
|
+
@errors = []
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class OptionParserFactory
|
25
|
+
class << self
|
26
|
+
def build
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Part of the Optimus package for managing E-Prime data
|
2
|
+
#
|
3
|
+
# Copyright (C) 2008-09 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
|
+
# This is the main wrapper class --
|
9
|
+
|
10
|
+
require 'optimus'
|
11
|
+
|
12
|
+
module Optimus
|
13
|
+
module Runners
|
14
|
+
module YamlTemplate
|
15
|
+
class Runner
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/tabfile_parser.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
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
8
|
|
9
|
-
module
|
9
|
+
module Optimus
|
10
10
|
class Reader
|
11
11
|
|
12
|
-
# This class is for reading tab-delimited
|
12
|
+
# This class is for reading tab-delimited Optimus files. (Or, really, any tab-delimited file).
|
13
13
|
# The main option of interest is the :skip_lines option, which specifies how many lines
|
14
14
|
# to skip before finding column names. For example:
|
15
15
|
#
|
16
16
|
# TabfileParser.new(stream, :skip_lines => 1)
|
17
17
|
#
|
18
|
-
# is what you'd use for skipping the filename line in a standard
|
18
|
+
# is what you'd use for skipping the filename line in a standard optimus Excel file.
|
19
19
|
#
|
20
20
|
# Note: you'll generally be using subclasses of this, and not manually specifying skip_lines.
|
21
21
|
|
@@ -26,7 +26,7 @@ module Eprime
|
|
26
26
|
@columns = options[:columns]
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def to_optimus
|
30
30
|
lines = @file.readlines
|
31
31
|
@skip_lines.times do
|
32
32
|
lines.shift
|
@@ -35,7 +35,7 @@ module Eprime
|
|
35
35
|
file_columns = lines.shift.split("\t").map {|elt| elt.strip }
|
36
36
|
expected_size = file_columns.size
|
37
37
|
columns = file_columns
|
38
|
-
data =
|
38
|
+
data = Optimus::Data.new(columns)
|
39
39
|
current_line = @skip_lines+1
|
40
40
|
lines.each do |line|
|
41
41
|
current_line += 1
|
data/lib/tabfile_writer.rb
CHANGED
@@ -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
|
@@ -9,9 +9,9 @@
|
|
9
9
|
# way easier (by handling in-band tabs, etc)
|
10
10
|
require 'csv'
|
11
11
|
|
12
|
-
module
|
12
|
+
module Optimus
|
13
13
|
|
14
|
-
# Writes an
|
14
|
+
# Writes an Optimus::Data object as a tab-delmited file -- hopefully exactly
|
15
15
|
# like E-DataAid.
|
16
16
|
class TabfileWriter
|
17
17
|
|
@@ -19,17 +19,17 @@ module Eprime
|
|
19
19
|
# Valid things in the options hash:
|
20
20
|
# :write_top_line => true, if you want to include the filename
|
21
21
|
# (if it's a file output stream) as the first line output
|
22
|
-
def initialize(
|
22
|
+
def initialize(optimus_data, outstream, options = {})
|
23
23
|
standard_options = {
|
24
24
|
:write_top_line => false,
|
25
25
|
:columns => nil,
|
26
26
|
:column_labels => true
|
27
27
|
}
|
28
28
|
good_opts = standard_options.merge(options)
|
29
|
-
@
|
29
|
+
@optimus = optimus_data
|
30
30
|
@outstream = outstream
|
31
31
|
@write_top_line = good_opts[:write_top_line]
|
32
|
-
@columns = good_opts[:columns] || @
|
32
|
+
@columns = good_opts[:columns] || @optimus.columns
|
33
33
|
@column_labels = good_opts[:column_labels]
|
34
34
|
end
|
35
35
|
|
@@ -43,7 +43,7 @@ module Eprime
|
|
43
43
|
if @column_labels
|
44
44
|
tsv << @columns
|
45
45
|
end
|
46
|
-
@
|
46
|
+
@optimus.each do |row|
|
47
47
|
vals = @columns.map { |col_name| row[col_name] }
|
48
48
|
tsv << vals
|
49
49
|
end
|
@@ -1,22 +1,23 @@
|
|
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
|
-
# This is a complete general
|
8
|
+
# This is a complete general optimus transforer -- it supports computed columns
|
9
9
|
# row filters, and multipass operation. In general, once you've read a file in,
|
10
10
|
# this is probably what you want to use.
|
11
11
|
# Essentially, this is just a wrapper around the ColumnCalculator,
|
12
12
|
# RowFilter, and Multipasser classes
|
13
13
|
|
14
|
-
require '
|
14
|
+
require 'optimus'
|
15
15
|
require 'transformers/column_calculator'
|
16
16
|
require 'transformers/row_filter'
|
17
17
|
require 'transformers/multipasser'
|
18
|
+
require 'parsed_calculator'
|
18
19
|
|
19
|
-
module
|
20
|
+
module Optimus
|
20
21
|
module Transformers
|
21
22
|
class BasicTransformer
|
22
23
|
def initialize(data)
|
@@ -34,34 +35,34 @@ module Eprime
|
|
34
35
|
end
|
35
36
|
|
36
37
|
def data=(data)
|
37
|
-
|
38
|
-
@data =
|
38
|
+
reset_all!
|
39
|
+
@data = Optimus::Data.new.merge(data)
|
39
40
|
end
|
40
41
|
|
41
42
|
def computed_column(*args)
|
42
|
-
|
43
|
+
reset_all!
|
43
44
|
@computed_columns << args
|
44
45
|
end
|
45
46
|
|
46
47
|
def copydown_column(*args)
|
47
|
-
|
48
|
+
reset_all!
|
48
49
|
@copydown_columns << args
|
49
50
|
end
|
50
51
|
|
51
52
|
def counter_column(*args)
|
52
|
-
|
53
|
+
reset_all!
|
53
54
|
@counter_columns << args
|
54
55
|
end
|
55
56
|
|
56
57
|
def row_filter=(filter)
|
57
|
-
|
58
|
+
reset_filtered!
|
58
59
|
@row_filter = filter
|
59
60
|
end
|
60
61
|
|
61
62
|
alias :row_filter :row_filter=
|
62
63
|
|
63
64
|
def add_pass(*args)
|
64
|
-
|
65
|
+
reset_all!
|
65
66
|
p = Multipasser::Pass.new(*args)
|
66
67
|
yield p if block_given?
|
67
68
|
@passes << p
|
@@ -75,30 +76,40 @@ module Eprime
|
|
75
76
|
compute! and return @processed
|
76
77
|
end
|
77
78
|
|
78
|
-
def
|
79
|
+
def reset_all!
|
80
|
+
@computed = nil
|
81
|
+
@processed = nil
|
82
|
+
return true
|
83
|
+
end
|
84
|
+
|
85
|
+
def reset_filtered!
|
79
86
|
@processed = nil
|
80
87
|
return true
|
81
88
|
end
|
82
89
|
|
83
90
|
def compute!
|
84
91
|
return @processed if @processed
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
92
|
+
|
93
|
+
if @computed.nil?
|
94
|
+
@computed = ColumnCalculator.new
|
95
|
+
@computed.data = @data
|
96
|
+
@computed_columns.each do |c|
|
97
|
+
@computed.computed_column *c
|
98
|
+
end
|
99
|
+
@copydown_columns.each do |c|
|
100
|
+
@computed.copydown_column *c
|
101
|
+
end
|
102
|
+
@counter_columns.each do |c|
|
103
|
+
@computed.counter_column *c
|
104
|
+
end
|
95
105
|
end
|
96
|
-
|
106
|
+
|
107
|
+
filtered = RowFilter.new(@computed, @row_filter)
|
97
108
|
multi = Multipasser.new(filtered)
|
98
109
|
@passes.each do |p|
|
99
110
|
multi.add_pass(p)
|
100
111
|
end
|
101
|
-
@processed =
|
112
|
+
@processed = Optimus::Data.new.merge(multi)
|
102
113
|
end
|
103
114
|
end
|
104
115
|
end
|