loverload 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -137,8 +137,58 @@ dummy.before_save(proc{|this| is proc}) #=> "Puke rainbow and leprechaun"
137
137
  dummy.before_save('string') #=> "Puke rainbow, leprechaun, and gold"
138
138
  ```
139
139
 
140
+ It also support __functor__ 'guard' arguments
141
+ ``` ruby
142
+ class Dummy
143
+ include Loverload
144
+
145
+ def_overload :hello do
146
+ with_params ->(num){ num.odd? } do |num|
147
+ "Odd"
148
+ end
149
+
150
+ with_params ->(num){ num.even? } do |num|
151
+ "Even"
152
+ end
153
+ end
154
+ end
155
+
156
+ dummy = Dummy.new
157
+ dummy.hello(1) #=> 'Odd'
158
+ dummy.hello(2) #=> 'Even'
159
+ dummy.hello(100) #> 'Even'
160
+ ```
161
+
162
+ It also support __functor__ fibonnaci with recursive method, but kinda reversed on method definition.
163
+ ``` ruby
164
+ class Dummy
165
+ include Loverload
166
+
167
+ def_overload :fibonnaci do
168
+ with_params 1 do |n|
169
+ 1
170
+ end
171
+
172
+ with_params 0 do |n|
173
+ 0
174
+ end
175
+
176
+ with_params Integer do |n|
177
+ fibonnaci(n - 1) + fibonnaci(n - 2)
178
+ end
179
+ end
180
+ end
181
+
182
+ dummy = Dummy.new
183
+
184
+ [*0..10].map(&dummy.method(:fibonnaci)) #=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
185
+ ```
186
+
140
187
  ## TODO
141
- - Make it less ugly
188
+ - Cache?
189
+
190
+ ## NOTES
191
+ Couple weeks ago, while searching for the same library, I found yanked gem called [overload](http://rubygems.org/gems/overload) from 2009, it's such an coincidence that we used similar implementation, inside it's readme, the author mentioned [functor](https://github.com/waves/functor), similar gem with different approach. Then I decided to change __loverload__ implementation using __functor__ approach, an simple but expensive approach.
142
192
 
143
193
  ## Contributing
144
194
 
@@ -1,49 +1,40 @@
1
1
  module Loverload
2
2
  class Method
3
3
  def initialize klass, method_name, &with_params_block
4
- @klass = klass
5
- @method_name = method_name
4
+ @klass, @method_name = klass, method_name
5
+ @klass.instance_variable_set :@__dictionary__, {} unless
6
+ @klass.instance_variable_defined? :@__dictionary__
7
+
6
8
  instance_eval(&with_params_block)
7
9
  end
8
10
 
9
11
  def with_params *pars, &block
10
- default = "__#{ @method_name }_#{ block.arity }"
11
- method_name = "__name_#{ default }_#{ type_signature(pars) }"
12
- method_alias = "__alias_#{ default }_#{ alias_signature(pars) }"
13
-
14
- @klass.define_method method_name do |*args|
15
- instance_exec(*args, &block)
16
- end
17
-
18
- @klass.send :alias_method, method_alias, method_name
19
- @klass.send :alias_method, default, method_name
20
-
21
- [default, method_name, method_alias].each{ |m| @klass.send :private, m }
12
+ dictionary[method_signature(block.arity, *pars)] = block
22
13
  end
23
14
 
24
15
  def overload instance, *args
25
- default = "__#{ @method_name }_#{ args.size }"
26
- method_name = "__name_#{ default }_#{ type_signature(args.map(&:class)) }"
27
- method_alias = "__alias_#{ default }_#{ alias_signature(args.map(&:class)) }"
28
-
29
- if instance.respond_to? method_name, true
30
- instance.send method_name, *args
31
- elsif instance.respond_to? method_alias, true
32
- instance.send method_alias, *args
33
- elsif instance.respond_to? default, true
34
- instance.send default, *args
35
- else
36
- raise NoMethodError, "Undefined method '#{ @method_name }' for #{ type_signature(args.map(&:class)) }"
37
- end
16
+ instance.instance_exec *args, &find(*args)
38
17
  end
39
18
 
40
19
  private
41
- def type_signature array_of_class
42
- array_of_class.to_s.gsub(/[\[\]]/, '')
20
+ def find *args
21
+ dictionary.find do |signature, _|
22
+ match? signature, method_signature(args.size, *args)
23
+ end.tap{ |arr| raise NoMethodError unless arr }.last
24
+ end
25
+
26
+ def match? signature, args
27
+ signature.zip(args).all? do |type, arg|
28
+ type === arg
29
+ end
30
+ end
31
+
32
+ def dictionary
33
+ @klass.instance_variable_get(:@__dictionary__)
43
34
  end
44
35
 
45
- def alias_signature array_of_class
46
- 'Object' * array_of_class.size
36
+ def method_signature size, *meta
37
+ [*@method_name, size, *meta]
47
38
  end
48
39
  end
49
40
  end
@@ -1,3 +1,3 @@
1
1
  module Loverload
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/loverload.rb CHANGED
@@ -2,16 +2,26 @@ require "loverload/version"
2
2
  require "loverload/method"
3
3
 
4
4
  module Loverload
5
+ NULL = Object.new
6
+
5
7
  def self.included(base)
6
8
  base.extend(ClassMethods)
7
9
  end
8
10
 
9
11
  module ClassMethods
10
- def def_overload method_name, &with_params_block
11
- method = Method.new(self, method_name, &with_params_block)
12
+ def def_overload method_name_or_class, method_name = NULL, &with_params_block
13
+ if method_name_or_class.is_a?(Class) && method_name != NULL
14
+ method = Method.new(method_name_or_class, method_name, &with_params_block)
15
+
16
+ define_singleton_method method_name do |*args|
17
+ method.overload(method_name_or_class, *args)
18
+ end
19
+ else
20
+ method = Method.new(self, method_name_or_class, &with_params_block)
12
21
 
13
- define_method method_name do |*args|
14
- method.overload(self, *args)
22
+ define_method method_name_or_class do |*args|
23
+ method.overload(self, *args)
24
+ end
15
25
  end
16
26
  end
17
27
  end
@@ -1,6 +1,8 @@
1
1
  require 'loverload'
2
2
 
3
3
  describe Loverload do
4
+ after { Dummy.send :remove_instance_variable, :@__dictionary__ }
5
+
4
6
  it "makes your code more magical" do
5
7
  class Dummy
6
8
  include Loverload
@@ -26,6 +28,22 @@ describe Loverload do
26
28
  dummy.hello('Teja', 21).should eql 'Hello Teja Age 21'
27
29
  end
28
30
 
31
+ it "raise no method error" do
32
+ class Dummy
33
+ include Loverload
34
+
35
+ def_overload :hello do
36
+ with_params Fixnum do |n|
37
+ "Hello"
38
+ end
39
+ end
40
+ end
41
+
42
+ dummy = Dummy.new
43
+ dummy.hello(1).should eql 'Hello'
44
+ expect{ dummy.hello('Teja') }.to raise_error
45
+ end
46
+
29
47
  it "makes your code even more magical" do
30
48
  class Dummy
31
49
  include Loverload
@@ -165,4 +183,169 @@ describe Loverload do
165
183
  dummy.method_2.should eql 'method_2'
166
184
  dummy.method_2(1).should eql 'method_2 with arg'
167
185
  end
186
+
187
+ it "can overload class methods" do
188
+ class Dummy
189
+ include Loverload
190
+
191
+ def_overload self, :hello do
192
+ with_params do
193
+ "Hello Nobody"
194
+ end
195
+
196
+ with_params do |name|
197
+ "Hello #{ name }"
198
+ end
199
+
200
+ with_params do |name, age|
201
+ "Hello #{ name } Age #{ age }"
202
+ end
203
+ end
204
+ end
205
+
206
+ Dummy.hello.should eql 'Hello Nobody'
207
+ Dummy.hello('Teja').should eql 'Hello Teja'
208
+ Dummy.hello('Teja', 21).should eql 'Hello Teja Age 21'
209
+ end
210
+
211
+ it "can call another class methods" do
212
+ class Dummy
213
+ include Loverload
214
+
215
+ def self.hello_nobody
216
+ "Hello Nobody"
217
+ end
218
+
219
+ def_overload self, :hello do
220
+ with_params do
221
+ hello_nobody
222
+ end
223
+ end
224
+ end
225
+
226
+ Dummy.hello.should eql 'Hello Nobody'
227
+ end
228
+
229
+ it "can use immediate value" do
230
+ class Dummy
231
+ include Loverload
232
+
233
+ def_overload :hello do
234
+ with_params 1 do |num|
235
+ "One"
236
+ end
237
+
238
+ with_params 2 do |num|
239
+ "Two"
240
+ end
241
+ end
242
+ end
243
+
244
+ dummy = Dummy.new
245
+ dummy.hello(1).should eql 'One'
246
+ dummy.hello(2).should eql 'Two'
247
+ end
248
+
249
+ it "works with inheritance" do
250
+ class Dummy
251
+ include Loverload
252
+
253
+ def_overload :hello do
254
+ with_params 1 do |num|
255
+ "One"
256
+ end
257
+
258
+ with_params 2 do |num|
259
+ "Two"
260
+ end
261
+ end
262
+ end
263
+
264
+ class Dummy2 < Dummy
265
+ end
266
+
267
+ dummy = Dummy2.new
268
+ dummy.hello(1).should eql 'One'
269
+ dummy.hello(2).should eql 'Two'
270
+ end
271
+
272
+ it "works with inheritance and overrides" do
273
+ class Dummy
274
+ include Loverload
275
+
276
+ def_overload :hello do
277
+ with_params 1 do |num|
278
+ "One"
279
+ end
280
+
281
+ with_params 2 do |num|
282
+ "Two"
283
+ end
284
+ end
285
+ end
286
+
287
+ class Dummy2 < Dummy
288
+ def_overload :hello do
289
+ with_params 1 do |num|
290
+ "1"
291
+ end
292
+
293
+ with_params 2 do |num|
294
+ "2"
295
+ end
296
+ end
297
+ end
298
+
299
+ dummy = Dummy2.new
300
+ dummy.hello(1).should eql '1'
301
+ dummy.hello(2).should eql '2'
302
+ end
303
+
304
+ it "has `guard` signature method like functor" do
305
+ class Dummy
306
+ include Loverload
307
+
308
+ def_overload :hello do
309
+ with_params ->(num){ num.odd? } do |num|
310
+ "Odd"
311
+ end
312
+
313
+ with_params ->(num){ num.even? } do |num|
314
+ "Even"
315
+ end
316
+ end
317
+ end
318
+
319
+ dummy = Dummy.new
320
+ dummy.hello(1).should eql 'Odd'
321
+ dummy.hello(2).should eql 'Even'
322
+ dummy.hello(100).should eql 'Even'
323
+ end
324
+
325
+ it "can do fibonnaci like functor" do
326
+ # f.given( Integer ) { | n | f.call( n - 1 ) + f.call( n - 2 ) }
327
+ # f.given( 0 ) { |x| 0 }
328
+ # f.given( 1 ) { |x| 1 }
329
+
330
+ class Dummy
331
+ include Loverload
332
+
333
+ def_overload :fibonnaci do
334
+ with_params 1 do |n|
335
+ 1
336
+ end
337
+
338
+ with_params 0 do |n|
339
+ 0
340
+ end
341
+
342
+ with_params Integer do |n|
343
+ fibonnaci(n - 1) + fibonnaci(n - 2)
344
+ end
345
+ end
346
+ end
347
+
348
+ dummy = Dummy.new
349
+ [*0..10].map(&dummy.method(:fibonnaci)).should eql [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
350
+ end
168
351
  end
metadata CHANGED
@@ -2,79 +2,79 @@
2
2
  name: loverload
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.1
5
+ version: 0.1.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Teja Sophista V.R.
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-25 00:00:00.000000000 Z
12
+ date: 2013-07-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  prerelease: false
16
- type: :development
17
16
  name: bundler
17
+ type: :development
18
18
  version_requirements: !ruby/object:Gem::Requirement
19
- none: false
20
19
  requirements:
21
20
  - - ~>
22
21
  - !ruby/object:Gem::Version
23
22
  version: '1.3'
24
- requirement: !ruby/object:Gem::Requirement
25
23
  none: false
24
+ requirement: !ruby/object:Gem::Requirement
26
25
  requirements:
27
26
  - - ~>
28
27
  - !ruby/object:Gem::Version
29
28
  version: '1.3'
29
+ none: false
30
30
  - !ruby/object:Gem::Dependency
31
31
  prerelease: false
32
- type: :development
33
32
  name: rake
33
+ type: :development
34
34
  version_requirements: !ruby/object:Gem::Requirement
35
- none: false
36
35
  requirements:
37
36
  - - ! '>='
38
37
  - !ruby/object:Gem::Version
39
38
  version: '0'
40
- requirement: !ruby/object:Gem::Requirement
41
39
  none: false
40
+ requirement: !ruby/object:Gem::Requirement
42
41
  requirements:
43
42
  - - ! '>='
44
43
  - !ruby/object:Gem::Version
45
44
  version: '0'
45
+ none: false
46
46
  - !ruby/object:Gem::Dependency
47
47
  prerelease: false
48
- type: :development
49
48
  name: rspec
49
+ type: :development
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
- none: false
52
51
  requirements:
53
52
  - - ! '>='
54
53
  - !ruby/object:Gem::Version
55
54
  version: '0'
56
- requirement: !ruby/object:Gem::Requirement
57
55
  none: false
56
+ requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
58
  - - ! '>='
60
59
  - !ruby/object:Gem::Version
61
60
  version: '0'
61
+ none: false
62
62
  - !ruby/object:Gem::Dependency
63
63
  prerelease: false
64
- type: :development
65
64
  name: debugger
65
+ type: :development
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
- none: false
68
67
  requirements:
69
68
  - - ! '>='
70
69
  - !ruby/object:Gem::Version
71
70
  version: '0'
72
- requirement: !ruby/object:Gem::Requirement
73
71
  none: false
72
+ requirement: !ruby/object:Gem::Requirement
74
73
  requirements:
75
74
  - - ! '>='
76
75
  - !ruby/object:Gem::Version
77
76
  version: '0'
77
+ none: false
78
78
  description: DSL for building method overloading in Ruby more magical
79
79
  email:
80
80
  - tejanium@yahoo.com
@@ -100,17 +100,23 @@ rdoc_options: []
100
100
  require_paths:
101
101
  - lib
102
102
  required_ruby_version: !ruby/object:Gem::Requirement
103
- none: false
104
103
  requirements:
105
104
  - - ! '>='
106
105
  - !ruby/object:Gem::Version
106
+ segments:
107
+ - 0
108
+ hash: 2984216650687558397
107
109
  version: '0'
108
- required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  none: false
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
112
  requirements:
111
113
  - - ! '>='
112
114
  - !ruby/object:Gem::Version
115
+ segments:
116
+ - 0
117
+ hash: 2984216650687558397
113
118
  version: '0'
119
+ none: false
114
120
  requirements: []
115
121
  rubyforge_project:
116
122
  rubygems_version: 1.8.25