dentaku 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bc147a87584da15958dfa99d62dcbc680333b21d2f9a35758ab11b4d7327787b
4
- data.tar.gz: a3138608c305adc7ff88168e5379bc5f7da7fa0712b60d9f5d4afb8c63bfa2c3
3
+ metadata.gz: d7a7a3fa41f933a1f88a76e736c32e71dcf87f391a7a4ba09d37b2abad8269b2
4
+ data.tar.gz: 3045bd6715d486669c2fe015165a2bef31928fccdf4e6a07f59a67257b9f4867
5
5
  SHA512:
6
- metadata.gz: 24da7dff044e4909cc1a6f900fb91c1aa30064e940ddf57e1c68112b0d61331b66fa066173012daeb302f757d10ea7ccec1cc505c95d6a8f32c019b2d7d219ff
7
- data.tar.gz: 5745ef2e7896a3e0570d236e0b04bdd627659b15da2234855f81adde950c18c3b04d73eaeb34ae836756bfeb37f54bff9886d8730912a32c9e2700161807ac10
6
+ metadata.gz: 2f8b4a5d727ec64a0308a57570fc51ff09864174fd0669956acb6b26b0d6b5694d6a0ec563eb107b577db79dd37ddd383fc36ec47bd17ebb11008981e2d5c729
7
+ data.tar.gz: 1cb16ed5d1bbad1c896d3907761206178093531ef02fe27eabaa19e1b5187f66f1d9d6586d410107133c08c520596dd7b9a6d5b47f23decb47e80ed2cbdd0e28
@@ -1,5 +1,9 @@
1
1
  # Change Log
2
2
 
3
+ ## [v3.3.0] 2018-12-04
4
+ - add array literal syntax
5
+ - return correct type from string function AST nodes
6
+
3
7
  ## [v3.2.1] 2018-10-24
4
8
  - make `evaluate` rescue more exceptions
5
9
 
@@ -162,7 +166,8 @@
162
166
  ## [v0.1.0] 2012-01-20
163
167
  - initial release
164
168
 
165
- [HEAD]: https://github.com/rubysolo/dentaku/compare/v3.2.1...HEAD
169
+ [HEAD]: https://github.com/rubysolo/dentaku/compare/v3.3.0...HEAD
170
+ [v3.3.0]: https://github.com/rubysolo/dentaku/compare/v3.2.1...v3.3.0
166
171
  [v3.2.1]: https://github.com/rubysolo/dentaku/compare/v3.2.0...v3.2.1
167
172
  [v3.2.0]: https://github.com/rubysolo/dentaku/compare/v3.1.0...v3.2.0
168
173
  [v3.1.0]: https://github.com/rubysolo/dentaku/compare/v3.0.0...v3.1.0
@@ -11,6 +11,7 @@ require_relative './ast/negation'
11
11
  require_relative './ast/comparators'
12
12
  require_relative './ast/combinators'
13
13
  require_relative './ast/access'
14
+ require_relative './ast/array'
14
15
  require_relative './ast/grouping'
15
16
  require_relative './ast/case'
16
17
  require_relative './ast/function_registry'
@@ -0,0 +1,23 @@
1
+ module Dentaku
2
+ module AST
3
+ class Array
4
+ def self.arity
5
+ end
6
+
7
+ def self.peek(*)
8
+ end
9
+
10
+ def initialize(*elements)
11
+ @elements = *elements
12
+ end
13
+
14
+ def value(context = {})
15
+ @elements.map { |el| el.value(context) }
16
+ end
17
+
18
+ def dependencies(context = {})
19
+ @elements.flat_map { |el| el.dependencies(context) }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -3,7 +3,20 @@ require_relative '../function'
3
3
  module Dentaku
4
4
  module AST
5
5
  module StringFunctions
6
- class Left < Function
6
+ class Base < Function
7
+ def type
8
+ :string
9
+ end
10
+
11
+ def negative_argument_failure(fun, arg = 'length')
12
+ raise Dentaku::ArgumentError.for(
13
+ :invalid_value,
14
+ function_name: "#{fun}()"
15
+ ), "#{fun}() requires #{arg} to be positive"
16
+ end
17
+ end
18
+
19
+ class Left < Base
7
20
  def initialize(*args)
8
21
  super
9
22
  @string, @length = *@args
@@ -12,11 +25,12 @@ module Dentaku
12
25
  def value(context = {})
13
26
  string = @string.value(context).to_s
14
27
  length = @length.value(context)
28
+ negative_argument_failure('LEFT') if length < 0
15
29
  string[0, length]
16
30
  end
17
31
  end
18
32
 
19
- class Right < Function
33
+ class Right < Base
20
34
  def initialize(*args)
21
35
  super
22
36
  @string, @length = *@args
@@ -25,11 +39,12 @@ module Dentaku
25
39
  def value(context = {})
26
40
  string = @string.value(context).to_s
27
41
  length = @length.value(context)
42
+ negative_argument_failure('RIGHT') if length < 0
28
43
  string[length * -1, length] || string
29
44
  end
30
45
  end
31
46
 
32
- class Mid < Function
47
+ class Mid < Base
33
48
  def initialize(*args)
34
49
  super
35
50
  @string, @offset, @length = *@args
@@ -38,12 +53,14 @@ module Dentaku
38
53
  def value(context = {})
39
54
  string = @string.value(context).to_s
40
55
  offset = @offset.value(context)
56
+ negative_argument_failure('MID', 'offset') if offset < 0
41
57
  length = @length.value(context)
58
+ negative_argument_failure('MID') if length < 0
42
59
  string[offset - 1, length].to_s
43
60
  end
44
61
  end
45
62
 
46
- class Len < Function
63
+ class Len < Base
47
64
  def initialize(*args)
48
65
  super
49
66
  @string = @args[0]
@@ -53,9 +70,13 @@ module Dentaku
53
70
  string = @string.value(context).to_s
54
71
  string.length
55
72
  end
73
+
74
+ def type
75
+ :numeric
76
+ end
56
77
  end
57
78
 
58
- class Find < Function
79
+ class Find < Base
59
80
  def initialize(*args)
60
81
  super
61
82
  @needle, @haystack = *@args
@@ -68,9 +89,13 @@ module Dentaku
68
89
  pos = haystack.index(needle)
69
90
  pos && pos + 1
70
91
  end
92
+
93
+ def type
94
+ :numeric
95
+ end
71
96
  end
72
97
 
73
- class Substitute < Function
98
+ class Substitute < Base
74
99
  def initialize(*args)
75
100
  super
76
101
  @original, @search, @replacement = *@args
@@ -85,7 +110,7 @@ module Dentaku
85
110
  end
86
111
  end
87
112
 
88
- class Concat < Function
113
+ class Concat < Base
89
114
  def initialize(*args)
90
115
  super
91
116
  end
@@ -95,7 +120,7 @@ module Dentaku
95
120
  end
96
121
  end
97
122
 
98
- class Contains < Function
123
+ class Contains < Base
99
124
  def initialize(*args)
100
125
  super
101
126
  @needle, @haystack = *args
@@ -104,6 +129,10 @@ module Dentaku
104
129
  def value(context = {})
105
130
  @haystack.value(context).to_s.include? @needle.value(context).to_s
106
131
  end
132
+
133
+ def type
134
+ :logical
135
+ end
107
136
  end
108
137
  end
109
138
  end
@@ -205,11 +205,28 @@ module Dentaku
205
205
  end
206
206
 
207
207
  unless operations.last == AST::Access
208
- fail! :unbalanced_bracket, token
208
+ fail! :unbalanced_bracket, token: token
209
209
  end
210
210
  consume
211
211
  end
212
212
 
213
+ when :array
214
+ case token.value
215
+ when :array_start
216
+ operations.push AST::Array
217
+ arities.push 0
218
+ when :array_end
219
+ while operations.any? && operations.last != AST::Array
220
+ consume
221
+ end
222
+
223
+ unless operations.last == AST::Array
224
+ fail! :unbalanced_bracket, token: token
225
+ end
226
+
227
+ consume(arities.pop.succ)
228
+ end
229
+
213
230
  when :grouping
214
231
  case token.value
215
232
  when :open
@@ -237,7 +254,7 @@ module Dentaku
237
254
 
238
255
  when :comma
239
256
  arities[-1] += 1
240
- while operations.any? && operations.last != AST::Grouping
257
+ while operations.any? && operations.last != AST::Grouping && operations.last != AST::Array
241
258
  consume
242
259
  end
243
260
 
@@ -43,6 +43,7 @@ module Dentaku
43
43
  :combinator,
44
44
  :operator,
45
45
  :grouping,
46
+ :array,
46
47
  :access,
47
48
  :case_statement,
48
49
  :comparator,
@@ -129,6 +130,11 @@ module Dentaku
129
130
  new(:grouping, '\(|\)|,', lambda { |raw| names[raw] })
130
131
  end
131
132
 
133
+ def array
134
+ names = { array_start: '{', array_end: '}', }.invert
135
+ new(:array, '\{|\}|,', lambda { |raw| names[raw] })
136
+ end
137
+
132
138
  def access
133
139
  names = { lbracket: '[', rbracket: ']' }.invert
134
140
  new(:access, '\[|\]', lambda { |raw| names[raw] })
@@ -1,3 +1,3 @@
1
1
  module Dentaku
2
- VERSION = "3.2.1"
2
+ VERSION = "3.3.0"
3
3
  end
@@ -25,6 +25,16 @@ describe Dentaku::AST::StringFunctions::Left do
25
25
  it 'handles size greater than input string length correctly' do
26
26
  expect(subject.value('string' => 'abcdefg', 'length' => 40)).to eq 'abcdefg'
27
27
  end
28
+
29
+ it 'has the proper type' do
30
+ expect(subject.type).to eq(:string)
31
+ end
32
+
33
+ it 'raises an error if given invalid length' do
34
+ expect {
35
+ subject.value('string' => 'abcdefg', 'length' => -2)
36
+ }.to raise_error(Dentaku::ArgumentError, /LEFT\(\) requires length to be positive/)
37
+ end
28
38
  end
29
39
 
30
40
  describe Dentaku::AST::StringFunctions::Right do
@@ -42,6 +52,10 @@ describe Dentaku::AST::StringFunctions::Right do
42
52
  subject = described_class.new(literal('abcdefg'), literal(40))
43
53
  expect(subject.value).to eq 'abcdefg'
44
54
  end
55
+
56
+ it 'has the proper type' do
57
+ expect(subject.type).to eq(:string)
58
+ end
45
59
  end
46
60
 
47
61
  describe Dentaku::AST::StringFunctions::Mid do
@@ -64,6 +78,10 @@ describe Dentaku::AST::StringFunctions::Mid do
64
78
  subject = described_class.new(literal('abcdefg'), literal(4), literal(40))
65
79
  expect(subject.value).to eq 'defg'
66
80
  end
81
+
82
+ it 'has the proper type' do
83
+ expect(subject.type).to eq(:string)
84
+ end
67
85
  end
68
86
 
69
87
  describe Dentaku::AST::StringFunctions::Len do
@@ -76,6 +94,10 @@ describe Dentaku::AST::StringFunctions::Len do
76
94
  subject = described_class.new(literal(''))
77
95
  expect(subject.value).to eq 0
78
96
  end
97
+
98
+ it 'has the proper type' do
99
+ expect(subject.type).to eq(:numeric)
100
+ end
79
101
  end
80
102
 
81
103
  describe Dentaku::AST::StringFunctions::Find do
@@ -93,6 +115,10 @@ describe Dentaku::AST::StringFunctions::Find do
93
115
  subject = described_class.new(literal('DE'), literal(''))
94
116
  expect(subject.value).to be_nil
95
117
  end
118
+
119
+ it 'has the proper type' do
120
+ expect(subject.type).to eq(:numeric)
121
+ end
96
122
  end
97
123
 
98
124
  describe Dentaku::AST::StringFunctions::Substitute do
@@ -110,6 +136,10 @@ describe Dentaku::AST::StringFunctions::Substitute do
110
136
  subject = described_class.new(literal('ABCDEFG'), literal('DE'), literal(''))
111
137
  expect(subject.value).to eq 'ABCFG'
112
138
  end
139
+
140
+ it 'has the proper type' do
141
+ expect(subject.type).to eq(:string)
142
+ end
113
143
  end
114
144
 
115
145
  describe Dentaku::AST::StringFunctions::Concat do
@@ -132,6 +162,10 @@ describe Dentaku::AST::StringFunctions::Concat do
132
162
  subject = described_class.new(literal(''), literal(''))
133
163
  expect(subject.value).to eq ''
134
164
  end
165
+
166
+ it 'has the proper type' do
167
+ expect(subject.type).to eq(:string)
168
+ end
135
169
  end
136
170
 
137
171
  describe Dentaku::AST::StringFunctions::Contains do
@@ -141,4 +175,8 @@ describe Dentaku::AST::StringFunctions::Contains do
141
175
  subject = described_class.new(literal('app'), literal('orange'))
142
176
  expect(subject.value).to be_falsy
143
177
  end
178
+
179
+ it 'has the proper type' do
180
+ expect(subject.type).to eq(:logical)
181
+ end
144
182
  end
@@ -79,6 +79,7 @@ describe Dentaku::Calculator do
79
79
  describe 'evaluate!' do
80
80
  it 'raises exception when formula has error' do
81
81
  expect { calculator.evaluate!('1 + + 1') }.to raise_error(Dentaku::ParseError)
82
+ expect { calculator.evaluate!('(1 > 5) OR LEFT("abc", 1)') }.to raise_error(Dentaku::ParseError)
82
83
  end
83
84
 
84
85
  it 'raises unbound variable errors' do
@@ -149,6 +150,7 @@ describe Dentaku::Calculator do
149
150
 
150
151
  it 'evaluates arrays' do
151
152
  expect(calculator.evaluate([1, 2, 3])).to eq([1, 2, 3])
153
+ expect(calculator.evaluate!('{1,2,3}')).to eq([1, 2, 3])
152
154
  end
153
155
  end
154
156
 
@@ -179,6 +179,12 @@ describe Dentaku::Tokenizer do
179
179
  expect(tokens.map(&:value)).to eq(['size', :lt, 3, :or, 'admin', :eq, 1])
180
180
  end
181
181
 
182
+ it 'tokenizes curly brackets for array literals' do
183
+ tokens = tokenizer.tokenize('{}')
184
+ expect(tokens.map(&:category)).to eq(%i(array array))
185
+ expect(tokens.map(&:value)).to eq(%i(array_start array_end))
186
+ end
187
+
182
188
  it 'tokenizes square brackets for data structure access' do
183
189
  tokens = tokenizer.tokenize('a[1]')
184
190
  expect(tokens.map(&:category)).to eq(%i(identifier access numeric access))
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dentaku
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 3.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Solomon White
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-25 00:00:00.000000000 Z
11
+ date: 2018-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: codecov
@@ -143,6 +143,7 @@ files:
143
143
  - lib/dentaku/ast.rb
144
144
  - lib/dentaku/ast/access.rb
145
145
  - lib/dentaku/ast/arithmetic.rb
146
+ - lib/dentaku/ast/array.rb
146
147
  - lib/dentaku/ast/bitwise.rb
147
148
  - lib/dentaku/ast/case.rb
148
149
  - lib/dentaku/ast/case/case_conditional.rb