dentaku 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,11 +1,11 @@
1
1
  require 'dentaku'
2
2
 
3
3
  describe Dentaku do
4
- it 'should evaulate an expression' do
5
- Dentaku('5+3').should eql(8)
4
+ it 'evaulates an expression' do
5
+ expect(Dentaku('5+3')).to eql(8)
6
6
  end
7
7
 
8
- it 'should bind values to variables' do
9
- Dentaku('oranges > 7', {:oranges => 10}).should be_true
8
+ it 'binds values to variables' do
9
+ expect(Dentaku('oranges > 7', {:oranges => 10})).to be_truthy
10
10
  end
11
11
  end
@@ -5,104 +5,104 @@ describe Dentaku::Evaluator do
5
5
  let(:evaluator) { Dentaku::Evaluator.new }
6
6
 
7
7
  describe 'rule scanning' do
8
- it 'should find a matching rule' do
8
+ it 'finds a matching rule' do
9
9
  rule = [Dentaku::TokenMatcher.new(:numeric, nil)]
10
10
  stream = [Dentaku::Token.new(:numeric, 1), Dentaku::Token.new(:operator, :add), Dentaku::Token.new(:numeric, 1)]
11
11
  position, _match = evaluator.find_rule_match(rule, stream)
12
- position.should eq(0)
12
+ expect(position).to eq(0)
13
13
  end
14
14
  end
15
15
 
16
16
  describe 'evaluating' do
17
- it 'empty expression should be truthy' do
18
- evaluator.evaluate([]).should be
17
+ it 'empty expression is be truthy' do
18
+ expect(evaluator.evaluate([])).to be
19
19
  end
20
20
 
21
- it 'empty expression should equal 0' do
22
- evaluator.evaluate([]).should eq(0)
21
+ it 'empty expression equals 0' do
22
+ expect(evaluator.evaluate([])).to eq(0)
23
23
  end
24
24
 
25
- it 'single numeric should return value' do
26
- evaluator.evaluate([Dentaku::Token.new(:numeric, 10)]).should eq(10)
27
- evaluator.evaluate([Dentaku::Token.new(:string, 'a')]).should eq('a')
25
+ it 'single numeric evaluates to its value' do
26
+ expect(evaluator.evaluate([Dentaku::Token.new(:numeric, 10)])).to eq(10)
27
+ expect(evaluator.evaluate([Dentaku::Token.new(:string, 'a')])).to eq('a')
28
28
  end
29
29
 
30
- it 'should evaluate one apply step' do
30
+ it 'evaluates one apply step' do
31
31
  stream = token_stream(1, :add, 1, :add, 1)
32
32
  expected = token_stream(2, :add, 1)
33
33
 
34
- evaluator.evaluate_step(stream, 0, 3, :apply).should eq(expected)
34
+ expect(evaluator.evaluate_step(stream, 0, 3, :apply)).to eq(expected)
35
35
  end
36
36
 
37
- it 'should evaluate one grouping step' do
37
+ it 'evaluates one grouping step' do
38
38
  stream = token_stream(:open, 1, :add, 1, :close, :multiply, 5)
39
39
  expected = token_stream(2, :multiply, 5)
40
40
 
41
- evaluator.evaluate_step(stream, 0, 5, :evaluate_group).should eq(expected)
41
+ expect(evaluator.evaluate_step(stream, 0, 5, :evaluate_group)).to eq(expected)
42
42
  end
43
43
 
44
44
  it 'supports unary minus' do
45
- evaluator.evaluate(token_stream(:subtract, 1)).should eq(-1)
46
- evaluator.evaluate(token_stream(1, :subtract, :subtract, 1)).should eq(2)
45
+ expect(evaluator.evaluate(token_stream(:subtract, 1))).to eq(-1)
46
+ expect(evaluator.evaluate(token_stream(1, :subtract, :subtract, 1))).to eq(2)
47
47
  end
48
48
 
49
49
  it 'supports unary percentage' do
50
- evaluator.evaluate(token_stream(50, :mod)).should eq(0.5)
51
- evaluator.evaluate(token_stream(50, :mod, :multiply, 100)).should eq(50)
50
+ expect(evaluator.evaluate(token_stream(50, :mod))).to eq(0.5)
51
+ expect(evaluator.evaluate(token_stream(50, :mod, :multiply, 100))).to eq(50)
52
52
  end
53
53
 
54
54
  describe 'maths' do
55
- it 'should perform addition' do
56
- evaluator.evaluate(token_stream(1, :add, 1)).should eq(2)
55
+ it 'performs addition' do
56
+ expect(evaluator.evaluate(token_stream(1, :add, 1))).to eq(2)
57
57
  end
58
58
 
59
- it 'should respect order of precedence' do
60
- evaluator.evaluate(token_stream(1, :add, 1, :multiply, 5)).should eq(6)
61
- evaluator.evaluate(token_stream(2, :add, 10, :mod, 2)).should eq(2)
59
+ it 'respects order of precedence' do
60
+ expect(evaluator.evaluate(token_stream(1, :add, 1, :multiply, 5))).to eq(6)
61
+ expect(evaluator.evaluate(token_stream(2, :add, 10, :mod, 2))).to eq(2)
62
62
  end
63
63
 
64
- it 'should respect explicit grouping' do
65
- evaluator.evaluate(token_stream(:open, 1, :add, 1, :close, :multiply, 5)).should eq(10)
64
+ it 'respects explicit grouping' do
65
+ expect(evaluator.evaluate(token_stream(:open, 1, :add, 1, :close, :multiply, 5))).to eq(10)
66
66
  end
67
67
 
68
- it 'should return floating point from division when there is a remainder' do
69
- evaluator.evaluate(token_stream(5, :divide, 4)).should eq(1.25)
68
+ it 'returns floating point from division when there is a remainder' do
69
+ expect(evaluator.evaluate(token_stream(5, :divide, 4))).to eq(1.25)
70
70
  end
71
71
  end
72
72
 
73
73
  describe 'functions' do
74
- it 'should be evaluated' do
75
- evaluator.evaluate(token_stream(:round, :open, 5, :divide, 3.0, :close)).should eq 2
76
- evaluator.evaluate(token_stream(:round, :open, 5, :divide, 3.0, :comma, 2, :close)).should eq 1.67
77
- evaluator.evaluate(token_stream(:roundup, :open, 5, :divide, 1.2, :close)).should eq 5
78
- evaluator.evaluate(token_stream(:rounddown, :open, 5, :divide, 1.2, :close)).should eq 4
74
+ it 'is evaluated' do
75
+ expect(evaluator.evaluate(token_stream(:round, :open, 5, :divide, 3.0, :close))).to eq 2
76
+ expect(evaluator.evaluate(token_stream(:round, :open, 5, :divide, 3.0, :comma, 2, :close))).to eq 1.67
77
+ expect(evaluator.evaluate(token_stream(:roundup, :open, 5, :divide, 1.2, :close))).to eq 5
78
+ expect(evaluator.evaluate(token_stream(:rounddown, :open, 5, :divide, 1.2, :close))).to eq 4
79
79
  end
80
80
  end
81
81
 
82
82
  describe 'logic' do
83
- it 'should evaluate conditional' do
84
- evaluator.evaluate(token_stream(5, :gt, 1)).should be_true
83
+ it 'evaluates conditional' do
84
+ expect(evaluator.evaluate(token_stream(5, :gt, 1))).to be_truthy
85
85
  end
86
86
 
87
- it 'should expand inequality ranges' do
87
+ it 'expands inequality ranges' do
88
88
  stream = token_stream(5, :lt, 10, :le, 10)
89
89
  expected = token_stream(5, :lt, 10, :and, 10, :le, 10)
90
- evaluator.evaluate_step(stream, 0, 5, :expand_range).should eq(expected)
90
+ expect(evaluator.evaluate_step(stream, 0, 5, :expand_range)).to eq(expected)
91
91
 
92
- evaluator.evaluate(token_stream(5, :lt, 10, :le, 10)).should be_true
93
- evaluator.evaluate(token_stream(3, :gt, 5, :ge, 1)).should be_false
92
+ expect(evaluator.evaluate(token_stream(5, :lt, 10, :le, 10))).to be_truthy
93
+ expect(evaluator.evaluate(token_stream(3, :gt, 5, :ge, 1))).to be_falsey
94
94
 
95
- lambda { evaluator.evaluate(token_stream(3, :gt, 2, :lt, 1)) }.should raise_error
95
+ expect { evaluator.evaluate(token_stream(3, :gt, 2, :lt, 1)) }.to raise_error
96
96
  end
97
97
 
98
- it 'should evaluate combined conditionals' do
99
- evaluator.evaluate(token_stream(5, :gt, 1, :or, :false)).should be_true
100
- evaluator.evaluate(token_stream(5, :gt, 1, :and, :false)).should be_false
98
+ it 'evaluates combined conditionals' do
99
+ expect(evaluator.evaluate(token_stream(5, :gt, 1, :or, :false))).to be_truthy
100
+ expect(evaluator.evaluate(token_stream(5, :gt, 1, :and, :false))).to be_falsey
101
101
  end
102
102
 
103
- it 'should support negation of a logical value' do
104
- evaluator.evaluate(token_stream(:not, :open, 5, :gt, 1, :or, :false, :close)).should be_false
105
- evaluator.evaluate(token_stream(:not, :open, 5, :gt, 1, :and, :false, :close)).should be_true
103
+ it 'negates a logical value' do
104
+ expect(evaluator.evaluate(token_stream(:not, :open, 5, :gt, 1, :or, :false, :close))).to be_falsey
105
+ expect(evaluator.evaluate(token_stream(:not, :open, 5, :gt, 1, :and, :false, :close))).to be_truthy
106
106
  end
107
107
  end
108
108
  end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'dentaku/expression'
3
+
4
+ describe Dentaku::Expression do
5
+ describe 'an all literal expression' do
6
+ it 'is fully bound' do
7
+ static = described_class.new('1 + 1')
8
+ expect(static).not_to be_unbound
9
+ end
10
+ end
11
+
12
+ describe 'an expression with variable identifiers' do
13
+ it 'is unbound' do
14
+ dynamic = described_class.new('a > 5')
15
+ expect(dynamic).to be_unbound
16
+ end
17
+
18
+ describe 'with values set for all variables' do
19
+ it 'is fully bound' do
20
+ dynamic = described_class.new('a > 5', {a: 7})
21
+ expect(dynamic).not_to be_unbound
22
+ end
23
+ end
24
+ end
25
+ end
@@ -34,24 +34,24 @@ describe Dentaku::Calculator do
34
34
  c.add_functions(fns)
35
35
  end
36
36
 
37
- it 'should include NOW' do
37
+ it 'includes NOW' do
38
38
  now = with_external_funcs.evaluate('NOW()')
39
- now.should_not be_nil
40
- now.should_not be_empty
39
+ expect(now).not_to be_nil
40
+ expect(now).not_to be_empty
41
41
  end
42
42
 
43
- it 'should include EXP' do
44
- with_external_funcs.evaluate('EXP(2,3)').should eq(8)
45
- with_external_funcs.evaluate('EXP(3,2)').should eq(9)
46
- with_external_funcs.evaluate('EXP(mantissa,exponent)', mantissa: 2, exponent: 4).should eq(16)
43
+ it 'includes EXP' do
44
+ expect(with_external_funcs.evaluate('EXP(2,3)')).to eq(8)
45
+ expect(with_external_funcs.evaluate('EXP(3,2)')).to eq(9)
46
+ expect(with_external_funcs.evaluate('EXP(mantissa,exponent)', mantissa: 2, exponent: 4)).to eq(16)
47
47
  end
48
48
 
49
- it 'should include MAX' do
50
- with_external_funcs.evaluate('MAX(8,6,7,5,3,0,9)').should eq(9)
49
+ it 'includes MAX' do
50
+ expect(with_external_funcs.evaluate('MAX(8,6,7,5,3,0,9)')).to eq(9)
51
51
  end
52
52
 
53
- it 'should include MIN' do
54
- with_external_funcs.evaluate('MIN(8,6,7,5,3,0,9)').should eq(0)
53
+ it 'includes MIN' do
54
+ expect(with_external_funcs.evaluate('MIN(8,6,7,5,3,0,9)')).to eq(0)
55
55
  end
56
56
  end
57
57
  end
@@ -2,102 +2,102 @@ require 'spec_helper'
2
2
  require 'dentaku/token_matcher'
3
3
 
4
4
  describe Dentaku::TokenMatcher do
5
- it 'with single category should match token category' do
5
+ it 'with single category matches token category' do
6
6
  matcher = described_class.new(:numeric)
7
7
  token = Dentaku::Token.new(:numeric, 5)
8
8
 
9
- matcher.should == token
9
+ expect(matcher).to eq(token)
10
10
  end
11
11
 
12
- it 'with multiple categories should match any included token category' do
12
+ it 'with multiple categories matches any included token category' do
13
13
  matcher = described_class.new([:comparator, :operator])
14
14
  numeric = Dentaku::Token.new(:numeric, 5)
15
15
  comparator = Dentaku::Token.new(:comparator, :lt)
16
16
  operator = Dentaku::Token.new(:operator, :add)
17
17
 
18
- matcher.should == comparator
19
- matcher.should == operator
20
- matcher.should_not == numeric
18
+ expect(matcher).to eq(comparator)
19
+ expect(matcher).to eq(operator)
20
+ expect(matcher).not_to eq(numeric)
21
21
  end
22
22
 
23
- it 'with single category and value should match token category and value' do
23
+ it 'with single category and value matches token category and value' do
24
24
  matcher = described_class.new(:operator, :add)
25
25
  addition = Dentaku::Token.new(:operator, :add)
26
26
  subtraction = Dentaku::Token.new(:operator, :subtract)
27
27
 
28
- matcher.should == addition
29
- matcher.should_not == subtraction
28
+ expect(matcher).to eq(addition)
29
+ expect(matcher).not_to eq(subtraction)
30
30
  end
31
31
 
32
- it 'with multiple values should match any included token value' do
32
+ it 'with multiple values matches any included token value' do
33
33
  matcher = described_class.new(:operator, [:add, :subtract])
34
34
  add = Dentaku::Token.new(:operator, :add)
35
35
  sub = Dentaku::Token.new(:operator, :subtract)
36
36
  mul = Dentaku::Token.new(:operator, :multiply)
37
37
  div = Dentaku::Token.new(:operator, :divide)
38
38
 
39
- matcher.should == add
40
- matcher.should == sub
41
- matcher.should_not == mul
42
- matcher.should_not == div
39
+ expect(matcher).to eq(add)
40
+ expect(matcher).to eq(sub)
41
+ expect(matcher).not_to eq(mul)
42
+ expect(matcher).not_to eq(div)
43
43
  end
44
44
 
45
- it 'should be invertible' do
45
+ it 'is invertible' do
46
46
  matcher = described_class.new(:operator, [:add, :subtract]).invert
47
47
  add = Dentaku::Token.new(:operator, :add)
48
48
  mul = Dentaku::Token.new(:operator, :multiply)
49
49
  cmp = Dentaku::Token.new(:comparator, :lt)
50
50
 
51
- matcher.should_not == add
52
- matcher.should == mul
53
- matcher.should == cmp
51
+ expect(matcher).not_to eq(add)
52
+ expect(matcher).to eq(mul)
53
+ expect(matcher).to eq(cmp)
54
54
  end
55
55
 
56
56
  describe 'stream matching' do
57
57
  let(:stream) { token_stream(5, 11, 9, 24, :hello, 8) }
58
58
 
59
- describe :standard do
59
+ describe 'standard' do
60
60
  let(:standard) { described_class.new(:numeric) }
61
61
 
62
- it 'should match zero or more occurrences in a token stream' do
63
- substream = standard.match(stream)
64
- substream.should be_matched
65
- substream.length.should eq 1
66
- substream.map(&:value).should eq [5]
62
+ it 'matches zero or more occurrences in a token stream' do
63
+ matched, substream = standard.match(stream)
64
+ expect(matched).to be_truthy
65
+ expect(substream.length).to eq 1
66
+ expect(substream.map(&:value)).to eq [5]
67
67
 
68
- substream = standard.match(stream, 4)
69
- substream.should be_empty
70
- substream.should_not be_matched
68
+ matched, substream = standard.match(stream, 4)
69
+ expect(substream).to be_empty
70
+ expect(matched).not_to be_truthy
71
71
  end
72
72
  end
73
73
 
74
- describe :star do
74
+ describe 'star' do
75
75
  let(:star) { described_class.new(:numeric).star }
76
76
 
77
- it 'should match zero or more occurrences in a token stream' do
78
- substream = star.match(stream)
79
- substream.should be_matched
80
- substream.length.should eq 4
81
- substream.map(&:value).should eq [5, 11, 9, 24]
77
+ it 'matches zero or more occurrences in a token stream' do
78
+ matched, substream = star.match(stream)
79
+ expect(matched).to be_truthy
80
+ expect(substream.length).to eq 4
81
+ expect(substream.map(&:value)).to eq [5, 11, 9, 24]
82
82
 
83
- substream = star.match(stream, 4)
84
- substream.should be_empty
85
- substream.should be_matched
83
+ matched, substream = star.match(stream, 4)
84
+ expect(substream).to be_empty
85
+ expect(matched).to be_truthy
86
86
  end
87
87
  end
88
88
 
89
- describe :plus do
89
+ describe 'plus' do
90
90
  let(:plus) { described_class.new(:numeric).plus }
91
91
 
92
- it 'should match one or more occurrences in a token stream' do
93
- substream = plus.match(stream)
94
- substream.should be_matched
95
- substream.length.should eq 4
96
- substream.map(&:value).should eq [5, 11, 9, 24]
92
+ it 'matches one or more occurrences in a token stream' do
93
+ matched, substream = plus.match(stream)
94
+ expect(matched).to be_truthy
95
+ expect(substream.length).to eq 4
96
+ expect(substream.map(&:value)).to eq [5, 11, 9, 24]
97
97
 
98
- substream = plus.match(stream, 4)
99
- substream.should be_empty
100
- substream.should_not be_matched
98
+ matched, substream = plus.match(stream, 4)
99
+ expect(substream).to be_empty
100
+ expect(matched).not_to be_truthy
101
101
  end
102
102
  end
103
103
  end
@@ -2,26 +2,26 @@ require 'dentaku/token_scanner'
2
2
 
3
3
  describe Dentaku::TokenScanner do
4
4
  let(:whitespace) { described_class.new(:whitespace, '\s') }
5
- let(:numeric) { described_class.new(:numeric, '(\d+(\.\d+)?|\.\d+)', lambda{|raw| raw =~ /\./ ? raw.to_f : raw.to_i }) }
5
+ let(:numeric) { described_class.new(:numeric, '(\d+(\.\d+)?|\.\d+)', lambda{|raw| raw =~ /\./ ? BigDecimal.new(raw) : raw.to_i }) }
6
6
 
7
- it 'should return a token for a matching string' do
7
+ it 'returns a token for a matching string' do
8
8
  token = whitespace.scan(' ')
9
- token.category.should eq(:whitespace)
10
- token.value.should eq(' ')
9
+ expect(token.category).to eq(:whitespace)
10
+ expect(token.value).to eq(' ')
11
11
  end
12
12
 
13
- it 'should return falsy for a non-matching string' do
14
- whitespace.scan('A').should_not be
13
+ it 'returns falsy for a non-matching string' do
14
+ expect(whitespace.scan('A')).not_to be
15
15
  end
16
16
 
17
- it 'should perform raw value conversion' do
17
+ it 'performs raw value conversion' do
18
18
  token = numeric.scan('5')
19
- token.category.should eq(:numeric)
20
- token.value.should eq(5)
19
+ expect(token.category).to eq(:numeric)
20
+ expect(token.value).to eq(5)
21
21
  end
22
22
 
23
- it 'should return a list of all configured scanners' do
24
- described_class.scanners.length.should eq 10
23
+ it 'returns a list of all configured scanners' do
24
+ expect(described_class.scanners.length).to eq 10
25
25
  end
26
26
  end
27
27
 
@@ -1,10 +1,10 @@
1
1
  require 'dentaku/token'
2
2
 
3
3
  describe Dentaku::Token do
4
- it 'should have a category and a value' do
4
+ it 'has a category and a value' do
5
5
  token = Dentaku::Token.new(:numeric, 5)
6
- token.category.should eq(:numeric)
7
- token.value.should eq(5)
8
- token.is?(:numeric).should be_true
6
+ expect(token.category).to eq(:numeric)
7
+ expect(token.value).to eq(5)
8
+ expect(token.is?(:numeric)).to be_truthy
9
9
  end
10
10
  end
@@ -3,117 +3,135 @@ require 'dentaku/tokenizer'
3
3
  describe Dentaku::Tokenizer do
4
4
  let(:tokenizer) { described_class.new }
5
5
 
6
- it 'should handle an empty expression' do
7
- tokenizer.tokenize('').should be_empty
6
+ it 'handles an empty expression' do
7
+ expect(tokenizer.tokenize('')).to be_empty
8
8
  end
9
9
 
10
- it 'should tokenize addition' do
10
+ it 'tokenizes addition' do
11
11
  tokens = tokenizer.tokenize('1+1')
12
- tokens.map(&:category).should eq([:numeric, :operator, :numeric])
13
- tokens.map(&:value).should eq([1, :add, 1])
12
+ expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
13
+ expect(tokens.map(&:value)).to eq([1, :add, 1])
14
+ end
15
+
16
+ it 'tokenizes comparison with =' do
17
+ tokens = tokenizer.tokenize('number = 5')
18
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric])
19
+ expect(tokens.map(&:value)).to eq([:number, :eq, 5])
20
+ end
21
+
22
+ it 'tokenizes comparison with =' do
23
+ tokens = tokenizer.tokenize('number = 5')
24
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric])
25
+ expect(tokens.map(&:value)).to eq([:number, :eq, 5])
26
+ end
27
+
28
+ it 'tokenizes comparison with alternate ==' do
29
+ tokens = tokenizer.tokenize('number == 5')
30
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric])
31
+ expect(tokens.map(&:value)).to eq([:number, :eq, 5])
14
32
  end
15
33
 
16
- it 'should ignore whitespace' do
34
+ it 'ignores whitespace' do
17
35
  tokens = tokenizer.tokenize('1 / 1 ')
18
- tokens.map(&:category).should eq([:numeric, :operator, :numeric])
19
- tokens.map(&:value).should eq([1, :divide, 1])
36
+ expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
37
+ expect(tokens.map(&:value)).to eq([1, :divide, 1])
20
38
  end
21
39
 
22
- it 'should handle floating point' do
40
+ it 'handles floating point' do
23
41
  tokens = tokenizer.tokenize('1.5 * 3.7')
24
- tokens.map(&:category).should eq([:numeric, :operator, :numeric])
25
- tokens.map(&:value).should eq([1.5, :multiply, 3.7])
42
+ expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
43
+ expect(tokens.map(&:value)).to eq([1.5, :multiply, 3.7])
26
44
  end
27
45
 
28
- it 'should not require leading zero' do
46
+ it 'does not require leading zero' do
29
47
  tokens = tokenizer.tokenize('.5 * 3.7')
30
- tokens.map(&:category).should eq([:numeric, :operator, :numeric])
31
- tokens.map(&:value).should eq([0.5, :multiply, 3.7])
48
+ expect(tokens.map(&:category)).to eq([:numeric, :operator, :numeric])
49
+ expect(tokens.map(&:value)).to eq([0.5, :multiply, 3.7])
32
50
  end
33
51
 
34
- it 'should accept arbitrary identifiers' do
52
+ it 'accepts arbitrary identifiers' do
35
53
  tokens = tokenizer.tokenize('monkeys > 1500')
36
- tokens.map(&:category).should eq([:identifier, :comparator, :numeric])
37
- tokens.map(&:value).should eq([:monkeys, :gt, 1500])
54
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric])
55
+ expect(tokens.map(&:value)).to eq([:monkeys, :gt, 1500])
38
56
  end
39
57
 
40
- it 'should recognize double-quoted strings' do
58
+ it 'recognizes double-quoted strings' do
41
59
  tokens = tokenizer.tokenize('animal = "giraffe"')
42
- tokens.map(&:category).should eq([:identifier, :comparator, :string])
43
- tokens.map(&:value).should eq([:animal, :eq, 'giraffe'])
60
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :string])
61
+ expect(tokens.map(&:value)).to eq([:animal, :eq, 'giraffe'])
44
62
  end
45
63
 
46
- it 'should recognize single-quoted strings' do
64
+ it 'recognizes single-quoted strings' do
47
65
  tokens = tokenizer.tokenize("animal = 'giraffe'")
48
- tokens.map(&:category).should eq([:identifier, :comparator, :string])
49
- tokens.map(&:value).should eq([:animal, :eq, 'giraffe'])
66
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :string])
67
+ expect(tokens.map(&:value)).to eq([:animal, :eq, 'giraffe'])
50
68
  end
51
69
 
52
- it 'should match "<=" before "<"' do
70
+ it 'matches "<=" before "<"' do
53
71
  tokens = tokenizer.tokenize('perimeter <= 7500')
54
- tokens.map(&:category).should eq([:identifier, :comparator, :numeric])
55
- tokens.map(&:value).should eq([:perimeter, :le, 7500])
72
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric])
73
+ expect(tokens.map(&:value)).to eq([:perimeter, :le, 7500])
56
74
  end
57
75
 
58
- it 'should match "and" for logical expressions' do
76
+ it 'matches "and" for logical expressions' do
59
77
  tokens = tokenizer.tokenize('octopi <= 7500 AND sharks > 1500')
60
- tokens.map(&:category).should eq([:identifier, :comparator, :numeric, :combinator, :identifier, :comparator, :numeric])
61
- tokens.map(&:value).should eq([:octopi, :le, 7500, :and, :sharks, :gt, 1500])
78
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric, :combinator, :identifier, :comparator, :numeric])
79
+ expect(tokens.map(&:value)).to eq([:octopi, :le, 7500, :and, :sharks, :gt, 1500])
62
80
  end
63
81
 
64
- it 'should match "or" for logical expressions' do
82
+ it 'matches "or" for logical expressions' do
65
83
  tokens = tokenizer.tokenize('size < 3 or admin = 1')
66
- tokens.map(&:category).should eq([:identifier, :comparator, :numeric, :combinator, :identifier, :comparator, :numeric])
67
- tokens.map(&:value).should eq([:size, :lt, 3, :or, :admin, :eq, 1])
84
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric, :combinator, :identifier, :comparator, :numeric])
85
+ expect(tokens.map(&:value)).to eq([:size, :lt, 3, :or, :admin, :eq, 1])
68
86
  end
69
87
 
70
- it 'should detect unbalanced parentheses' do
71
- lambda { tokenizer.tokenize('(5+3') }.should raise_error
72
- lambda { tokenizer.tokenize(')') }.should raise_error
88
+ it 'detects unbalanced parentheses' do
89
+ expect { tokenizer.tokenize('(5+3') }.to raise_error
90
+ expect { tokenizer.tokenize(')') }.to raise_error
73
91
  end
74
92
 
75
- it 'should recognize identifiers that share initial substrings with combinators' do
93
+ it 'recognizes identifiers that share initial substrings with combinators' do
76
94
  tokens = tokenizer.tokenize('andover < 10')
77
- tokens.length.should eq(3)
78
- tokens.map(&:category).should eq([:identifier, :comparator, :numeric])
79
- tokens.map(&:value).should eq([:andover, :lt, 10])
95
+ expect(tokens.length).to eq(3)
96
+ expect(tokens.map(&:category)).to eq([:identifier, :comparator, :numeric])
97
+ expect(tokens.map(&:value)).to eq([:andover, :lt, 10])
80
98
  end
81
99
 
82
100
  describe 'functions' do
83
101
  it 'include IF' do
84
102
  tokens = tokenizer.tokenize('if(x < 10, y, z)')
85
- tokens.length.should eq(10)
86
- tokens.map(&:category).should eq([:function, :grouping, :identifier, :comparator, :numeric, :grouping, :identifier, :grouping, :identifier, :grouping])
87
- tokens.map(&:value).should eq([:if, :open, :x, :lt, 10, :comma, :y, :comma, :z, :close])
103
+ expect(tokens.length).to eq(10)
104
+ expect(tokens.map(&:category)).to eq([:function, :grouping, :identifier, :comparator, :numeric, :grouping, :identifier, :grouping, :identifier, :grouping])
105
+ expect(tokens.map(&:value)).to eq([:if, :open, :x, :lt, 10, :comma, :y, :comma, :z, :close])
88
106
  end
89
107
 
90
108
  it 'include ROUND/UP/DOWN' do
91
109
  tokens = tokenizer.tokenize('round(8.2)')
92
- tokens.length.should eq(4)
93
- tokens.map(&:category).should eq([:function, :grouping, :numeric, :grouping])
94
- tokens.map(&:value).should eq([:round, :open, 8.2, :close])
110
+ expect(tokens.length).to eq(4)
111
+ expect(tokens.map(&:category)).to eq([:function, :grouping, :numeric, :grouping])
112
+ expect(tokens.map(&:value)).to eq([:round, :open, BigDecimal.new('8.2'), :close])
95
113
 
96
114
  tokens = tokenizer.tokenize('round(8.75, 1)')
97
- tokens.length.should eq(6)
98
- tokens.map(&:category).should eq([:function, :grouping, :numeric, :grouping, :numeric, :grouping])
99
- tokens.map(&:value).should eq([:round, :open, 8.75, :comma, 1, :close])
115
+ expect(tokens.length).to eq(6)
116
+ expect(tokens.map(&:category)).to eq([:function, :grouping, :numeric, :grouping, :numeric, :grouping])
117
+ expect(tokens.map(&:value)).to eq([:round, :open, BigDecimal.new('8.75'), :comma, 1, :close])
100
118
 
101
119
  tokens = tokenizer.tokenize('ROUNDUP(8.2)')
102
- tokens.length.should eq(4)
103
- tokens.map(&:category).should eq([:function, :grouping, :numeric, :grouping])
104
- tokens.map(&:value).should eq([:roundup, :open, 8.2, :close])
120
+ expect(tokens.length).to eq(4)
121
+ expect(tokens.map(&:category)).to eq([:function, :grouping, :numeric, :grouping])
122
+ expect(tokens.map(&:value)).to eq([:roundup, :open, BigDecimal.new('8.2'), :close])
105
123
 
106
124
  tokens = tokenizer.tokenize('RoundDown(8.2)')
107
- tokens.length.should eq(4)
108
- tokens.map(&:category).should eq([:function, :grouping, :numeric, :grouping])
109
- tokens.map(&:value).should eq([:rounddown, :open, 8.2, :close])
125
+ expect(tokens.length).to eq(4)
126
+ expect(tokens.map(&:category)).to eq([:function, :grouping, :numeric, :grouping])
127
+ expect(tokens.map(&:value)).to eq([:rounddown, :open, BigDecimal.new('8.2'), :close])
110
128
  end
111
129
 
112
130
  it 'include NOT' do
113
131
  tokens = tokenizer.tokenize('not(8 < 5)')
114
- tokens.length.should eq(6)
115
- tokens.map(&:category).should eq([:function, :grouping, :numeric, :comparator, :numeric, :grouping])
116
- tokens.map(&:value).should eq([:not, :open, 8, :lt, 5, :close])
132
+ expect(tokens.length).to eq(6)
133
+ expect(tokens.map(&:category)).to eq([:function, :grouping, :numeric, :comparator, :numeric, :grouping])
134
+ expect(tokens.map(&:value)).to eq([:not, :open, 8, :lt, 5, :close])
117
135
  end
118
136
  end
119
137
  end