dentaku 3.3.0 → 3.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -2
- data/.travis.yml +4 -6
- data/CHANGELOG.md +7 -1
- data/lib/dentaku/ast/arithmetic.rb +1 -1
- data/lib/dentaku/ast/case.rb +5 -3
- data/lib/dentaku/ast/case/case_conditional.rb +5 -2
- data/lib/dentaku/ast/function.rb +1 -1
- data/lib/dentaku/flat_hash.rb +2 -2
- data/lib/dentaku/parser.rb +17 -11
- data/lib/dentaku/token_matcher.rb +1 -1
- data/lib/dentaku/token_scanner.rb +1 -1
- data/lib/dentaku/tokenizer.rb +6 -1
- data/lib/dentaku/version.rb +1 -1
- data/spec/ast/addition_spec.rb +1 -1
- data/spec/ast/and_function_spec.rb +6 -6
- data/spec/ast/and_spec.rb +1 -1
- data/spec/ast/arithmetic_spec.rb +17 -17
- data/spec/ast/avg_spec.rb +5 -5
- data/spec/ast/count_spec.rb +7 -7
- data/spec/ast/division_spec.rb +1 -1
- data/spec/ast/function_spec.rb +8 -8
- data/spec/ast/max_spec.rb +3 -3
- data/spec/ast/min_spec.rb +3 -3
- data/spec/ast/mul_spec.rb +6 -6
- data/spec/ast/node_spec.rb +8 -8
- data/spec/ast/numeric_spec.rb +1 -1
- data/spec/ast/or_spec.rb +6 -6
- data/spec/ast/round_spec.rb +4 -4
- data/spec/ast/rounddown_spec.rb +4 -4
- data/spec/ast/roundup_spec.rb +4 -4
- data/spec/ast/sum_spec.rb +6 -6
- data/spec/ast/switch_spec.rb +5 -5
- data/spec/bulk_expression_solver_spec.rb +1 -1
- data/spec/calculator_spec.rb +30 -26
- data/spec/external_function_spec.rb +3 -3
- data/spec/parser_spec.rb +72 -123
- data/spec/spec_helper.rb +6 -4
- data/spec/token_matcher_spec.rb +8 -8
- data/spec/token_scanner_spec.rb +4 -4
- data/spec/tokenizer_spec.rb +8 -8
- metadata +2 -2
data/spec/ast/function_spec.rb
CHANGED
@@ -14,7 +14,7 @@ describe Dentaku::AST::Function do
|
|
14
14
|
described_class.register("flarble", :string, -> { "flarble" })
|
15
15
|
expect { described_class.get("flarble") }.not_to raise_error
|
16
16
|
function = described_class.get("flarble").new
|
17
|
-
expect(function.value).to eq
|
17
|
+
expect(function.value).to eq("flarble")
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'does not throw an error when registering a function with a name that matches a currently defined constant' do
|
@@ -24,13 +24,13 @@ describe Dentaku::AST::Function do
|
|
24
24
|
describe "#arity" do
|
25
25
|
it "gives the correct arity for custom functions" do
|
26
26
|
zero = described_class.register("zero", :numeric, ->() { 0 })
|
27
|
-
expect(zero.arity).to eq
|
27
|
+
expect(zero.arity).to eq(0)
|
28
28
|
|
29
29
|
one = described_class.register("one", :numeric, ->(x) { x * 2 })
|
30
|
-
expect(one.arity).to eq
|
30
|
+
expect(one.arity).to eq(1)
|
31
31
|
|
32
32
|
two = described_class.register("two", :numeric, ->(x, y) { x + y })
|
33
|
-
expect(two.arity).to eq
|
33
|
+
expect(two.arity).to eq(2)
|
34
34
|
|
35
35
|
many = described_class.register("many", :numeric, ->(*args) { args.max })
|
36
36
|
expect(many.arity).to be_nil
|
@@ -38,19 +38,19 @@ describe Dentaku::AST::Function do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'casts a String to an Integer if possible' do
|
41
|
-
expect(described_class.numeric('3')).to eq
|
41
|
+
expect(described_class.numeric('3')).to eq(3)
|
42
42
|
end
|
43
43
|
|
44
44
|
it 'casts a String to a BigDecimal if possible and if Integer would loose information' do
|
45
|
-
expect(described_class.numeric('3.2')).to eq
|
45
|
+
expect(described_class.numeric('3.2')).to eq(3.2)
|
46
46
|
end
|
47
47
|
|
48
48
|
it 'casts a String to a BigDecimal with a negative number' do
|
49
|
-
expect(described_class.numeric('-3.2')).to eq
|
49
|
+
expect(described_class.numeric('-3.2')).to eq(-3.2)
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'casts a String to a BigDecimal without a leading zero' do
|
53
|
-
expect(described_class.numeric('-.2')).to eq
|
53
|
+
expect(described_class.numeric('-.2')).to eq(-0.2)
|
54
54
|
end
|
55
55
|
|
56
56
|
it 'raises an error if the value could not be cast to a Numeric' do
|
data/spec/ast/max_spec.rb
CHANGED
@@ -5,16 +5,16 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Max' do
|
6
6
|
it 'returns the largest numeric value in an array of Numeric values' do
|
7
7
|
result = Dentaku('MAX(1, x, 1.8)', x: 2.3)
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(2.3)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the largest value even if a String is passed' do
|
12
12
|
result = Dentaku('MAX(1, x, 1.8)', x: '2.3')
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(2.3)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the largest value even if an Array is passed' do
|
17
17
|
result = Dentaku('MAX(1, x, 1.8)', x: [1.5, 2.3, 1.7])
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(2.3)
|
19
19
|
end
|
20
20
|
end
|
data/spec/ast/min_spec.rb
CHANGED
@@ -5,16 +5,16 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Min' do
|
6
6
|
it 'returns the smallest numeric value in an array of Numeric values' do
|
7
7
|
result = Dentaku('MIN(1, x, 1.8)', x: 2.3)
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(1)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the smallest value even if a String is passed' do
|
12
12
|
result = Dentaku('MIN(1, x, 1.8)', x: '0.3')
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(0.3)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the smallest value even if an Array is passed' do
|
17
17
|
result = Dentaku('MIN(1, x, 1.8)', x: [1.5, 0.3, 1.7])
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(0.3)
|
19
19
|
end
|
20
20
|
end
|
data/spec/ast/mul_spec.rb
CHANGED
@@ -5,34 +5,34 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Mul' do
|
6
6
|
it 'returns the product of an array of Numeric values' do
|
7
7
|
result = Dentaku('MUL(1, x, 1.8)', x: 2.3)
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(4.14)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the product of a single entry array of a Numeric value' do
|
12
12
|
result = Dentaku('MUL(x)', x: 2.3)
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(2.3)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'coerces string inputs to numeric' do
|
17
17
|
result = Dentaku('mul(1, x, 1.8)', x: '2.3')
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(4.14)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns the product even if an array is passed' do
|
22
22
|
result = Dentaku('mul(1, x, 2.3)', x: [4, 5])
|
23
|
-
expect(result).to eq
|
23
|
+
expect(result).to eq(46)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'handles nested calls' do
|
27
27
|
result = Dentaku('mul(1, x, mul(4, 5))', x: '2.3')
|
28
|
-
expect(result).to eq
|
28
|
+
expect(result).to eq(46)
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'checking errors' do
|
32
32
|
let(:calculator) { Dentaku::Calculator.new }
|
33
33
|
|
34
34
|
it 'raises an error if no arguments are passed' do
|
35
|
-
expect { calculator.evaluate!('MUL()') }.to raise_error(ArgumentError)
|
35
|
+
expect { calculator.evaluate!('MUL()') }.to raise_error(Dentaku::ArgumentError)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/spec/ast/node_spec.rb
CHANGED
@@ -6,30 +6,30 @@ require 'dentaku/parser'
|
|
6
6
|
describe Dentaku::AST::Node do
|
7
7
|
it 'returns list of dependencies' do
|
8
8
|
node = make_node('x + 5')
|
9
|
-
expect(node.dependencies).to eq
|
9
|
+
expect(node.dependencies).to eq(['x'])
|
10
10
|
|
11
11
|
node = make_node('5 < x')
|
12
|
-
expect(node.dependencies).to eq
|
12
|
+
expect(node.dependencies).to eq(['x'])
|
13
13
|
|
14
14
|
node = make_node('5 < 7')
|
15
|
-
expect(node.dependencies).to eq
|
15
|
+
expect(node.dependencies).to eq([])
|
16
16
|
|
17
17
|
node = make_node('(y * 7)')
|
18
|
-
expect(node.dependencies).to eq
|
18
|
+
expect(node.dependencies).to eq(['y'])
|
19
19
|
|
20
20
|
node = make_node('if(x > 5, y, z)')
|
21
|
-
expect(node.dependencies).to eq
|
21
|
+
expect(node.dependencies).to eq(['x', 'y', 'z'])
|
22
22
|
|
23
23
|
node = make_node('if(x > 5, y, z)')
|
24
|
-
expect(node.dependencies('x' => 7)).to eq
|
24
|
+
expect(node.dependencies('x' => 7)).to eq(['y', 'z'])
|
25
25
|
|
26
26
|
node = make_node('')
|
27
|
-
expect(node.dependencies).to eq
|
27
|
+
expect(node.dependencies).to eq([])
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'returns unique list of dependencies' do
|
31
31
|
node = make_node('x + x')
|
32
|
-
expect(node.dependencies).to eq
|
32
|
+
expect(node.dependencies).to eq(['x'])
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
data/spec/ast/numeric_spec.rb
CHANGED
data/spec/ast/or_spec.rb
CHANGED
@@ -7,29 +7,29 @@ describe 'Dentaku::AST::Or' do
|
|
7
7
|
|
8
8
|
it 'returns false if all of the arguments are false' do
|
9
9
|
result = Dentaku('OR(1 = "1", 0 = 1)')
|
10
|
-
expect(result).to eq
|
10
|
+
expect(result).to eq(false)
|
11
11
|
end
|
12
12
|
|
13
13
|
it 'supports nested expressions' do
|
14
14
|
result = Dentaku('OR(y = 1, x = 1)', x: 1, y: 2)
|
15
|
-
expect(result).to eq
|
15
|
+
expect(result).to eq(true)
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'returns true if any of the arguments is true' do
|
19
19
|
result = Dentaku('OR(1 = "1", "2" = "2", true = false, false)')
|
20
|
-
expect(result).to eq
|
20
|
+
expect(result).to eq(true)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'returns true if any nested OR function returns true' do
|
24
24
|
result = Dentaku('OR(OR(1 = 0), OR(true = false, OR(true)))')
|
25
|
-
expect(result).to eq
|
25
|
+
expect(result).to eq(true)
|
26
26
|
end
|
27
27
|
|
28
28
|
it 'raises an error if no arguments are passed' do
|
29
|
-
expect { calculator.evaluate!('OR()') }.to raise_error(ArgumentError)
|
29
|
+
expect { calculator.evaluate!('OR()') }.to raise_error(Dentaku::ArgumentError)
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'raises an error if a non logical argument is passed' do
|
33
|
-
expect { calculator.evaluate!('OR("r")') }.to raise_error(ArgumentError)
|
33
|
+
expect { calculator.evaluate!('OR("r")') }.to raise_error(Dentaku::ArgumentError)
|
34
34
|
end
|
35
35
|
end
|
data/spec/ast/round_spec.rb
CHANGED
@@ -5,21 +5,21 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Round' do
|
6
6
|
it 'returns the rounded down value' do
|
7
7
|
result = Dentaku('ROUND(1.8)')
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(2)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the rounded down value to the given precision' do
|
12
12
|
result = Dentaku('ROUND(x, y)', x: 1.8453, y: 3)
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(1.845)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the rounded down value to the given precision, also with strings' do
|
17
17
|
result = Dentaku('ROUND(x, y)', x: '1.8453', y: '3')
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(1.845)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns the rounded down value to the given precision, also with nil' do
|
22
22
|
result = Dentaku('ROUND(x, y)', x: '1.8453', y: nil)
|
23
|
-
expect(result).to eq
|
23
|
+
expect(result).to eq(2)
|
24
24
|
end
|
25
25
|
end
|
data/spec/ast/rounddown_spec.rb
CHANGED
@@ -5,21 +5,21 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Round' do
|
6
6
|
it 'returns the rounded value' do
|
7
7
|
result = Dentaku('ROUNDDOWN(1.8)')
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(1)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the rounded value to the given precision' do
|
12
12
|
result = Dentaku('ROUNDDOWN(x, y)', x: 1.8453, y: 3)
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(1.845)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the rounded value to the given precision, also with strings' do
|
17
17
|
result = Dentaku('ROUNDDOWN(x, y)', x: '1.8453', y: '3')
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(1.845)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns the rounded value to the given precision, also with nil' do
|
22
22
|
result = Dentaku('ROUNDDOWN(x, y)', x: '1.8453', y: nil)
|
23
|
-
expect(result).to eq
|
23
|
+
expect(result).to eq(1)
|
24
24
|
end
|
25
25
|
end
|
data/spec/ast/roundup_spec.rb
CHANGED
@@ -5,21 +5,21 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Round' do
|
6
6
|
it 'returns the rounded value' do
|
7
7
|
result = Dentaku('ROUNDUP(1.8)')
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(2)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the rounded value to the given precision' do
|
12
12
|
result = Dentaku('ROUNDUP(x, y)', x: 1.8453, y: 3)
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(1.846)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the rounded value to the given precision, also with strings' do
|
17
17
|
result = Dentaku('ROUNDUP(x, y)', x: '1.8453', y: '3')
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(1.846)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns the rounded value to the given precision, also with nil' do
|
22
22
|
result = Dentaku('ROUNDUP(x, y)', x: '1.8453', y: nil)
|
23
|
-
expect(result).to eq
|
23
|
+
expect(result).to eq(2)
|
24
24
|
end
|
25
25
|
end
|
data/spec/ast/sum_spec.rb
CHANGED
@@ -5,34 +5,34 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Sum' do
|
6
6
|
it 'returns the sum of an array of Numeric values' do
|
7
7
|
result = Dentaku('SUM(1, x, 1.8)', x: 2.3)
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq(5.1)
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns the sum of a single entry array of a Numeric value' do
|
12
12
|
result = Dentaku('SUM(x)', x: 2.3)
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(2.3)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the sum even if a String is passed' do
|
17
17
|
result = Dentaku('SUM(1, x, 1.8)', x: '2.3')
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq(5.1)
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns the sum even if an array is passed' do
|
22
22
|
result = Dentaku('SUM(1, x, 2.3)', x: [4, 5])
|
23
|
-
expect(result).to eq
|
23
|
+
expect(result).to eq(12.3)
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'returns the sum of nested sums' do
|
27
27
|
result = Dentaku('SUM(1, x, SUM(4, 5))', x: '2.3')
|
28
|
-
expect(result).to eq
|
28
|
+
expect(result).to eq(12.3)
|
29
29
|
end
|
30
30
|
|
31
31
|
context 'checking errors' do
|
32
32
|
let(:calculator) { Dentaku::Calculator.new }
|
33
33
|
|
34
34
|
it 'raises an error if no arguments are passed' do
|
35
|
-
expect { calculator.evaluate!('SUM()') }.to raise_error(ArgumentError)
|
35
|
+
expect { calculator.evaluate!('SUM()') }.to raise_error(Dentaku::ArgumentError)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/spec/ast/switch_spec.rb
CHANGED
@@ -5,26 +5,26 @@ require 'dentaku'
|
|
5
5
|
describe 'Dentaku::AST::Function::Switch' do
|
6
6
|
it 'returns the match if present in argumtents' do
|
7
7
|
result = Dentaku('SWITCH(1, 1, "one", 2, "two")')
|
8
|
-
expect(result).to eq
|
8
|
+
expect(result).to eq('one')
|
9
9
|
end
|
10
10
|
|
11
11
|
it 'returns nil if no match was found' do
|
12
12
|
result = Dentaku('SWITCH(3, 1, "one", 2, "two")')
|
13
|
-
expect(result).to eq
|
13
|
+
expect(result).to eq(nil)
|
14
14
|
end
|
15
15
|
|
16
16
|
it 'returns the default value if present and no match was found' do
|
17
17
|
result = Dentaku('SWITCH(3, 1, "one", 2, "two", "no match")')
|
18
|
-
expect(result).to eq
|
18
|
+
expect(result).to eq('no match')
|
19
19
|
end
|
20
20
|
|
21
21
|
it 'returns the first match if multiple matches exist' do
|
22
22
|
result = Dentaku('SWITCH(1, 1, "one", 2, "two", 1, "three")')
|
23
|
-
expect(result).to eq
|
23
|
+
expect(result).to eq('one')
|
24
24
|
end
|
25
25
|
|
26
26
|
it 'does not return a match where a value matches the search value' do
|
27
27
|
result = Dentaku('SWITCH(1, "one", 1, 2, "two", 3)')
|
28
|
-
expect(result).to eq
|
28
|
+
expect(result).to eq(3)
|
29
29
|
end
|
30
30
|
end
|
@@ -137,7 +137,7 @@ RSpec.describe Dentaku::BulkExpressionSolver do
|
|
137
137
|
f: "e[0] + 1"
|
138
138
|
}
|
139
139
|
results = described_class.new(expressions, calculator).solve
|
140
|
-
expect(results[:f]).to eq
|
140
|
+
expect(results[:f]).to eq(10)
|
141
141
|
end
|
142
142
|
|
143
143
|
it 'uses stored values for expressions when they are known' do
|
data/spec/calculator_spec.rb
CHANGED
@@ -103,6 +103,10 @@ describe Dentaku::Calculator do
|
|
103
103
|
expect { calculator.evaluate!('ROUNDUP(a)', a: nil) }.to raise_error(Dentaku::ArgumentError)
|
104
104
|
expect { calculator.evaluate!('SUM(a,b)', a: nil, b: nil) }.to raise_error(Dentaku::ArgumentError)
|
105
105
|
end
|
106
|
+
|
107
|
+
it 'raises argument error if a function is called with incorrect arity' do
|
108
|
+
expect { calculator.evaluate!('IF(a,b)', a: 1, b: 1) }.to raise_error(Dentaku::ArgumentError)
|
109
|
+
end
|
106
110
|
end
|
107
111
|
|
108
112
|
it 'supports unicode characters in identifiers' do
|
@@ -121,31 +125,31 @@ describe Dentaku::Calculator do
|
|
121
125
|
|
122
126
|
it 'can store the value `false`' do
|
123
127
|
calculator.store('i_am_false', false)
|
124
|
-
expect(calculator.evaluate!('i_am_false')).to eq
|
128
|
+
expect(calculator.evaluate!('i_am_false')).to eq(false)
|
125
129
|
end
|
126
130
|
|
127
131
|
it 'can store multiple values' do
|
128
132
|
calculator.store(first: 1, second: 2)
|
129
|
-
expect(calculator.evaluate!('first')).to eq
|
130
|
-
expect(calculator.evaluate!('second')).to eq
|
133
|
+
expect(calculator.evaluate!('first')).to eq(1)
|
134
|
+
expect(calculator.evaluate!('second')).to eq(2)
|
131
135
|
end
|
132
136
|
|
133
137
|
it 'stores formulas' do
|
134
138
|
calculator.store_formula('area', 'length * width')
|
135
|
-
expect(calculator.evaluate!('area', length: 5, width: 5)).to eq
|
139
|
+
expect(calculator.evaluate!('area', length: 5, width: 5)).to eq(25)
|
136
140
|
end
|
137
141
|
|
138
142
|
it 'stores nested hashes' do
|
139
143
|
calculator.store(a: {basket: {of: 'apples'}}, b: 2)
|
140
|
-
expect(calculator.evaluate!('a.basket.of')).to eq
|
141
|
-
expect(calculator.evaluate!('b')).to eq
|
144
|
+
expect(calculator.evaluate!('a.basket.of')).to eq('apples')
|
145
|
+
expect(calculator.evaluate!('b')).to eq(2)
|
142
146
|
end
|
143
147
|
|
144
148
|
it 'stores arrays' do
|
145
149
|
calculator.store(a: [1, 2, 3])
|
146
|
-
expect(calculator.evaluate!('a[0]')).to eq
|
147
|
-
expect(calculator.evaluate!('a[x]', x: 1)).to eq
|
148
|
-
expect(calculator.evaluate!('a[x+1]', x: 1)).to eq
|
150
|
+
expect(calculator.evaluate!('a[0]')).to eq(1)
|
151
|
+
expect(calculator.evaluate!('a[x]', x: 1)).to eq(2)
|
152
|
+
expect(calculator.evaluate!('a[x+1]', x: 1)).to eq(3)
|
149
153
|
end
|
150
154
|
|
151
155
|
it 'evaluates arrays' do
|
@@ -203,7 +207,7 @@ describe Dentaku::Calculator do
|
|
203
207
|
|
204
208
|
it 'is case-insensitive' do
|
205
209
|
result = with_memory.solve!(total_fruit: "Apples + pears", pears: 10)
|
206
|
-
expect(result[:total_fruit]).to eq
|
210
|
+
expect(result[:total_fruit]).to eq(13)
|
207
211
|
end
|
208
212
|
|
209
213
|
it "lets you know if a variable is unbound" do
|
@@ -223,7 +227,7 @@ describe Dentaku::Calculator do
|
|
223
227
|
width: "length * 2",
|
224
228
|
)
|
225
229
|
|
226
|
-
expect(result[:weight]).to eq
|
230
|
+
expect(result[:weight]).to eq(130.368)
|
227
231
|
end
|
228
232
|
|
229
233
|
it 'raises an exception if there are cyclic dependencies' do
|
@@ -304,14 +308,14 @@ describe Dentaku::Calculator do
|
|
304
308
|
unbound = 'foo * 1.5'
|
305
309
|
expect { calculator.evaluate!(unbound) }.to raise_error(Dentaku::UnboundVariableError)
|
306
310
|
expect { calculator.evaluate!(unbound) }.to raise_error do |error|
|
307
|
-
expect(error.unbound_variables).to eq
|
311
|
+
expect(error.unbound_variables).to eq(['foo'])
|
308
312
|
end
|
309
313
|
expect { calculator.evaluate!('a + b') }.to raise_error do |error|
|
310
|
-
expect(error.unbound_variables).to eq
|
314
|
+
expect(error.unbound_variables).to eq(['a', 'b'])
|
311
315
|
end
|
312
316
|
expect(calculator.evaluate(unbound)).to be_nil
|
313
|
-
expect(calculator.evaluate(unbound) { :bar }).to eq
|
314
|
-
expect(calculator.evaluate(unbound) { |e| e }).to eq
|
317
|
+
expect(calculator.evaluate(unbound) { :bar }).to eq(:bar)
|
318
|
+
expect(calculator.evaluate(unbound) { |e| e }).to eq(unbound)
|
315
319
|
end
|
316
320
|
|
317
321
|
it 'fails to evaluate incomplete statements' do
|
@@ -390,7 +394,7 @@ describe Dentaku::Calculator do
|
|
390
394
|
it 'include ROUND' do
|
391
395
|
expect(calculator.evaluate('round(8.2)')).to eq(8)
|
392
396
|
expect(calculator.evaluate('round(8.8)')).to eq(9)
|
393
|
-
expect(calculator.evaluate('round(8.75, 1)')).to eq(BigDecimal
|
397
|
+
expect(calculator.evaluate('round(8.75, 1)')).to eq(BigDecimal('8.8'))
|
394
398
|
|
395
399
|
expect(calculator.evaluate('ROUND(apples * 0.93)', apples: 10)).to eq(9)
|
396
400
|
end
|
@@ -406,7 +410,7 @@ describe Dentaku::Calculator do
|
|
406
410
|
it 'evaluates functions with negative numbers' do
|
407
411
|
expect(calculator.evaluate('if (-1 < 5, -1, 5)')).to eq(-1)
|
408
412
|
expect(calculator.evaluate('if (-1 = -1, -1, 5)')).to eq(-1)
|
409
|
-
expect(calculator.evaluate('round(-1.23, 1)')).to eq(BigDecimal
|
413
|
+
expect(calculator.evaluate('round(-1.23, 1)')).to eq(BigDecimal('-1.2'))
|
410
414
|
expect(calculator.evaluate('NOT(some_boolean) AND -1 > 3', some_boolean: true)).to be_falsey
|
411
415
|
end
|
412
416
|
|
@@ -506,14 +510,14 @@ describe Dentaku::Calculator do
|
|
506
510
|
expect(calculator.evaluate(formula, number: 6)).to eq(2)
|
507
511
|
end
|
508
512
|
|
509
|
-
it '
|
513
|
+
it 'raises an exception when no match and there is no default value' do
|
510
514
|
formula = <<-FORMULA
|
511
515
|
CASE number
|
512
516
|
WHEN 42
|
513
517
|
THEN 1
|
514
518
|
END
|
515
519
|
FORMULA
|
516
|
-
expect { calculator.evaluate(formula, number: 2) }
|
520
|
+
expect { calculator.evaluate!(formula, number: 2) }
|
517
521
|
.to raise_error("No block matched the switch value '2'")
|
518
522
|
end
|
519
523
|
|
@@ -579,9 +583,9 @@ describe Dentaku::Calculator do
|
|
579
583
|
Math.methods(false).each do |method|
|
580
584
|
it method do
|
581
585
|
if Math.method(method).arity == 2
|
582
|
-
expect(calculator.evaluate("#{method}(x,y)", x: 1, y: '2')).to eq
|
586
|
+
expect(calculator.evaluate("#{method}(x,y)", x: 1, y: '2')).to eq(Math.send(method, 1, 2))
|
583
587
|
else
|
584
|
-
expect(calculator.evaluate("#{method}(1)")).to eq
|
588
|
+
expect(calculator.evaluate("#{method}(1)")).to eq(Math.send(method, 1))
|
585
589
|
end
|
586
590
|
end
|
587
591
|
end
|
@@ -615,7 +619,7 @@ describe Dentaku::Calculator do
|
|
615
619
|
end
|
616
620
|
|
617
621
|
it 'clears all items from cache' do
|
618
|
-
expect(calculator.ast_cache.length).to eq
|
622
|
+
expect(calculator.ast_cache.length).to eq(3)
|
619
623
|
calculator.clear_cache
|
620
624
|
expect(calculator.ast_cache.keys).to be_empty
|
621
625
|
end
|
@@ -638,21 +642,21 @@ describe Dentaku::Calculator do
|
|
638
642
|
it 'concatenates strings' do
|
639
643
|
expect(
|
640
644
|
calculator.evaluate('CONCAT(s1, s2, s3)', 's1' => 'ab', 's2' => 'cd', 's3' => 'ef')
|
641
|
-
).to eq
|
645
|
+
).to eq('abcdef')
|
642
646
|
end
|
643
647
|
end
|
644
648
|
|
645
649
|
describe 'zero-arity functions' do
|
646
650
|
it 'can be used in formulas' do
|
647
651
|
calculator.add_function(:two, :numeric, -> { 2 })
|
648
|
-
expect(calculator.evaluate("max(two(), 1)")).to eq
|
649
|
-
expect(calculator.evaluate("max(1, two())")).to eq
|
652
|
+
expect(calculator.evaluate("max(two(), 1)")).to eq(2)
|
653
|
+
expect(calculator.evaluate("max(1, two())")).to eq(2)
|
650
654
|
end
|
651
655
|
end
|
652
656
|
|
653
657
|
describe 'aliases' do
|
654
658
|
it 'accepts aliases as instance option' do
|
655
|
-
expect(with_aliases.evaluate('rrround(5.1)')).to eq
|
659
|
+
expect(with_aliases.evaluate('rrround(5.1)')).to eq(5)
|
656
660
|
end
|
657
661
|
end
|
658
662
|
|