delorean_lang 0.6.3 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 2c68ada6d28bb5e65382a50c03e73518273929711569c689cba11387583cc5c9
4
- data.tar.gz: 6a5ec88595b66cfc946f03337bdec9dc470ea8f1d31f47820b82424b8d039ffe
2
+ SHA1:
3
+ metadata.gz: 3da8ff66652a79d2c5e7b38c57f35ba6821e3140
4
+ data.tar.gz: 6c6095ab7aeca95707b88f1966210085ac5a4a5a
5
5
  SHA512:
6
- metadata.gz: 1f49e8633ba3e904ee9341f97682773919cb546316e6a06eab3dc5fa575c63a57720e2fb4bf5f95a5bf9f8b465cf525305232e00fa4eeac2a4fcb3d26dbcdff0
7
- data.tar.gz: f17a7f9f187a55fca8ba0c4d1dad11c7f4c62d265f4c92e8fbafb92c932bda6d8c1d935a9d70e876c3c3d65f9fe74e32fc94d2c2b59d54fa98fb671db75fc00d
6
+ metadata.gz: 3ca7618ab74138cf05b64caaaef1e726acbcfa60d98fdb0bd85a4ff5c3033571acca3314568fcb906f4708c877c65b97bd4ade67b6a3a507943df2bc3a03cab7
7
+ data.tar.gz: ec8046cb9e85260ab4d6c44a09e853556e906d30e70ca86a48c2f522786bfe776f1176f12c829f7407f8da6c1bcf7d1e6acbb8b3c614ff1242da734f8aca32d8
data/.rubocop.yml CHANGED
@@ -81,3 +81,7 @@ Naming/RescuedExceptionsVariableName:
81
81
  Metrics/ParameterLists:
82
82
  Exclude:
83
83
  - 'spec/spec_helper.rb'
84
+
85
+ Style/AccessModifierDeclarations:
86
+ Exclude:
87
+ - 'lib/delorean/functions.rb'
data/README.md CHANGED
@@ -188,7 +188,7 @@ By default Delorean has some methods whitelisted, such as `length`, `min`, `max`
188
188
 
189
189
  ```
190
190
 
191
- Another way is to define methods using `delorean_fn` and `cached_delorean_fn`.
191
+ Another way is to define methods using `delorean_fn` with optional `private` and `cache` flags.
192
192
  Use `extend Delorean::Functions` or `include Delorean::Model` in your module or class.
193
193
 
194
194
  ```ruby
@@ -198,6 +198,10 @@ class Dummy < ActiveRecord::Base
198
198
  delorean_fn(:heres_my_number, sig: [0, Float::INFINITY]) do |*a|
199
199
  a.inject(0, :+)
200
200
  end
201
+
202
+ delorean_fn :private_cached_number, cache: true, private: true do |*a|
203
+ a.inject(0, :+)
204
+ end
201
205
  end
202
206
 
203
207
  module DummyModule
@@ -219,10 +223,10 @@ ExampleScript:
219
223
 
220
224
  ### Caching
221
225
 
222
- Delorean provides `cached_delorean_function` method that will cache result based on arguments.
226
+ Delorean provides `cache` flag for `delorean_fn` method that will cache result based on arguments.
223
227
 
224
228
  ```ruby
225
- cached_delorean_fn :returns_cached_openstruct, sig: 1 do |timestamp|
229
+ delorean_fn :returns_cached_openstruct, cache: true do |timestamp|
226
230
  User.all
227
231
  end
228
232
 
data/delorean.gemspec CHANGED
@@ -17,12 +17,12 @@ Gem::Specification.new do |gem|
17
17
  gem.version = Delorean::VERSION
18
18
  gem.licenses = ['MIT']
19
19
 
20
- gem.add_dependency 'activerecord', '>= 3.2'
21
- gem.add_dependency 'treetop', '~> 1.5'
20
+ gem.add_dependency 'activerecord'
21
+ gem.add_dependency 'treetop'
22
22
  gem.add_development_dependency 'pry'
23
- gem.add_development_dependency 'rspec', '~> 2.1'
23
+ gem.add_development_dependency 'rspec'
24
24
  gem.add_development_dependency 'rspec-instafail'
25
25
  gem.add_development_dependency 'rubocop'
26
26
  gem.add_development_dependency 'rubocop-performance'
27
- gem.add_development_dependency 'sqlite3', '~> 1.3.10'
27
+ gem.add_development_dependency 'sqlite3'
28
28
  end
data/lib/delorean/base.rb CHANGED
@@ -66,14 +66,7 @@ module Delorean
66
66
  # return true when we called obj.instance_of?(Hash) and do not
67
67
  # work with the "case/when" matcher!!! For now, this is a
68
68
  # hacky workaround. This is likely some sort of Ruby bug.
69
- if obj.instance_of?(Hash)
70
- # FIXME: this implementation doesn't handle something like
71
- # {}.length. i.e. length is a whitelisted function, but not
72
- # an attr. This implementation returns nil instead of 0.
73
- return obj[attr] if obj.member?(attr)
74
-
75
- return attr.is_a?(String) ? obj[attr.to_sym] : nil
76
- end
69
+ return _get_hash_attr(obj, attr, _e) if obj.instance_of?(Hash)
77
70
 
78
71
  # NOTE: should keep this function consistent with _index
79
72
  case obj
@@ -99,6 +92,29 @@ module Delorean
99
92
  end
100
93
  end
101
94
 
95
+ def self._get_hash_attr(obj, attr, _e, index_call = false)
96
+ return obj[attr] if obj.key?(attr)
97
+
98
+ return obj[attr.to_sym] if attr.is_a?(String) && obj.key?(attr.to_sym)
99
+
100
+ # Shouldn't try to call the method if hash['length'] was called.
101
+ return nil if index_call
102
+
103
+ # Return nil when it's obviously not a method
104
+ return nil unless attr.is_a?(String) || attr.is_a?(Symbol)
105
+
106
+ # hash.length might be either hash['length'] or hash.length call.
107
+ # If key is not found, check if object responds to method and call it.
108
+ # If not succeeded, return nil, assuming that it was an attribute call.
109
+ return nil unless obj.respond_to?(attr)
110
+
111
+ begin
112
+ return _instance_call(obj, attr, [], _e)
113
+ rescue StandardError
114
+ return nil
115
+ end
116
+ end
117
+
102
118
  ######################################################################
103
119
 
104
120
  def self._index(obj, args, _e)
@@ -108,7 +124,11 @@ module Delorean
108
124
  # FIXME: even Javascript which is superpermissive raises an
109
125
  # exception on null getattr.
110
126
  nil
111
- when Hash, NodeCall, Class, OpenStruct
127
+ when Hash
128
+ raise InvalidIndex unless args.length == 1
129
+
130
+ _get_hash_attr(obj, args[0], _e, true)
131
+ when NodeCall, Class, OpenStruct
112
132
  raise InvalidIndex unless args.length == 1
113
133
 
114
134
  _get_attr(obj, args[0], _e)
@@ -266,7 +266,7 @@ module Delorean
266
266
  if multi_line
267
267
  # if line starts with >4 spaces, assume it's a multline
268
268
  # continuation.
269
- if line =~ /\A {5}/
269
+ if /\A {5}/.match?(line)
270
270
  multi_line += line
271
271
  next
272
272
  else
@@ -2,29 +2,39 @@
2
2
 
3
3
  module Delorean
4
4
  module Functions
5
- def delorean_fn(name, _options = {}, &block)
5
+ def delorean_fn(name, options = {}, &block)
6
+ if options[:cache] == true
7
+ new_options = options.reject { |key, _| key == :cache }
8
+ return _cached_delorean_fn(name, new_options, &block)
9
+ end
10
+
6
11
  any_args = Delorean::Ruby::Whitelists::Matchers::Arguments::ANYTHING
7
12
 
8
13
  define_singleton_method(name, block)
9
14
 
10
- ::Delorean::Ruby.whitelist.add_class_method name do |method|
11
- method.called_on self, with: any_args
15
+ if options[:private] == true
16
+ singleton_class.class_eval { private name }
17
+ else
18
+ ::Delorean::Ruby.whitelist.add_class_method name do |method|
19
+ method.called_on self, with: any_args
20
+ end
12
21
  end
13
22
 
14
23
  name.to_sym
15
24
  end
16
25
 
17
- # FIXME: IDEA: we just make :cache an argument to delorean_fn.
18
- # That way, we don't need the cached_ flavors. It'll make all
19
- # this code a lot simpler. We should also just add the :private
20
- # mechanism here.
26
+ def clear_lookup_cache!
27
+ ::Delorean::Cache.adapter.clear!(klass: self)
28
+ end
29
+
30
+ private
21
31
 
22
32
  # By default implements a VERY HACKY class-based (per process) caching
23
- # mechanism for database lookup results. Issues include: cached
24
- # values are ActiveRecord objects. Query results can be very
25
- # large lists which we count as one item in the cache. Caching
33
+ # mechanism for database lookup results. Issues include: cached
34
+ # values are ActiveRecord objects. Query results can be very
35
+ # large lists which we count as one item in the cache. Caching
26
36
  # mechanism will result in large processes.
27
- def cached_delorean_fn(name, options = {})
37
+ def _cached_delorean_fn(name, options = {})
28
38
  delorean_fn(name, options) do |*args|
29
39
  delorean_cache_adapter = ::Delorean::Cache.adapter
30
40
  # Check if caching should be performed
@@ -55,9 +65,5 @@ module Delorean
55
65
  res
56
66
  end
57
67
  end
58
-
59
- def clear_lookup_cache!
60
- ::Delorean::Cache.adapter.clear!(klass: self)
61
- end
62
68
  end
63
69
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delorean
4
- VERSION = '0.6.3'
4
+ VERSION = '1.0.0'
5
5
  end
data/spec/dev_spec.rb CHANGED
@@ -18,7 +18,7 @@ describe 'Delorean' do
18
18
  ' c =?',
19
19
  ' d = 456',
20
20
  )
21
- engine.enumerate_nodes.should == SortedSet.new(['A', 'X', 'XX', 'Y'])
21
+ expect(engine.enumerate_nodes).to eq(SortedSet.new(['A', 'X', 'XX', 'Y']))
22
22
  end
23
23
 
24
24
  it 'can enumerate attrs by node' do
@@ -41,11 +41,11 @@ describe 'Delorean' do
41
41
  }
42
42
  res = engine.enumerate_attrs
43
43
 
44
- res.keys.sort.should == exp.keys.sort
44
+ expect(res.keys.sort).to eq(exp.keys.sort)
45
45
 
46
46
  exp.each do |k, v|
47
- engine.enumerate_attrs_by_node(k).sort.should == v
48
- res[k].sort.should == v
47
+ expect(engine.enumerate_attrs_by_node(k).sort).to eq(v)
48
+ expect(res[k].sort).to eq(v)
49
49
  end
50
50
  end
51
51
 
@@ -64,7 +64,7 @@ describe 'Delorean' do
64
64
  ' e =? 11',
65
65
  )
66
66
 
67
- engine.enumerate_params.should == Set.new(['a', 'c', 'e'])
67
+ expect(engine.enumerate_params).to eq(Set.new(['a', 'c', 'e']))
68
68
  end
69
69
 
70
70
  it 'can enumerate params by node' do
@@ -81,9 +81,9 @@ describe 'Delorean' do
81
81
  ' c =? 22',
82
82
  ' e =? 11',
83
83
  )
84
- engine.enumerate_params_by_node('X').should == Set.new(['a'])
85
- engine.enumerate_params_by_node('XX').should == Set.new(['a', 'c'])
86
- engine.enumerate_params_by_node('YY').should == Set.new(['a', 'c', 'e'])
87
- engine.enumerate_params_by_node('Z').should == Set.new([])
84
+ expect(engine.enumerate_params_by_node('X')).to eq(Set.new(['a']))
85
+ expect(engine.enumerate_params_by_node('XX')).to eq(Set.new(['a', 'c']))
86
+ expect(engine.enumerate_params_by_node('YY')).to eq(Set.new(['a', 'c', 'e']))
87
+ expect(engine.enumerate_params_by_node('Z')).to eq(Set.new([]))
88
88
  end
89
89
  end
data/spec/eval_spec.rb CHANGED
@@ -25,10 +25,10 @@ describe 'Delorean' do
25
25
  ' d = a ** 3 - 10*0.2',
26
26
  )
27
27
 
28
- engine.evaluate('A', ['a']).should == [123]
28
+ expect(engine.evaluate('A', ['a'])).to eq([123])
29
29
 
30
30
  r = engine.evaluate('A', ['x', 'b'])
31
- r.should == [-246, -124]
31
+ expect(r).to eq([-246, -124])
32
32
 
33
33
  expect(engine.evaluate('A', 'd')).to eq 1_860_865.0
34
34
  end
@@ -40,7 +40,7 @@ describe 'Delorean' do
40
40
  )
41
41
 
42
42
  r = engine.evaluate('A', 'c')
43
- r.should == -122
43
+ expect(r).to eq(-122)
44
44
  end
45
45
 
46
46
  it 'proper string interpolation' do
@@ -49,7 +49,7 @@ describe 'Delorean' do
49
49
  )
50
50
 
51
51
  r = engine.evaluate('A', 'a')
52
- r.should == "\n123\n"
52
+ expect(r).to eq("\n123\n")
53
53
  end
54
54
 
55
55
  it 'should handle getattr in expressions' do
@@ -57,7 +57,7 @@ describe 'Delorean' do
57
57
  " a = {'x':123, 'y':456, 'z':789}",
58
58
  ' b = A.a.x * A.a.y - A.a.z',
59
59
  )
60
- engine.evaluate('A', ['b']).should == [123 * 456 - 789]
60
+ expect(engine.evaluate('A', ['b'])).to eq([123 * 456 - 789])
61
61
  end
62
62
 
63
63
  it 'should handle numeric getattr' do
@@ -65,7 +65,7 @@ describe 'Delorean' do
65
65
  " a = {1:123, 0:456, 'z':789, 2: {'a':444}}",
66
66
  ' b = A.a.1 * A.a.0 - A.a.z - A.a.2.a',
67
67
  )
68
- engine.evaluate('A', ['b']).should == [123 * 456 - 789 - 444]
68
+ expect(engine.evaluate('A', ['b'])).to eq([123 * 456 - 789 - 444])
69
69
  end
70
70
 
71
71
  it 'should be able to evaluate multiple node attrs' do
@@ -77,7 +77,7 @@ describe 'Delorean' do
77
77
 
78
78
  h = { 'a' => 16 }
79
79
  r = engine.evaluate('A', ['c', 'b'], h)
80
- r.should == [4, 5]
80
+ expect(r).to eq([4, 5])
81
81
  end
82
82
 
83
83
  it 'should give error when accessing undefined attr' do
@@ -86,9 +86,9 @@ describe 'Delorean' do
86
86
  ' c = a.to_ss',
87
87
  )
88
88
 
89
- lambda {
90
- engine.evaluate('A', 'c')
91
- }.should raise_error(Delorean::InvalidGetAttribute)
89
+ expect { engine.evaluate('A', 'c') }.to raise_error(
90
+ Delorean::InvalidGetAttribute
91
+ )
92
92
  end
93
93
 
94
94
  it 'should be able to call 0-ary functions without ()' do
@@ -96,8 +96,7 @@ describe 'Delorean' do
96
96
  ' a = 1',
97
97
  ' d = a.to_s',
98
98
  )
99
-
100
- engine.evaluate('A', 'd').should == '1'
99
+ expect(engine.evaluate('A', 'd')).to eq('1')
101
100
  end
102
101
 
103
102
  it 'should handle default param values' do
@@ -107,7 +106,7 @@ describe 'Delorean' do
107
106
  )
108
107
 
109
108
  r = engine.evaluate('A', 'c')
110
- r.should == 1
109
+ expect(r).to eq(1)
111
110
  end
112
111
 
113
112
  it 'order of attr evaluation should not matter' do
@@ -117,8 +116,8 @@ describe 'Delorean' do
117
116
  ' a =? 2',
118
117
  ' c = A.a',
119
118
  )
120
- engine.evaluate('B', %w[c a]).should == [1, 2]
121
- engine.evaluate('B', %w[a c]).should == [2, 1]
119
+ expect(engine.evaluate('B', %w[c a])).to eq([1, 2])
120
+ expect(engine.evaluate('B', %w[a c])).to eq([2, 1])
122
121
  end
123
122
 
124
123
  it 'params should behave properly with inheritance' do
@@ -131,9 +130,9 @@ describe 'Delorean' do
131
130
  ' b = B.a',
132
131
  ' c = A.a',
133
132
  )
134
- engine.evaluate('C', %w[a b c]).should == [3, 2, 1]
135
- engine.evaluate('C', %w[a b c], 'a' => 4).should == [4, 4, 4]
136
- engine.evaluate('C', %w[c b a]).should == [1, 2, 3]
133
+ expect(engine.evaluate('C', %w[a b c])).to eq([3, 2, 1])
134
+ expect(engine.evaluate('C', %w[a b c], 'a' => 4)).to eq([4, 4, 4])
135
+ expect(engine.evaluate('C', %w[c b a])).to eq([1, 2, 3])
137
136
  end
138
137
 
139
138
  it 'should give error when param is undefined for eval' do
@@ -142,9 +141,9 @@ describe 'Delorean' do
142
141
  ' c = a / 123.0',
143
142
  )
144
143
 
145
- lambda {
146
- engine.evaluate('A', 'c')
147
- }.should raise_error(Delorean::UndefinedParamError)
144
+ expect { engine.evaluate('A', 'c') }.to raise_error(
145
+ Delorean::UndefinedParamError
146
+ )
148
147
  end
149
148
 
150
149
  it 'should handle simple param computation' do
@@ -154,7 +153,7 @@ describe 'Delorean' do
154
153
  )
155
154
 
156
155
  r = engine.evaluate('A', 'c', 'a' => 123)
157
- r.should == 1
156
+ expect(r).to eq(1)
158
157
  end
159
158
 
160
159
  it 'should give error on unknown node' do
@@ -162,9 +161,9 @@ describe 'Delorean' do
162
161
  ' a = 1',
163
162
  )
164
163
 
165
- lambda {
166
- engine.evaluate('B', 'a')
167
- }.should raise_error(Delorean::UndefinedNodeError)
164
+ expect { engine.evaluate('B', 'a') }.to raise_error(
165
+ Delorean::UndefinedNodeError
166
+ )
168
167
  end
169
168
 
170
169
  it 'should handle runtime errors and report module/line number' do
@@ -179,10 +178,10 @@ describe 'Delorean' do
179
178
  res = Delorean::Engine.grok_runtime_exception(exc)
180
179
  end
181
180
 
182
- res.should == {
181
+ expect(res).to eq(
183
182
  'error' => 'divided by 0',
184
183
  'backtrace' => [['XXX', 2, '/'], ['XXX', 2, 'a'], ['XXX', 3, 'b']],
185
- }
184
+ )
186
185
  end
187
186
 
188
187
  it 'should handle runtime errors 2' do
@@ -196,7 +195,7 @@ describe 'Delorean' do
196
195
  res = Delorean::Engine.grok_runtime_exception(exc)
197
196
  end
198
197
 
199
- res['backtrace'].should == [['XXX', 2, 'b']]
198
+ expect(res['backtrace']).to eq([['XXX', 2, 'b']])
200
199
  end
201
200
 
202
201
  it 'should handle optional args to external fns' do
@@ -205,8 +204,8 @@ describe 'Delorean' do
205
204
  " c = Dummy.one_or_two([1,2,3], ['a', 'b'])",
206
205
  )
207
206
 
208
- engine.evaluate('A', 'b').should == [['a', 'b'], nil]
209
- engine.evaluate('A', 'c').should == [[1, 2, 3], ['a', 'b']]
207
+ expect(engine.evaluate('A', 'b')).to eq([['a', 'b'], nil])
208
+ expect(engine.evaluate('A', 'c')).to eq([[1, 2, 3], ['a', 'b']])
210
209
  end
211
210
 
212
211
  it 'should handle operator precedence properly' do
@@ -218,10 +217,10 @@ describe 'Delorean' do
218
217
  )
219
218
 
220
219
  r = engine.evaluate('A', 'd')
221
- r.should == -50
220
+ expect(r).to eq(-50)
222
221
 
223
222
  r = engine.evaluate('A', 'e')
224
- r.should == -124
223
+ expect(r).to eq(-124)
225
224
  end
226
225
 
227
226
  it 'should handle if/else' do
@@ -232,10 +231,10 @@ describe 'Delorean' do
232
231
 
233
232
  engine.parse text
234
233
  r = engine.evaluate('A', 'e', 'd' => -100)
235
- r.should == 'gungamstyle'
234
+ expect(r).to eq('gungamstyle')
236
235
 
237
236
  r = engine.evaluate('A', 'e')
238
- r.should == 'korea'
237
+ expect(r).to eq('korea')
239
238
  end
240
239
 
241
240
  it 'should be able to access specific node attrs ' do
@@ -250,9 +249,9 @@ describe 'Delorean' do
250
249
  )
251
250
 
252
251
  r = engine.evaluate('B', 'c')
253
- r.should == 123 * 123
252
+ expect(r).to eq(123 * 123)
254
253
  r = engine.evaluate('C', 'c', 'c' => 5)
255
- r.should == 123 * 123 + 5
254
+ expect(r).to eq(123 * 123 + 5)
256
255
  end
257
256
 
258
257
  it 'should be able to access nodes and node attrs dynamically ' do
@@ -264,7 +263,7 @@ describe 'Delorean' do
264
263
  )
265
264
 
266
265
  r = engine.evaluate('B', 'c')
267
- r.should == 123 * 456
266
+ expect(r).to eq(123 * 456)
268
267
  end
269
268
 
270
269
  it 'should be able to call class methods on ActiveRecord classes' do
@@ -274,7 +273,7 @@ describe 'Delorean' do
274
273
  ' d = Dummy.call_me_maybe(5) + b + c',
275
274
  )
276
275
  r = engine.evaluate('A', ['b', 'c', 'd'])
277
- r.should == [10, 0, 15]
276
+ expect(r).to eq([10, 0, 15])
278
277
  end
279
278
 
280
279
  it 'should be able to access ActiveRecord whitelisted fns using .x syntax' do
@@ -282,7 +281,7 @@ describe 'Delorean' do
282
281
  ' b = Dummy.i_just_met_you("CRJ", 1.234).name2',
283
282
  )
284
283
  r = engine.evaluate('A', 'b')
285
- r.should == 'CRJ-1.234'
284
+ expect(r).to eq('CRJ-1.234')
286
285
  end
287
286
 
288
287
  it 'should be able to get attr on Hash objects using a.b syntax' do
@@ -292,7 +291,7 @@ describe 'Delorean' do
292
291
  ' d = b.b',
293
292
  ' e = b.this_is_crazy',
294
293
  )
295
- engine.evaluate('A', %w[c d e]).should == [456, 789, nil]
294
+ expect(engine.evaluate('A', %w[c d e])).to eq([456, 789, nil])
296
295
  end
297
296
 
298
297
  it 'get attr on nil should return nil' do
@@ -302,7 +301,7 @@ describe 'Delorean' do
302
301
  ' d = b.gaga || 55',
303
302
  )
304
303
  r = engine.evaluate('A', ['b', 'c', 'd'])
305
- r.should == [nil, nil, 55]
304
+ expect(r).to eq([nil, nil, 55])
306
305
  end
307
306
 
308
307
  it 'should be able to get attr on node' do
@@ -311,7 +310,7 @@ describe 'Delorean' do
311
310
  ' b = A',
312
311
  ' c = b.a * 2',
313
312
  )
314
- engine.evaluate('A', %w[a c]).should == [123, 123 * 2]
313
+ expect(engine.evaluate('A', %w[a c])).to eq([123, 123 * 2])
315
314
  end
316
315
 
317
316
  getattr_code = <<eoc
@@ -329,7 +328,7 @@ eoc
329
328
 
330
329
  it 'should be able to get attr on node 2' do
331
330
  engine.parse getattr_code
332
- engine.evaluate('E', 'xx').should == [1, 2, 3]
331
+ expect(engine.evaluate('E', 'xx')).to eq([1, 2, 3])
333
332
  end
334
333
 
335
334
  it 'should be able to call class methods on AR classes in modules' do
@@ -338,10 +337,10 @@ eoc
338
337
  ' c = M::N::NestedDummy.heres_my_number(867, 5309)',
339
338
  )
340
339
  r = engine.evaluate('A', 'b')
341
- r.should == 867 + 5309
340
+ expect(r).to eq(867 + 5309)
342
341
 
343
342
  r = engine.evaluate('A', 'c')
344
- r.should == 867 + 5309
343
+ expect(r).to eq(867 + 5309)
345
344
  end
346
345
 
347
346
  it 'should be able to use AR classes as values and call their methods' do
@@ -351,10 +350,10 @@ eoc
351
350
  ' c = M::N::NestedDummy.heres_my_number(867, 5309)',
352
351
  )
353
352
  r = engine.evaluate('A', 'b')
354
- r.should == 867 + 5309
353
+ expect(r).to eq(867 + 5309)
355
354
 
356
355
  r = engine.evaluate('A', 'c')
357
- r.should == 867 + 5309
356
+ expect(r).to eq(867 + 5309)
358
357
  end
359
358
 
360
359
  it 'should be able to use ruby modules as values and call their methods' do
@@ -365,10 +364,10 @@ eoc
365
364
  )
366
365
  # binding.pry
367
366
  r = engine.evaluate('A', 'b')
368
- r.should == 867 + 5309
367
+ expect(r).to eq(867 + 5309)
369
368
 
370
369
  r = engine.evaluate('A', 'c')
371
- r.should == 867 + 5309
370
+ expect(r).to eq(867 + 5309)
372
371
  end
373
372
 
374
373
  it 'should be able call method defined in a parent or matched to' do
@@ -381,16 +380,16 @@ eoc
381
380
  )
382
381
 
383
382
  r = engine.evaluate('A', 'b')
384
- r.should == :test_fn_result
383
+ expect(r).to eq(:test_fn_result)
385
384
 
386
385
  r = engine.evaluate('A', 'c')
387
- r.should == :test_fn2_result
386
+ expect(r).to eq(:test_fn2_result)
388
387
 
389
388
  r = engine.evaluate('A', 'd')
390
- r.should == :test_fn2_result_different
389
+ expect(r).to eq(:test_fn2_result_different)
391
390
 
392
391
  r = engine.evaluate('A', 'e')
393
- r.should == :test_fn2_result_different
392
+ expect(r).to eq(:test_fn2_result_different)
394
393
  end
395
394
 
396
395
  it 'should raise exception if method is not whitelisted' do
@@ -401,20 +400,38 @@ eoc
401
400
  ' c = Dummy.this_is_crazy()',
402
401
  )
403
402
 
404
- lambda {
405
- engine.evaluate('A', 'a')
406
- }.should raise_error(
403
+ expect { engine.evaluate('A', 'a') }.to raise_error(
407
404
  Delorean::InvalidGetAttribute,
408
405
  "attr lookup failed: 'test_fn4' on <Class> DeloreanFunctionsChildClass - no such method test_fn4"
409
406
  )
410
407
 
411
- lambda {
412
- engine.evaluate('A', 'b')
413
- }.should raise_error(RuntimeError, 'no such method test_fn4')
408
+ expect { engine.evaluate('A', 'b') }.to raise_error(
409
+ RuntimeError, 'no such method test_fn4'
410
+ )
411
+
412
+ expect { engine.evaluate('A', 'c') }.to raise_error(
413
+ RuntimeError, 'no such method this_is_crazy'
414
+ )
415
+ end
416
+
417
+ it 'should be able to call cached_delorean_fn' do
418
+ engine.parse defn(
419
+ 'A:',
420
+ ' b = Dummy.returns_cached_openstruct(1, 2)',
421
+ ' c = Dummy.returns_cached_openstruct(1, 2)',
422
+ ' d = Dummy.returns_cached_openstruct(1, 3)',
423
+ )
424
+
425
+ expect(OpenStruct).to receive(:new).twice.and_call_original
414
426
 
415
- lambda {
416
- engine.evaluate('A', 'c')
417
- }.should raise_error(RuntimeError, 'no such method this_is_crazy')
427
+ r = engine.evaluate('A', 'b')
428
+ expect(r['1']).to eq(2)
429
+
430
+ r = engine.evaluate('A', 'c')
431
+ expect(r['1']).to eq(2)
432
+
433
+ r = engine.evaluate('A', 'd')
434
+ expect(r['1']).to eq(3)
418
435
  end
419
436
 
420
437
  it 'should raise exception if required arguments are missing' do
@@ -428,32 +445,56 @@ eoc
428
445
  )
429
446
 
430
447
  r = engine.evaluate('A', 'a')
431
- r.should == { a: 1, b: 2, c: 3, d: 4, e: 5, rest: [6, 7, 8, 9, 10] }
448
+ expect(r).to eq(a: 1, b: 2, c: 3, d: 4, e: 5, rest: [6, 7, 8, 9, 10])
432
449
 
433
450
  r = engine.evaluate('A', 'b')
434
- r.should == { a: 1, b: 2, c: 3, d: 4, e: nil, rest: [] }
451
+ expect(r).to eq(a: 1, b: 2, c: 3, d: 4, e: nil, rest: [])
435
452
 
436
- lambda {
437
- r = engine.evaluate('A', 'c')
438
- }.should raise_error(
453
+ expect { r = engine.evaluate('A', 'c') }.to raise_error(
439
454
  ArgumentError,
440
455
  'wrong number of arguments (given 2, expected 3+)'
441
456
  )
442
457
 
443
- lambda {
444
- r = engine.evaluate('A', 'd')
445
- }.should raise_error(
458
+ expect { r = engine.evaluate('A', 'd') }.to raise_error(
446
459
  ArgumentError,
447
460
  'wrong number of arguments (given 0, expected 3+)'
448
461
  )
449
462
  end
450
463
 
464
+ it 'should raise exception if private method is called' do
465
+ engine.parse defn(
466
+ 'A:',
467
+ ' a = DeloreanFunctionsClass.test_private_fn',
468
+ ' b = DeloreanFunctionsChildClass.test_private_fn'
469
+ )
470
+
471
+ expect do
472
+ engine.evaluate('A', 'a')
473
+ end.to raise_error(
474
+ Delorean::InvalidGetAttribute,
475
+ "attr lookup failed: 'test_private_fn' on <Class> DeloreanFunctionsClass - no such method test_private_fn"
476
+ )
477
+
478
+ expect do
479
+ engine.evaluate('A', 'b')
480
+ end.to raise_error(
481
+ "attr lookup failed: 'test_private_fn' on <Class> DeloreanFunctionsChildClass - no such method test_private_fn"
482
+ )
483
+
484
+ expect do
485
+ DeloreanFunctionsClass.test_private_fn
486
+ end.to raise_error(
487
+ NoMethodError,
488
+ "private method `test_private_fn' called for DeloreanFunctionsClass:Class"
489
+ )
490
+ end
491
+
451
492
  it 'should ignore undeclared params sent to eval which match attr names' do
452
493
  engine.parse defn('A:',
453
494
  ' d = 12',
454
495
  )
455
496
  r = engine.evaluate('A', 'd', 'd' => 5, 'e' => 6)
456
- r.should == 12
497
+ expect(r).to eq(12)
457
498
  end
458
499
 
459
500
  it 'should handle different param defaults on nodes' do
@@ -467,19 +508,19 @@ eoc
467
508
  )
468
509
 
469
510
  r = engine.evaluate('C', 'c', 'p' => 5)
470
- r.should == 5 * 123
511
+ expect(r).to eq(5 * 123)
471
512
 
472
513
  r = engine.evaluate('B', 'c', 'p' => 10)
473
- r.should == 10 * 123
514
+ expect(r).to eq(10 * 123)
474
515
 
475
516
  r = engine.evaluate('A', 'c')
476
- r.should == 1 * 123
517
+ expect(r).to eq(1 * 123)
477
518
 
478
519
  r = engine.evaluate('B', 'c')
479
- r.should == 2 * 123
520
+ expect(r).to eq(2 * 123)
480
521
 
481
522
  r = engine.evaluate('C', 'c')
482
- r.should == 3 * 123
523
+ expect(r).to eq(3 * 123)
483
524
  end
484
525
 
485
526
  it 'should allow overriding of attrs as params' do
@@ -491,14 +532,14 @@ eoc
491
532
  )
492
533
 
493
534
  r = engine.evaluate('A', 'b', 'a' => 10)
494
- r.should == 2 * 3
535
+ expect(r).to eq(2 * 3)
495
536
 
496
537
  r = engine.evaluate('B', 'b', 'a' => 10)
497
- r.should == 10 * 3
538
+ expect(r).to eq(10 * 3)
498
539
 
499
- lambda {
500
- r = engine.evaluate('B', 'b')
501
- }.should raise_error(Delorean::UndefinedParamError)
540
+ expect { r = engine.evaluate('B', 'b') }.to raise_error(
541
+ Delorean::UndefinedParamError
542
+ )
502
543
  end
503
544
 
504
545
  sample_script = <<eof
@@ -519,17 +560,17 @@ eof
519
560
  engine.parse sample_script
520
561
 
521
562
  r = engine.evaluate('C', 'c')
522
- r.should == 4
563
+ expect(r).to eq(4)
523
564
 
524
565
  r = engine.evaluate('B', 'pc')
525
- r.should == 4 + 5
566
+ expect(r).to eq(4 + 5)
526
567
 
527
568
  r = engine.evaluate('C', 'pc')
528
- r.should == 4 + 3
569
+ expect(r).to eq(4 + 3)
529
570
 
530
- lambda {
531
- r = engine.evaluate('A', 'pc')
532
- }.should raise_error(Delorean::UndefinedParamError)
571
+ expect { r = engine.evaluate('A', 'pc') }.to raise_error(
572
+ Delorean::UndefinedParamError
573
+ )
533
574
  end
534
575
 
535
576
  it 'engines of same name should be independent' do
@@ -551,17 +592,24 @@ eof
551
592
  ' d = 111',
552
593
  )
553
594
 
554
- engine.evaluate('A', ['a', 'b']).should == [123, 123 * 3]
555
- engin2.evaluate('A', ['a', 'b']).should == [222.0, 222.0 / 5]
595
+ expect(engine.evaluate('A', ['a', 'b'])).to eq(
596
+ [123, 123 * 3]
597
+ )
598
+ expect(engin2.evaluate('A', ['a', 'b'])).to eq(
599
+ [222.0, 222.0 / 5]
600
+ )
556
601
 
557
- engine.evaluate('B', ['a', 'b', 'c']).should == [123, 123 * 3, 123 * 3 * 2]
558
- engin2.evaluate('B', ['a', 'b', 'c']).should ==
602
+ expect(engine.evaluate('B', ['a', 'b', 'c'])).to eq(
603
+ [123, 123 * 3, 123 * 3 * 2]
604
+ )
605
+ expect(engin2.evaluate('B', ['a', 'b', 'c'])).to eq(
559
606
  [222.0, 222.0 / 5, 222.0 / 5 * 3]
607
+ )
560
608
 
561
- engin2.evaluate('C', 'd').should == 111
562
- lambda {
563
- engine.evaluate('C', 'd')
564
- }.should raise_error(Delorean::UndefinedNodeError)
609
+ expect(engin2.evaluate('C', 'd')).to eq(111)
610
+ expect { engine.evaluate('C', 'd') }.to raise_error(
611
+ Delorean::UndefinedNodeError
612
+ )
565
613
  end
566
614
 
567
615
  it 'should handle invalid expression evaluation' do
@@ -578,12 +626,12 @@ eof
578
626
  ' e = [1, 1+1, 1+1+1, 1*2*4]',
579
627
  )
580
628
 
581
- engine.evaluate('A', %w[b c d e]).should ==
629
+ expect(engine.evaluate('A', %w[b c d e])).to eq(
582
630
  [[],
583
631
  [1, 2, 3],
584
632
  [[], [1, 2, 3], [], [1, 2, 3], 1, 2, '123', 1.1, -1.23],
585
633
  [1, 2, 3, 8],
586
- ]
634
+ ])
587
635
  end
588
636
 
589
637
  it 'should eval list expressions' do
@@ -593,11 +641,11 @@ eof
593
641
  ' d = c*2',
594
642
  )
595
643
 
596
- engine.evaluate('A', %w[b c d]).should ==
644
+ expect(engine.evaluate('A', %w[b c d])).to eq(
597
645
  [[],
598
646
  [1, 2, 3],
599
647
  [1, 2, 3] * 2,
600
- ]
648
+ ])
601
649
  end
602
650
 
603
651
  it 'should eval sets and set comprehension' do
@@ -606,8 +654,9 @@ eof
606
654
  ' b = {i*5 for i in {1,2,3}}',
607
655
  ' c = {1,2,3} | {4,5}',
608
656
  )
609
- engine.evaluate('A', ['a', 'b', 'c']).should ==
657
+ expect(engine.evaluate('A', ['a', 'b', 'c'])).to eq(
610
658
  [Set[], Set[5, 10, 15], Set[1, 2, 3, 4, 5]]
659
+ )
611
660
  end
612
661
 
613
662
  it 'should eval list comprehension' do
@@ -615,22 +664,22 @@ eof
615
664
  ' b = [i*5 for i in [1,2,3]]',
616
665
  ' c = [a-b for a, b in [[1,2],[4,3]]]'
617
666
  )
618
- engine.evaluate('A', 'b').should == [5, 10, 15]
619
- engine.evaluate('A', 'c').should == [-1, 1]
667
+ expect(engine.evaluate('A', 'b')).to eq([5, 10, 15])
668
+ expect(engine.evaluate('A', 'c')).to eq([-1, 1])
620
669
  end
621
670
 
622
671
  it 'should eval nested list comprehension' do
623
672
  engine.parse defn('A:',
624
673
  ' b = [[a+c for c in [4,5]] for a in [1,2,3]]',
625
674
  )
626
- engine.evaluate('A', 'b').should == [[5, 6], [6, 7], [7, 8]]
675
+ expect(engine.evaluate('A', 'b')).to eq([[5, 6], [6, 7], [7, 8]])
627
676
  end
628
677
 
629
678
  it 'should eval list comprehension variable override' do
630
679
  engine.parse defn('A:',
631
680
  ' b = [b/2.0 for b in [1,2,3]]',
632
681
  )
633
- engine.evaluate('A', 'b').should == [0.5, 1.0, 1.5]
682
+ expect(engine.evaluate('A', 'b')).to eq([0.5, 1.0, 1.5])
634
683
  end
635
684
 
636
685
  it 'should eval list comprehension variable override (2)' do
@@ -638,7 +687,7 @@ eof
638
687
  ' a = 1',
639
688
  ' b = [a+1 for a in [1,2,3]]',
640
689
  )
641
- engine.evaluate('A', 'b').should == [2, 3, 4]
690
+ expect(engine.evaluate('A', 'b')).to eq([2, 3, 4])
642
691
  end
643
692
 
644
693
  it 'should eval conditional list comprehension' do
@@ -646,15 +695,15 @@ eof
646
695
  ' b = [i*5 for i in [1,2,3,4,5] if i%2 == 1]',
647
696
  ' c = [i/10.0 for i in [1,2,3,4,5] if i>4]',
648
697
  )
649
- engine.evaluate('A', 'b').should == [5, 15, 25]
650
- engine.evaluate('A', 'c').should == [0.5]
698
+ expect(engine.evaluate('A', 'b')).to eq([5, 15, 25])
699
+ expect(engine.evaluate('A', 'c')).to eq([0.5])
651
700
  end
652
701
 
653
702
  it 'should handle list comprehension unpacking' do
654
703
  engine.parse defn('A:',
655
704
  ' b = [a-b for a, b in [[1,2],[20,10]]]',
656
705
  )
657
- engine.evaluate('A', 'b').should == [-1, 10]
706
+ expect(engine.evaluate('A', 'b')).to eq([-1, 10])
658
707
  end
659
708
 
660
709
  it 'should handle list comprehension with conditions using loop var' do
@@ -662,7 +711,7 @@ eof
662
711
  engine.parse defn('A:',
663
712
  " b = [n for n in {'pt' : 1} if n[1]+1]",
664
713
  )
665
- engine.evaluate('A', 'b').should == [['pt', 1]]
714
+ expect(engine.evaluate('A', 'b')).to eq([['pt', 1]])
666
715
  end
667
716
 
668
717
  it 'should eval hashes' do
@@ -675,14 +724,14 @@ eof
675
724
  ' g = {b:b, [b]:[1,23], []:345}',
676
725
  )
677
726
 
678
- engine.evaluate('A', %w[b c d e f g]).should ==
727
+ expect(engine.evaluate('A', %w[b c d e f g])).to eq(
679
728
  [{},
680
729
  { 'a' => 1, 'b' => 2, 'c' => 3 },
681
730
  { 123 * 2 => -123, 'b_b' => 2 },
682
731
  { 'x' => 1, 'y' => 2, 'z' => 3, 'zz' => 8 },
683
732
  { 'a' => nil, 'b' => [1, nil, 2] },
684
733
  { {} => {}, [{}] => [1, 23], [] => 345 },
685
- ]
734
+ ])
686
735
  end
687
736
 
688
737
  it 'handles literal hashes with conditionals' do
@@ -693,11 +742,11 @@ eof
693
742
  ' d = {1: {1: 2 if b}, 3: 3 if c, 2: {2: 3 if a}}',
694
743
  )
695
744
 
696
- engine.evaluate('A', %w[a b d]).should == [
697
- { 'a' => 1 },
698
- { 'a' => { 'a' => 1 }, 2 => { 'a' => 1 }, 'c' => nil },
699
- { 1 => { 1 => 2 }, 2 => { 2 => 3 } },
700
- ]
745
+ expect(engine.evaluate('A', %w[a b d])).to eq([
746
+ { 'a' => 1 },
747
+ { 'a' => { 'a' => 1 }, 2 => { 'a' => 1 }, 'c' => nil },
748
+ { 1 => { 1 => 2 }, 2 => { 2 => 3 } },
749
+ ])
701
750
  end
702
751
 
703
752
  it 'should eval hash comprehension' do
@@ -705,8 +754,8 @@ eof
705
754
  ' b = {i*5 :i for i in [1,2,3]}',
706
755
  ' c = [kv for kv in {1:11, 2:22}]',
707
756
  )
708
- engine.evaluate('A', 'b').should == { 5 => 1, 10 => 2, 15 => 3 }
709
- engine.evaluate('A', 'c').should == [[1, 11], [2, 22]]
757
+ expect(engine.evaluate('A', 'b')).to eq(5 => 1, 10 => 2, 15 => 3)
758
+ expect(engine.evaluate('A', 'c')).to eq([[1, 11], [2, 22]])
710
759
  end
711
760
 
712
761
  it 'for-in-hash should iterate over key/value pairs' do
@@ -717,9 +766,9 @@ eof
717
766
  ' e = [kv for kv in b if kv[1]]',
718
767
  ' f = [k-v for k, v in b if k>1]',
719
768
  )
720
- engine.evaluate('A', 'c').should == [-10, -20]
721
- engine.evaluate('A', 'd').should == { 1 => 11, 2 => 22 }
722
- engine.evaluate('A', 'f').should == [-20]
769
+ expect(engine.evaluate('A', 'c')).to eq([-10, -20])
770
+ expect(engine.evaluate('A', 'd')).to eq(1 => 11, 2 => 22)
771
+ expect(engine.evaluate('A', 'f')).to eq([-20])
723
772
 
724
773
  # FIXME: this is a known bug in Delorean caused by the strange way
725
774
  # that select iterates over hashes and provides args to the block.
@@ -730,11 +779,11 @@ eof
730
779
  engine.parse defn('A:',
731
780
  ' b = { a:{a+c:a-c for c in [4,5]} for a in [1,2,3]}',
732
781
  )
733
- engine.evaluate('A', 'b').should == {
782
+ expect(engine.evaluate('A', 'b')).to eq(
734
783
  1 => { 5 => -3, 6 => -4 },
735
784
  2 => { 6 => -2, 7 => -3 },
736
785
  3 => { 7 => -1, 8 => -2 }
737
- }
786
+ )
738
787
  end
739
788
 
740
789
  it 'should eval conditional hash comprehension' do
@@ -742,8 +791,20 @@ eof
742
791
  ' b = {i*5:i+5 for i in [1,2,3,4,5] if i%2 == 1}',
743
792
  ' c = {i/10.0:i*10 for i in [1,2,3,4,5] if i>4}',
744
793
  )
745
- engine.evaluate('A', 'b').should == { 5 => 6, 15 => 8, 25 => 10 }
746
- engine.evaluate('A', 'c').should == { 0.5 => 50 }
794
+ expect(engine.evaluate('A', 'b')).to eq(5 => 6, 15 => 8, 25 => 10)
795
+ expect(engine.evaluate('A', 'c')).to eq(0.5 => 50)
796
+ end
797
+
798
+ it 'should eval hash methods such as length' do
799
+ engine.parse defn('A:',
800
+ ' b = {}',
801
+ " c = {'a':1, 'b': 2,'c':3}",
802
+ ' length1 = b.length',
803
+ ' length2 = c.length',
804
+ )
805
+
806
+ expect(engine.evaluate('A', 'length1')).to eq(0)
807
+ expect(engine.evaluate('A', 'length2')).to eq(3)
747
808
  end
748
809
 
749
810
  it 'should eval node calls as intermediate results' do
@@ -754,7 +815,7 @@ eof
754
815
  ' f = e.d / e.a',
755
816
  )
756
817
 
757
- engine.evaluate('A', ['d', 'f']).should == [26, 2]
818
+ expect(engine.evaluate('A', ['d', 'f'])).to eq([26, 2])
758
819
  end
759
820
 
760
821
  it 'allows node calls from attrs' do
@@ -767,7 +828,7 @@ eof
767
828
  ' f = d.b + d.c + e().a',
768
829
  )
769
830
 
770
- engine.evaluate('A', ['f']).should == [16 + 5 + 13]
831
+ expect(engine.evaluate('A', ['f'])).to eq([16 + 5 + 13])
771
832
  end
772
833
 
773
834
  it 'should eval multi-var hash comprehension' do
@@ -775,8 +836,8 @@ eof
775
836
  ' b = {k*5 : v+1 for k, v in {1:2, 7:-30}}',
776
837
  ' c = [k-v for k, v in {1:2, 7:-30}]',
777
838
  )
778
- engine.evaluate('A', 'b').should == { 5 => 3, 35 => -29 }
779
- engine.evaluate('A', 'c').should == [-1, 37]
839
+ expect(engine.evaluate('A', 'b')).to eq(5 => 3, 35 => -29)
840
+ expect(engine.evaluate('A', 'c')).to eq([-1, 37])
780
841
  end
781
842
 
782
843
  it 'should be able to amend node calls' do
@@ -791,8 +852,9 @@ eof
791
852
  ' j = d(a=6).aa',
792
853
  )
793
854
 
794
- engine.evaluate('A', ['g', 'h', 'j']).should ==
855
+ expect(engine.evaluate('A', ['g', 'h', 'j'])).to eq(
795
856
  [3 * 2 + 4 * 2, 5 * 2, 6 * 2]
857
+ )
796
858
  end
797
859
 
798
860
  it 'should be able to amend node calls 2' do
@@ -802,7 +864,7 @@ eof
802
864
  ' e = [d.a, d(a=4).a]',
803
865
  )
804
866
 
805
- engine.evaluate('A', ['e']).should == [[3, 4]]
867
+ expect(engine.evaluate('A', ['e'])).to eq([[3, 4]])
806
868
  end
807
869
 
808
870
  it 'should eval module calls 1' do
@@ -812,7 +874,7 @@ eof
812
874
  ' d = n().a',
813
875
  )
814
876
 
815
- engine.evaluate('A', %w[d]).should == [123]
877
+ expect(engine.evaluate('A', %w[d])).to eq([123])
816
878
  end
817
879
 
818
880
  it 'should eval module calls 2' do
@@ -825,12 +887,13 @@ eof
825
887
  " e = nil() % ['b']",
826
888
  )
827
889
 
828
- engine.evaluate('A', %w[n c d e]).should == [
829
- 'A',
830
- { 'a' => 123, 'b' => 579 },
831
- { 'a' => 123, 'b' => 579 },
832
- { 'b' => 579 }
833
- ]
890
+ expect(engine.evaluate('A', %w[n c d e])).to eq(
891
+ [
892
+ 'A',
893
+ { 'a' => 123, 'b' => 579 },
894
+ { 'a' => 123, 'b' => 579 },
895
+ { 'b' => 579 }
896
+ ])
834
897
  end
835
898
 
836
899
  it 'should eval module calls 3' do
@@ -841,7 +904,7 @@ eof
841
904
  ' d = n().a',
842
905
  )
843
906
 
844
- engine.evaluate('B', %w[d]).should == [123]
907
+ expect(engine.evaluate('B', %w[d])).to eq([123])
845
908
  end
846
909
 
847
910
  it 'should be possible to implement recursive calls' do
@@ -850,7 +913,7 @@ eof
850
913
  ' fact = if n <= 1 then 1 else n * A(n=n-1).fact',
851
914
  )
852
915
 
853
- engine.evaluate('A', 'fact', 'n' => 10).should == 3_628_800
916
+ expect(engine.evaluate('A', 'fact', 'n' => 10)).to eq(3_628_800)
854
917
  end
855
918
 
856
919
  it 'should eval module calls by node name' do
@@ -858,7 +921,7 @@ eof
858
921
  ' a = 123',
859
922
  ' b = A().a',
860
923
  )
861
- engine.evaluate('A', 'b').should == 123
924
+ expect(engine.evaluate('A', 'b')).to eq(123)
862
925
  end
863
926
 
864
927
  it 'should eval multiline expressions' do
@@ -868,7 +931,7 @@ eof
868
931
  ' for a in [1,2,3]',
869
932
  ' ]',
870
933
  )
871
- engine.evaluate('A', 'b').should == [2, 3, 4]
934
+ expect(engine.evaluate('A', 'b')).to eq([2, 3, 4])
872
935
  end
873
936
 
874
937
  it 'should eval multiline expressions (2)' do
@@ -885,12 +948,13 @@ eof
885
948
  " ) % ['b']",
886
949
  )
887
950
 
888
- engine.evaluate('A', %w[n c d e]).should == [
889
- 'A',
890
- { 'a' => 123, 'b' => 579 },
891
- { 'a' => 123, 'b' => 579 },
892
- { 'b' => 579 }
893
- ]
951
+ expect(engine.evaluate('A', %w[n c d e])).to eq(
952
+ [
953
+ 'A',
954
+ { 'a' => 123, 'b' => 579 },
955
+ { 'a' => 123, 'b' => 579 },
956
+ { 'b' => 579 }
957
+ ])
894
958
  end
895
959
 
896
960
  it 'should eval in expressions' do
@@ -902,8 +966,7 @@ eof
902
966
  ' d = [i*2 for i in s if i in a]',
903
967
  )
904
968
 
905
- engine.evaluate('A', %w[b c d]).should ==
906
- [false, true, [66, 88]]
969
+ expect(engine.evaluate('A', %w[b c d])).to eq([false, true, [66, 88]])
907
970
  end
908
971
 
909
972
  it 'should eval imports' do
@@ -914,8 +977,7 @@ eof
914
977
  ' a = 111',
915
978
  ' c = AAA::X(a=456).b',
916
979
  )
917
- engine.evaluate('B', ['a', 'b', 'c'], {}).should ==
918
- [111, 222, 456 * 2]
980
+ expect(engine.evaluate('B', ['a', 'b', 'c'], {})).to eq([111, 222, 456 * 2])
919
981
  end
920
982
 
921
983
  it 'should eval imports (2)' do
@@ -939,23 +1001,24 @@ eof
939
1001
 
940
1002
  e2 = sset.get_engine('BBB')
941
1003
 
942
- e2.evaluate('B', ['a', 'b', 'c', 'd']).should ==
943
- [111, 222, -2, 222]
1004
+ expect(e2.evaluate('B', ['a', 'b', 'c', 'd'])).to eq([111, 222, -2, 222])
944
1005
 
945
1006
  engine.parse defn('import BBB',
946
1007
  'B: BBB::B',
947
1008
  ' e = d + 3',
948
1009
  )
949
1010
 
950
- engine.evaluate('B', ['a', 'b', 'c', 'd', 'e']).should ==
1011
+ expect(engine.evaluate('B', ['a', 'b', 'c', 'd', 'e'])).to eq(
951
1012
  [111, 222, -2, 222, 225]
1013
+ )
952
1014
 
953
1015
  e4 = sset.get_engine('CCC')
954
1016
 
955
- e4.evaluate('B', ['a', 'b', 'c', 'd', 'e']).should ==
1017
+ expect(e4.evaluate('B', ['a', 'b', 'c', 'd', 'e'])).to eq(
956
1018
  [111, 222, -2, 222, 666]
1019
+ )
957
1020
 
958
- e4.evaluate('C', ['a', 'b', 'd']).should == [123, 123 * 2, 123 * 3 * 2]
1021
+ expect(e4.evaluate('C', ['a', 'b', 'd'])).to eq([123, 123 * 2, 123 * 3 * 2])
959
1022
  end
960
1023
 
961
1024
  it 'should eval imports (3)' do
@@ -970,8 +1033,8 @@ eof
970
1033
  )
971
1034
 
972
1035
  e4 = sset.get_engine('CCC')
973
- e4.evaluate('X', 'xx').should == [1, 2, 3]
974
- e4.evaluate('X', 'yy').should == [1, 2, 3]
1036
+ expect(e4.evaluate('X', 'xx')).to eq([1, 2, 3])
1037
+ expect(e4.evaluate('X', 'yy')).to eq([1, 2, 3])
975
1038
  end
976
1039
 
977
1040
  it 'should eval imports (4) - with ::' do
@@ -1004,8 +1067,8 @@ eof
1004
1067
  )
1005
1068
 
1006
1069
  e4 = sset.get_engine('CCC')
1007
- e4.evaluate('X', 'xx').should == [1, 2, 3]
1008
- e4.evaluate('X', 'zz').should == [2, 4, 6]
1070
+ expect(e4.evaluate('X', 'xx')).to eq([1, 2, 3])
1071
+ expect(e4.evaluate('X', 'zz')).to eq([2, 4, 6])
1009
1072
  end
1010
1073
 
1011
1074
  it 'should eval imports (4) - inheritance - with ::' do
@@ -1035,7 +1098,7 @@ eof
1035
1098
  )
1036
1099
 
1037
1100
  e4 = sset.get_engine('CCC')
1038
- e4.evaluate('X', 'zz').should == [2, 4, 6]
1101
+ expect(e4.evaluate('X', 'zz')).to eq([2, 4, 6])
1039
1102
  end
1040
1103
 
1041
1104
  it 'can eval indexing' do
@@ -1048,7 +1111,7 @@ eof
1048
1111
  ' f = a[1,2]',
1049
1112
  )
1050
1113
  r = engine.evaluate('A', ['b', 'c', 'e', 'f'])
1051
- r.should == [2, 3, 456, [2, 3]]
1114
+ expect(r).to eq([2, 3, 456, [2, 3]])
1052
1115
  end
1053
1116
 
1054
1117
  it 'can eval indexing 2' do
@@ -1059,12 +1122,13 @@ eof
1059
1122
  " d = c['b'].x * c['a'] - c['b'].y",
1060
1123
  )
1061
1124
  r = engine.evaluate('A', ['a', 'b', 'c', 'd'])
1062
- r.should == [
1063
- 1,
1064
- { 'x' => 123, 'y' => 456 },
1065
- { 'a' => 1, 'b' => { 'x' => 123, 'y' => 456 } },
1066
- -333
1067
- ]
1125
+ expect(r).to eq(
1126
+ [
1127
+ 1,
1128
+ { 'x' => 123, 'y' => 456 },
1129
+ { 'a' => 1, 'b' => { 'x' => 123, 'y' => 456 } },
1130
+ -333
1131
+ ])
1068
1132
  end
1069
1133
 
1070
1134
  it 'can handle exceptions with / syntax' do
@@ -1077,20 +1141,22 @@ eof
1077
1141
  " f = A() / 'a'",
1078
1142
  )
1079
1143
  r = engine.evaluate('A', ['a', 'b', 'c'])
1080
- r.should == [
1081
- 1,
1082
- { 'x' => 123, 'y' => 456 },
1083
- { 'a' => 1, 'b' => { 'x' => 123, 'y' => 456 } }
1084
- ]
1144
+ expect(r).to eq(
1145
+ [
1146
+ 1,
1147
+ { 'x' => 123, 'y' => 456 },
1148
+ { 'a' => 1, 'b' => { 'x' => 123, 'y' => 456 } }
1149
+ ])
1085
1150
 
1086
1151
  r = engine.evaluate('A', ['a', 'd'])
1087
- r.should == [
1088
- 1,
1089
- { 'error' => 'hello', 'backtrace' => [['XXX', 4, 'e'], ['XXX', 6, 'd']] }
1090
- ]
1152
+ expect(r).to eq(
1153
+ [
1154
+ 1,
1155
+ { 'error' => 'hello', 'backtrace' => [['XXX', 4, 'e'], ['XXX', 6, 'd']] }
1156
+ ])
1091
1157
 
1092
1158
  r = engine.evaluate('A', ['f'])
1093
- r.should == [1]
1159
+ expect(r).to eq([1])
1094
1160
  end
1095
1161
 
1096
1162
  it 'should properly eval overridden attrs' do
@@ -1105,12 +1171,12 @@ eof
1105
1171
  ' m = [x().b for x in [A, B]]',
1106
1172
  )
1107
1173
 
1108
- engine.evaluate('A', 'b').should == 5
1109
- engine.evaluate('B', 'b').should == 2
1110
- engine.evaluate('B', 'x').should == 3
1111
- engine.evaluate('B', 'k').should == [5, 2]
1112
- engine.evaluate('B', 'l').should == [5, 2]
1113
- engine.evaluate('B', 'm').should == [5, 2]
1174
+ expect(engine.evaluate('A', 'b')).to eq(5)
1175
+ expect(engine.evaluate('B', 'b')).to eq(2)
1176
+ expect(engine.evaluate('B', 'x')).to eq(3)
1177
+ expect(engine.evaluate('B', 'k')).to eq([5, 2])
1178
+ expect(engine.evaluate('B', 'l')).to eq([5, 2])
1179
+ expect(engine.evaluate('B', 'm')).to eq([5, 2])
1114
1180
  end
1115
1181
 
1116
1182
  it 'implements simple version of self (_)' do
@@ -1128,14 +1194,14 @@ eof
1128
1194
  " v = {**_, 'a': 123}",
1129
1195
  )
1130
1196
 
1131
- engine.evaluate('A', 'x', 'a' => 3, 'b' => 5).should == 15
1197
+ expect(engine.evaluate('A', 'x', 'a' => 3, 'b' => 5)).to eq(15)
1132
1198
  h = { 'a' => 1, 'b' => 2, 'c' => 3 }
1133
- engine.evaluate('A', 'y', 'a' => 1, 'b' => 2, 'c' => 3).should == h
1134
- engine.evaluate('A', 'z', 'a' => 1, 'b' => 2, 'c' => 3).should == -1
1135
- engine.evaluate('A', 'w', 'a' => 4, 'b' => 5, 'c' => 3).should == -1
1136
- engine.evaluate('A', 'v', 'a' => 4, 'b' => 5, 'c' => 3).should == {
1199
+ expect(engine.evaluate('A', 'y', 'a' => 1, 'b' => 2, 'c' => 3)).to eq(h)
1200
+ expect(engine.evaluate('A', 'z', 'a' => 1, 'b' => 2, 'c' => 3)).to eq(-1)
1201
+ expect(engine.evaluate('A', 'w', 'a' => 4, 'b' => 5, 'c' => 3)).to eq(-1)
1202
+ expect(engine.evaluate('A', 'v', 'a' => 4, 'b' => 5, 'c' => 3)).to eq(
1137
1203
  'a' => 123, 'b' => 5, 'c' => 3
1138
- }
1204
+ )
1139
1205
  end
1140
1206
 
1141
1207
  it 'implements positional args in node calls' do
@@ -1149,8 +1215,9 @@ eof
1149
1215
  ' z = B(10, 20, a=3, b=7).x',
1150
1216
  " y = B('x', 'y').y",
1151
1217
  )
1152
- engine.evaluate('A', ['a', 'z', 'y'], 0 => 123, 1 => 456).should ==
1218
+ expect(engine.evaluate('A', ['a', 'z', 'y'], 0 => 123, 1 => 456)).to eq(
1153
1219
  [123 - 456, 40, ['x', 'y', nil]]
1220
+ )
1154
1221
  end
1155
1222
 
1156
1223
  it 'can call 0-arity functions in list comprehension' do