calco 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +34 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +26 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +22 -0
- data/README.md +360 -0
- data/Rakefile +1 -0
- data/calco.gemspec +23 -0
- data/examples/ages.ods +0 -0
- data/examples/compute_cells.rb +61 -0
- data/examples/data.csv +8 -0
- data/examples/example.rb +97 -0
- data/examples/multiplication_tables.ods +0 -0
- data/examples/multiplication_tables.rb +73 -0
- data/examples/register_function.rb +44 -0
- data/examples/using_date_functions.rb +42 -0
- data/examples/write_csv.rb +68 -0
- data/examples/write_ods.rb +69 -0
- data/lib/calco.rb +17 -0
- data/lib/calco/core_ext/fixnum.rb +22 -0
- data/lib/calco/core_ext/float.rb +22 -0
- data/lib/calco/core_ext/range.rb +15 -0
- data/lib/calco/core_ext/string.rb +20 -0
- data/lib/calco/date_functions.rb +13 -0
- data/lib/calco/definition_dsl.rb +127 -0
- data/lib/calco/elements/aggregator.rb +17 -0
- data/lib/calco/elements/builtin_function.rb +84 -0
- data/lib/calco/elements/constant.rb +31 -0
- data/lib/calco/elements/current.rb +19 -0
- data/lib/calco/elements/element.rb +31 -0
- data/lib/calco/elements/empty.rb +9 -0
- data/lib/calco/elements/formula.rb +42 -0
- data/lib/calco/elements/if.rb +26 -0
- data/lib/calco/elements/operation.rb +34 -0
- data/lib/calco/elements/operator.rb +17 -0
- data/lib/calco/elements/or.rb +26 -0
- data/lib/calco/elements/value_extractor.rb +42 -0
- data/lib/calco/elements/variable.rb +35 -0
- data/lib/calco/engines/calculator_builtin_functions.rb +32 -0
- data/lib/calco/engines/csv_engine.rb +80 -0
- data/lib/calco/engines/default_engine.rb +140 -0
- data/lib/calco/engines/office_engine.rb +263 -0
- data/lib/calco/engines/simple_calculator_engine.rb +151 -0
- data/lib/calco/math_functions.rb +9 -0
- data/lib/calco/sheet.rb +363 -0
- data/lib/calco/spreadsheet.rb +172 -0
- data/lib/calco/string_functions.rb +9 -0
- data/lib/calco/style.rb +15 -0
- data/lib/calco/time_functions.rb +12 -0
- data/lib/calco/version.rb +3 -0
- data/spec/absolute_references_spec.rb +86 -0
- data/spec/builtin_functions_spec.rb +161 -0
- data/spec/calculator_engine_spec.rb +251 -0
- data/spec/conditions_spec.rb +118 -0
- data/spec/content_change_spec.rb +190 -0
- data/spec/csv_engine_spec.rb +324 -0
- data/spec/default_engine_spec.rb +135 -0
- data/spec/definitions_spec.rb +65 -0
- data/spec/errors_spec.rb +189 -0
- data/spec/functions_spec.rb +251 -0
- data/spec/header_row_spec.rb +63 -0
- data/spec/range_spec.rb +189 -0
- data/spec/sheet_selections_spec.rb +49 -0
- data/spec/sheet_spec.rb +229 -0
- data/spec/smart_types_spec.rb +43 -0
- data/spec/spreadsheet_spec.rb +80 -0
- data/spec/styles_spec.rb +29 -0
- data/spec/variables_spec.rb +41 -0
- metadata +158 -0
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'date'
|
2
|
+
require 'time'
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
require 'calco/engines/csv_engine'
|
6
|
+
|
7
|
+
module Calco
|
8
|
+
|
9
|
+
describe CSVEngine do
|
10
|
+
|
11
|
+
it "writes header when writing row 0" do
|
12
|
+
|
13
|
+
create_spreadsheet_and_save do |spreadsheet|
|
14
|
+
|
15
|
+
sheet = spreadsheet.sheet('A').current
|
16
|
+
|
17
|
+
sheet.write_row 0
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
expect(@result).to eq('c1,,c3,c4,c5')
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
it "writes empty values, numbers and functions" do
|
26
|
+
|
27
|
+
create_spreadsheet_and_save do |spreadsheet|
|
28
|
+
|
29
|
+
sheet = spreadsheet.sheet('B').current
|
30
|
+
|
31
|
+
sheet.write_row 1
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
expect(@result).to eq('"",=2*C1,11')
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
it "writes functions for times" do
|
40
|
+
|
41
|
+
create_spreadsheet_and_save do |spreadsheet|
|
42
|
+
|
43
|
+
sheet = spreadsheet.sheet('time').current
|
44
|
+
|
45
|
+
sheet.write_row 1
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
expect(@result).to eq('"=TIMEVALUE(""13:45:00"")"')
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
it "writes functions for dates" do
|
54
|
+
|
55
|
+
create_spreadsheet_and_save do |spreadsheet|
|
56
|
+
|
57
|
+
sheet = spreadsheet.sheet('date').current
|
58
|
+
|
59
|
+
sheet.write_row 1
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
expect(@result).to eq('"=DATEVALUE(""2013-07-27"")"')
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
it "writes functions for dates and style" do
|
68
|
+
|
69
|
+
create_spreadsheet_and_save do |spreadsheet|
|
70
|
+
|
71
|
+
sheet = spreadsheet.sheet('date-style').current
|
72
|
+
|
73
|
+
sheet.write_row 1
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
expect(@result).to eq('"=DATEVALUE(""2013-07-27"")+STYLE(IF(CURRENT()=TODAY();""red"";""default""))"')
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
it "writes functions for times and style" do
|
82
|
+
|
83
|
+
create_spreadsheet_and_save do |spreadsheet|
|
84
|
+
|
85
|
+
sheet = spreadsheet.sheet('time-style').current
|
86
|
+
|
87
|
+
sheet.write_row 1
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
expect(@result).to eq('"=TIMEVALUE(""13:45:00"")+STYLE(IF(CURRENT()=NOW();""red"";""default""))"')
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
it "writes functions for money" do
|
96
|
+
|
97
|
+
create_spreadsheet_and_save do |spreadsheet|
|
98
|
+
|
99
|
+
sheet = spreadsheet.sheet('dollar').current
|
100
|
+
|
101
|
+
sheet.write_row 1
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
expect(@result).to eq('=DOLLAR(11)')
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
it "writes money even for formulas" do
|
110
|
+
|
111
|
+
create_spreadsheet_and_save do |spreadsheet|
|
112
|
+
|
113
|
+
sheet = spreadsheet.sheet('dollar-formulas').current
|
114
|
+
|
115
|
+
sheet.write_row 1
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
expect(@result.split(',')).to eq(['=DOLLAR(11)', '=DOLLAR(2*A1)'])
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
it "surrounds formulas and style with money" do
|
124
|
+
|
125
|
+
create_spreadsheet_and_save do |spreadsheet|
|
126
|
+
|
127
|
+
sheet = spreadsheet.sheet('dollar-conditional').current
|
128
|
+
|
129
|
+
sheet.write_row 1
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
expect(@result).to eq('=DOLLAR(11),"=DOLLAR(2*A1+STYLE(IF(CURRENT()>2;""big"";""default"")))"')
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
it "writes % values" do
|
138
|
+
|
139
|
+
create_spreadsheet_and_save do |spreadsheet|
|
140
|
+
|
141
|
+
sheet = spreadsheet.sheet('%').current
|
142
|
+
|
143
|
+
sheet.write_row 1
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
expect(@result).to eq('=(0.3*100)%')
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
it "writes % functions" do
|
152
|
+
|
153
|
+
create_spreadsheet_and_save do |spreadsheet|
|
154
|
+
|
155
|
+
sheet = spreadsheet.sheet('%-formulas').current
|
156
|
+
|
157
|
+
sheet.write_row 1
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
expect(@result).to eq('11,=(2*A1)%')
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
it "writes sum aggregation" do
|
166
|
+
|
167
|
+
create_spreadsheet_and_save do |spreadsheet|
|
168
|
+
|
169
|
+
sheet = spreadsheet.sheet('sum').current
|
170
|
+
|
171
|
+
sheet.write_row 1
|
172
|
+
sheet.write_row 2
|
173
|
+
sheet.write_row 3
|
174
|
+
|
175
|
+
sheet.replace_content :values, :total
|
176
|
+
|
177
|
+
sheet.write_row 4
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
expect(@result.split).to match_array(['=DOLLAR(11)'] * 3 + ['=DOLLAR(SUM(A1:A3))'])
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
it "writes empty rows" do
|
186
|
+
|
187
|
+
create_spreadsheet_and_save do |spreadsheet|
|
188
|
+
|
189
|
+
sheet = spreadsheet.sheet('B').current
|
190
|
+
|
191
|
+
sheet.write_row 1
|
192
|
+
sheet.empty_row
|
193
|
+
sheet.write_row 3
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
expect(@result).to eq('"",=2*C1,11' "\n\n" '"",=2*C3,11')
|
198
|
+
|
199
|
+
end
|
200
|
+
|
201
|
+
it "supports constants in column layouts" do
|
202
|
+
|
203
|
+
create_spreadsheet_and_save do |spreadsheet|
|
204
|
+
|
205
|
+
sheet = spreadsheet.sheet('constants').current
|
206
|
+
|
207
|
+
sheet.write_row 1
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
expect(@result).to eq('11,x 2,=2*A1')
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
before do
|
216
|
+
@engine = Calco::CSVEngine.new
|
217
|
+
end
|
218
|
+
|
219
|
+
def create_spreadsheet_and_save &block
|
220
|
+
|
221
|
+
@doc = spreadsheet(@engine) do
|
222
|
+
|
223
|
+
definitions do
|
224
|
+
|
225
|
+
set a: ''
|
226
|
+
set b: 11
|
227
|
+
set c: Time.parse('13:45')
|
228
|
+
set d: Date.parse('2013-07-27')
|
229
|
+
set e: 0.3
|
230
|
+
|
231
|
+
function double: 2 * b
|
232
|
+
|
233
|
+
function total: sum(b[(1..-1).as_grouping])
|
234
|
+
|
235
|
+
end
|
236
|
+
|
237
|
+
sheet "A" do
|
238
|
+
|
239
|
+
column value_of(:a), :title => "c1"
|
240
|
+
|
241
|
+
column :double
|
242
|
+
|
243
|
+
column value_of(:b), :title => "c3"
|
244
|
+
column value_of(:c), :title => "c4"
|
245
|
+
column value_of(:d), :title => "c5"
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
sheet "B" do
|
250
|
+
|
251
|
+
column value_of(:a)
|
252
|
+
|
253
|
+
column :double
|
254
|
+
|
255
|
+
column value_of(:b)
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
sheet "time" do
|
260
|
+
column value_of(:c)
|
261
|
+
end
|
262
|
+
|
263
|
+
sheet "date" do
|
264
|
+
column value_of(:d)
|
265
|
+
end
|
266
|
+
|
267
|
+
sheet "time-style" do
|
268
|
+
column value_of(:c), style: _if(current == now(), 'red', 'default')
|
269
|
+
end
|
270
|
+
|
271
|
+
sheet "date-style" do
|
272
|
+
column value_of(:d), style: _if(current == today(), 'red', 'default')
|
273
|
+
end
|
274
|
+
|
275
|
+
sheet "dollar" do
|
276
|
+
column value_of(:b), :type => '$'
|
277
|
+
end
|
278
|
+
|
279
|
+
sheet "dollar-formulas" do
|
280
|
+
column value_of(:b), :type => '$'
|
281
|
+
column :double, :type => '$'
|
282
|
+
end
|
283
|
+
|
284
|
+
sheet "dollar-conditional" do
|
285
|
+
column value_of(:b), :type => '$'
|
286
|
+
column :double, :type => '$', style: _if(current > 2, 'big', 'default')
|
287
|
+
end
|
288
|
+
|
289
|
+
sheet "%" do
|
290
|
+
column value_of(:e), :type => '%'
|
291
|
+
end
|
292
|
+
|
293
|
+
sheet "%-formulas" do
|
294
|
+
column value_of(:b)
|
295
|
+
column :double, :type => '%'
|
296
|
+
end
|
297
|
+
|
298
|
+
sheet "sum" do
|
299
|
+
column value_of(:b), :type => '$', :id => :values
|
300
|
+
end
|
301
|
+
|
302
|
+
sheet "constants" do
|
303
|
+
|
304
|
+
column value_of(:b)
|
305
|
+
|
306
|
+
column "x 2"
|
307
|
+
|
308
|
+
column :double
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
buffer = StringIO.new
|
315
|
+
|
316
|
+
@doc.save buffer, &block
|
317
|
+
|
318
|
+
@result = buffer.string.strip
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
|
324
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'calco'
|
2
|
+
|
3
|
+
module Calco
|
4
|
+
|
5
|
+
describe DefaultEngine do
|
6
|
+
|
7
|
+
it 'generates value of var for "column value_of(:var)"' do
|
8
|
+
|
9
|
+
doc = spreadsheet do
|
10
|
+
|
11
|
+
definitions do
|
12
|
+
|
13
|
+
set a: "12:58"
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
sheet do
|
18
|
+
|
19
|
+
column value_of(:a)
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
row = doc.current.row(1)
|
26
|
+
|
27
|
+
expect(row[0]).to eq('12:58:00')
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'generates (invalid) reference to same cell for "column :var"' do
|
32
|
+
|
33
|
+
doc = spreadsheet do
|
34
|
+
|
35
|
+
definitions do
|
36
|
+
|
37
|
+
set a: "12:58"
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
sheet do
|
42
|
+
|
43
|
+
column :a
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
row = doc.current.row(1)
|
50
|
+
|
51
|
+
expect(row[0]).to eq('A1')
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'generates "" for "column skip"' do
|
56
|
+
|
57
|
+
doc = spreadsheet do
|
58
|
+
|
59
|
+
definitions do
|
60
|
+
|
61
|
+
set a: "12:58"
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
sheet do
|
66
|
+
|
67
|
+
column skip
|
68
|
+
column value_of(:a)
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
row = doc.current.row(1)
|
75
|
+
|
76
|
+
expect(row[0]).to eq('')
|
77
|
+
expect(row[1]).to eq('12:58:00')
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
it "generates all values as string literals" do
|
82
|
+
|
83
|
+
doc = spreadsheet do
|
84
|
+
|
85
|
+
definitions do
|
86
|
+
|
87
|
+
set a: 'Hello'
|
88
|
+
set b: 12
|
89
|
+
|
90
|
+
function c: a + "Hi"
|
91
|
+
function d: b + 123
|
92
|
+
function e: 76.9
|
93
|
+
function f: "Max"
|
94
|
+
|
95
|
+
set g: "2013-09-29"
|
96
|
+
set h: "12:58"
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
sheet do
|
101
|
+
|
102
|
+
column value_of(:a)
|
103
|
+
column value_of(:b)
|
104
|
+
|
105
|
+
column :c
|
106
|
+
column :d
|
107
|
+
column :e
|
108
|
+
column :f
|
109
|
+
|
110
|
+
column value_of(:g)
|
111
|
+
column value_of(:h)
|
112
|
+
|
113
|
+
column :h
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
row = doc.current.row(1)
|
120
|
+
|
121
|
+
expect(row[0]).to eq('"Hello"')
|
122
|
+
expect(row[1]).to eq('12')
|
123
|
+
expect(row[2]).to eq('A1+"Hi"')
|
124
|
+
expect(row[3]).to eq('B1+123')
|
125
|
+
expect(row[4]).to eq('76.9')
|
126
|
+
expect(row[5]).to eq('"Max"')
|
127
|
+
expect(row[6]).to eq('2013-09-29')
|
128
|
+
expect(row[7]).to eq('12:58:00')
|
129
|
+
expect(row[8]).to eq('I1')
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|