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,65 @@
|
|
1
|
+
require 'calco'
|
2
|
+
|
3
|
+
RSpec.configure do |c|
|
4
|
+
c.alias_example_to :check
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "definitions" do
|
8
|
+
|
9
|
+
check "definitions setup" do
|
10
|
+
|
11
|
+
doc = spreadsheet do
|
12
|
+
|
13
|
+
definitions do
|
14
|
+
|
15
|
+
set a: 8
|
16
|
+
set b: 'hello'
|
17
|
+
|
18
|
+
function f1: a
|
19
|
+
function f2: b
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
sheet "A" do
|
24
|
+
column value_of(:a)
|
25
|
+
column value_of(:b)
|
26
|
+
column :f1
|
27
|
+
column :f2
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
check "definitions are visible to all sheets" do
|
35
|
+
|
36
|
+
doc = spreadsheet do
|
37
|
+
|
38
|
+
definitions do
|
39
|
+
|
40
|
+
set a: 8
|
41
|
+
|
42
|
+
function f1: a
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
sheet "A" do
|
47
|
+
column value_of(:a)
|
48
|
+
column :f1
|
49
|
+
end
|
50
|
+
|
51
|
+
sheet "B" do
|
52
|
+
column value_of(:a)
|
53
|
+
column :f1
|
54
|
+
end
|
55
|
+
|
56
|
+
sheet "C" do
|
57
|
+
column value_of(:a)
|
58
|
+
column :f1
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/spec/errors_spec.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'calco'
|
2
|
+
|
3
|
+
RSpec.configure do |c|
|
4
|
+
c.alias_example_to :detect
|
5
|
+
end
|
6
|
+
|
7
|
+
describe 'Spreadsheet errors' do
|
8
|
+
|
9
|
+
detect "variable does not exist" do
|
10
|
+
|
11
|
+
expect {
|
12
|
+
|
13
|
+
spreadsheet do
|
14
|
+
|
15
|
+
sheet do
|
16
|
+
|
17
|
+
column value_of(:some_var)
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
}.to raise_error("Unknown variable some_var")
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
detect "function using an unknown variable" do
|
28
|
+
|
29
|
+
expect {
|
30
|
+
|
31
|
+
doc = spreadsheet do
|
32
|
+
|
33
|
+
definitions do
|
34
|
+
|
35
|
+
function some_var + 1
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
}.to raise_error("Unknown function or variable 'some_var'")
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
detect "assiging value to unknown variable" do
|
46
|
+
|
47
|
+
doc = spreadsheet do
|
48
|
+
|
49
|
+
sheet do
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
expect {
|
56
|
+
|
57
|
+
doc.save($stdout) do |spreadsheet|
|
58
|
+
|
59
|
+
sheet = spreadsheet.current
|
60
|
+
|
61
|
+
sheet[:some_var] = 12
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
}.to raise_error("Unknown variable 'some_var'")
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
detect "reference to an unknown function" do
|
70
|
+
|
71
|
+
expect {
|
72
|
+
|
73
|
+
spreadsheet do
|
74
|
+
|
75
|
+
sheet do
|
76
|
+
|
77
|
+
column :some_function
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
}.to raise_error("Unknown function or variable 'some_function'")
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
detect "using an unknown function" do
|
88
|
+
|
89
|
+
expect {
|
90
|
+
|
91
|
+
spreadsheet do
|
92
|
+
|
93
|
+
definitions do
|
94
|
+
|
95
|
+
function name: some_function
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
}.to raise_error("Unknown function or variable 'some_function'")
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
detect "declaring a variable twice" do
|
106
|
+
|
107
|
+
expect {
|
108
|
+
|
109
|
+
spreadsheet do
|
110
|
+
|
111
|
+
definitions do
|
112
|
+
|
113
|
+
set var: 12
|
114
|
+
set var: "hello"
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
}.to raise_error("Variable 'var' already set")
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
detect "declaring a function twice" do
|
125
|
+
|
126
|
+
expect {
|
127
|
+
|
128
|
+
spreadsheet do
|
129
|
+
|
130
|
+
definitions do
|
131
|
+
|
132
|
+
function f: 12
|
133
|
+
function f: "hello"
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
}.to raise_error("Function 'f' already defined")
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
detect "unnamed option for column" do
|
144
|
+
|
145
|
+
expect {
|
146
|
+
|
147
|
+
spreadsheet do
|
148
|
+
|
149
|
+
definitions do
|
150
|
+
|
151
|
+
set price: 11
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
sheet do
|
156
|
+
column :price, 'pp'
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
}.to raise_error(ArgumentError, "Options should be a Hash")
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
detect "unknown column id" do
|
166
|
+
|
167
|
+
expect {
|
168
|
+
|
169
|
+
doc = spreadsheet do
|
170
|
+
|
171
|
+
definitions do
|
172
|
+
|
173
|
+
set a: 'a'
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
sheet do
|
178
|
+
column :a
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
doc.current.replace_content :no_id, nil
|
184
|
+
|
185
|
+
}.to raise_error(RuntimeError, "Column id 'no_id' not found")
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
@@ -0,0 +1,251 @@
|
|
1
|
+
require 'calco'
|
2
|
+
|
3
|
+
RSpec.configure do |c|
|
4
|
+
c.alias_example_to :support
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "Functions support" do
|
8
|
+
|
9
|
+
support "operators" do
|
10
|
+
|
11
|
+
doc = spreadsheet do
|
12
|
+
|
13
|
+
definitions do
|
14
|
+
|
15
|
+
set price: 14.4
|
16
|
+
set product: 'USB 8Gb'
|
17
|
+
set tax: 13
|
18
|
+
set quantity: 30
|
19
|
+
|
20
|
+
function total: price * quantity * (tax / 100 + 1)
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
sheet do
|
25
|
+
|
26
|
+
column value_of(:product)
|
27
|
+
column value_of(:price)
|
28
|
+
column value_of(:quantity)
|
29
|
+
column value_of(:tax)
|
30
|
+
column skip
|
31
|
+
column :total
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
row = doc.row(1)
|
38
|
+
|
39
|
+
expect(row[0]).to eq('"USB 8Gb"')
|
40
|
+
expect(row[1]).to eq('14.4')
|
41
|
+
expect(row[2]).to eq('30')
|
42
|
+
expect(row[3]).to eq('13')
|
43
|
+
|
44
|
+
expect(row[5]).to eq('(B1*C1)*((D1/100)+1)')
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
support "functions using functions" do
|
49
|
+
|
50
|
+
doc = spreadsheet do
|
51
|
+
|
52
|
+
definitions do
|
53
|
+
|
54
|
+
set price: 14.4
|
55
|
+
set product: 'USB 8Gb'
|
56
|
+
set tax: 13
|
57
|
+
set quantity: 30
|
58
|
+
|
59
|
+
function total: price * quantity
|
60
|
+
function total_with_taxes: total * (tax / 100 + 1)
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
sheet do
|
65
|
+
|
66
|
+
column value_of(:product)
|
67
|
+
column value_of(:price)
|
68
|
+
column value_of(:quantity)
|
69
|
+
column value_of(:tax)
|
70
|
+
column skip
|
71
|
+
column :total
|
72
|
+
column :total_with_taxes
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
row = doc.row(1)
|
79
|
+
|
80
|
+
expect(row[0]).to eq('"USB 8Gb"')
|
81
|
+
expect(row[1]).to eq('14.4')
|
82
|
+
expect(row[2]).to eq('30')
|
83
|
+
expect(row[3]).to eq('13')
|
84
|
+
|
85
|
+
expect(row[5]).to eq('B1*C1')
|
86
|
+
expect(row[6]).to eq('F1*((D1/100)+1)')
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
support "conditions with functions" do
|
91
|
+
|
92
|
+
doc = spreadsheet do
|
93
|
+
|
94
|
+
definitions do
|
95
|
+
|
96
|
+
set x: 9
|
97
|
+
|
98
|
+
function f0: x + 3
|
99
|
+
function f1: f0 * f0
|
100
|
+
function f2: f1 + f0
|
101
|
+
function f3: f2 + 7
|
102
|
+
|
103
|
+
function cond: _if(f1 > 2, f2, f3)
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
sheet do
|
108
|
+
|
109
|
+
column value_of(:x)
|
110
|
+
column :f0
|
111
|
+
column :f1
|
112
|
+
column :f2
|
113
|
+
column :f3
|
114
|
+
|
115
|
+
column :cond
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
row = doc.row(1)
|
122
|
+
|
123
|
+
expect(row[0]).to eq('9')
|
124
|
+
expect(row[1]).to eq('A1+3')
|
125
|
+
expect(row[2]).to eq('B1*B1')
|
126
|
+
expect(row[3]).to eq('C1+B1')
|
127
|
+
expect(row[4]).to eq('D1+7')
|
128
|
+
expect(row[5]).to eq('IF(C1>2;D1;E1)')
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
support "containing literals" do
|
133
|
+
|
134
|
+
some_day = Date.new(1998, 7, 12)
|
135
|
+
|
136
|
+
doc = spreadsheet do
|
137
|
+
|
138
|
+
definitions do
|
139
|
+
|
140
|
+
function a: 'string'
|
141
|
+
function b: 12
|
142
|
+
function c: 34.9
|
143
|
+
function d: some_day
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
sheet do
|
148
|
+
|
149
|
+
column :a
|
150
|
+
column :b
|
151
|
+
column :c
|
152
|
+
column :d
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
row = doc.current.row(1)
|
159
|
+
|
160
|
+
expect(row[0]).to eq('"string"')
|
161
|
+
expect(row[1]).to eq("12")
|
162
|
+
expect(row[2]).to eq("34.9")
|
163
|
+
expect(row[3]).to eq(some_day.to_s)
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
support "starting with an integer" do
|
168
|
+
|
169
|
+
doc = spreadsheet do
|
170
|
+
|
171
|
+
definitions do
|
172
|
+
|
173
|
+
set x: 12
|
174
|
+
|
175
|
+
function add: 66 + x
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
sheet do
|
180
|
+
|
181
|
+
column value_of(:x)
|
182
|
+
column :add
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
row = doc.row(1)
|
189
|
+
|
190
|
+
expect(row[0]).to eq('12')
|
191
|
+
expect(row[1]).to eq('66+A1')
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
support "starting with a float" do
|
196
|
+
|
197
|
+
doc = spreadsheet do
|
198
|
+
|
199
|
+
definitions do
|
200
|
+
|
201
|
+
set x: 12.9
|
202
|
+
|
203
|
+
function add: 34.7 + x
|
204
|
+
|
205
|
+
end
|
206
|
+
|
207
|
+
sheet do
|
208
|
+
|
209
|
+
column value_of(:x)
|
210
|
+
column :add
|
211
|
+
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
row = doc.row(1)
|
217
|
+
|
218
|
+
expect(row[0]).to eq('12.9')
|
219
|
+
expect(row[1]).to eq('34.7+A1')
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
support "starting with a string" do
|
224
|
+
|
225
|
+
doc = spreadsheet do
|
226
|
+
|
227
|
+
definitions do
|
228
|
+
|
229
|
+
set name: "Joe"
|
230
|
+
|
231
|
+
function greeting: "Hello " + name
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
sheet do
|
236
|
+
|
237
|
+
column value_of(:name)
|
238
|
+
column :greeting
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
end
|
243
|
+
|
244
|
+
row = doc.row(1)
|
245
|
+
|
246
|
+
expect(row[0]).to eq('"Joe"')
|
247
|
+
expect(row[1]).to eq('"Hello "+A1')
|
248
|
+
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|