delorean_lang 0.0.43 → 0.1.00

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,60 +8,27 @@ describe "Delorean" do
8
8
 
9
9
  it "should handle MAX as a node name" do
10
10
  engine.parse defn("MAX:",
11
- " a = MAX(1, 2, 3, 0, -10)",
11
+ " a = [1, 2, 3, 0, -10].max()",
12
12
  )
13
13
 
14
14
  r = engine.evaluate("MAX", "a")
15
15
  r.should == 3
16
16
  end
17
17
 
18
- it "should handle MAX" do
19
- engine.parse defn("A:",
20
- " a = MAX(1, 2, 3)",
21
- )
22
-
23
- r = engine.evaluate("A", "a")
24
- r.should == 3
25
- end
26
-
27
- it "should handle insufficient args" do
28
- lambda {
29
- engine.parse defn("A:",
30
- " a = MAX(1)",
31
- )
32
- }.should raise_error(Delorean::BadCallError)
33
- end
34
-
35
18
  it "should handle MIN" do
36
19
  engine.parse defn("A:",
37
- " a = MIN(1, 2, -3, 4)",
20
+ " a = [1, 2, -3, 4].min()",
38
21
  )
39
22
 
40
23
  r = engine.evaluate("A", "a")
41
24
  r.should == -3
42
25
  end
43
26
 
44
- it "should handle MAXLIST" do
45
- engine.parse defn("A:",
46
- " a = MAXLIST([1, 2, 3])",
47
- )
48
-
49
- engine.evaluate("A", "a").should == 3
50
- end
51
-
52
- it "should handle MINLIST" do
53
- engine.parse defn("A:",
54
- " a = MINLIST([1, 10, -3])",
55
- )
56
-
57
- engine.evaluate("A", "a").should == -3
58
- end
59
-
60
27
  it "should handle ROUND" do
61
28
  engine.parse defn("A:",
62
- " a = ROUND(12.3456, 2)",
63
- " b = ROUND(12.3456, 1)",
64
- " c = ROUND(12.3456)",
29
+ " a = 12.3456.round(2)",
30
+ " b = 12.3456.round(1)",
31
+ " c = 12.3456.round()",
65
32
  )
66
33
 
67
34
  r = engine.evaluate_attrs("A", ["a", "b", "c"])
@@ -70,9 +37,9 @@ describe "Delorean" do
70
37
 
71
38
  it "should handle NUMBER" do
72
39
  engine.parse defn("A:",
73
- " a = NUMBER(12.3456)",
74
- " b = NUMBER('12.3456')",
75
- " c = NUMBER('12')",
40
+ " a = 12.3456.to_f()",
41
+ " b = '12.3456'.to_f()",
42
+ " c = '12'.to_f()",
76
43
  )
77
44
 
78
45
  r = engine.evaluate_attrs("A", ["a", "b", "c"])
@@ -81,10 +48,10 @@ describe "Delorean" do
81
48
 
82
49
  it "should handle ABS" do
83
50
  engine.parse defn("A:",
84
- " a = ABS(-123)",
85
- " b = ABS(-1.1)",
86
- " c = ABS(2.3)",
87
- " d = ABS(0)",
51
+ " a = (-123).abs()",
52
+ " b = (-1.1).abs()",
53
+ " c = 2.3.abs()",
54
+ " d = 0.abs()",
88
55
  )
89
56
 
90
57
  r = engine.evaluate_attrs("A", ["a", "b", "c", "d"])
@@ -93,9 +60,9 @@ describe "Delorean" do
93
60
 
94
61
  it "should handle STRING" do
95
62
  engine.parse defn("A:",
96
- " a = STRING('hello')",
97
- " b = STRING(12.3456)",
98
- " c = STRING([1,2,3])",
63
+ " a = 'hello'.to_s()",
64
+ " b = 12.3456.to_s()",
65
+ " c = [1,2,3].to_s()",
99
66
  )
100
67
 
101
68
  r = engine.evaluate_attrs("A", ["a", "b", "c"])
@@ -105,21 +72,16 @@ describe "Delorean" do
105
72
  it "should handle TIMEPART" do
106
73
  engine.parse defn("A:",
107
74
  " p =?",
108
- " p2 =?",
109
- " h = TIMEPART(p, 'h')",
110
- " m = TIMEPART(p, 'm')",
111
- " s = TIMEPART(p, 's')",
112
- " d = TIMEPART(p, 'd')",
113
- " d2 = TIMEPART(p2, 'd')",
114
- " h2 = TIMEPART(p2, 'h')",
75
+ " h = p.hour()",
76
+ " m = p.min()",
77
+ " s = p.sec()",
78
+ " d = p.to_date()",
115
79
  )
116
80
 
117
81
  p = Time.now
118
- params = {"p" => p, "p2" => Float::INFINITY}
119
- r = engine.evaluate_attrs("A", %w{h m s d d2}, params)
120
- r.should == [p.hour, p.min, p.sec, p.to_date, Float::INFINITY]
121
-
122
- expect { engine.evaluate_attrs("A", ["h2"], params) }.to raise_error
82
+ params = {"p" => p}
83
+ r = engine.evaluate_attrs("A", %w{h m s d}, params)
84
+ r.should == [p.hour, p.min, p.sec, p.to_date]
123
85
 
124
86
  # Non time argument should raise an error
125
87
  expect { engine.evaluate_attrs("A", ["m"], {"p" => 123}) }.to raise_error
@@ -129,9 +91,9 @@ describe "Delorean" do
129
91
  it "should handle DATEPART" do
130
92
  engine.parse defn("A:",
131
93
  " p =?",
132
- " y = DATEPART(p, 'y')",
133
- " d = DATEPART(p, 'd')",
134
- " m = DATEPART(p, 'm')",
94
+ " y = p.year()",
95
+ " d = p.day()",
96
+ " m = p.month()",
135
97
  )
136
98
 
137
99
  p = Date.today
@@ -140,45 +102,6 @@ describe "Delorean" do
140
102
 
141
103
  # Non date argument should raise an error
142
104
  expect { engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => 123}) }.to raise_error
143
- # Invalid part argument should raise an error
144
- engine.reset
145
- engine.parse defn("A:",
146
- " p =?",
147
- " x = DATEPART(p, 'x')",
148
- )
149
- expect { engine.evaluate_attrs("A", ["x"], {"p" => p}) }.to raise_error
150
- end
151
-
152
- it "should handle DATEADD" do
153
- engine.parse defn("A:",
154
- " p =?",
155
- " y = DATEADD(p, 1, 'y')",
156
- " d = DATEADD(p, 30, 'd')",
157
- " m = DATEADD(p, 2, 'm')",
158
- )
159
-
160
- p = Date.today
161
- r = engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => p})
162
- r.should == [p + 1.years, p + 30.days, p + 2.months]
163
-
164
- # Non date argument should raise an error
165
- expect { engine.evaluate_attrs("A", ["y", "d", "m"], {"p" => 123}) }.to raise_error
166
-
167
- # Invalid interval argument should raise an error
168
- engine.reset
169
- engine.parse defn("A:",
170
- " p =?",
171
- " m = DATEADD(p, 1.3, 'm')",
172
- )
173
- expect { engine.evaluate_attrs("A", ["m"], {"p" => p}) }.to raise_error
174
-
175
- # Invalid part argument should raise an error
176
- engine.reset
177
- engine.parse defn("A:",
178
- " p =?",
179
- " x = DATEADD(p, 1, 'x')",
180
- )
181
- expect { engine.evaluate_attrs("A", ["x"], {"p" => p}) }.to raise_error
182
105
  end
183
106
 
184
107
  it "should handle FLATTEN" do
@@ -186,7 +109,7 @@ describe "Delorean" do
186
109
 
187
110
  engine.parse defn("A:",
188
111
  " a = #{x}",
189
- " b = FLATTEN(a) + FLATTEN(a, 1)"
112
+ " b = a.flatten() + a.flatten(1)"
190
113
  )
191
114
 
192
115
  engine.evaluate("A", "b").should == x.flatten + x.flatten(1)
@@ -210,14 +133,16 @@ describe "Delorean" do
210
133
 
211
134
  engine.parse defn("A:",
212
135
  " a = #{x}",
213
- " b = RUBY('flatten', a)",
214
- " c = RUBY('flatten', a, 1)",
136
+ " b = a.flatten()",
137
+ " c = a.flatten(1)",
215
138
  " d = b+c",
216
- " dd = RUBY('flatten', d)",
217
- " e = RUBY('sort', dd)",
218
- " f = RUBY('uniq', e)",
219
- " g = RUBY('length', e)",
220
- " gg = RUBY('length', a)",
139
+ " dd = d.flatten()",
140
+ " e = dd.sort()",
141
+ " f = e.uniq()",
142
+ " g = e.length()",
143
+ " gg = a.length()",
144
+ " l = a.member(5)",
145
+ " m = [a.member(5), a.member(55)]",
221
146
  )
222
147
 
223
148
  engine.evaluate("A", "c").should == x.flatten(1)
@@ -227,6 +152,7 @@ describe "Delorean" do
227
152
  engine.evaluate("A", "f").should == dd.sort.uniq
228
153
  engine.evaluate("A", "g").should == dd.length
229
154
  engine.evaluate("A", "gg").should == x.length
155
+ engine.evaluate("A", "m").should == [x.member?(5), x.member?(55)]
230
156
  end
231
157
 
232
158
  it "should handle RUBY slice function" do
@@ -234,7 +160,7 @@ describe "Delorean" do
234
160
 
235
161
  engine.parse defn("A:",
236
162
  " a = #{x}",
237
- " b = RUBY('slice',a,0,4)",
163
+ " b = a.slice(0, 4)",
238
164
  )
239
165
  engine.evaluate("A", "b").should == x.slice(0,4)
240
166
  end
@@ -50,6 +50,13 @@ describe "Delorean" do
50
50
  )
51
51
  end
52
52
 
53
+ it "can parse indexing with getattr" do
54
+ engine.parse defn("A:",
55
+ " a = {'x': [1,2,3]}",
56
+ " b = a.x[1]",
57
+ )
58
+ end
59
+
53
60
  it "should accept default param definitions" do
54
61
  lambda {
55
62
  engine.parse defn("A:",
@@ -290,6 +297,15 @@ describe "Delorean" do
290
297
  }.should_not raise_error
291
298
  end
292
299
 
300
+ it "should parse calls followed by getattr" do
301
+ lambda {
302
+ engine.parse defn("A:",
303
+ " a = -1",
304
+ " b = A().a",
305
+ )
306
+ }.should_not raise_error
307
+ end
308
+
293
309
  it "should be able to chain method calls on model functions" do
294
310
  lambda {
295
311
  engine.parse defn("A:",
@@ -304,6 +320,14 @@ describe "Delorean" do
304
320
  )
305
321
  end
306
322
 
323
+ it "should get exception on arg count to class method call" do
324
+ lambda {
325
+ engine.parse defn("A:",
326
+ ' b = Dummy.i_just_met_you("CRJ")',
327
+ )
328
+ }.should raise_error(Delorean::BadCallError)
329
+ end
330
+
307
331
  it "shouldn't be able to call ActiveRecord methods without signature" do
308
332
  lambda {
309
333
  engine.parse defn("A:",
@@ -328,10 +352,6 @@ describe "Delorean" do
328
352
  )
329
353
  end
330
354
 
331
- it "should raise error on node attr access without all needed params" do
332
- pending
333
- end
334
-
335
355
  it "should be able to access derived attrs" do
336
356
  engine.parse defn("A:",
337
357
  " b =? 22",
@@ -614,15 +634,21 @@ describe "Delorean" do
614
634
  " a = 123",
615
635
  " b = 456 + a",
616
636
  " n = 'A'",
617
- " c = @('a', 'b', x: 123, y: 456)",
618
- " d = @n('a', 'b', x: 123, y: 456)",
637
+ " c = nil(x: 123, y: 456)",
638
+ " d = n(x: 123, y: 456)",
619
639
  )
620
640
  end
621
641
 
622
642
  it "should parse module calls by node name" do
623
643
  engine.parse defn("A:",
624
644
  " a = 123",
625
- " d = @A('a')",
645
+ " d = A()",
646
+ )
647
+ end
648
+
649
+ it "should parse instance calls" do
650
+ engine.parse defn("A:",
651
+ " a = [1,2,[4]].flatten(1)",
626
652
  )
627
653
  end
628
654
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delorean_lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.43
4
+ version: 0.1.00
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-11 00:00:00.000000000 Z
12
+ date: 2013-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: treetop
@@ -96,7 +96,6 @@ files:
96
96
  - lib/delorean/delorean.treetop
97
97
  - lib/delorean/engine.rb
98
98
  - lib/delorean/error.rb
99
- - lib/delorean/functions.rb
100
99
  - lib/delorean/model.rb
101
100
  - lib/delorean/nodes.rb
102
101
  - lib/delorean/version.rb
@@ -1,200 +0,0 @@
1
- module Delorean
2
- module Functions
3
-
4
- ######################################################################
5
-
6
- def MAX(_e, *args)
7
- args.max
8
- end
9
-
10
- MAX_SIG = [ 2, Float::INFINITY ]
11
-
12
- ######################################################################
13
-
14
- def MIN(_e, *args)
15
- args.min
16
- end
17
-
18
- MIN_SIG = MAX_SIG
19
-
20
- ######################################################################
21
-
22
- def MAXLIST(_e, arg)
23
- raise "argument must be list" unless arg.is_a? Array
24
- arg.max
25
- end
26
-
27
- MAXLIST_SIG = [ 1, 1 ]
28
-
29
- ######################################################################
30
-
31
- def MINLIST(_e, arg)
32
- raise "argument must be list" unless arg.is_a? Array
33
- arg.min
34
- end
35
-
36
- MINLIST_SIG = [ 1, 1 ]
37
-
38
- ######################################################################
39
-
40
- def ROUND(_e, number, *args)
41
- number.round(*args)
42
- end
43
-
44
- ROUND_SIG = [ 1, 2 ]
45
-
46
- ######################################################################
47
-
48
- def ABS(_e, n)
49
- raise "#{n} is not a number" unless
50
- n.is_a?(Float) || n.is_a?(Fixnum) || n.is_a?(BigDecimal)
51
- n.abs
52
- end
53
-
54
- ABS_SIG = [ 1, 1 ]
55
-
56
- ######################################################################
57
-
58
- def NUMBER(_e, s)
59
- # FIXME: handle BigDecimal
60
- return s if s.is_a?(Float) || s.is_a?(Fixnum) || s.is_a?(BigDecimal)
61
- raise "Can't convert #{s} to number" unless
62
- s =~ /^\d+(\.\d+)?$/
63
-
64
- s.to_f
65
- end
66
-
67
- NUMBER_SIG = [ 1, 1 ]
68
-
69
- ######################################################################
70
-
71
- def STRING(_e, obj)
72
- obj.to_s
73
- end
74
-
75
- STRING_SIG = [ 1, 1 ]
76
-
77
- ######################################################################
78
-
79
- def TIMEPART(_e, time, part)
80
- if time == Float::INFINITY
81
- return time if part == "d"
82
- raise "Can only access date part of Infinity"
83
- end
84
-
85
- raise "non-time arg to TIMEPART" unless
86
- time.is_a?(DateTime) || time.is_a?(Time)
87
-
88
- case part
89
- when "h" then time.hour
90
- when "m" then time.min
91
- when "s" then time.sec
92
- when "d" then time.to_date
93
- else
94
- raise "unknown part arg to TIMEPART"
95
- end
96
- end
97
-
98
- TIMEPART_SIG = [ 2, 2 ]
99
-
100
- ######################################################################
101
-
102
- def DATEPART(_e, date, part)
103
- raise "non-date arg to DATEPART" unless date.is_a?(Date)
104
-
105
- case part
106
- when "m" then date.month
107
- when "d" then date.day
108
- when "y" then date.year
109
- else
110
- raise "unknown part arg to DATEPART"
111
- end
112
- end
113
-
114
- DATEPART_SIG = [ 2, 2 ]
115
-
116
- ######################################################################
117
-
118
- def DATEADD(_e, date, interval, part)
119
- raise "non-date arg to DATEADD" unless date.is_a?(Date)
120
- raise "non-integer interval arg to DATEADD" unless interval.is_a?(Fixnum)
121
-
122
- case part
123
- when "m" then date >> interval
124
- when "d" then date + interval
125
- when "y" then date >> (interval * 12)
126
- else
127
- raise "unknown part arg to DATEADD"
128
- end
129
- end
130
-
131
- DATEADD_SIG = [ 3, 3 ]
132
-
133
- ######################################################################
134
-
135
- def FLATTEN(_e, array, *args)
136
- raise "non-array arg to FLATTEN" unless array.is_a?(Array)
137
- raise "non-integer flatten on call to FLATTEN" unless
138
- (args.empty? || args[0].is_a?(Fixnum))
139
- array.flatten(*args)
140
- end
141
-
142
- FLATTEN_SIG = [ 1, 2 ]
143
-
144
- ######################################################################
145
-
146
- def ERR(_e, *args)
147
- str = args.map(&:to_s).join(", ")
148
- raise str
149
- end
150
-
151
- ERR_SIG = [ 1, Float::INFINITY ]
152
-
153
- ######################################################################
154
-
155
- RUBY_METHODS = {
156
- sort: [Array],
157
- reverse: [Array],
158
- min: [Array],
159
- max: [Array],
160
- uniq: [Array],
161
- length: [[Array, String]],
162
- flatten: [Array, [Fixnum, nil]],
163
- slice: [Array, Fixnum, Fixnum],
164
- member?: [Array, [Fixnum, String]],
165
- compact: [Array],
166
- split: [String, String],
167
- }
168
-
169
- def RUBY(_e, method, *args)
170
- raise "method must be a string" unless method.class.name=="String"
171
- msg = method.to_sym
172
-
173
- raise "no such method #{method}" unless RUBY_METHODS.member? msg
174
-
175
- sig = RUBY_METHODS[msg]
176
- raise "too many args to #{method}" if args.length>sig.length
177
-
178
- sig.each_with_index { |s, i|
179
- s = [s] unless s.is_a?(Array)
180
-
181
- ok = false
182
- s.each { |sc|
183
- if (sc.nil? && i>=args.length) || (sc && args[i].class <= sc)
184
- ok = true
185
- break
186
- end
187
- }
188
-
189
- raise "bad arg #{i} to method #{method}: #{args[i]}/#{args[i].class}" unless ok
190
- }
191
-
192
- args[0].send(msg, *args[1, args.length])
193
- end
194
-
195
- RUBY_SIG = [ 1, Float::INFINITY ]
196
-
197
- ######################################################################
198
-
199
- end
200
- end