dentaku 3.0.0 → 3.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +119 -0
  3. data/.travis.yml +8 -9
  4. data/CHANGELOG.md +9 -0
  5. data/Gemfile +0 -5
  6. data/LICENSE +21 -0
  7. data/README.md +44 -3
  8. data/Rakefile +4 -1
  9. data/dentaku.gemspec +8 -4
  10. data/lib/dentaku.rb +15 -2
  11. data/lib/dentaku/ast.rb +1 -0
  12. data/lib/dentaku/ast/access.rb +2 -2
  13. data/lib/dentaku/ast/arithmetic.rb +7 -7
  14. data/lib/dentaku/ast/bitwise.rb +2 -2
  15. data/lib/dentaku/ast/case.rb +5 -5
  16. data/lib/dentaku/ast/case/case_conditional.rb +1 -1
  17. data/lib/dentaku/ast/case/case_else.rb +2 -2
  18. data/lib/dentaku/ast/case/case_switch_variable.rb +2 -2
  19. data/lib/dentaku/ast/case/case_then.rb +2 -2
  20. data/lib/dentaku/ast/case/case_when.rb +2 -2
  21. data/lib/dentaku/ast/combinators.rb +10 -2
  22. data/lib/dentaku/ast/comparators.rb +34 -6
  23. data/lib/dentaku/ast/function.rb +1 -1
  24. data/lib/dentaku/ast/function_registry.rb +1 -1
  25. data/lib/dentaku/ast/functions/if.rb +6 -2
  26. data/lib/dentaku/ast/functions/max.rb +1 -1
  27. data/lib/dentaku/ast/functions/min.rb +1 -1
  28. data/lib/dentaku/ast/functions/ruby_math.rb +1 -1
  29. data/lib/dentaku/ast/functions/string_functions.rb +8 -8
  30. data/lib/dentaku/ast/functions/sum.rb +12 -0
  31. data/lib/dentaku/ast/grouping.rb +2 -2
  32. data/lib/dentaku/ast/identifier.rb +8 -5
  33. data/lib/dentaku/ast/negation.rb +2 -2
  34. data/lib/dentaku/ast/node.rb +1 -1
  35. data/lib/dentaku/ast/operation.rb +1 -1
  36. data/lib/dentaku/bulk_expression_solver.rb +39 -20
  37. data/lib/dentaku/calculator.rb +38 -28
  38. data/lib/dentaku/dependency_resolver.rb +1 -1
  39. data/lib/dentaku/flat_hash.rb +31 -0
  40. data/lib/dentaku/parser.rb +7 -6
  41. data/lib/dentaku/string_casing.rb +7 -0
  42. data/lib/dentaku/token.rb +1 -1
  43. data/lib/dentaku/token_matcher.rb +4 -4
  44. data/lib/dentaku/token_scanner.rb +18 -7
  45. data/lib/dentaku/tokenizer.rb +26 -2
  46. data/lib/dentaku/version.rb +1 -1
  47. data/spec/ast/arithmetic_spec.rb +2 -2
  48. data/spec/ast/comparator_spec.rb +57 -0
  49. data/spec/ast/function_spec.rb +1 -1
  50. data/spec/ast/max_spec.rb +5 -0
  51. data/spec/ast/min_spec.rb +5 -0
  52. data/spec/ast/sum_spec.rb +38 -0
  53. data/spec/benchmark.rb +2 -2
  54. data/spec/bulk_expression_solver_spec.rb +89 -1
  55. data/spec/calculator_spec.rb +40 -7
  56. data/spec/dentaku_spec.rb +11 -0
  57. data/spec/external_function_spec.rb +7 -7
  58. data/spec/parser_spec.rb +11 -11
  59. data/spec/spec_helper.rb +21 -3
  60. data/spec/token_matcher_spec.rb +0 -1
  61. data/spec/token_spec.rb +6 -0
  62. data/spec/tokenizer_spec.rb +37 -0
  63. metadata +70 -5
@@ -4,16 +4,21 @@ require 'dentaku/token_scanner'
4
4
 
5
5
  module Dentaku
6
6
  class Tokenizer
7
+ attr_reader :case_sensitive, :aliases
8
+
7
9
  LPAREN = TokenMatcher.new(:grouping, :open)
8
10
  RPAREN = TokenMatcher.new(:grouping, :close)
9
11
 
10
- def tokenize(string)
12
+ def tokenize(string, options = {})
11
13
  @nesting = 0
12
14
  @tokens = []
15
+ @aliases = options.fetch(:aliases, Dentaku.aliases)
13
16
  input = strip_comments(string.to_s.dup)
17
+ input = replace_aliases(input)
18
+ @case_sensitive = options.fetch(:case_sensitive, false)
14
19
 
15
20
  until input.empty?
16
- scanned = TokenScanner.scanners.any? do |scanner|
21
+ scanned = TokenScanner.scanners(case_sensitive: case_sensitive).any? do |scanner|
17
22
  scanned, input = scan(input, scanner)
18
23
  scanned
19
24
  end
@@ -58,6 +63,25 @@ module Dentaku
58
63
  input.gsub(/\/\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//, '')
59
64
  end
60
65
 
66
+ def replace_aliases(string)
67
+ return string unless @aliases.any?
68
+
69
+ string.gsub!(alias_regex) do |match|
70
+ match_regex = /^#{Regexp.escape(match)}$/i
71
+
72
+ @aliases.detect do |(_key, aliases)|
73
+ !aliases.grep(match_regex).empty?
74
+ end.first
75
+ end
76
+
77
+ string
78
+ end
79
+
80
+ def alias_regex
81
+ values = @aliases.values.flatten.join('|')
82
+ /(?<=\p{Punct}|[[:space:]]|\A)(#{values})(?=\()/i
83
+ end
84
+
61
85
  private
62
86
 
63
87
  def fail!(reason, **meta)
@@ -1,3 +1,3 @@
1
1
  module Dentaku
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0"
3
3
  end
@@ -8,10 +8,10 @@ describe Dentaku::AST::Arithmetic do
8
8
  let(:two) { Dentaku::AST::Numeric.new Dentaku::Token.new(:numeric, 2) }
9
9
  let(:x) { Dentaku::AST::Identifier.new Dentaku::Token.new(:identifier, 'x') }
10
10
  let(:y) { Dentaku::AST::Identifier.new Dentaku::Token.new(:identifier, 'y') }
11
- let(:ctx) {{'x' => 1, 'y' => 2}}
11
+ let(:ctx) { {'x' => 1, 'y' => 2} }
12
12
 
13
13
  it 'performs an arithmetic operation with numeric operands' do
14
- expect(add(one, two)).to eq 3
14
+ expect(add(one, two)).to eq 3
15
15
  expect(sub(one, two)).to eq -1
16
16
  expect(mul(one, two)).to eq 2
17
17
  expect(div(one, two)).to eq 0.5
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+ require 'dentaku/ast/comparators'
3
+
4
+ require 'dentaku/token'
5
+
6
+ describe Dentaku::AST::Comparator do
7
+ let(:one) { Dentaku::AST::Numeric.new Dentaku::Token.new(:numeric, 1) }
8
+ let(:two) { Dentaku::AST::Numeric.new Dentaku::Token.new(:numeric, 2) }
9
+ let(:x) { Dentaku::AST::Identifier.new Dentaku::Token.new(:identifier, 'x') }
10
+ let(:y) { Dentaku::AST::Identifier.new Dentaku::Token.new(:identifier, 'y') }
11
+ let(:ctx) { { 'x' => 'hello', 'y' => 'world' } }
12
+
13
+ it 'performs comparison with numeric operands' do
14
+ expect(less_than(one, two).value(ctx)).to be_truthy
15
+ expect(less_than(two, one).value(ctx)).to be_falsey
16
+ expect(greater_than(two, one).value(ctx)).to be_truthy
17
+ expect(not_equal(x, y).value(ctx)).to be_truthy
18
+ expect(equal(x, y).value(ctx)).to be_falsey
19
+ end
20
+
21
+ it 'returns correct operator symbols' do
22
+ expect(less_than(one, two).operator).to eq(:<)
23
+ expect(less_than_or_equal(one, two).operator).to eq(:<=)
24
+ expect(greater_than(one, two).operator).to eq(:>)
25
+ expect(greater_than_or_equal(one, two).operator).to eq(:>=)
26
+ expect(not_equal(x, y).operator).to eq(:!=)
27
+ expect(equal(x, y).operator).to eq(:==)
28
+ expect { Dentaku::AST::Comparator.new(one, two).operator }
29
+ .to raise_error(NotImplementedError)
30
+ end
31
+
32
+ private
33
+
34
+ def less_than(left, right)
35
+ Dentaku::AST::LessThan.new(left, right)
36
+ end
37
+
38
+ def less_than_or_equal(left, right)
39
+ Dentaku::AST::LessThanOrEqual.new(left, right)
40
+ end
41
+
42
+ def greater_than(left, right)
43
+ Dentaku::AST::GreaterThan.new(left, right)
44
+ end
45
+
46
+ def greater_than_or_equal(left, right)
47
+ Dentaku::AST::GreaterThanOrEqual.new(left, right)
48
+ end
49
+
50
+ def not_equal(left, right)
51
+ Dentaku::AST::NotEqual.new(left, right)
52
+ end
53
+
54
+ def equal(left, right)
55
+ Dentaku::AST::Equal.new(left, right)
56
+ end
57
+ end
@@ -29,7 +29,7 @@ describe Dentaku::AST::Function do
29
29
  one = described_class.register("one", :numeric, ->(x) { x * 2 })
30
30
  expect(one.arity).to eq 1
31
31
 
32
- two = described_class.register("two", :numeric, ->(x,y) { x + y })
32
+ two = described_class.register("two", :numeric, ->(x, y) { x + y })
33
33
  expect(two.arity).to eq 2
34
34
 
35
35
  many = described_class.register("many", :numeric, ->(*args) { args.max })
@@ -12,4 +12,9 @@ describe 'Dentaku::AST::Function::Max' do
12
12
  result = Dentaku('MAX(1, x, 1.8)', x: '2.3')
13
13
  expect(result).to eq 2.3
14
14
  end
15
+
16
+ it 'returns the largest value even if an Array is passed' do
17
+ result = Dentaku('MAX(1, x, 1.8)', x: [1.5, 2.3, 1.7])
18
+ expect(result).to eq 2.3
19
+ end
15
20
  end
@@ -12,4 +12,9 @@ describe 'Dentaku::AST::Function::Min' do
12
12
  result = Dentaku('MIN(1, x, 1.8)', x: '0.3')
13
13
  expect(result).to eq 0.3
14
14
  end
15
+
16
+ it 'returns the smallest value even if an Array is passed' do
17
+ result = Dentaku('MIN(1, x, 1.8)', x: [1.5, 0.3, 1.7])
18
+ expect(result).to eq 0.3
19
+ end
15
20
  end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+ require 'dentaku/ast/functions/sum'
3
+ require 'dentaku'
4
+
5
+ describe 'Dentaku::AST::Function::Sum' do
6
+ it 'returns the sum of an array of Numeric values' do
7
+ result = Dentaku('SUM(1, x, 1.8)', x: 2.3)
8
+ expect(result).to eq 5.1
9
+ end
10
+
11
+ it 'returns the sum of a single entry array of a Numeric value' do
12
+ result = Dentaku('SUM(x)', x: 2.3)
13
+ expect(result).to eq 2.3
14
+ end
15
+
16
+ it 'returns the sum even if a String is passed' do
17
+ result = Dentaku('SUM(1, x, 1.8)', x: '2.3')
18
+ expect(result).to eq 5.1
19
+ end
20
+
21
+ it 'returns the sum even if an array is passed' do
22
+ result = Dentaku('SUM(1, x, 2.3)', x: [4, 5])
23
+ expect(result).to eq 12.3
24
+ end
25
+
26
+ it 'returns the sum of nested sums' do
27
+ result = Dentaku('SUM(1, x, SUM(4, 5))', x: '2.3')
28
+ expect(result).to eq 12.3
29
+ end
30
+
31
+ context 'checking errors' do
32
+ let(:calculator) { Dentaku::Calculator.new }
33
+
34
+ it 'raises an error if no arguments are passed' do
35
+ expect { calculator.evaluate!('SUM()') }.to raise_error(ArgumentError)
36
+ end
37
+ end
38
+ end
@@ -9,12 +9,12 @@ puts "Ruby version #{RUBY_VERSION}"
9
9
 
10
10
  with_duplicate_variables = [
11
11
  "R1+R2+R3+R4+R5+R6",
12
- {"R1"=>100000, "R2"=>0, "R3"=>200000, "R4"=>0, "R5"=>500000, "R6"=>0, "r1"=>100000, "r2"=>0, "r3"=>200000, "r4"=>0, "r5"=>500000, "r6"=>0}
12
+ {"R1" => 100000, "R2" => 0, "R3" => 200000, "R4" => 0, "R5" => 500000, "R6" => 0, "r1" => 100000, "r2" => 0, "r3" => 200000, "r4" => 0, "r5" => 500000, "r6" => 0}
13
13
  ]
14
14
 
15
15
  without_duplicate_variables = [
16
16
  "R1+R2+R3+R4+R5+R6",
17
- {"R1"=>100000, "R2"=>0, "R3"=>200000, "R4"=>0, "R5"=>500000, "R6"=>0}
17
+ {"R1" => 100000, "R2" => 0, "R3" => 200000, "R4" => 0, "R5" => 500000, "R6" => 0}
18
18
  ]
19
19
 
20
20
  def test(args, custom_function: true)
@@ -1,5 +1,8 @@
1
1
  require 'spec_helper'
2
+ require 'dentaku'
2
3
  require 'dentaku/bulk_expression_solver'
4
+ require 'dentaku/calculator'
5
+ require 'dentaku/exceptions'
3
6
 
4
7
  RSpec.describe Dentaku::BulkExpressionSolver do
5
8
  let(:calculator) { Dentaku::Calculator.new }
@@ -33,7 +36,46 @@ RSpec.describe Dentaku::BulkExpressionSolver do
33
36
  it "does not require keys to be parseable" do
34
37
  expressions = { "the value of x, incremented" => "x + 1" }
35
38
  solver = described_class.new(expressions, calculator.store("x" => 3))
36
- expect(solver.solve!).to eq({ "the value of x, incremented" => 4 })
39
+ expect(solver.solve!).to eq("the value of x, incremented" => 4)
40
+ end
41
+
42
+ it "evaluates expressions in hashes and arrays, and expands the results" do
43
+ calculator.store(
44
+ fruit_quantities: {
45
+ apple: 5,
46
+ pear: 9
47
+ },
48
+ fruit_prices: {
49
+ apple: 1.66,
50
+ pear: 2.50
51
+ }
52
+ )
53
+ expressions = {
54
+ weekly_budget: {
55
+ fruit: "weekly_budget.apples + weekly_budget.pears",
56
+ apples: "fruit_quantities.apple * discounted_fruit_prices.apple",
57
+ pears: "fruit_quantities.pear * discounted_fruit_prices.pear",
58
+ },
59
+ discounted_fruit_prices: {
60
+ apple: "round(fruit_prices.apple * discounts[0], 2)",
61
+ pear: "round(fruit_prices.pear * discounts[1], 2)"
62
+ },
63
+ discounts: ["0.4 * 2", "0.3 * 2"],
64
+ }
65
+ solver = described_class.new(expressions, calculator)
66
+
67
+ expect(solver.solve!).to eq(
68
+ weekly_budget: {
69
+ fruit: 20.15,
70
+ apples: 6.65,
71
+ pears: 13.50
72
+ },
73
+ discounted_fruit_prices: {
74
+ apple: 1.33,
75
+ pear: 1.50
76
+ },
77
+ discounts: [0.8, 0.6]
78
+ )
37
79
  end
38
80
  end
39
81
 
@@ -73,5 +115,51 @@ RSpec.describe Dentaku::BulkExpressionSolver do
73
115
  end
74
116
  expect(exception.recipient_variable).to eq('more_apples')
75
117
  end
118
+
119
+ it 'safely handles argument errors' do
120
+ expressions = {i: "a / 5 + d", a: "m * 12", d: "a + b"}
121
+ result = described_class.new(expressions, calculator.store(m: 3)).solve
122
+ expect(result).to eq(
123
+ i: :undefined,
124
+ d: :undefined,
125
+ a: 36,
126
+ )
127
+ end
128
+
129
+ it 'supports nested hashes of expressions using dot notation' do
130
+ expressions = {
131
+ a: "25",
132
+ b: {
133
+ c: "a / 5",
134
+ d: [3, 4, 5]
135
+ },
136
+ e: ["b.c + b.d[1]"],
137
+ f: "e[0] + 1"
138
+ }
139
+ results = described_class.new(expressions, calculator).solve
140
+ expect(results[:f]).to eq 10
141
+ end
142
+
143
+ it 'uses stored values for expressions when they are known' do
144
+ calculator.store(Force: 50, Mass: 25)
145
+ expressions = {
146
+ Force: "Mass * Acceleration",
147
+ Mass: "Force / Acceleration",
148
+ Acceleration: "Force / Mass",
149
+ }
150
+ solver = described_class.new(expressions, calculator)
151
+ results = solver.solve
152
+ expect(results).to eq(Force: 50, Mass: 25, Acceleration: 2)
153
+ end
154
+
155
+ it 'solves all array expressions for which context exists, returning :undefined for the rest' do
156
+ calculator.store(first: 1, equation: 3)
157
+ system = {'key' => ['first * equation', 'second * equation'] }
158
+ solver = described_class.new(system, calculator)
159
+ expect(solver.dependencies).to eq('key' => ['second'])
160
+ results = solver.solve
161
+ expect(results).to eq('key' => [3, :undefined])
162
+ expect { solver.solve! }.to raise_error(Dentaku::UnboundVariableError)
163
+ end
76
164
  end
77
165
  end
@@ -2,8 +2,10 @@ require 'spec_helper'
2
2
  require 'dentaku'
3
3
 
4
4
  describe Dentaku::Calculator do
5
- let(:calculator) { described_class.new }
6
- let(:with_memory) { described_class.new.store(apples: 3) }
5
+ let(:calculator) { described_class.new }
6
+ let(:with_memory) { described_class.new.store(apples: 3) }
7
+ let(:with_aliases) { described_class.new(aliases: { round: ['rrround'] }) }
8
+ let(:without_nested_data) { described_class.new(nested_data_support: false) }
7
9
 
8
10
  it 'evaluates an expression' do
9
11
  expect(calculator.evaluate('7+3')).to eq(10)
@@ -32,6 +34,7 @@ describe Dentaku::Calculator do
32
34
  expect(calculator.evaluate('0.253/0.253')).to eq(1)
33
35
  expect(calculator.evaluate('0.253/d', d: 0.253)).to eq(1)
34
36
  expect(calculator.evaluate('10 + x', x: 'abc')).to be_nil
37
+ expect(calculator.evaluate('x * y', x: '.123', y: '100')).to eq(12.3)
35
38
  expect(calculator.evaluate('a/b', a: '10', b: '2')).to eq(5)
36
39
  expect(calculator.evaluate('t + 1*24*60*60', t: Time.local(2017, 1, 1))).to eq(Time.local(2017, 1, 2))
37
40
  expect(calculator.evaluate("2 | 3 * 9")).to eq (27)
@@ -65,17 +68,21 @@ describe Dentaku::Calculator do
65
68
  end
66
69
 
67
70
  it 'stores nested hashes' do
68
- calculator.store({a: {basket: {of: 'apples'}}, b: 2})
71
+ calculator.store(a: {basket: {of: 'apples'}}, b: 2)
69
72
  expect(calculator.evaluate!('a.basket.of')).to eq 'apples'
70
73
  expect(calculator.evaluate!('b')).to eq 2
71
74
  end
72
75
 
73
76
  it 'stores arrays' do
74
- calculator.store({a: [1, 2, 3]})
77
+ calculator.store(a: [1, 2, 3])
75
78
  expect(calculator.evaluate!('a[0]')).to eq 1
76
79
  expect(calculator.evaluate!('a[x]', x: 1)).to eq 2
77
80
  expect(calculator.evaluate!('a[x+1]', x: 1)).to eq 3
78
81
  end
82
+
83
+ it 'evalutates arrays' do
84
+ expect(calculator.evaluate([1, 2, 3])).to eq([1, 2, 3])
85
+ end
79
86
  end
80
87
 
81
88
  describe 'dependencies' do
@@ -92,6 +99,10 @@ describe Dentaku::Calculator do
92
99
  it "doesn't consider variables in memory as dependencies" do
93
100
  expect(with_memory.dependencies("apples + oranges")).to eq(['oranges'])
94
101
  end
102
+
103
+ it "finds no dependencies in array literals" do
104
+ expect(calculator.dependencies([1, 2, 3])).to eq([])
105
+ end
95
106
  end
96
107
 
97
108
  describe 'solve!' do
@@ -286,7 +297,7 @@ describe Dentaku::Calculator do
286
297
  expect(calculator.evaluate('round(8.8)')).to eq(9)
287
298
  expect(calculator.evaluate('round(8.75, 1)')).to eq(BigDecimal.new('8.8'))
288
299
 
289
- expect(calculator.evaluate('ROUND(apples * 0.93)', { apples: 10 })).to eq(9)
300
+ expect(calculator.evaluate('ROUND(apples * 0.93)', apples: 10)).to eq(9)
290
301
  end
291
302
 
292
303
  it 'include NOT' do
@@ -483,11 +494,11 @@ describe Dentaku::Calculator do
483
494
  end
484
495
 
485
496
  it 'disables the AST cache' do
486
- expect(calculator.disable_cache{ |c| c.cache_ast? }).to be false
497
+ expect(calculator.disable_cache { |c| c.cache_ast? }).to be false
487
498
  end
488
499
 
489
500
  it 'calculates normally' do
490
- expect(calculator.disable_cache{ |c| c.evaluate("2 + 2") }).to eq(4)
501
+ expect(calculator.disable_cache { |c| c.evaluate("2 + 2") }).to eq(4)
491
502
  end
492
503
  end
493
504
 
@@ -539,4 +550,26 @@ describe Dentaku::Calculator do
539
550
  expect(calculator.evaluate("max(1, two())")).to eq 2
540
551
  end
541
552
  end
553
+
554
+ describe 'aliases' do
555
+ it 'accepts aliases as instance option' do
556
+ expect(with_aliases.evaluate('rrround(5.1)')).to eq 5
557
+ end
558
+ end
559
+
560
+ describe 'nested_data' do
561
+ it 'default to nested data enabled' do
562
+ expect(calculator.nested_data_support).to be_truthy
563
+ end
564
+
565
+ it 'allow opt out of nested data support' do
566
+ expect(without_nested_data.nested_data_support).to be_falsy
567
+ end
568
+
569
+ it 'should allow optout of nested hash' do
570
+ expect do
571
+ without_nested_data.solve!('a.b.c')
572
+ end.to raise_error(Dentaku::UnboundVariableError)
573
+ end
574
+ end
542
575
  end
@@ -25,4 +25,15 @@ describe Dentaku do
25
25
  Dentaku('true AND')
26
26
  }.to raise_error(Dentaku::ParseError)
27
27
  end
28
+
29
+ it 'evaluates with class-level shortcut functions' do
30
+ expect(Dentaku.evaluate('2+2')).to eq(4)
31
+ expect(Dentaku.evaluate!('2+2')).to eq(4)
32
+ expect { Dentaku.evaluate!('a+1') }.to raise_error(Dentaku::UnboundVariableError)
33
+ end
34
+
35
+ it 'evaluates with class-level aliases' do
36
+ Dentaku.aliases = { roundup: ['roundupup'] }
37
+ expect(Dentaku.evaluate('roundupup(6.1)')).to eq(7)
38
+ end
28
39
  end
@@ -11,7 +11,7 @@ describe Dentaku::Calculator do
11
11
  c.add_function(:now, :string, -> { Time.now.to_s })
12
12
 
13
13
  fns = [
14
- [:pow, :numeric, ->(mantissa, exponent) { mantissa ** exponent }],
14
+ [:pow, :numeric, ->(mantissa, exponent) { mantissa**exponent }],
15
15
  [:biggest, :numeric, ->(*args) { args.max }],
16
16
  [:smallest, :numeric, ->(*args) { args.min }],
17
17
  ]
@@ -49,7 +49,7 @@ describe Dentaku::Calculator do
49
49
  }
50
50
  )
51
51
 
52
- expect(calculator.evaluate("INCLUDES(list, 2)", list: [1,2,3])).to eq(true)
52
+ expect(calculator.evaluate("INCLUDES(list, 2)", list: [1, 2, 3])).to eq(true)
53
53
  end
54
54
  end
55
55
 
@@ -61,15 +61,15 @@ describe Dentaku::Calculator do
61
61
 
62
62
  it 'does not store functions across all calculators' do
63
63
  calculator1 = Dentaku::Calculator.new
64
- calculator1.add_function(:my_function, :numeric, ->(x) { 2*x + 1 })
64
+ calculator1.add_function(:my_function, :numeric, ->(x) { 2 * x + 1 })
65
65
 
66
66
  calculator2 = Dentaku::Calculator.new
67
- calculator2.add_function(:my_function, :numeric, ->(x) { 4*x + 3 })
67
+ calculator2.add_function(:my_function, :numeric, ->(x) { 4 * x + 3 })
68
68
 
69
- expect(calculator1.evaluate("1 + my_function(2)")). to eq (1 + 2*2 + 1)
70
- expect(calculator2.evaluate("1 + my_function(2)")). to eq (1 + 4*2 + 3)
69
+ expect(calculator1.evaluate("1 + my_function(2)")). to eq (1 + 2 * 2 + 1)
70
+ expect(calculator2.evaluate("1 + my_function(2)")). to eq (1 + 4 * 2 + 3)
71
71
 
72
- expect{Dentaku::Calculator.new.evaluate("1 + my_function(2)")}.to raise_error(Dentaku::ParseError)
72
+ expect { Dentaku::Calculator.new.evaluate("1 + my_function(2)") }.to raise_error(Dentaku::ParseError)
73
73
  end
74
74
 
75
75
  it 'self.add_function adds to default/global function registry' do