delorean_lang 0.5.4 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afc7142d7683c1fe4d606a86dd7c46eff3ae672b1eb58db13cb587c18b9ea741
4
- data.tar.gz: a522e77939cbcaa4b8592980ced9281179a07e171fe3e34b69adba13661a8215
3
+ metadata.gz: 2c6e040929f0803bd19bee9c0cd459a1a1bdcbdc20e99da3998a2e8c7f0ef1d3
4
+ data.tar.gz: 175ad860916a349b6a7bfe493e17a4e6c18a7eaaf3ce5625e7a71117f49581fa
5
5
  SHA512:
6
- metadata.gz: 03b53dcf912b0311f12151e6fa189e797f767205cd36d6aac6547d58ab6fad6cfbe6905766caae199c15d4898360829a2249379d61634fec98062fc33753b8ae
7
- data.tar.gz: d21c189ed7f03b98cc5c21525a1c031b4a6d43477291744a7016e75f411ca9aad5cafe4c2b87451059036438d5c60d6c14fc9a94fd703be7f902b802dfbe2fe2
6
+ metadata.gz: 51d8f5e885171313517eab09ea2536bfb807aae2fde1e450ccce5ffabf4b3250dfebd84384f32a67856d6eaa00fc8b8c56cd15ec2c9d7b07f7a48e84495e994d
7
+ data.tar.gz: 9896fef50b9852c7347048e5db5d4bb4412a78beb218d46117b0c805e8a9eccc3cb63aada6b9a04abf042d0357ea2e05977b9ab25e8f46acd662ef283c24b44e
data/.rubocop.yml CHANGED
@@ -17,8 +17,7 @@ Style/StringLiterals:
17
17
  Metrics/LineLength:
18
18
  Max: 80
19
19
  Exclude:
20
- - 'spec/func_spec.rb'
21
- - 'spec/parse_spec.rb'
20
+ - 'spec/**/*'
22
21
 
23
22
  Metrics/ModuleLength:
24
23
  Max: 100
@@ -78,3 +77,7 @@ Naming/HeredocDelimiterCase:
78
77
 
79
78
  Naming/RescuedExceptionsVariableName:
80
79
  Enabled: false
80
+
81
+ Metrics/ParameterLists:
82
+ Exclude:
83
+ - 'spec/spec_helper.rb'
data/Gemfile CHANGED
@@ -4,8 +4,3 @@ source 'https://rubygems.org'
4
4
 
5
5
  # Specify your gem's dependencies in delorean.gemspec
6
6
  gemspec
7
-
8
- group :development, :test do
9
- gem 'pry'
10
- gem 'rspec-instafail', require: false
11
- end
data/README.md CHANGED
@@ -172,6 +172,10 @@ There are two ways of calling ruby code from delorean. First one is to whitelist
172
172
  method.called_on Enumerable, with: [Integer]
173
173
  end
174
174
 
175
+ ::Delorean::Ruby.whitelist.add_class_method :last do |method|
176
+ method.called_on ActiveRecord::Base, with: [Integer]
177
+ end
178
+
175
179
  ```
176
180
 
177
181
  By default Delorean has some methods whitelisted, such as `length`, `min`, `max`, etc. Those can be found in `/lib/delorean/ruby/whitelists/default`. If you don't want to use defaults, you can override whitelist with and empty one.
data/delorean.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency 'treetop', '~> 1.5'
22
22
  gem.add_development_dependency 'pry'
23
23
  gem.add_development_dependency 'rspec', '~> 2.1'
24
+ gem.add_development_dependency 'rspec-instafail'
24
25
  gem.add_development_dependency 'rubocop'
25
26
  gem.add_development_dependency 'rubocop-performance'
26
27
  gem.add_development_dependency 'sqlite3', '~> 1.3.10'
data/lib/delorean/base.rb CHANGED
@@ -160,15 +160,16 @@ module Delorean
160
160
  raise "bad method #{method}"
161
161
  end
162
162
 
163
- # FIXME: this is pretty hacky -- should probably merge
164
- # whitelist and SIG mechanisms.
165
163
  if obj.is_a?(Class) || obj.is_a?(Module)
166
- _e[:_engine].parse_check_call_fn(method, args.count, obj)
167
- return obj.send(msg, *args)
164
+ matcher = ::Delorean::Ruby.whitelist.class_method_matcher(
165
+ method_name: msg
166
+ )
167
+ klass = obj
168
+ else
169
+ matcher = ::Delorean::Ruby.whitelist.matcher(method_name: msg)
170
+ klass = obj.class
168
171
  end
169
172
 
170
- matcher = ::Delorean::Ruby.whitelist.matcher(method_name: msg)
171
-
172
173
  raise "no such method #{method}" unless matcher
173
174
 
174
175
  if matcher.match_to?
@@ -177,7 +178,7 @@ module Delorean
177
178
  )
178
179
  end
179
180
 
180
- matcher.match!(klass: obj.class, args: args)
181
+ matcher.match!(klass: klass, args: args)
181
182
 
182
183
  obj.send(msg, *args)
183
184
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delorean
4
- SIG = '_SIG'.freeze
5
- MOD = 'DELOREAN__'.freeze
6
- POST = '__D'.freeze
4
+ MOD = 'DELOREAN__'
5
+ POST = '__D'
7
6
  end
@@ -202,7 +202,7 @@ module Delorean
202
202
  raise exc.new(msg, @module_name, curr_line)
203
203
  end
204
204
 
205
- def parse_check_call_fn(fn, argcount, class_name = nil)
205
+ def parse_check_call_fn(fn, _argcount, class_name = nil)
206
206
  klass = case class_name
207
207
  when nil
208
208
  @m::BaseClass
@@ -214,20 +214,6 @@ module Delorean
214
214
 
215
215
  err(UndefinedFunctionError, "Function #{fn} not found") unless
216
216
  klass.methods.member? fn.to_sym
217
-
218
- # signature methods must be named FUNCTION_NAME_SIG
219
- sig = "#{fn}#{SIG}".upcase.to_sym
220
-
221
- err(UndefinedFunctionError, "Signature #{sig} not found") unless
222
- klass.constants.member? sig
223
-
224
- min, max = klass.const_get(sig)
225
-
226
- err(BadCallError, "Too many args to #{fn} (#{argcount} > #{max})") if
227
- argcount > max
228
-
229
- err(BadCallError, "Too few args to #{fn} (#{argcount} < #{min})") if
230
- argcount < min
231
217
  end
232
218
 
233
219
  def parser
@@ -2,19 +2,14 @@
2
2
 
3
3
  module Delorean
4
4
  module Functions
5
- def delorean_fn(name, options = {})
6
- define_singleton_method(name) do |*args|
7
- yield(*args)
8
- end
9
-
10
- sig = options[:sig]
5
+ def delorean_fn(name, _options = {}, &block)
6
+ any_args = Delorean::Ruby::Whitelists::Matchers::Arguments::ANYTHING
11
7
 
12
- raise 'no signature' unless sig
8
+ define_singleton_method(name, block)
13
9
 
14
- sig = [sig, sig] if sig.is_a? Integer
15
- raise 'Bad signature' unless sig.is_a?(Array) && (sig.length == 2)
16
-
17
- const_set(name.to_s.upcase + Delorean::SIG, sig)
10
+ ::Delorean::Ruby.whitelist.add_class_method name do |method|
11
+ method.called_on self, with: any_args
12
+ end
18
13
  end
19
14
 
20
15
  # FIXME: IDEA: we just make :cache an argument to delorean_fn.
@@ -400,13 +400,13 @@ eos
400
400
  end
401
401
 
402
402
  if vcode.is_a?(ClassText)
403
+ # FIXME: Do we really need this check here?
403
404
  # ruby class call
404
405
  class_name = vcode.text
405
406
  context.parse_check_call_fn(i.text_value, arg_count, class_name)
406
- "#{class_name}.#{i.text_value}(#{args_str})"
407
- else
408
- "_instance_call(#{vcode}, '#{i.text_value}', [#{args_str}], _e)"
409
407
  end
408
+
409
+ "_instance_call(#{vcode}, '#{i.text_value}', [#{args_str}], _e)"
410
410
  end
411
411
  end
412
412
 
@@ -8,6 +8,7 @@ module Delorean
8
8
  module Whitelists
9
9
  class Base
10
10
  attr_reader :matchers
11
+ attr_reader :class_method_matchers
11
12
 
12
13
  def add_method(method_name, match_to: nil, &block)
13
14
  return method_name_error unless method_name.is_a?(Symbol)
@@ -19,19 +20,48 @@ module Delorean
19
20
  )
20
21
  end
21
22
 
23
+ matcher = matchers[method_name.to_sym]
24
+
25
+ return matcher.extend_matcher(&block) if matcher
26
+
22
27
  matchers[method_name.to_sym] = method_matcher_class.new(
23
28
  method_name: method_name, &block
24
29
  )
25
30
  end
26
31
 
32
+ def add_class_method(method_name, match_to: nil, &block)
33
+ return method_name_error unless method_name.is_a?(Symbol)
34
+ return block_and_match_error if !match_to.nil? && block_given?
35
+
36
+ unless match_to.nil?
37
+ return add_class_matched_method(
38
+ method_name: method_name, match_to: match_to
39
+ )
40
+ end
41
+
42
+ matcher = class_method_matchers[method_name.to_sym]
43
+
44
+ return matcher.extend_matcher(&block) if matcher
45
+
46
+ class_method_matchers[method_name.to_sym] = method_matcher_class.new(
47
+ method_name: method_name, &block
48
+ )
49
+ end
50
+
27
51
  def matcher(method_name:)
28
52
  matchers[method_name.to_sym]
29
53
  end
30
54
 
55
+ def class_method_matcher(method_name:)
56
+ class_method_matchers[method_name.to_sym]
57
+ end
58
+
31
59
  private
32
60
 
33
61
  def initialize
34
62
  @matchers = {}
63
+ @class_method_matchers = {}
64
+
35
65
  initialize_hook
36
66
  end
37
67
 
@@ -39,13 +69,24 @@ module Delorean
39
69
  correct_match_to = match_to.is_a?(String) || match_to.is_a?(Symbol)
40
70
  return wrong_match_to_error unless correct_match_to
41
71
 
42
- matcher = ::Delorean::Ruby::Whitelists::Matchers::Method.new(
72
+ matcher = method_matcher_class.new(
43
73
  method_name: method_name, match_to: match_to.to_sym
44
74
  )
45
75
 
46
76
  matchers[method_name.to_sym] = matcher
47
77
  end
48
78
 
79
+ def add_class_matched_method(method_name:, match_to:)
80
+ correct_match_to = match_to.is_a?(String) || match_to.is_a?(Symbol)
81
+ return wrong_match_to_error unless correct_match_to
82
+
83
+ matcher = method_matcher_class.new(
84
+ method_name: method_name, match_to: match_to.to_sym
85
+ )
86
+
87
+ class_method_matchers[method_name.to_sym] = matcher
88
+ end
89
+
49
90
  def block_and_match_error
50
91
  raise(
51
92
  ::Delorean::Ruby::Whitelists::WhitelistError,
@@ -5,6 +5,8 @@ module Delorean
5
5
  module Whitelists
6
6
  module Matchers
7
7
  class Arguments
8
+ ANYTHING = :_delorean_anything
9
+
8
10
  attr_reader :called_on, :method_name, :with
9
11
 
10
12
  def initialize(called_on:, method_name:, with: [])
@@ -14,6 +16,8 @@ module Delorean
14
16
  end
15
17
 
16
18
  def match!(args:)
19
+ return if with == ANYTHING
20
+
17
21
  raise "too many args to #{method_name}" if args.size > with.size
18
22
 
19
23
  with.each_with_index do |s, i|
@@ -23,6 +23,12 @@ module Delorean
23
23
  )
24
24
 
25
25
  arguments_matchers << matcher
26
+
27
+ # Sort matchers by reversed ancestors chain length, so
28
+ # matcher method would find the closest ancestor in hierarchy
29
+ arguments_matchers.sort_by! do |obj|
30
+ -obj.called_on.ancestors.size
31
+ end
26
32
  end
27
33
 
28
34
  def matcher(klass:)
@@ -42,6 +48,10 @@ module Delorean
42
48
  def match_to?
43
49
  !match_to.nil?
44
50
  end
51
+
52
+ def extend_matcher
53
+ yield self if block_given?
54
+ end
45
55
  end
46
56
  end
47
57
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Delorean
4
- VERSION = '0.5.4'.freeze
4
+ VERSION = '0.6.0'
5
5
  end
data/spec/eval_spec.rb CHANGED
@@ -371,6 +371,83 @@ eoc
371
371
  r.should == 867 + 5309
372
372
  end
373
373
 
374
+ it 'should be able call method defined in a parent or matched to' do
375
+ engine.parse defn(
376
+ 'A:',
377
+ ' b = DeloreanFunctionsChildClass.test_fn',
378
+ ' c = DeloreanFunctionsChildClass.test_fn2',
379
+ ' d = DifferentClassSameMethod.test_fn2',
380
+ ' e = DifferentClassSameMethod.match_to_test_fn2',
381
+ )
382
+
383
+ r = engine.evaluate('A', 'b')
384
+ r.should == :test_fn_result
385
+
386
+ r = engine.evaluate('A', 'c')
387
+ r.should == :test_fn2_result
388
+
389
+ r = engine.evaluate('A', 'd')
390
+ r.should == :test_fn2_result_different
391
+
392
+ r = engine.evaluate('A', 'e')
393
+ r.should == :test_fn2_result_different
394
+ end
395
+
396
+ it 'should raise exception if method is not whitelisted' do
397
+ engine.parse defn(
398
+ 'A:',
399
+ ' a = DeloreanFunctionsChildClass.test_fn4',
400
+ ' b = DeloreanFunctionsChildClass.test_fn4()',
401
+ ' c = Dummy.this_is_crazy()',
402
+ )
403
+
404
+ lambda {
405
+ engine.evaluate('A', 'a')
406
+ }.should raise_error(
407
+ Delorean::InvalidGetAttribute,
408
+ "attr lookup failed: 'test_fn4' on <Class> DeloreanFunctionsChildClass - no such method test_fn4"
409
+ )
410
+
411
+ lambda {
412
+ engine.evaluate('A', 'b')
413
+ }.should raise_error(RuntimeError, 'no such method test_fn4')
414
+
415
+ lambda {
416
+ engine.evaluate('A', 'c')
417
+ }.should raise_error(RuntimeError, 'no such method this_is_crazy')
418
+ end
419
+
420
+ it 'should raise exception if required arguments are missing' do
421
+ engine.parse defn(
422
+ 'A:',
423
+ ' a = DifferentClassSameMethod.test_fn3(1, 2, 3, 4, 5,
424
+ 6, 7, 8, 9, 10)',
425
+ ' b = DifferentClassSameMethod.test_fn3(1, 2, 3, 4) ',
426
+ ' c = DifferentClassSameMethod.test_fn3(1, 2) ',
427
+ ' d = DifferentClassSameMethod.test_fn3() ',
428
+ )
429
+
430
+ r = engine.evaluate('A', 'a')
431
+ r.should == { a: 1, b: 2, c: 3, d: 4, e: 5, rest: [6, 7, 8, 9, 10] }
432
+
433
+ r = engine.evaluate('A', 'b')
434
+ r.should == { a: 1, b: 2, c: 3, d: 4, e: nil, rest: [] }
435
+
436
+ lambda {
437
+ r = engine.evaluate('A', 'c')
438
+ }.should raise_error(
439
+ ArgumentError,
440
+ 'wrong number of arguments (given 2, expected 3+)'
441
+ )
442
+
443
+ lambda {
444
+ r = engine.evaluate('A', 'd')
445
+ }.should raise_error(
446
+ ArgumentError,
447
+ 'wrong number of arguments (given 0, expected 3+)'
448
+ )
449
+ end
450
+
374
451
  it 'should ignore undeclared params sent to eval which match attr names' do
375
452
  engine.parse defn('A:',
376
453
  ' d = 12',
data/spec/parse_spec.rb CHANGED
@@ -393,21 +393,21 @@ describe 'Delorean' do
393
393
  )
394
394
  end
395
395
 
396
- it 'should get exception on arg count to class method call' do
397
- lambda {
398
- engine.parse defn('A:',
399
- ' b = Dummy.i_just_met_you(1, 2, 3)',
400
- )
401
- }.should raise_error(Delorean::BadCallError)
402
- end
403
-
404
- it "shouldn't be able to call ActiveRecord methods without signature" do
405
- lambda {
406
- engine.parse defn('A:',
407
- ' b = Dummy.this_is_crazy()',
408
- )
409
- }.should raise_error(Delorean::UndefinedFunctionError)
410
- end
396
+ # it 'should get exception on arg count to class method call' do
397
+ # lambda {
398
+ # engine.parse defn('A:',
399
+ # ' b = Dummy.i_just_met_you(1, 2, 3)',
400
+ # )
401
+ # }.should raise_error(Delorean::BadCallError)
402
+ # end
403
+ #
404
+ # it "shouldn't be able to call ActiveRecord methods without signature" do
405
+ # lambda {
406
+ # engine.parse defn('A:',
407
+ # ' b = Dummy.this_is_crazy()',
408
+ # )
409
+ # }.should raise_error(Delorean::UndefinedFunctionError)
410
+ # end
411
411
 
412
412
  it 'should be able to call class methods on ActiveRecord classes in modules' do
413
413
  engine.parse defn('A:',
@@ -5,11 +5,14 @@ require 'delorean/ruby/whitelists/empty'
5
5
 
6
6
  describe 'Delorean Ruby whitelisting' do
7
7
  it 'allows to override whitelist with an empty one' do
8
+ old_whitelist = ::Delorean::Ruby.whitelist
8
9
  ::Delorean::Ruby.whitelist = whitelist
9
10
  expect(whitelist.matchers).to be_empty
10
11
 
11
12
  ::Delorean::Ruby.whitelist = ::Delorean::Ruby::Whitelists::Default.new
12
13
  expect(::Delorean::Ruby.whitelist.matchers).to_not be_empty
14
+
15
+ ::Delorean::Ruby.whitelist = old_whitelist
13
16
  end
14
17
 
15
18
  let(:whitelist) { ::Delorean::Ruby::Whitelists::Empty.new }
@@ -76,4 +79,108 @@ describe 'Delorean Ruby whitelisting' do
76
79
  expect(matcher.match_to?).to be true
77
80
  end
78
81
  end
82
+
83
+ describe 'class_methods' do
84
+ let(:method_matcher) do
85
+ Delorean::Ruby.whitelist.class_method_matcher(method_name: :test_method)
86
+ end
87
+
88
+ let(:engine) do
89
+ engine = Delorean::Engine.new 'XXX'
90
+
91
+ engine.parse defn(
92
+ 'A:',
93
+ ' a = RootClass.test_method(1)',
94
+ ' b = RootClass.test_method(true)',
95
+ ' c = RootClassChild.test_method("test")',
96
+ ' d = RootClassChild.test_method(1)',
97
+ ' e = RootClassChildsChild.test_method(true)',
98
+ ' f = RootClassChildsChild.test_method(1)',
99
+ ' g = RootClassChildsChildsChild.test_method(true)',
100
+ ' h = RootClassChildsChildsChild.test_method(1)',
101
+ ' i = RootClassChildsChildsChild.test_method()',
102
+ ' j = RootClassChildsChildsChild.test_method',
103
+ ' k = RootClassChildsChildsChild.test_method(true, true)',
104
+ ' l = RootClassChildsChildsChild.test_method2(true)'
105
+ )
106
+
107
+ engine
108
+ end
109
+
110
+ it 'fetches the closest method matcher in class hierarchy' do
111
+ arg_matcher = method_matcher.matcher(klass: RootClass)
112
+ expect(arg_matcher.with).to eq [Integer]
113
+
114
+ arg_matcher = method_matcher.matcher(klass: RootClassChild)
115
+ expect(arg_matcher.with).to eq [String]
116
+
117
+ arg_matcher = method_matcher.matcher(klass: RootClassChildsChild)
118
+ expect(arg_matcher.with).to eq [TrueClass]
119
+
120
+ arg_matcher = method_matcher.matcher(klass: RootClassChildsChildsChild)
121
+ expect(arg_matcher.with).to eq [TrueClass]
122
+ end
123
+
124
+ it 'allows to call methods correctly' do
125
+ r = engine.evaluate('A', 'a')
126
+ expect(r).to eq :test_method_with_int_arg
127
+
128
+ r = engine.evaluate('A', 'c')
129
+ expect(r).to eq :test_method_with_str_arg
130
+
131
+ r = engine.evaluate('A', 'e')
132
+ expect(r).to eq :test_method_with_true_arg
133
+
134
+ r = engine.evaluate('A', 'g')
135
+ expect(r).to eq :test_method_with_true_arg
136
+ end
137
+
138
+ it 'raises exception if argument type mismatched' do
139
+ expect { engine.evaluate('A', 'b') }.to raise_error(
140
+ RuntimeError,
141
+ 'bad arg 0, method test_method: true/TrueClass [Integer]'
142
+ )
143
+
144
+ expect { engine.evaluate('A', 'd') }.to raise_error(
145
+ RuntimeError,
146
+ 'bad arg 0, method test_method: 1/Integer [String]'
147
+ )
148
+
149
+ expect { engine.evaluate('A', 'f') }.to raise_error(
150
+ RuntimeError,
151
+ 'bad arg 0, method test_method: 1/Integer [TrueClass]'
152
+ )
153
+
154
+ expect { engine.evaluate('A', 'h') }.to raise_error(
155
+ RuntimeError,
156
+ 'bad arg 0, method test_method: 1/Integer [TrueClass]'
157
+ )
158
+ end
159
+
160
+ it 'raises exception if argument is not present' do
161
+ expect { engine.evaluate('A', 'i') }.to raise_error(
162
+ RuntimeError,
163
+ 'bad arg 0, method test_method: /NilClass [TrueClass]'
164
+ )
165
+
166
+ expect { engine.evaluate('A', 'j') }.to raise_error(
167
+ Delorean::InvalidGetAttribute,
168
+ "attr lookup failed: 'test_method' on <Class> RootClassChildsChildsChild - bad arg 0, method test_method: /NilClass [TrueClass]"
169
+ )
170
+ end
171
+
172
+ it 'raises exception if too many arguments' do
173
+ expect { engine.evaluate('A', 'k') }.to raise_error(
174
+ RuntimeError,
175
+ 'too many args to test_method'
176
+ )
177
+ end
178
+
179
+ it 'raises exception method is not whitelisted' do
180
+ expect { engine.evaluate('A', 'l') }.to raise_error(
181
+ RuntimeError,
182
+ 'no such method test_method2'
183
+ )
184
+ end
185
+ end
79
186
  end
data/spec/spec_helper.rb CHANGED
@@ -3,10 +3,10 @@
3
3
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
4
  $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
 
6
+ require 'pry'
6
7
  require 'rspec'
7
8
  require 'delorean_lang'
8
9
  require 'active_record'
9
- require 'pry'
10
10
 
11
11
  # Requires supporting files with custom matchers and macros, etc,
12
12
  # in ./support/ and its subdirectories.
@@ -36,18 +36,14 @@ class Dummy < ActiveRecord::Base
36
36
 
37
37
  belongs_to :dummy
38
38
 
39
- def self.i_just_met_you(name, number)
39
+ delorean_fn :i_just_met_you do |name, number|
40
40
  Dummy.new(name: name, number: number)
41
41
  end
42
42
 
43
- I_JUST_MET_YOU_SIG = [1, 2].freeze
44
-
45
- def self.call_me_maybe(*a)
43
+ delorean_fn :call_me_maybe do |*a|
46
44
  a.inject(0, :+)
47
45
  end
48
46
 
49
- CALL_ME_MAYBE_SIG = [0, Float::INFINITY].freeze
50
-
51
47
  def self.this_is_crazy; end
52
48
 
53
49
  def self.miss_you_so_bad
@@ -55,18 +51,14 @@ class Dummy < ActiveRecord::Base
55
51
  Dummy.new(name: 'jello', number: 456, dummy: d)
56
52
  end
57
53
 
58
- MISS_YOU_SO_BAD_SIG = [0, 0].freeze
59
-
60
54
  delorean_fn :all_of_me, sig: 0 do
61
55
  [{ 'name' => 'hello', 'foo' => 'bar' }]
62
56
  end
63
57
 
64
- def self.i_threw_a_hash_in_the_well
58
+ delorean_fn :i_threw_a_hash_in_the_well do
65
59
  { a: 123, 'a' => 456, b: 789 }
66
60
  end
67
61
 
68
- I_THREW_A_HASH_IN_THE_WELL_SIG = [0, 0].freeze
69
-
70
62
  def name2
71
63
  "#{name}-#{number.round(4)}"
72
64
  end
@@ -96,7 +88,6 @@ class DummyChild < Dummy
96
88
  def self.hello
97
89
  DummyChild.new(name: 'child', number: 99_999)
98
90
  end
99
- HELLO_SIG = [0, 0].freeze
100
91
  end
101
92
 
102
93
  module M
@@ -106,10 +97,10 @@ module M
106
97
  delorean_fn(:heres_my_number, sig: [0, Float::INFINITY]) do |*a|
107
98
  a.inject(0, :+)
108
99
  end
100
+
109
101
  def self.sup
110
102
  LittleDummy.new
111
103
  end
112
- SUP_SIG = [0, 0].freeze
113
104
  end
114
105
 
115
106
  module N
@@ -134,6 +125,80 @@ module M
134
125
  DummyModule = ::DummyModule
135
126
  end
136
127
 
128
+ class DeloreanFunctionsClass
129
+ extend Delorean::Functions
130
+
131
+ delorean_fn :test_fn, sig: 0 do
132
+ :test_fn_result
133
+ end
134
+ end
135
+
136
+ class DeloreanFunctionsChildClass < DeloreanFunctionsClass
137
+ delorean_fn :test_fn2, sig: 0 do
138
+ :test_fn2_result
139
+ end
140
+
141
+ def self.test_fn4; end
142
+ end
143
+
144
+ class DifferentClassSameMethod
145
+ extend Delorean::Functions
146
+
147
+ delorean_fn :test_fn2, sig: 0 do
148
+ :test_fn2_result_different
149
+ end
150
+
151
+ delorean_fn :test_fn3, sig: 0 do |a, b, c, d = :default, e = nil, *args|
152
+ {
153
+ a: a,
154
+ b: b,
155
+ c: c,
156
+ d: d,
157
+ e: e,
158
+ rest: args
159
+ }
160
+ end
161
+ end
162
+
163
+ class RootClass
164
+ def self.test_method(_int_arg)
165
+ :test_method_with_int_arg
166
+ end
167
+ end
168
+
169
+ Delorean::Ruby.whitelist.add_class_method :test_method do |method|
170
+ method.called_on RootClass, with: [Integer]
171
+ end
172
+
173
+ class RootClassChild < RootClass
174
+ def self.test_method(_str_arg)
175
+ :test_method_with_str_arg
176
+ end
177
+ end
178
+
179
+ Delorean::Ruby.whitelist.add_class_method :test_method do |method|
180
+ method.called_on RootClassChild, with: [String]
181
+ end
182
+
183
+ class RootClassChildsChild < RootClassChild
184
+ def self.test_method(_true_arg)
185
+ :test_method_with_true_arg
186
+ end
187
+ end
188
+
189
+ Delorean::Ruby.whitelist.add_class_method :test_method do |method|
190
+ method.called_on RootClassChildsChild, with: [TrueClass]
191
+ end
192
+
193
+ class RootClassChildsChildsChild < RootClassChildsChild
194
+ def self.test_method2(bool_arg); end
195
+ end
196
+
197
+ Delorean::Ruby.whitelist.add_class_method(
198
+ :match_to_test_fn2,
199
+ match_to: :test_fn2
200
+ )
201
+
137
202
  ######################################################################
138
203
 
139
204
  class TestContainer < Delorean::AbstractContainer
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delorean_lang
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.4
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arman Bostani
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-05-08 00:00:00.000000000 Z
11
+ date: 2019-05-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-instafail
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rubocop
71
85
  requirement: !ruby/object:Gem::Requirement