delorean_lang 0.5.1 → 0.5.2

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 (41) hide show
  1. checksums.yaml +5 -5
  2. data/.gitlab-ci.yml +1 -2
  3. data/.rubocop.yml +45 -5
  4. data/.rubocop_todo.yml +1 -634
  5. data/Gemfile +3 -1
  6. data/README.md +22 -0
  7. data/Rakefile +3 -1
  8. data/delorean.gemspec +18 -17
  9. data/lib/delorean/abstract_container.rb +4 -2
  10. data/lib/delorean/base.rb +30 -27
  11. data/lib/delorean/cache.rb +2 -0
  12. data/lib/delorean/cache/adapters.rb +2 -0
  13. data/lib/delorean/cache/adapters/base.rb +2 -0
  14. data/lib/delorean/cache/adapters/ruby_cache.rb +5 -0
  15. data/lib/delorean/const.rb +5 -3
  16. data/lib/delorean/debug.rb +6 -5
  17. data/lib/delorean/delorean.rb +466 -147
  18. data/lib/delorean/delorean.treetop +13 -1
  19. data/lib/delorean/engine.rb +61 -50
  20. data/lib/delorean/error.rb +2 -1
  21. data/lib/delorean/model.rb +12 -9
  22. data/lib/delorean/nodes.rb +130 -67
  23. data/lib/delorean/ruby.rb +2 -0
  24. data/lib/delorean/ruby/whitelists.rb +2 -0
  25. data/lib/delorean/ruby/whitelists/base.rb +7 -3
  26. data/lib/delorean/ruby/whitelists/default.rb +6 -6
  27. data/lib/delorean/ruby/whitelists/empty.rb +3 -2
  28. data/lib/delorean/ruby/whitelists/matchers.rb +2 -0
  29. data/lib/delorean/ruby/whitelists/matchers/arguments.rb +2 -0
  30. data/lib/delorean/ruby/whitelists/matchers/method.rb +5 -2
  31. data/lib/delorean/ruby/whitelists/whitelist_error.rb +2 -0
  32. data/lib/delorean/version.rb +3 -1
  33. data/lib/delorean_lang.rb +3 -1
  34. data/spec/cache_spec.rb +4 -2
  35. data/spec/dev_spec.rb +68 -69
  36. data/spec/eval_spec.rb +824 -729
  37. data/spec/func_spec.rb +172 -176
  38. data/spec/parse_spec.rb +516 -522
  39. data/spec/ruby/whitelist_spec.rb +6 -3
  40. data/spec/spec_helper.rb +26 -23
  41. metadata +27 -27
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists'
2
4
 
3
5
  module Delorean
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists/default'
2
4
 
3
5
  module Delorean
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists/whitelist_error'
2
4
  require 'delorean/ruby/whitelists/matchers'
3
5
 
@@ -11,9 +13,11 @@ module Delorean
11
13
  return method_name_error unless method_name.is_a?(Symbol)
12
14
  return block_and_match_error if !match_to.nil? && block_given?
13
15
 
14
- return add_matched_method(
15
- method_name: method_name, match_to: match_to
16
- ) unless match_to.nil?
16
+ unless match_to.nil?
17
+ return add_matched_method(
18
+ method_name: method_name, match_to: match_to
19
+ )
20
+ end
17
21
 
18
22
  matchers[method_name.to_sym] = method_matcher_class.new(
19
23
  method_name: method_name, &block
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists/base'
2
4
 
3
5
  module Delorean
4
6
  module Ruby
5
7
  module Whitelists
6
8
  class Default < ::Delorean::Ruby::Whitelists::Base
7
- TI_TYPES = [Time, ActiveSupport::TimeWithZone]
9
+ TI_TYPES = [Time, ActiveSupport::TimeWithZone].freeze
8
10
  DT_TYPES = [Date] + TI_TYPES
9
- NUM_OR_STR = [Numeric, String]
10
- NUM_OR_NIL = [nil, Integer]
11
+ NUM_OR_STR = [Numeric, String].freeze
12
+ NUM_OR_NIL = [nil, Integer].freeze
11
13
 
12
14
  def initialize_hook
13
15
  _add_default_methods
@@ -63,7 +65,7 @@ module Delorean
63
65
  end
64
66
 
65
67
  add_method :except do |method|
66
- method.called_on Hash, with: [String] + [[nil, String]]*9
68
+ method.called_on Hash, with: [String] + [[nil, String]] * 9
67
69
  end
68
70
 
69
71
  add_method :reverse do |method|
@@ -132,8 +134,6 @@ module Delorean
132
134
  method.called_on Set, with: [Enumerable]
133
135
  end
134
136
 
135
-
136
-
137
137
  add_method :keys do |method|
138
138
  method.called_on Hash
139
139
  end
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists/base'
2
4
 
3
5
  module Delorean
4
6
  module Ruby
5
7
  module Whitelists
6
8
  class Empty < ::Delorean::Ruby::Whitelists::Base
7
- def initialize_hook
8
- end
9
+ def initialize_hook; end
9
10
  end
10
11
  end
11
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists/matchers/method'
2
4
 
3
5
  module Delorean
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delorean
2
4
  module Ruby
3
5
  module Whitelists
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delorean/ruby/whitelists/matchers/arguments'
2
4
 
3
5
  module Delorean
@@ -24,11 +26,12 @@ module Delorean
24
26
  end
25
27
 
26
28
  def matcher(klass:)
27
- matcher = arguments_matchers.find do
28
- |matcher_object| klass <= matcher_object.called_on
29
+ matcher = arguments_matchers.find do |matcher_object|
30
+ klass <= matcher_object.called_on
29
31
  end
30
32
 
31
33
  raise "no such method #{method_name} for #{klass}" if matcher.nil?
34
+
32
35
  matcher
33
36
  end
34
37
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delorean
2
4
  module Ruby
3
5
  module Whitelists
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Delorean
2
- VERSION = "0.5.1"
4
+ VERSION = '0.5.2'.freeze
3
5
  end
@@ -1,4 +1,6 @@
1
- require "delorean/version"
1
+ # frozen_string_literal: true
2
+
3
+ require 'delorean/version'
2
4
 
3
5
  require 'treetop'
4
6
  require 'delorean/abstract_container'
@@ -1,6 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
4
 
3
- describe "Delorean cache" do
5
+ describe 'Delorean cache' do
4
6
  before do
5
7
  Dummy.clear_lookup_cache!
6
8
  end
@@ -60,6 +62,6 @@ describe "Delorean cache" do
60
62
  )
61
63
 
62
64
  expect(item_10).to be_a(OpenStruct)
63
- expect(item_10["10"]).to eq(10)
65
+ expect(item_10['10']).to eq(10)
64
66
  end
65
67
  end
@@ -1,90 +1,89 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ # frozen_string_literal: true
2
2
 
3
- describe "Delorean" do
3
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
4
4
 
5
- let(:engine) {
6
- Delorean::Engine.new("YYY")
7
- }
5
+ describe 'Delorean' do
6
+ let(:engine) do
7
+ Delorean::Engine.new('YYY')
8
+ end
8
9
 
9
- it "can enumerate nodes" do
10
- engine.parse defn("X:",
11
- " a = 123",
12
- " b = a",
13
- "Y: X",
14
- "A:",
15
- "XX: Y",
16
- " a = 11",
17
- " c =?",
18
- " d = 456",
19
- )
20
- engine.enumerate_nodes.should == SortedSet.new(["A", "X", "XX", "Y"])
10
+ it 'can enumerate nodes' do
11
+ engine.parse defn('X:',
12
+ ' a = 123',
13
+ ' b = a',
14
+ 'Y: X',
15
+ 'A:',
16
+ 'XX: Y',
17
+ ' a = 11',
18
+ ' c =?',
19
+ ' d = 456',
20
+ )
21
+ engine.enumerate_nodes.should == SortedSet.new(['A', 'X', 'XX', 'Y'])
21
22
  end
22
23
 
23
- it "can enumerate attrs by node" do
24
- engine.parse defn("X:",
25
- " a = 123",
26
- " b = a",
27
- "Y: X",
28
- "Z:",
29
- "XX: Y",
30
- " a = 11",
31
- " c =?",
32
- " d = 456",
33
- )
24
+ it 'can enumerate attrs by node' do
25
+ engine.parse defn('X:',
26
+ ' a = 123',
27
+ ' b = a',
28
+ 'Y: X',
29
+ 'Z:',
30
+ 'XX: Y',
31
+ ' a = 11',
32
+ ' c =?',
33
+ ' d = 456',
34
+ )
34
35
 
35
36
  exp = {
36
- "X" => ["a", "b"],
37
- "Y" => ["a", "b"],
38
- "Z" => [],
39
- "XX" => ["a", "b", "c", "d"],
37
+ 'X' => ['a', 'b'],
38
+ 'Y' => ['a', 'b'],
39
+ 'Z' => [],
40
+ 'XX' => ['a', 'b', 'c', 'd'],
40
41
  }
41
42
  res = engine.enumerate_attrs
42
43
 
43
44
  res.keys.sort.should == exp.keys.sort
44
45
 
45
- exp.each {
46
- |k, v|
47
-
46
+ exp.each do |k, v|
48
47
  engine.enumerate_attrs_by_node(k).sort.should == v
49
48
  res[k].sort.should == v
50
- }
49
+ end
51
50
  end
52
51
 
53
- it "can enumerate params" do
54
- engine.parse defn("X:",
55
- " a =? 123",
56
- " b = a",
57
- "Y: X",
58
- "Z:",
59
- "XX: Y",
60
- " a = 11",
61
- " c =?",
62
- " d = 123",
63
- "YY: XX",
64
- " c =? 22",
65
- " e =? 11",
66
- )
52
+ it 'can enumerate params' do
53
+ engine.parse defn('X:',
54
+ ' a =? 123',
55
+ ' b = a',
56
+ 'Y: X',
57
+ 'Z:',
58
+ 'XX: Y',
59
+ ' a = 11',
60
+ ' c =?',
61
+ ' d = 123',
62
+ 'YY: XX',
63
+ ' c =? 22',
64
+ ' e =? 11',
65
+ )
67
66
 
68
- engine.enumerate_params.should == Set.new(["a", "c", "e"])
67
+ engine.enumerate_params.should == Set.new(['a', 'c', 'e'])
69
68
  end
70
69
 
71
- it "can enumerate params by node" do
72
- engine.parse defn("X:",
73
- " a =? 123",
74
- " b = a",
75
- "Y: X",
76
- "Z:",
77
- "XX: Y",
78
- " a = 11",
79
- " c =?",
80
- " d = 123",
81
- "YY: XX",
82
- " c =? 22",
83
- " e =? 11",
84
- )
85
- engine.enumerate_params_by_node("X").should == Set.new(["a"])
86
- engine.enumerate_params_by_node("XX").should == Set.new(["a", "c"])
87
- engine.enumerate_params_by_node("YY").should == Set.new(["a", "c", "e"])
88
- engine.enumerate_params_by_node("Z").should == Set.new([])
70
+ it 'can enumerate params by node' do
71
+ engine.parse defn('X:',
72
+ ' a =? 123',
73
+ ' b = a',
74
+ 'Y: X',
75
+ 'Z:',
76
+ 'XX: Y',
77
+ ' a = 11',
78
+ ' c =?',
79
+ ' d = 123',
80
+ 'YY: XX',
81
+ ' c =? 22',
82
+ ' e =? 11',
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([])
89
88
  end
90
89
  end
@@ -1,316 +1,317 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- describe "Delorean" do
3
-
4
- let(:sset) {
5
- TestContainer.new({
6
- "AAA" =>
7
- defn("X:",
8
- " a =? 123",
9
- " b = a*2",
10
- )
11
- })
12
- }
13
-
14
- let(:engine) {
15
- Delorean::Engine.new "XXX", sset
16
- }
17
-
18
- it "evaluate simple expressions" do
19
- engine.parse defn("A:",
20
- " a = 123",
21
- " x = -(a * 2)",
22
- " b = -(a + 1)",
23
- " c = -a + 1",
24
- " d = a ** 3 - 10*0.2",
25
- )
26
-
27
- engine.evaluate("A", ["a"]).should == [123]
28
-
29
- r = engine.evaluate("A", ["x", "b"])
4
+ describe 'Delorean' do
5
+ let(:sset) do
6
+ TestContainer.new(
7
+ 'AAA' =>
8
+ defn('X:',
9
+ ' a =? 123',
10
+ ' b = a*2',
11
+ )
12
+ )
13
+ end
14
+
15
+ let(:engine) do
16
+ Delorean::Engine.new 'XXX', sset
17
+ end
18
+
19
+ it 'evaluate simple expressions' do
20
+ engine.parse defn('A:',
21
+ ' a = 123',
22
+ ' x = -(a * 2)',
23
+ ' b = -(a + 1)',
24
+ ' c = -a + 1',
25
+ ' d = a ** 3 - 10*0.2',
26
+ )
27
+
28
+ engine.evaluate('A', ['a']).should == [123]
29
+
30
+ r = engine.evaluate('A', ['x', 'b'])
30
31
  r.should == [-246, -124]
31
32
 
32
- expect(engine.evaluate("A", "d")).to eq 1860865.0
33
+ expect(engine.evaluate('A', 'd')).to eq 1_860_865.0
33
34
  end
34
35
 
35
- it "proper unary expression evaluation" do
36
- engine.parse defn("A:",
37
- " a = 123",
38
- " c = -a + 1",
39
- )
36
+ it 'proper unary expression evaluation' do
37
+ engine.parse defn('A:',
38
+ ' a = 123',
39
+ ' c = -a + 1',
40
+ )
40
41
 
41
- r = engine.evaluate("A", "c")
42
+ r = engine.evaluate('A', 'c')
42
43
  r.should == -122
43
44
  end
44
45
 
45
- it "proper string interpolation" do
46
- engine.parse defn("A:",
46
+ it 'proper string interpolation' do
47
+ engine.parse defn('A:',
47
48
  ' a = "\n123\n"',
48
- )
49
+ )
49
50
 
50
- r = engine.evaluate("A", "a")
51
+ r = engine.evaluate('A', 'a')
51
52
  r.should == "\n123\n"
52
53
  end
53
54
 
54
- it "should handle getattr in expressions" do
55
- engine.parse defn("A:",
55
+ it 'should handle getattr in expressions' do
56
+ engine.parse defn('A:',
56
57
  " a = {'x':123, 'y':456, 'z':789}",
57
- " b = A.a.x * A.a.y - A.a.z",
58
- )
59
- engine.evaluate("A", ["b"]).should == [123*456-789]
58
+ ' b = A.a.x * A.a.y - A.a.z',
59
+ )
60
+ engine.evaluate('A', ['b']).should == [123 * 456 - 789]
60
61
  end
61
62
 
62
- it "should handle numeric getattr" do
63
- engine.parse defn("A:",
63
+ it 'should handle numeric getattr' do
64
+ engine.parse defn('A:',
64
65
  " a = {1:123, 0:456, 'z':789, 2: {'a':444}}",
65
- " b = A.a.1 * A.a.0 - A.a.z - A.a.2.a",
66
- )
67
- engine.evaluate("A", ["b"]).should == [123*456-789-444]
66
+ ' b = A.a.1 * A.a.0 - A.a.z - A.a.2.a',
67
+ )
68
+ engine.evaluate('A', ['b']).should == [123 * 456 - 789 - 444]
68
69
  end
69
70
 
70
- it "should be able to evaluate multiple node attrs" do
71
- engine.parse defn("A:",
72
- " a =? 123",
73
- " b = a % 11",
74
- " c = a / 4.0",
75
- )
71
+ it 'should be able to evaluate multiple node attrs' do
72
+ engine.parse defn('A:',
73
+ ' a =? 123',
74
+ ' b = a % 11',
75
+ ' c = a / 4.0',
76
+ )
76
77
 
77
- h = {"a" => 16}
78
- r = engine.evaluate("A", ["c", "b"], h)
78
+ h = { 'a' => 16 }
79
+ r = engine.evaluate('A', ['c', 'b'], h)
79
80
  r.should == [4, 5]
80
81
  end
81
82
 
82
- it "should give error when accessing undefined attr" do
83
- engine.parse defn("A:",
84
- " a = 1",
85
- " c = a.to_ss",
86
- )
83
+ it 'should give error when accessing undefined attr' do
84
+ engine.parse defn('A:',
85
+ ' a = 1',
86
+ ' c = a.to_ss',
87
+ )
87
88
 
88
89
  lambda {
89
- r = engine.evaluate("A", "c")
90
+ engine.evaluate('A', 'c')
90
91
  }.should raise_error(Delorean::InvalidGetAttribute)
91
92
  end
92
93
 
93
- it "should be able to call 0-ary functions without ()" do
94
- engine.parse defn("A:",
95
- " a = 1",
96
- " d = a.to_s",
97
- )
94
+ it 'should be able to call 0-ary functions without ()' do
95
+ engine.parse defn('A:',
96
+ ' a = 1',
97
+ ' d = a.to_s',
98
+ )
98
99
 
99
- engine.evaluate("A", "d").should == "1"
100
+ engine.evaluate('A', 'd').should == '1'
100
101
  end
101
102
 
102
- it "should handle default param values" do
103
- engine.parse defn("A:",
104
- " a =? 123",
105
- " c = a / 123.0",
106
- )
103
+ it 'should handle default param values' do
104
+ engine.parse defn('A:',
105
+ ' a =? 123',
106
+ ' c = a / 123.0',
107
+ )
107
108
 
108
- r = engine.evaluate("A", "c")
109
+ r = engine.evaluate('A', 'c')
109
110
  r.should == 1
110
111
  end
111
112
 
112
- it "order of attr evaluation should not matter" do
113
- engine.parse defn("A:",
114
- " a =? 1",
115
- "B:",
116
- " a =? 2",
117
- " c = A.a",
118
- )
119
- engine.evaluate("B", %w{c a}).should == [1, 2]
120
- engine.evaluate("B", %w{a c}).should == [2, 1]
121
- end
122
-
123
- it "params should behave properly with inheritance" do
124
- engine.parse defn("A:",
125
- " a =? 1",
126
- "B: A",
127
- " a =? 2",
128
- "C: B",
129
- " a =? 3",
130
- " b = B.a",
131
- " c = A.a",
132
- )
133
- engine.evaluate("C", %w{a b c}).should == [3, 2, 1]
134
- engine.evaluate("C", %w{a b c}, {"a" => 4}).should == [4, 4, 4]
135
- engine.evaluate("C", %w{c b a}).should == [1, 2, 3]
136
- end
137
-
138
- it "should give error when param is undefined for eval" do
139
- engine.parse defn("A:",
140
- " a =?",
141
- " c = a / 123.0",
142
- )
113
+ it 'order of attr evaluation should not matter' do
114
+ engine.parse defn('A:',
115
+ ' a =? 1',
116
+ 'B:',
117
+ ' a =? 2',
118
+ ' c = A.a',
119
+ )
120
+ engine.evaluate('B', %w[c a]).should == [1, 2]
121
+ engine.evaluate('B', %w[a c]).should == [2, 1]
122
+ end
123
+
124
+ it 'params should behave properly with inheritance' do
125
+ engine.parse defn('A:',
126
+ ' a =? 1',
127
+ 'B: A',
128
+ ' a =? 2',
129
+ 'C: B',
130
+ ' a =? 3',
131
+ ' b = B.a',
132
+ ' c = A.a',
133
+ )
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]
137
+ end
138
+
139
+ it 'should give error when param is undefined for eval' do
140
+ engine.parse defn('A:',
141
+ ' a =?',
142
+ ' c = a / 123.0',
143
+ )
143
144
 
144
145
  lambda {
145
- r = engine.evaluate("A", "c")
146
+ engine.evaluate('A', 'c')
146
147
  }.should raise_error(Delorean::UndefinedParamError)
147
148
  end
148
149
 
149
- it "should handle simple param computation" do
150
- engine.parse defn("A:",
151
- " a =?",
152
- " c = a / 123.0",
153
- )
150
+ it 'should handle simple param computation' do
151
+ engine.parse defn('A:',
152
+ ' a =?',
153
+ ' c = a / 123.0',
154
+ )
154
155
 
155
- r = engine.evaluate("A", "c", {"a" => 123})
156
+ r = engine.evaluate('A', 'c', 'a' => 123)
156
157
  r.should == 1
157
158
  end
158
159
 
159
- it "should give error on unknown node" do
160
- engine.parse defn("A:",
161
- " a = 1",
162
- )
160
+ it 'should give error on unknown node' do
161
+ engine.parse defn('A:',
162
+ ' a = 1',
163
+ )
163
164
 
164
165
  lambda {
165
- r = engine.evaluate("B", "a")
166
+ engine.evaluate('B', 'a')
166
167
  }.should raise_error(Delorean::UndefinedNodeError)
167
168
  end
168
169
 
169
- it "should handle runtime errors and report module/line number" do
170
- engine.parse defn("A:",
171
- " a = 1/0",
172
- " b = 10 * a",
173
- )
170
+ it 'should handle runtime errors and report module/line number' do
171
+ engine.parse defn('A:',
172
+ ' a = 1/0',
173
+ ' b = 10 * a',
174
+ )
174
175
 
175
176
  begin
176
- engine.evaluate("A", "b")
177
- rescue => exc
177
+ engine.evaluate('A', 'b')
178
+ rescue StandardError => exc
178
179
  res = Delorean::Engine.grok_runtime_exception(exc)
179
180
  end
180
181
 
181
182
  res.should == {
182
- "error" => "divided by 0",
183
- "backtrace" => [["XXX", 2, "/"], ["XXX", 2, "a"], ["XXX", 3, "b"]],
183
+ 'error' => 'divided by 0',
184
+ 'backtrace' => [['XXX', 2, '/'], ['XXX', 2, 'a'], ['XXX', 3, 'b']],
184
185
  }
185
186
  end
186
187
 
187
- it "should handle runtime errors 2" do
188
- engine.parse defn("A:",
188
+ it 'should handle runtime errors 2' do
189
+ engine.parse defn('A:',
189
190
  " b = Dummy.call_me_maybe('a', 'b')",
190
- )
191
+ )
191
192
 
192
193
  begin
193
- engine.evaluate("A", "b")
194
- rescue => exc
194
+ engine.evaluate('A', 'b')
195
+ rescue StandardError => exc
195
196
  res = Delorean::Engine.grok_runtime_exception(exc)
196
197
  end
197
198
 
198
- res["backtrace"].should == [["XXX", 2, "b"]]
199
+ res['backtrace'].should == [['XXX', 2, 'b']]
199
200
  end
200
201
 
201
- it "should handle optional args to external fns" do
202
- engine.parse defn("A:",
202
+ it 'should handle optional args to external fns' do
203
+ engine.parse defn('A:',
203
204
  " b = Dummy.one_or_two(['a', 'b'])",
204
205
  " c = Dummy.one_or_two([1,2,3], ['a', 'b'])",
205
- )
206
+ )
206
207
 
207
- engine.evaluate("A", "b").should == [['a', 'b'], nil]
208
- engine.evaluate("A", "c").should == [[1,2,3], ['a', 'b']]
208
+ engine.evaluate('A', 'b').should == [['a', 'b'], nil]
209
+ engine.evaluate('A', 'c').should == [[1, 2, 3], ['a', 'b']]
209
210
  end
210
211
 
211
- it "should handle operator precedence properly" do
212
- engine.parse defn("A:",
213
- " b = 3+2*4-1",
214
- " c = b*3+5",
215
- " d = b*2-c*2",
216
- " e = if (d < -10) then -123-1 else -456+1",
217
- )
212
+ it 'should handle operator precedence properly' do
213
+ engine.parse defn('A:',
214
+ ' b = 3+2*4-1',
215
+ ' c = b*3+5',
216
+ ' d = b*2-c*2',
217
+ ' e = if (d < -10) then -123-1 else -456+1',
218
+ )
218
219
 
219
- r = engine.evaluate("A", "d")
220
+ r = engine.evaluate('A', 'd')
220
221
  r.should == -50
221
222
 
222
- r = engine.evaluate("A", "e")
223
+ r = engine.evaluate('A', 'e')
223
224
  r.should == -124
224
225
  end
225
226
 
226
- it "should handle if/else" do
227
- text = defn("A:",
228
- " d =? -10",
227
+ it 'should handle if/else' do
228
+ text = defn('A:',
229
+ ' d =? -10',
229
230
  ' e = if d < -10 then "gungam"+"style" else "korea"'
230
- )
231
+ )
231
232
 
232
233
  engine.parse text
233
- r = engine.evaluate("A", "e", {"d" => -100})
234
- r.should == "gungamstyle"
235
-
236
- r = engine.evaluate("A", "e")
237
- r.should == "korea"
238
- end
239
-
240
- it "should be able to access specific node attrs " do
241
- engine.parse defn("A:",
242
- " b = 123",
243
- " c =?",
244
- "B: A",
245
- " b = 111",
246
- " c = A.b * 123",
247
- "C:",
248
- " c = A.c + B.c",
249
- )
250
-
251
- r = engine.evaluate("B", "c")
252
- r.should == 123*123
253
- r = engine.evaluate("C", "c", {"c" => 5})
254
- r.should == 123*123 + 5
255
- end
256
-
257
- it "should be able to access nodes and node attrs dynamically " do
258
- engine.parse defn("A:",
259
- " b = 123",
260
- "B:",
261
- " b = A",
262
- " c = b.b * 456",
263
- )
264
-
265
- r = engine.evaluate("B", "c")
266
- r.should == 123*456
267
- end
268
-
269
- it "should be able to call class methods on ActiveRecord classes" do
270
- engine.parse defn("A:",
271
- " b = Dummy.call_me_maybe(1, 2, 3, 4)",
272
- " c = Dummy.call_me_maybe()",
273
- " d = Dummy.call_me_maybe(5) + b + c",
274
- )
275
- r = engine.evaluate("A", ["b", "c", "d"])
234
+ r = engine.evaluate('A', 'e', 'd' => -100)
235
+ r.should == 'gungamstyle'
236
+
237
+ r = engine.evaluate('A', 'e')
238
+ r.should == 'korea'
239
+ end
240
+
241
+ it 'should be able to access specific node attrs ' do
242
+ engine.parse defn('A:',
243
+ ' b = 123',
244
+ ' c =?',
245
+ 'B: A',
246
+ ' b = 111',
247
+ ' c = A.b * 123',
248
+ 'C:',
249
+ ' c = A.c + B.c',
250
+ )
251
+
252
+ r = engine.evaluate('B', 'c')
253
+ r.should == 123 * 123
254
+ r = engine.evaluate('C', 'c', 'c' => 5)
255
+ r.should == 123 * 123 + 5
256
+ end
257
+
258
+ it 'should be able to access nodes and node attrs dynamically ' do
259
+ engine.parse defn('A:',
260
+ ' b = 123',
261
+ 'B:',
262
+ ' b = A',
263
+ ' c = b.b * 456',
264
+ )
265
+
266
+ r = engine.evaluate('B', 'c')
267
+ r.should == 123 * 456
268
+ end
269
+
270
+ it 'should be able to call class methods on ActiveRecord classes' do
271
+ engine.parse defn('A:',
272
+ ' b = Dummy.call_me_maybe(1, 2, 3, 4)',
273
+ ' c = Dummy.call_me_maybe()',
274
+ ' d = Dummy.call_me_maybe(5) + b + c',
275
+ )
276
+ r = engine.evaluate('A', ['b', 'c', 'd'])
276
277
  r.should == [10, 0, 15]
277
278
  end
278
279
 
279
- it "should be able to access ActiveRecord whitelisted fns using .x syntax" do
280
- engine.parse defn("A:",
280
+ it 'should be able to access ActiveRecord whitelisted fns using .x syntax' do
281
+ engine.parse defn('A:',
281
282
  ' b = Dummy.i_just_met_you("CRJ", 1.234).name2',
282
- )
283
- r = engine.evaluate("A", "b")
284
- r.should == "CRJ-1.234"
283
+ )
284
+ r = engine.evaluate('A', 'b')
285
+ r.should == 'CRJ-1.234'
285
286
  end
286
287
 
287
- it "should be able to get attr on Hash objects using a.b syntax" do
288
- engine.parse defn("A:",
288
+ it 'should be able to get attr on Hash objects using a.b syntax' do
289
+ engine.parse defn('A:',
289
290
  ' b = Dummy.i_threw_a_hash_in_the_well()',
290
- " c = b.a",
291
- " d = b.b",
292
- " e = b.this_is_crazy",
293
- )
294
- engine.evaluate("A", %w{c d e}).should == [456, 789, nil]
291
+ ' c = b.a',
292
+ ' d = b.b',
293
+ ' e = b.this_is_crazy',
294
+ )
295
+ engine.evaluate('A', %w[c d e]).should == [456, 789, nil]
295
296
  end
296
297
 
297
- it "get attr on nil should return nil" do
298
- engine.parse defn("A:",
298
+ it 'get attr on nil should return nil' do
299
+ engine.parse defn('A:',
299
300
  ' b = nil',
300
301
  ' c = b.gaga',
301
302
  ' d = b.gaga || 55',
302
- )
303
- r = engine.evaluate("A", ["b", "c", "d"])
303
+ )
304
+ r = engine.evaluate('A', ['b', 'c', 'd'])
304
305
  r.should == [nil, nil, 55]
305
306
  end
306
307
 
307
- it "should be able to get attr on node" do
308
- engine.parse defn("A:",
309
- " a = 123",
310
- " b = A",
311
- " c = b.a * 2",
312
- )
313
- engine.evaluate("A", %w{a c}).should == [123, 123*2]
308
+ it 'should be able to get attr on node' do
309
+ engine.parse defn('A:',
310
+ ' a = 123',
311
+ ' b = A',
312
+ ' c = b.a * 2',
313
+ )
314
+ engine.evaluate('A', %w[a c]).should == [123, 123 * 2]
314
315
  end
315
316
 
316
317
  getattr_code = <<eoc
@@ -326,80 +327,87 @@ E:
326
327
  xx = [n.x for n in D.xs]
327
328
  eoc
328
329
 
329
- it "should be able to get attr on node 2" do
330
+ it 'should be able to get attr on node 2' do
330
331
  engine.parse getattr_code
331
- engine.evaluate("E", "xx").should == [1,2,3]
332
+ engine.evaluate('E', 'xx').should == [1, 2, 3]
332
333
  end
333
334
 
334
- it "should be able to call class methods on AR classes in modules" do
335
- engine.parse defn("A:",
336
- " b = M::LittleDummy.heres_my_number(867, 5309)",
337
- )
338
- r = engine.evaluate("A", "b")
335
+ it 'should be able to call class methods on AR classes in modules' do
336
+ engine.parse defn('A:',
337
+ ' b = M::LittleDummy.heres_my_number(867, 5309)',
338
+ ' c = M::N::NestedDummy.heres_my_number(867, 5309)',
339
+ )
340
+ r = engine.evaluate('A', 'b')
341
+ r.should == 867 + 5309
342
+
343
+ r = engine.evaluate('A', 'c')
339
344
  r.should == 867 + 5309
340
345
  end
341
346
 
342
- it "should be able to use AR classes as values and call their methods" do
343
- engine.parse defn("A:",
344
- " a = M::LittleDummy",
345
- " b = a.heres_my_number(867, 5309)",
346
- )
347
- r = engine.evaluate("A", "b")
347
+ it 'should be able to use AR classes as values and call their methods' do
348
+ engine.parse defn('A:',
349
+ ' a = M::LittleDummy',
350
+ ' b = a.heres_my_number(867, 5309)',
351
+ ' c = M::N::NestedDummy.heres_my_number(867, 5309)',
352
+ )
353
+ r = engine.evaluate('A', 'b')
354
+ r.should == 867 + 5309
355
+
356
+ r = engine.evaluate('A', 'c')
348
357
  r.should == 867 + 5309
349
358
  end
350
359
 
351
- it "should ignore undeclared params sent to eval which match attr names" do
352
- engine.parse defn("A:",
353
- " d = 12",
354
- )
355
- r = engine.evaluate("A", "d", {"d" => 5, "e" => 6})
360
+ it 'should ignore undeclared params sent to eval which match attr names' do
361
+ engine.parse defn('A:',
362
+ ' d = 12',
363
+ )
364
+ r = engine.evaluate('A', 'd', 'd' => 5, 'e' => 6)
356
365
  r.should == 12
357
366
  end
358
367
 
359
- it "should handle different param defaults on nodes" do
360
- engine.parse defn("A:",
361
- " p =? 1",
362
- " c = p * 123",
363
- "B: A",
364
- " p =? 2",
365
- "C: A",
366
- " p =? 3",
367
- )
368
+ it 'should handle different param defaults on nodes' do
369
+ engine.parse defn('A:',
370
+ ' p =? 1',
371
+ ' c = p * 123',
372
+ 'B: A',
373
+ ' p =? 2',
374
+ 'C: A',
375
+ ' p =? 3',
376
+ )
368
377
 
369
- r = engine.evaluate("C", "c", {"p" => 5})
370
- r.should == 5*123
378
+ r = engine.evaluate('C', 'c', 'p' => 5)
379
+ r.should == 5 * 123
371
380
 
372
- r = engine.evaluate("B", "c", {"p" => 10})
373
- r.should == 10*123
381
+ r = engine.evaluate('B', 'c', 'p' => 10)
382
+ r.should == 10 * 123
374
383
 
375
- r = engine.evaluate("A", "c")
376
- r.should == 1*123
384
+ r = engine.evaluate('A', 'c')
385
+ r.should == 1 * 123
377
386
 
378
- r = engine.evaluate("B", "c")
379
- r.should == 2*123
387
+ r = engine.evaluate('B', 'c')
388
+ r.should == 2 * 123
380
389
 
381
- r = engine.evaluate("C", "c")
382
- r.should == 3*123
390
+ r = engine.evaluate('C', 'c')
391
+ r.should == 3 * 123
383
392
  end
384
393
 
385
- it "should allow overriding of attrs as params" do
386
- engine.parse defn("A:",
387
- " a = 2",
388
- " b = a*3",
389
- "B: A",
390
- " a =?",
391
- )
394
+ it 'should allow overriding of attrs as params' do
395
+ engine.parse defn('A:',
396
+ ' a = 2',
397
+ ' b = a*3',
398
+ 'B: A',
399
+ ' a =?',
400
+ )
392
401
 
393
- r = engine.evaluate("A", "b", {"a" => 10})
394
- r.should == 2*3
402
+ r = engine.evaluate('A', 'b', 'a' => 10)
403
+ r.should == 2 * 3
395
404
 
396
- r = engine.evaluate("B", "b", {"a" => 10})
397
- r.should == 10*3
405
+ r = engine.evaluate('B', 'b', 'a' => 10)
406
+ r.should == 10 * 3
398
407
 
399
408
  lambda {
400
- r = engine.evaluate("B", "b")
409
+ r = engine.evaluate('B', 'b')
401
410
  }.should raise_error(Delorean::UndefinedParamError)
402
-
403
411
  end
404
412
 
405
413
  sample_script = <<eof
@@ -416,663 +424,750 @@ B: A
416
424
  p =? 5
417
425
  eof
418
426
 
419
- it "should allow overriding of attrs as params" do
427
+ it 'should allow overriding of attrs as params' do
420
428
  engine.parse sample_script
421
429
 
422
- r = engine.evaluate("C", "c")
430
+ r = engine.evaluate('C', 'c')
423
431
  r.should == 4
424
432
 
425
- r = engine.evaluate("B", "pc")
433
+ r = engine.evaluate('B', 'pc')
426
434
  r.should == 4 + 5
427
435
 
428
- r = engine.evaluate("C", "pc")
436
+ r = engine.evaluate('C', 'pc')
429
437
  r.should == 4 + 3
430
438
 
431
439
  lambda {
432
- r = engine.evaluate("A", "pc")
440
+ r = engine.evaluate('A', 'pc')
433
441
  }.should raise_error(Delorean::UndefinedParamError)
434
442
  end
435
443
 
436
- it "engines of same name should be independent" do
444
+ it 'engines of same name should be independent' do
437
445
  engin2 = Delorean::Engine.new(engine.module_name)
438
446
 
439
- engine.parse defn("A:",
440
- " a = 123",
441
- " b = a*3",
442
- "B: A",
443
- " c = b*2",
444
- )
445
-
446
- engin2.parse defn("A:",
447
- " a = 222.0",
448
- " b = a/5",
449
- "B: A",
450
- " c = b*3",
451
- "C:",
452
- " d = 111",
453
- )
454
-
455
- engine.evaluate("A", ["a", "b"]).should == [123, 123*3]
456
- engin2.evaluate("A", ["a", "b"]).should == [222.0, 222.0/5]
457
-
458
- engine.evaluate("B", ["a", "b", "c"]).should == [123, 123*3, 123*3*2]
459
- engin2.evaluate("B", ["a", "b", "c"]).should ==
460
- [222.0, 222.0/5, 222.0/5*3]
461
-
462
- engin2.evaluate("C", "d").should == 111
447
+ engine.parse defn('A:',
448
+ ' a = 123',
449
+ ' b = a*3',
450
+ 'B: A',
451
+ ' c = b*2',
452
+ )
453
+
454
+ engin2.parse defn('A:',
455
+ ' a = 222.0',
456
+ ' b = a/5',
457
+ 'B: A',
458
+ ' c = b*3',
459
+ 'C:',
460
+ ' d = 111',
461
+ )
462
+
463
+ engine.evaluate('A', ['a', 'b']).should == [123, 123 * 3]
464
+ engin2.evaluate('A', ['a', 'b']).should == [222.0, 222.0 / 5]
465
+
466
+ engine.evaluate('B', ['a', 'b', 'c']).should == [123, 123 * 3, 123 * 3 * 2]
467
+ engin2.evaluate('B', ['a', 'b', 'c']).should ==
468
+ [222.0, 222.0 / 5, 222.0 / 5 * 3]
469
+
470
+ engin2.evaluate('C', 'd').should == 111
463
471
  lambda {
464
- engine.evaluate("C", "d")
472
+ engine.evaluate('C', 'd')
465
473
  }.should raise_error(Delorean::UndefinedNodeError)
466
474
  end
467
475
 
468
- it "should handle invalid expression evaluation" do
476
+ it 'should handle invalid expression evaluation' do
469
477
  # Should handle errors on expression such as -[] or -"xxx" or ("x"
470
478
  # + []) better. Currently, it raises NoMethodError.
471
479
  skip 'handle errors on expressions such as -[] or -"xxx"'
472
480
  end
473
481
 
474
- it "should eval lists" do
475
- engine.parse defn("A:",
476
- " b = []",
477
- " c = [1,2,3]",
482
+ it 'should eval lists' do
483
+ engine.parse defn('A:',
484
+ ' b = []',
485
+ ' c = [1,2,3]',
478
486
  " d = [b, c, b, c, 1, 2, '123', 1.1, -1.23]",
479
- " e = [1, 1+1, 1+1+1, 1*2*4]",
480
- )
487
+ ' e = [1, 1+1, 1+1+1, 1*2*4]',
488
+ )
481
489
 
482
- engine.evaluate("A", %w{b c d e}).should ==
490
+ engine.evaluate('A', %w[b c d e]).should ==
483
491
  [[],
484
492
  [1, 2, 3],
485
- [[], [1, 2, 3], [], [1, 2, 3], 1, 2, "123", 1.1, -1.23],
493
+ [[], [1, 2, 3], [], [1, 2, 3], 1, 2, '123', 1.1, -1.23],
486
494
  [1, 2, 3, 8],
487
495
  ]
488
496
  end
489
497
 
490
- it "should eval list expressions" do
491
- engine.parse defn("A:",
492
- " b = []+[]",
493
- " c = [1,2,3]+b",
494
- " d = c*2",
495
- )
498
+ it 'should eval list expressions' do
499
+ engine.parse defn('A:',
500
+ ' b = []+[]',
501
+ ' c = [1,2,3]+b',
502
+ ' d = c*2',
503
+ )
496
504
 
497
- engine.evaluate("A", %w{b c d}).should ==
505
+ engine.evaluate('A', %w[b c d]).should ==
498
506
  [[],
499
507
  [1, 2, 3],
500
- [1, 2, 3]*2,
508
+ [1, 2, 3] * 2,
501
509
  ]
502
510
  end
503
511
 
504
- it "should eval sets and set comprehension" do
505
- engine.parse defn("A:",
506
- " a = {-}",
507
- " b = {i*5 for i in {1,2,3}}",
508
- " c = {1,2,3} | {4,5}",
509
- )
510
- engine.evaluate("A", ["a", "b", "c"]).should ==
511
- [Set[], Set[5,10,15], Set[1,2,3,4,5]]
512
+ it 'should eval sets and set comprehension' do
513
+ engine.parse defn('A:',
514
+ ' a = {-}',
515
+ ' b = {i*5 for i in {1,2,3}}',
516
+ ' c = {1,2,3} | {4,5}',
517
+ )
518
+ engine.evaluate('A', ['a', 'b', 'c']).should ==
519
+ [Set[], Set[5, 10, 15], Set[1, 2, 3, 4, 5]]
512
520
  end
513
521
 
514
- it "should eval list comprehension" do
515
- engine.parse defn("A:",
516
- " b = [i*5 for i in [1,2,3]]",
517
- " c = [a-b for a, b in [[1,2],[4,3]]]"
518
- )
519
- engine.evaluate("A", "b").should == [5, 10, 15]
520
- engine.evaluate("A", "c").should == [-1, 1]
522
+ it 'should eval list comprehension' do
523
+ engine.parse defn('A:',
524
+ ' b = [i*5 for i in [1,2,3]]',
525
+ ' c = [a-b for a, b in [[1,2],[4,3]]]'
526
+ )
527
+ engine.evaluate('A', 'b').should == [5, 10, 15]
528
+ engine.evaluate('A', 'c').should == [-1, 1]
521
529
  end
522
530
 
523
- it "should eval nested list comprehension" do
524
- engine.parse defn("A:",
525
- " b = [[a+c for c in [4,5]] for a in [1,2,3]]",
526
- )
527
- engine.evaluate("A", "b").should == [[5, 6], [6, 7], [7, 8]]
528
-
531
+ it 'should eval nested list comprehension' do
532
+ engine.parse defn('A:',
533
+ ' b = [[a+c for c in [4,5]] for a in [1,2,3]]',
534
+ )
535
+ engine.evaluate('A', 'b').should == [[5, 6], [6, 7], [7, 8]]
529
536
  end
530
537
 
531
- it "should eval list comprehension variable override" do
532
- engine.parse defn("A:",
533
- " b = [b/2.0 for b in [1,2,3]]",
534
- )
535
- engine.evaluate("A", "b").should == [0.5, 1.0, 1.5]
538
+ it 'should eval list comprehension variable override' do
539
+ engine.parse defn('A:',
540
+ ' b = [b/2.0 for b in [1,2,3]]',
541
+ )
542
+ engine.evaluate('A', 'b').should == [0.5, 1.0, 1.5]
536
543
  end
537
544
 
538
- it "should eval list comprehension variable override (2)" do
539
- engine.parse defn("A:",
540
- " a = 1",
541
- " b = [a+1 for a in [1,2,3]]",
542
- )
543
- engine.evaluate("A", "b").should == [2, 3, 4]
545
+ it 'should eval list comprehension variable override (2)' do
546
+ engine.parse defn('A:',
547
+ ' a = 1',
548
+ ' b = [a+1 for a in [1,2,3]]',
549
+ )
550
+ engine.evaluate('A', 'b').should == [2, 3, 4]
544
551
  end
545
552
 
546
- it "should eval conditional list comprehension" do
547
- engine.parse defn("A:",
548
- " b = [i*5 for i in [1,2,3,4,5] if i%2 == 1]",
549
- " c = [i/10.0 for i in [1,2,3,4,5] if i>4]",
550
- )
551
- engine.evaluate("A", "b").should == [5, 15, 25]
552
- engine.evaluate("A", "c").should == [0.5]
553
+ it 'should eval conditional list comprehension' do
554
+ engine.parse defn('A:',
555
+ ' b = [i*5 for i in [1,2,3,4,5] if i%2 == 1]',
556
+ ' c = [i/10.0 for i in [1,2,3,4,5] if i>4]',
557
+ )
558
+ engine.evaluate('A', 'b').should == [5, 15, 25]
559
+ engine.evaluate('A', 'c').should == [0.5]
553
560
  end
554
561
 
555
- it "should handle list comprehension unpacking" do
556
- engine.parse defn("A:",
557
- " b = [a-b for a, b in [[1,2],[20,10]]]",
558
- )
559
- engine.evaluate("A", "b").should == [-1, 10]
562
+ it 'should handle list comprehension unpacking' do
563
+ engine.parse defn('A:',
564
+ ' b = [a-b for a, b in [[1,2],[20,10]]]',
565
+ )
566
+ engine.evaluate('A', 'b').should == [-1, 10]
560
567
  end
561
568
 
562
- it "should handle list comprehension with conditions using loop var" do
563
- skip "need to fix"
564
- engine.parse defn("A:",
569
+ it 'should handle list comprehension with conditions using loop var' do
570
+ skip 'need to fix'
571
+ engine.parse defn('A:',
565
572
  " b = [n for n in {'pt' : 1} if n[1]+1]",
566
- )
567
- engine.evaluate("A", "b").should == [['pt', 1]]
573
+ )
574
+ engine.evaluate('A', 'b').should == [['pt', 1]]
568
575
  end
569
576
 
570
- it "should eval hashes" do
571
- engine.parse defn("A:",
572
- " b = {}",
577
+ it 'should eval hashes' do
578
+ engine.parse defn('A:',
579
+ ' b = {}',
573
580
  " c = {'a':1, 'b': 2,'c':3}",
574
581
  " d = {123*2: -123, 'b_b': 1+1}",
575
582
  " e = {'x': 1, 'y': 1+1, 'z': 1+1+1, 'zz': 1*2*4}",
576
583
  " f = {'a': nil, 'b': [1, nil, 2]}",
577
- " g = {b:b, [b]:[1,23], []:345}",
578
- )
584
+ ' g = {b:b, [b]:[1,23], []:345}',
585
+ )
579
586
 
580
- engine.evaluate("A", %w{b c d e f g}).should ==
587
+ engine.evaluate('A', %w[b c d e f g]).should ==
581
588
  [{},
582
- {"a"=>1, "b"=>2, "c"=>3},
583
- {123*2=>-123, "b_b"=>2},
584
- {"x"=>1, "y"=>2, "z"=>3, "zz"=>8},
585
- {"a"=>nil, "b"=>[1, nil, 2]},
586
- {{}=>{}, [{}]=>[1, 23], []=>345},
589
+ { 'a' => 1, 'b' => 2, 'c' => 3 },
590
+ { 123 * 2 => -123, 'b_b' => 2 },
591
+ { 'x' => 1, 'y' => 2, 'z' => 3, 'zz' => 8 },
592
+ { 'a' => nil, 'b' => [1, nil, 2] },
593
+ { {} => {}, [{}] => [1, 23], [] => 345 },
587
594
  ]
588
595
  end
589
596
 
590
- it "handles literal hashes with conditionals" do
591
- engine.parse defn("A:",
597
+ it 'handles literal hashes with conditionals' do
598
+ engine.parse defn('A:',
592
599
  " a = {'a':1 if 123, 'b':'x' if nil}",
593
600
  " b = {'a':a if a, 2: a if true, 'c':nil if 2*2}",
594
- " c = 1>2",
595
- " d = {1: {1: 2 if b}, 3: 3 if c, 2: {2: 3 if a}}",
596
- )
597
-
598
- engine.evaluate("A", %w{a b d}).should == [
599
- {"a"=>1},
600
- {"a"=>{"a"=>1}, 2=>{"a"=>1}, "c"=>nil},
601
- {1=>{1=>2}, 2=>{2=>3}},
601
+ ' c = 1>2',
602
+ ' d = {1: {1: 2 if b}, 3: 3 if c, 2: {2: 3 if a}}',
603
+ )
604
+
605
+ engine.evaluate('A', %w[a b d]).should == [
606
+ { 'a' => 1 },
607
+ { 'a' => { 'a' => 1 }, 2 => { 'a' => 1 }, 'c' => nil },
608
+ { 1 => { 1 => 2 }, 2 => { 2 => 3 } },
602
609
  ]
603
610
  end
604
611
 
605
- it "should eval hash comprehension" do
606
- engine.parse defn("A:",
607
- " b = {i*5 :i for i in [1,2,3]}",
608
- " c = [kv for kv in {1:11, 2:22}]",
609
- )
610
- engine.evaluate("A", "b").should == {5=>1, 10=>2, 15=>3}
611
- engine.evaluate("A", "c").should == [[1, 11], [2, 22]]
612
+ it 'should eval hash comprehension' do
613
+ engine.parse defn('A:',
614
+ ' b = {i*5 :i for i in [1,2,3]}',
615
+ ' c = [kv for kv in {1:11, 2:22}]',
616
+ )
617
+ engine.evaluate('A', 'b').should == { 5 => 1, 10 => 2, 15 => 3 }
618
+ engine.evaluate('A', 'c').should == [[1, 11], [2, 22]]
612
619
  end
613
620
 
614
- it "for-in-hash should iterate over key/value pairs" do
615
- engine.parse defn("A:",
616
- " b = {1: 11, 2: 22}",
617
- " c = [kv[0]-kv[1] for kv in b]",
618
- " d = {kv[0] : kv[1] for kv in b}",
619
- " e = [kv for kv in b if kv[1]]",
620
- " f = [k-v for k, v in b if k>1]",
621
- )
622
- engine.evaluate("A", "c").should == [-10, -20]
623
- engine.evaluate("A", "d").should == {1=>11, 2=>22}
624
- engine.evaluate("A", "f").should == [-20]
621
+ it 'for-in-hash should iterate over key/value pairs' do
622
+ engine.parse defn('A:',
623
+ ' b = {1: 11, 2: 22}',
624
+ ' c = [kv[0]-kv[1] for kv in b]',
625
+ ' d = {kv[0] : kv[1] for kv in b}',
626
+ ' e = [kv for kv in b if kv[1]]',
627
+ ' f = [k-v for k, v in b if k>1]',
628
+ )
629
+ engine.evaluate('A', 'c').should == [-10, -20]
630
+ engine.evaluate('A', 'd').should == { 1 => 11, 2 => 22 }
631
+ engine.evaluate('A', 'f').should == [-20]
625
632
 
626
633
  # FIXME: this is a known bug in Delorean caused by the strange way
627
634
  # that select iterates over hashes and provides args to the block.
628
635
  # engine.evaluate("A", "e").should == [[1,11], [2,22]]
629
636
  end
630
637
 
631
- it "should eval nested hash comprehension" do
632
- engine.parse defn("A:",
633
- " b = { a:{a+c:a-c for c in [4,5]} for a in [1,2,3]}",
634
- )
635
- engine.evaluate("A", "b").should ==
636
- {1=>{5=>-3, 6=>-4}, 2=>{6=>-2, 7=>-3}, 3=>{7=>-1, 8=>-2}}
638
+ it 'should eval nested hash comprehension' do
639
+ engine.parse defn('A:',
640
+ ' b = { a:{a+c:a-c for c in [4,5]} for a in [1,2,3]}',
641
+ )
642
+ engine.evaluate('A', 'b').should == {
643
+ 1 => { 5 => -3, 6 => -4 },
644
+ 2 => { 6 => -2, 7 => -3 },
645
+ 3 => { 7 => -1, 8 => -2 }
646
+ }
637
647
  end
638
648
 
639
- it "should eval conditional hash comprehension" do
640
- engine.parse defn("A:",
641
- " b = {i*5:i+5 for i in [1,2,3,4,5] if i%2 == 1}",
642
- " c = {i/10.0:i*10 for i in [1,2,3,4,5] if i>4}",
643
- )
644
- engine.evaluate("A", "b").should == {5=>6, 15=>8, 25=>10}
645
- engine.evaluate("A", "c").should == {0.5=>50}
649
+ it 'should eval conditional hash comprehension' do
650
+ engine.parse defn('A:',
651
+ ' b = {i*5:i+5 for i in [1,2,3,4,5] if i%2 == 1}',
652
+ ' c = {i/10.0:i*10 for i in [1,2,3,4,5] if i>4}',
653
+ )
654
+ engine.evaluate('A', 'b').should == { 5 => 6, 15 => 8, 25 => 10 }
655
+ engine.evaluate('A', 'c').should == { 0.5 => 50 }
646
656
  end
647
657
 
648
- it "should eval node calls as intermediate results" do
649
- engine.parse defn("A:",
650
- " a =?",
651
- " e = A(a=13)",
652
- " d = e.a * 2",
653
- " f = e.d / e.a",
654
- )
658
+ it 'should eval node calls as intermediate results' do
659
+ engine.parse defn('A:',
660
+ ' a =?',
661
+ ' e = A(a=13)',
662
+ ' d = e.a * 2',
663
+ ' f = e.d / e.a',
664
+ )
655
665
 
656
- engine.evaluate("A", ["d", "f"]).should == [26, 2]
666
+ engine.evaluate('A', ['d', 'f']).should == [26, 2]
657
667
  end
658
668
 
659
- it "allows node calls from attrs" do
660
- engine.parse defn("A:",
661
- " a =?",
662
- " c =?",
663
- " b = a**2",
664
- " e = A(a=13)",
669
+ it 'allows node calls from attrs' do
670
+ engine.parse defn('A:',
671
+ ' a =?',
672
+ ' c =?',
673
+ ' b = a**2',
674
+ ' e = A(a=13)',
665
675
  " d = e(a=4, **{'c': 5})",
666
- " f = d.b + d.c + e().a",
667
- )
676
+ ' f = d.b + d.c + e().a',
677
+ )
668
678
 
669
- engine.evaluate("A", ["f"]).should == [16+5+13]
679
+ engine.evaluate('A', ['f']).should == [16 + 5 + 13]
670
680
  end
671
681
 
672
- it "should eval multi-var hash comprehension" do
673
- engine.parse defn("A:",
674
- " b = {k*5 : v+1 for k, v in {1:2, 7:-30}}",
675
- " c = [k-v for k, v in {1:2, 7:-30}]",
676
- )
677
- engine.evaluate("A", "b").should == {5=>3, 35=>-29}
678
- engine.evaluate("A", "c").should == [-1, 37]
682
+ it 'should eval multi-var hash comprehension' do
683
+ engine.parse defn('A:',
684
+ ' b = {k*5 : v+1 for k, v in {1:2, 7:-30}}',
685
+ ' c = [k-v for k, v in {1:2, 7:-30}]',
686
+ )
687
+ engine.evaluate('A', 'b').should == { 5 => 3, 35 => -29 }
688
+ engine.evaluate('A', 'c').should == [-1, 37]
679
689
  end
680
690
 
681
- it "should be able to amend node calls" do
682
- engine.parse defn("A:",
683
- " a =?",
684
- " aa = a*2",
685
- " c = A(a=12)",
691
+ it 'should be able to amend node calls' do
692
+ engine.parse defn('A:',
693
+ ' a =?',
694
+ ' aa = a*2',
695
+ ' c = A(a=12)',
686
696
  " d = c+{'a':3}",
687
697
  " f = c+{'a':4}",
688
- " g = d.aa + f.aa",
689
- " h = c(a=5).aa",
690
- " j = d(a=6).aa",
691
- )
698
+ ' g = d.aa + f.aa',
699
+ ' h = c(a=5).aa',
700
+ ' j = d(a=6).aa',
701
+ )
692
702
 
693
- engine.evaluate("A", ["g", "h", "j"]).should ==
694
- [3*2 + 4*2, 5*2, 6*2]
703
+ engine.evaluate('A', ['g', 'h', 'j']).should ==
704
+ [3 * 2 + 4 * 2, 5 * 2, 6 * 2]
695
705
  end
696
706
 
697
- it "should be able to amend node calls 2" do
698
- engine.parse defn("A:",
699
- " a =?",
700
- " d = A(a=3)",
701
- " e = [d.a, d(a=4).a]",
702
- )
707
+ it 'should be able to amend node calls 2' do
708
+ engine.parse defn('A:',
709
+ ' a =?',
710
+ ' d = A(a=3)',
711
+ ' e = [d.a, d(a=4).a]',
712
+ )
703
713
 
704
- engine.evaluate("A", ["e"]).should == [[3,4]]
714
+ engine.evaluate('A', ['e']).should == [[3, 4]]
705
715
  end
706
716
 
707
- it "should eval module calls 1" do
708
- engine.parse defn("A:",
709
- " a = 123",
710
- " n = A",
711
- " d = n().a",
712
- )
717
+ it 'should eval module calls 1' do
718
+ engine.parse defn('A:',
719
+ ' a = 123',
720
+ ' n = A',
721
+ ' d = n().a',
722
+ )
713
723
 
714
- engine.evaluate("A", %w{d}).should == [123]
724
+ engine.evaluate('A', %w[d]).should == [123]
715
725
  end
716
726
 
717
- it "should eval module calls 2" do
718
- engine.parse defn("A:",
719
- " a = 123",
720
- " b = 456 + a",
727
+ it 'should eval module calls 2' do
728
+ engine.parse defn('A:',
729
+ ' a = 123',
730
+ ' b = 456 + a',
721
731
  " n = 'A'",
722
732
  " c = nil(x = 123, y = 456) % ['a', 'b']",
723
733
  " d = n(x = 123, y = 456) % ['a', 'b']",
724
734
  " e = nil() % ['b']",
725
- )
735
+ )
726
736
 
727
- engine.evaluate("A", %w{n c d e}).should ==
728
- ["A", {"a"=>123, "b"=>579}, {"a"=>123, "b"=>579}, {"b"=>579}]
737
+ engine.evaluate('A', %w[n c d e]).should == [
738
+ 'A',
739
+ { 'a' => 123, 'b' => 579 },
740
+ { 'a' => 123, 'b' => 579 },
741
+ { 'b' => 579 }
742
+ ]
729
743
  end
730
744
 
731
- it "should eval module calls 3" do
732
- engine.parse defn("A:",
733
- " a = 123",
734
- "B:",
745
+ it 'should eval module calls 3' do
746
+ engine.parse defn('A:',
747
+ ' a = 123',
748
+ 'B:',
735
749
  " n = 'A'",
736
- " d = n().a",
737
- )
750
+ ' d = n().a',
751
+ )
738
752
 
739
- engine.evaluate("B", %w{d}).should == [123]
753
+ engine.evaluate('B', %w[d]).should == [123]
740
754
  end
741
755
 
742
- it "should be possible to implement recursive calls" do
743
- engine.parse defn("A:",
744
- " n =?",
745
- " fact = if n <= 1 then 1 else n * A(n=n-1).fact",
746
- )
756
+ it 'should be possible to implement recursive calls' do
757
+ engine.parse defn('A:',
758
+ ' n =?',
759
+ ' fact = if n <= 1 then 1 else n * A(n=n-1).fact',
760
+ )
747
761
 
748
- engine.evaluate("A", "fact", "n" => 10).should == 3628800
762
+ engine.evaluate('A', 'fact', 'n' => 10).should == 3_628_800
749
763
  end
750
764
 
751
- it "should eval module calls by node name" do
752
- engine.parse defn("A:",
753
- " a = 123",
754
- " b = A().a",
755
- )
756
- engine.evaluate("A", "b").should == 123
765
+ it 'should eval module calls by node name' do
766
+ engine.parse defn('A:',
767
+ ' a = 123',
768
+ ' b = A().a',
769
+ )
770
+ engine.evaluate('A', 'b').should == 123
757
771
  end
758
772
 
759
- it "should eval multiline expressions" do
760
- engine.parse defn("A:",
761
- " a = 1",
762
- " b = [a+1",
763
- " for a in [1,2,3]",
764
- " ]",
765
- )
766
- engine.evaluate("A", "b").should == [2, 3, 4]
773
+ it 'should eval multiline expressions' do
774
+ engine.parse defn('A:',
775
+ ' a = 1',
776
+ ' b = [a+1',
777
+ ' for a in [1,2,3]',
778
+ ' ]',
779
+ )
780
+ engine.evaluate('A', 'b').should == [2, 3, 4]
767
781
  end
768
782
 
769
- it "should eval multiline expressions (2)" do
770
- engine.parse defn("A:",
771
- " a = 123",
772
- " b = 456 + ",
773
- " a",
783
+ it 'should eval multiline expressions (2)' do
784
+ engine.parse defn('A:',
785
+ ' a = 123',
786
+ ' b = 456 + ',
787
+ ' a',
774
788
  " n = 'A'",
775
- " c = nil(x = 123,",
789
+ ' c = nil(x = 123,',
776
790
  " y = 456) % ['a', 'b']",
777
- " d = n(",
791
+ ' d = n(',
778
792
  " x = 123, y = 456) % ['a', 'b']",
779
- " e = nil(",
793
+ ' e = nil(',
780
794
  " ) % ['b']",
781
- )
795
+ )
782
796
 
783
- engine.evaluate("A", %w{n c d e}).should ==
784
- ["A", {"a"=>123, "b"=>579}, {"a"=>123, "b"=>579}, {"b"=>579}]
797
+ engine.evaluate('A', %w[n c d e]).should == [
798
+ 'A',
799
+ { 'a' => 123, 'b' => 579 },
800
+ { 'a' => 123, 'b' => 579 },
801
+ { 'b' => 579 }
802
+ ]
785
803
  end
786
804
 
787
- it "should eval in expressions" do
788
- engine.parse defn("A:",
789
- " a = [1,2,3,33,44]",
790
- " s = {22,33,44}",
791
- " b = (1 in a) && (2 in {22,44})",
792
- " c = (2 in a) && (22 in s)",
793
- " d = [i*2 for i in s if i in a]",
794
- )
805
+ it 'should eval in expressions' do
806
+ engine.parse defn('A:',
807
+ ' a = [1,2,3,33,44]',
808
+ ' s = {22,33,44}',
809
+ ' b = (1 in a) && (2 in {22,44})',
810
+ ' c = (2 in a) && (22 in s)',
811
+ ' d = [i*2 for i in s if i in a]',
812
+ )
795
813
 
796
- engine.evaluate("A", %w{b c d}).should ==
814
+ engine.evaluate('A', %w[b c d]).should ==
797
815
  [false, true, [66, 88]]
798
816
  end
799
817
 
800
- it "should eval imports" do
801
- engine.parse defn("import AAA",
802
- "A:",
803
- " b = 456",
804
- "B: AAA::X",
805
- " a = 111",
806
- " c = AAA::X(a=456).b",
807
- )
808
- engine.evaluate("B", ["a", "b", "c"], {}).should ==
809
- [111, 222, 456*2]
810
- end
811
-
812
- it "should eval imports (2)" do
813
- sset.merge({
814
- "BBB" =>
815
- defn("import AAA",
816
- "B: AAA::X",
817
- " a = 111",
818
- " c = AAA::X(a=-1).b",
819
- " d = a * 2",
820
- ),
821
- "CCC" =>
822
- defn("import BBB",
823
- "import AAA",
824
- "B: BBB::B",
825
- " e = d * 3",
826
- "C: AAA::X",
827
- " d = b * 3",
828
- ),
829
- })
830
-
831
- e2 = sset.get_engine("BBB")
832
-
833
- e2.evaluate("B", ["a", "b", "c", "d"]).should ==
818
+ it 'should eval imports' do
819
+ engine.parse defn('import AAA',
820
+ 'A:',
821
+ ' b = 456',
822
+ 'B: AAA::X',
823
+ ' a = 111',
824
+ ' c = AAA::X(a=456).b',
825
+ )
826
+ engine.evaluate('B', ['a', 'b', 'c'], {}).should ==
827
+ [111, 222, 456 * 2]
828
+ end
829
+
830
+ it 'should eval imports (2)' do
831
+ sset.merge(
832
+ 'BBB' =>
833
+ defn('import AAA',
834
+ 'B: AAA::X',
835
+ ' a = 111',
836
+ ' c = AAA::X(a=-1).b',
837
+ ' d = a * 2',
838
+ ),
839
+ 'CCC' =>
840
+ defn('import BBB',
841
+ 'import AAA',
842
+ 'B: BBB::B',
843
+ ' e = d * 3',
844
+ 'C: AAA::X',
845
+ ' d = b * 3',
846
+ ),
847
+ )
848
+
849
+ e2 = sset.get_engine('BBB')
850
+
851
+ e2.evaluate('B', ['a', 'b', 'c', 'd']).should ==
834
852
  [111, 222, -2, 222]
835
853
 
836
- engine.parse defn("import BBB",
837
- "B: BBB::B",
838
- " e = d + 3",
839
- )
854
+ engine.parse defn('import BBB',
855
+ 'B: BBB::B',
856
+ ' e = d + 3',
857
+ )
840
858
 
841
- engine.evaluate("B", ["a", "b", "c", "d", "e"]).should ==
859
+ engine.evaluate('B', ['a', 'b', 'c', 'd', 'e']).should ==
842
860
  [111, 222, -2, 222, 225]
843
861
 
844
- e4 = sset.get_engine("CCC")
862
+ e4 = sset.get_engine('CCC')
845
863
 
846
- e4.evaluate("B", ["a", "b", "c", "d", "e"]).should ==
864
+ e4.evaluate('B', ['a', 'b', 'c', 'd', 'e']).should ==
847
865
  [111, 222, -2, 222, 666]
848
866
 
849
- e4.evaluate("C", ["a", "b", "d"]).should == [123, 123*2, 123*3*2]
850
- end
851
-
852
- it "should eval imports (3)" do
853
- sset.merge({
854
- "BBB" => getattr_code,
855
- "CCC" =>
856
- defn("import BBB",
857
- "X:",
858
- " xx = [n.x for n in BBB::D().xs]",
859
- " yy = [n.x for n in BBB::D.xs]",
860
- ),
861
- })
862
-
863
- e4 = sset.get_engine("CCC")
864
- e4.evaluate("X", "xx").should == [1,2,3]
865
- e4.evaluate("X", "yy").should == [1,2,3]
866
- end
867
-
868
- it "can eval indexing" do
869
- engine.parse defn("A:",
870
- " a = [1,2,3]",
871
- " b = a[1]",
872
- " c = a[-1]",
867
+ e4.evaluate('C', ['a', 'b', 'd']).should == [123, 123 * 2, 123 * 3 * 2]
868
+ end
869
+
870
+ it 'should eval imports (3)' do
871
+ sset.merge(
872
+ 'BBB' => getattr_code,
873
+ 'CCC' =>
874
+ defn('import BBB',
875
+ 'X:',
876
+ ' xx = [n.x for n in BBB::D().xs]',
877
+ ' yy = [n.x for n in BBB::D.xs]',
878
+ ),
879
+ )
880
+
881
+ e4 = sset.get_engine('CCC')
882
+ e4.evaluate('X', 'xx').should == [1, 2, 3]
883
+ e4.evaluate('X', 'yy').should == [1, 2, 3]
884
+ end
885
+
886
+ it 'should eval imports (4) - with ::' do
887
+ sset.merge(
888
+ 'BBB' => getattr_code,
889
+ 'BBB::A' => defn(
890
+ 'X:',
891
+ ' xx = [1, 2, 3]'
892
+ ),
893
+ 'BBB::A::CC' => defn(
894
+ 'X:',
895
+ ' xx = [1, 2, 3]'
896
+ ),
897
+ 'DDD__Ef__Gh' => defn(
898
+ 'import BBB',
899
+ 'import BBB::A',
900
+ 'import BBB::A::CC',
901
+ 'EfNode:',
902
+ ' g = BBB::D.xs',
903
+ ' gh = BBB::A::X.xx',
904
+ ),
905
+ 'CCC' =>
906
+ defn('import BBB',
907
+ 'import DDD__Ef__Gh',
908
+ 'X:',
909
+ ' xx = [n.x for n in BBB::D().xs]',
910
+ ' yy = [n.x for n in BBB::D.xs]',
911
+ ' zz = [n * 2 for n in DDD__Ef__Gh::EfNode.gh]',
912
+ ),
913
+ )
914
+
915
+ e4 = sset.get_engine('CCC')
916
+ e4.evaluate('X', 'xx').should == [1, 2, 3]
917
+ e4.evaluate('X', 'zz').should == [2, 4, 6]
918
+ end
919
+
920
+ it 'should eval imports (4) - inheritance - with ::' do
921
+ sset.merge(
922
+ 'BBB' => getattr_code,
923
+ 'BBB::A' => defn(
924
+ 'X:',
925
+ ' xx = [1, 2, 3]'
926
+ ),
927
+ 'BBB::A::CC' => defn(
928
+ 'X:',
929
+ ' xx = [1, 2, 3]'
930
+ ),
931
+ 'DDD__Ef__Gh' => defn(
932
+ 'import BBB',
933
+ 'import BBB::A',
934
+ 'import BBB::A::CC',
935
+ 'EfNode: BBB::A::CC::X',
936
+ ' g = xx',
937
+ ),
938
+ 'CCC' =>
939
+ defn('import BBB',
940
+ 'import DDD__Ef__Gh',
941
+ 'X:',
942
+ ' zz = [n * 2 for n in DDD__Ef__Gh::EfNode.g]',
943
+ ),
944
+ )
945
+
946
+ e4 = sset.get_engine('CCC')
947
+ e4.evaluate('X', 'zz').should == [2, 4, 6]
948
+ end
949
+
950
+ it 'can eval indexing' do
951
+ engine.parse defn('A:',
952
+ ' a = [1,2,3]',
953
+ ' b = a[1]',
954
+ ' c = a[-1]',
873
955
  " d = {'a' : 123, 'b': 456}",
874
956
  " e = d['b']",
875
- " f = a[1,2]",
876
- )
877
- r = engine.evaluate("A", ["b", "c", "e", "f"])
878
- r.should == [2, 3, 456, [2,3]]
957
+ ' f = a[1,2]',
958
+ )
959
+ r = engine.evaluate('A', ['b', 'c', 'e', 'f'])
960
+ r.should == [2, 3, 456, [2, 3]]
879
961
  end
880
962
 
881
- it "can eval indexing 2" do
882
- engine.parse defn("A:",
883
- " a = 1",
963
+ it 'can eval indexing 2' do
964
+ engine.parse defn('A:',
965
+ ' a = 1',
884
966
  " b = {'x' : 123, 'y': 456}",
885
967
  " c = A() % ['a', 'b']",
886
968
  " d = c['b'].x * c['a'] - c['b'].y",
887
- )
888
- r = engine.evaluate("A", ["a", "b", "c", "d"])
889
- r.should ==
890
- [1, {"x"=>123, "y"=>456}, {"a"=>1, "b"=>{"x"=>123, "y"=>456}}, -333]
969
+ )
970
+ r = engine.evaluate('A', ['a', 'b', 'c', 'd'])
971
+ r.should == [
972
+ 1,
973
+ { 'x' => 123, 'y' => 456 },
974
+ { 'a' => 1, 'b' => { 'x' => 123, 'y' => 456 } },
975
+ -333
976
+ ]
891
977
  end
892
978
 
893
- it "can handle exceptions with / syntax" do
894
- engine.parse defn("A:",
895
- " a = 1",
979
+ it 'can handle exceptions with / syntax' do
980
+ engine.parse defn('A:',
981
+ ' a = 1',
896
982
  " b = {'x' : 123, 'y': 456}",
897
983
  " e = ERR('hello')",
898
984
  " c = A() / ['a', 'b']",
899
985
  " d = A() / ['a', 'e']",
900
986
  " f = A() / 'a'",
901
- )
902
- r = engine.evaluate("A", ["a", "b", "c"])
903
- r.should ==
904
- [1, {"x"=>123, "y"=>456}, {"a"=>1, "b"=>{"x"=>123, "y"=>456}}]
987
+ )
988
+ r = engine.evaluate('A', ['a', 'b', 'c'])
989
+ r.should == [
990
+ 1,
991
+ { 'x' => 123, 'y' => 456 },
992
+ { 'a' => 1, 'b' => { 'x' => 123, 'y' => 456 } }
993
+ ]
905
994
 
906
- r = engine.evaluate("A", ["a", "d"])
907
- r.should ==
908
- [1, {"error"=>"hello", "backtrace"=>[["XXX", 4, "e"], ["XXX", 6, "d"]]}]
995
+ r = engine.evaluate('A', ['a', 'd'])
996
+ r.should == [
997
+ 1,
998
+ { 'error' => 'hello', 'backtrace' => [['XXX', 4, 'e'], ['XXX', 6, 'd']] }
999
+ ]
909
1000
 
910
- r = engine.evaluate("A", ["f"])
1001
+ r = engine.evaluate('A', ['f'])
911
1002
  r.should == [1]
912
1003
  end
913
1004
 
914
- it "should properly eval overridden attrs" do
915
- engine.parse defn("A:",
916
- " a = 5",
917
- " b = a",
918
- "B: A",
919
- " a = 2",
920
- " x = A.b - B.b",
921
- " k = [A.b, B.b]",
922
- " l = [x.b for x in [A, B]]",
923
- " m = [x().b for x in [A, B]]",
924
- )
925
-
926
- engine.evaluate("A", "b").should == 5
927
- engine.evaluate("B", "b").should == 2
928
- engine.evaluate("B", "x").should == 3
929
- engine.evaluate("B", "k").should == [5, 2]
930
- engine.evaluate("B", "l").should == [5, 2]
931
- engine.evaluate("B", "m").should == [5, 2]
932
- end
933
-
934
- it "implements simple version of self (_)" do
935
- engine.parse defn("B:",
936
- " a =?",
937
- " b =?",
938
- " x = a - b",
939
- "A:",
940
- " a =?",
941
- " b =?",
942
- " x = _.a * _.b",
943
- " y = a && _",
944
- " z = (B() + _).x",
945
- " w = B(**_).x",
1005
+ it 'should properly eval overridden attrs' do
1006
+ engine.parse defn('A:',
1007
+ ' a = 5',
1008
+ ' b = a',
1009
+ 'B: A',
1010
+ ' a = 2',
1011
+ ' x = A.b - B.b',
1012
+ ' k = [A.b, B.b]',
1013
+ ' l = [x.b for x in [A, B]]',
1014
+ ' m = [x().b for x in [A, B]]',
1015
+ )
1016
+
1017
+ engine.evaluate('A', 'b').should == 5
1018
+ engine.evaluate('B', 'b').should == 2
1019
+ engine.evaluate('B', 'x').should == 3
1020
+ engine.evaluate('B', 'k').should == [5, 2]
1021
+ engine.evaluate('B', 'l').should == [5, 2]
1022
+ engine.evaluate('B', 'm').should == [5, 2]
1023
+ end
1024
+
1025
+ it 'implements simple version of self (_)' do
1026
+ engine.parse defn('B:',
1027
+ ' a =?',
1028
+ ' b =?',
1029
+ ' x = a - b',
1030
+ 'A:',
1031
+ ' a =?',
1032
+ ' b =?',
1033
+ ' x = _.a * _.b',
1034
+ ' y = a && _',
1035
+ ' z = (B() + _).x',
1036
+ ' w = B(**_).x',
946
1037
  " v = {**_, 'a': 123}",
947
- )
948
-
949
- engine.evaluate("A", "x", {"a"=>3, "b"=>5}).should == 15
950
- h = {"a"=>1, "b"=>2, "c"=>3}
951
- engine.evaluate("A", "y", {"a"=>1, "b"=>2, "c"=>3}).should == h
952
- engine.evaluate("A", "z", {"a"=>1, "b"=>2, "c"=>3}).should == -1
953
- engine.evaluate("A", "w", {"a"=>4, "b"=>5, "c"=>3}).should == -1
954
- engine.evaluate("A", "v", {"a"=>4, "b"=>5, "c"=>3}).should == {
955
- "a"=>123, "b"=>5, "c"=>3}
956
- end
957
-
958
- it "implements positional args in node calls" do
959
- engine.parse defn("B:",
960
- " a =?",
961
- " b =?",
962
- " x = (_.0 - _.1) * (a - b)",
963
- " y = [_.0, _.1, _.2]",
964
- "A:",
965
- " a = _.0 - _.1",
966
- " z = B(10, 20, a=3, b=7).x",
1038
+ )
1039
+
1040
+ engine.evaluate('A', 'x', 'a' => 3, 'b' => 5).should == 15
1041
+ h = { 'a' => 1, 'b' => 2, 'c' => 3 }
1042
+ engine.evaluate('A', 'y', 'a' => 1, 'b' => 2, 'c' => 3).should == h
1043
+ engine.evaluate('A', 'z', 'a' => 1, 'b' => 2, 'c' => 3).should == -1
1044
+ engine.evaluate('A', 'w', 'a' => 4, 'b' => 5, 'c' => 3).should == -1
1045
+ engine.evaluate('A', 'v', 'a' => 4, 'b' => 5, 'c' => 3).should == {
1046
+ 'a' => 123, 'b' => 5, 'c' => 3
1047
+ }
1048
+ end
1049
+
1050
+ it 'implements positional args in node calls' do
1051
+ engine.parse defn('B:',
1052
+ ' a =?',
1053
+ ' b =?',
1054
+ ' x = (_.0 - _.1) * (a - b)',
1055
+ ' y = [_.0, _.1, _.2]',
1056
+ 'A:',
1057
+ ' a = _.0 - _.1',
1058
+ ' z = B(10, 20, a=3, b=7).x',
967
1059
  " y = B('x', 'y').y",
968
- )
969
- engine.evaluate("A", ["a", "z", "y"], {0 => 123, 1 => 456}).should ==
970
- [123-456, 40, ["x", "y", nil]]
1060
+ )
1061
+ engine.evaluate('A', ['a', 'z', 'y'], 0 => 123, 1 => 456).should ==
1062
+ [123 - 456, 40, ['x', 'y', nil]]
971
1063
  end
972
1064
 
973
- it "can call 0-arity functions in list comprehension" do
974
- engine.parse defn("A:",
1065
+ it 'can call 0-arity functions in list comprehension' do
1066
+ engine.parse defn('A:',
975
1067
  ' b = [x.name for x in Dummy.all_of_me]',
976
- )
977
- r = engine.evaluate("A", "b")
978
- expect(r).to eq ["hello"]
1068
+ )
1069
+ r = engine.evaluate('A', 'b')
1070
+ expect(r).to eq ['hello']
979
1071
  end
980
1072
 
981
- it "node calls are not memoized/cached" do
982
- engine.parse defn("A:",
983
- " x = Dummy.side_effect",
984
- "B: A",
985
- " x = (A() + _).x + (A() + _).x"
1073
+ it 'node calls are not memoized/cached' do
1074
+ engine.parse defn('A:',
1075
+ ' x = Dummy.side_effect',
1076
+ 'B: A',
1077
+ ' x = (A() + _).x + (A() + _).x'
986
1078
  )
987
- r = engine.evaluate("B", "x")
1079
+ r = engine.evaluate('B', 'x')
988
1080
  expect(r).to eq 3
989
1081
  end
990
1082
 
991
- it "node calls with double splats" do
992
- engine.parse defn("A:",
993
- " a =?",
994
- " b =?",
995
- " c = a+b",
1083
+ it 'node calls with double splats' do
1084
+ engine.parse defn('A:',
1085
+ ' a =?',
1086
+ ' b =?',
1087
+ ' c = a+b',
996
1088
  " h = {'a': 123}",
997
1089
  " k = {'b': 456}",
998
- " x = A(**h, **k).c"
1090
+ ' x = A(**h, **k).c'
999
1091
  )
1000
- r = engine.evaluate("A", "x")
1092
+ r = engine.evaluate('A', 'x')
1001
1093
  expect(r).to eq 579
1002
1094
  end
1003
1095
 
1004
- it "hash literal with double splats" do
1005
- engine.parse defn("A:",
1006
- " a =?",
1007
- " b =?",
1096
+ it 'hash literal with double splats' do
1097
+ engine.parse defn('A:',
1098
+ ' a =?',
1099
+ ' b =?',
1008
1100
  " h = {'a': 123, **a}",
1009
1101
  " k = {'b': 456, **h, **a, **b}",
1010
- " l = {**k}",
1011
- " m = {**k, 1:1, 2:2, 3:33}",
1012
- " n = {**k if false, 1:1, 2:2, 3:33}",
1102
+ ' l = {**k}',
1103
+ ' m = {**k, 1:1, 2:2, 3:33}',
1104
+ ' n = {**k if false, 1:1, 2:2, 3:33}',
1013
1105
  )
1014
- r = engine.evaluate("A", ["h", "k", "l", "m", "n"],
1015
- {"a" => {3=>3, 4=>4}, "b" => {5=>5, "a" => "aa"}})
1106
+ r = engine.evaluate(
1107
+ 'A',
1108
+ ['h', 'k', 'l', 'm', 'n'],
1109
+ 'a' => { 3 => 3, 4 => 4 }, 'b' => { 5 => 5, 'a' => 'aa' }
1110
+ )
1111
+
1016
1112
  expect(r).to eq [
1017
- {"a"=>123, 3=>3, 4=>4},
1018
- {"b"=>456, "a"=>"aa", 3=>3, 4=>4, 5=>5},
1019
- {"b"=>456, "a"=>"aa", 3=>3, 4=>4, 5=>5},
1020
- {"b"=>456, "a"=>"aa", 3=>33, 4=>4, 5=>5, 1=>1, 2=>2},
1021
- {1=>1, 2=>2, 3=>33},
1022
- ]
1023
- end
1024
-
1025
- it "understands openstructs" do
1026
- engine.parse defn("A:",
1027
- " os = Dummy.returns_openstruct",
1028
- " abc = os.abc",
1029
- " not_found = os.not_found"
1030
- )
1031
- r = engine.evaluate("A", ["os", "abc", "not_found"])
1032
- expect(r[0].abc).to eq("def")
1033
- expect(r[1]).to eq("def")
1034
- expect(r[2]).to be_nil
1113
+ { 'a' => 123, 3 => 3, 4 => 4 },
1114
+ { 'b' => 456, 'a' => 'aa', 3 => 3, 4 => 4, 5 => 5 },
1115
+ { 'b' => 456, 'a' => 'aa', 3 => 3, 4 => 4, 5 => 5 },
1116
+ { 'b' => 456, 'a' => 'aa', 3 => 33, 4 => 4, 5 => 5, 1 => 1, 2 => 2 },
1117
+ { 1 => 1, 2 => 2, 3 => 33 },
1118
+ ]
1035
1119
  end
1036
1120
 
1037
- it "can use nodes as continuations" do
1121
+ it 'understands openstructs' do
1122
+ engine.parse defn('A:',
1123
+ ' os = Dummy.returns_openstruct',
1124
+ ' abc = os.abc',
1125
+ ' not_found = os.not_found'
1126
+ )
1127
+ r = engine.evaluate('A', ['os', 'abc', 'not_found'])
1128
+ expect(r[0].abc).to eq('def')
1129
+ expect(r[1]).to eq('def')
1130
+ expect(r[2]).to be_nil
1131
+ end
1038
1132
 
1133
+ it 'can use nodes as continuations' do
1039
1134
  # FIME: This is actually a trivial exmaple. Ideally we should be
1040
1135
  # able to pass arguments to the nodes when evaluating ys. If the
1041
1136
  # arguments do not change the computation of "x" then "x" should
1042
1137
  # not be recomputed. This would need some flow analysis though.
1043
1138
 
1044
- engine.parse defn("A:",
1045
- " a =?",
1046
- " x = Dummy.side_effect",
1047
- " y = x*a",
1048
- "B:",
1049
- " ns = [A(a=a) for a in [1, 1, 1]]",
1050
- " xs = [n.x for n in ns]",
1051
- " ys = [n.y for n in ns]",
1052
- " res = [xs, ys]",
1053
- )
1054
- r = engine.evaluate("B", "res")
1139
+ engine.parse defn('A:',
1140
+ ' a =?',
1141
+ ' x = Dummy.side_effect',
1142
+ ' y = x*a',
1143
+ 'B:',
1144
+ ' ns = [A(a=a) for a in [1, 1, 1]]',
1145
+ ' xs = [n.x for n in ns]',
1146
+ ' ys = [n.y for n in ns]',
1147
+ ' res = [xs, ys]',
1148
+ )
1149
+ r = engine.evaluate('B', 'res')
1055
1150
  expect(r[1]).to eq r[0]
1056
1151
  end
1057
1152
 
1058
- it "can use nodes as continuations -- simple" do
1059
- engine.parse defn("A:",
1060
- " x = Dummy.side_effect",
1061
- " y = x",
1062
- "B:",
1063
- " ns = A()",
1064
- " res = [ns.x, ns.y]",
1153
+ it 'can use nodes as continuations -- simple' do
1154
+ engine.parse defn('A:',
1155
+ ' x = Dummy.side_effect',
1156
+ ' y = x',
1157
+ 'B:',
1158
+ ' ns = A()',
1159
+ ' res = [ns.x, ns.y]',
1065
1160
  " res2 = ns % ['x', 'y']",
1066
1161
  )
1067
- r = engine.evaluate("B", "res")
1162
+ r = engine.evaluate('B', 'res')
1068
1163
  expect(r[1]).to eq r[0]
1069
1164
 
1070
1165
  # this one works as expected
1071
- r2 = engine.evaluate("B", "res2")
1166
+ r2 = engine.evaluate('B', 'res2')
1072
1167
  expect(r2.values.uniq.length).to eq 1
1073
1168
  end
1074
1169
 
1075
- it "Implements ability to use overridden superclass attrs" do
1170
+ it 'Implements ability to use overridden superclass attrs' do
1076
1171
  code = <<-DELOREAN
1077
1172
  A:
1078
1173
  x = 123
@@ -1086,7 +1181,7 @@ eof
1086
1181
 
1087
1182
  engine.parse code.gsub(/^ /, '')
1088
1183
 
1089
- r = engine.evaluate("B", ["x", "y", "xx", "yy"])
1184
+ r = engine.evaluate('B', ['x', 'y', 'xx', 'yy'])
1090
1185
  expect(r).to eq [5, 2460, 128, 1230]
1091
1186
  end
1092
1187
  end