loverload 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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