loverload 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in loverload.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Teja Sophista V.R.
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,149 @@
1
+ # Loverload
2
+
3
+ DSL for building method overloading in Ruby.
4
+
5
+ Rigid language like Java allow you to create method overloading:
6
+
7
+ ``` java
8
+ public void draw(String s) {
9
+ ...
10
+ }
11
+ public void draw(int i) {
12
+ ...
13
+ }
14
+ public void draw(double f) {
15
+ ...
16
+ }
17
+ public void draw(int i, double f) {
18
+ ...
19
+ }
20
+ ```
21
+
22
+ However, in Ruby, we don't have this kind of thing, _do we_?
23
+
24
+ ``` ruby
25
+ before_save NameSayer.new
26
+ before_save :say_my_name
27
+ before_save {|record| puts "My name is #{record.name}" }
28
+ before_save 'puts "My name is #{self.name}"'
29
+ ```
30
+
31
+ [An Intervention for ActiveRecord](https://speakerdeck.com/erniemiller/an-intervention-for-activerecord) by [Ernie Miller](http://erniemiller.org)
32
+
33
+
34
+ ## Installation
35
+
36
+ Add this line to your application's Gemfile:
37
+
38
+ gem 'loverload'
39
+
40
+ And then execute:
41
+
42
+ $ bundle
43
+
44
+ Or install it yourself as:
45
+
46
+ $ gem install loverload
47
+
48
+ ## Usage
49
+
50
+ Simple
51
+
52
+ ``` ruby
53
+ class Dummy
54
+ include Loverload
55
+
56
+ def_overload :hello do
57
+ with_params do
58
+ "Hello Nobody"
59
+ end
60
+
61
+ with_params do |name|
62
+ "Hello #{ name }"
63
+ end
64
+
65
+ with_params do |name, age|
66
+ "Hello #{ name } Age #{ age }"
67
+ end
68
+ end
69
+ end
70
+
71
+ dummy = Dummy.new
72
+ dummy.hello #=> 'Hello Nobody'
73
+ dummy.hello('Teja') #=> 'Hello Teja'
74
+ dummy.hello('Teja', 21) #=> 'Hello Teja Age 21'
75
+ ```
76
+
77
+ Strict
78
+ ``` ruby
79
+ class Dummy
80
+ include Loverload
81
+
82
+ def_overload :hello do
83
+ with_params String do |name|
84
+ "Hello Name: #{ name }"
85
+ end
86
+
87
+ with_params Fixnum do |age|
88
+ "Hello Age: #{ age }"
89
+ end
90
+
91
+ with_params String, Fixnum do |name, age|
92
+ "Hello Name: #{ name } Age: #{ age }"
93
+ end
94
+
95
+ with_params Fixnum, String do |age, name|
96
+ "Hello Age: #{ age } Name: #{ name }"
97
+ end
98
+ end
99
+ end
100
+
101
+ dummy = Dummy.new
102
+ dummy.hello('Teja') #=> 'Hello Name: Teja'
103
+ dummy.hello(21) #=> 'Hello Age: 21'
104
+ dummy.hello('Teja', 21) #=> 'Hello Name: Teja Age: 21'
105
+ dummy.hello(21, 'Teja') #=> 'Hello Age: 21 Name: Teja'
106
+ dummy.hello('Teja', 21, true) #=> NoMethodError
107
+ ```
108
+
109
+ This is how you do :before_save
110
+ ``` ruby
111
+ class Dummy
112
+ include Loverload
113
+
114
+ def_overload :before_save do
115
+ with_params Dummy do |dummy|
116
+ "Puke rainbow"
117
+ end
118
+
119
+ with_params Symbol do |symbol|
120
+ "Puke more rainbow"
121
+ end
122
+
123
+ with_params Proc do |proc|
124
+ "Puke rainbow and leprechaun"
125
+ end
126
+
127
+ with_params String do |string|
128
+ "Puke rainbow, leprechaun, and gold"
129
+ end
130
+ end
131
+ end
132
+
133
+ dummy = Dummy.new
134
+ dummy.before_save(Dummy.new) #=> "Puke rainbow"
135
+ dummy.before_save(:symbol) #=> "Puke more rainbow"
136
+ dummy.before_save(proc{|this| is proc}) #=> "Puke rainbow and leprechaun"
137
+ dummy.before_save('string') #=> "Puke rainbow, leprechaun, and gold"
138
+ ```
139
+
140
+ ## TODO
141
+ - Make it less ugly
142
+
143
+ ## Contributing
144
+
145
+ 1. Fork it
146
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
147
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
148
+ 4. Push to the branch (`git push origin my-new-feature`)
149
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/lib/loverload.rb ADDED
@@ -0,0 +1,18 @@
1
+ require "loverload/version"
2
+ require "loverload/method"
3
+
4
+ module Loverload
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def def_overload method_name, &with_params_block
11
+ method = Method.new(self, method_name, &with_params_block)
12
+
13
+ define_method method_name do |*args|
14
+ method.overload(self, *args)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ module Loverload
2
+ class Method
3
+ def initialize klass, method_name, &with_params_block
4
+ @klass = klass
5
+ @method_name = method_name
6
+ instance_eval(&with_params_block)
7
+ end
8
+
9
+ 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 }
22
+ end
23
+
24
+ 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
38
+ end
39
+
40
+ private
41
+ def type_signature array_of_class
42
+ array_of_class.to_s.gsub(/[\[\]]/, '')
43
+ end
44
+
45
+ def alias_signature array_of_class
46
+ 'Object' * array_of_class.size
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module Loverload
2
+ VERSION = "0.0.1"
3
+ end
data/loverload.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'loverload/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "loverload"
8
+ spec.version = Loverload::VERSION
9
+ spec.authors = ["Teja Sophista V.R."]
10
+ spec.email = ["tejanium@yahoo.com"]
11
+ spec.description = %q{DSL for building method overloading in Ruby more magical}
12
+ spec.summary = %q{DSL for building method overloading in Ruby}
13
+ spec.homepage = "http://github.com/tejanium/loverload"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "debugger"
25
+ end
@@ -0,0 +1,168 @@
1
+ require 'loverload'
2
+
3
+ describe Loverload do
4
+ it "makes your code more magical" do
5
+ class Dummy
6
+ include Loverload
7
+
8
+ def_overload :hello do
9
+ with_params do
10
+ "Hello Nobody"
11
+ end
12
+
13
+ with_params do |name|
14
+ "Hello #{ name }"
15
+ end
16
+
17
+ with_params do |name, age|
18
+ "Hello #{ name } Age #{ age }"
19
+ end
20
+ end
21
+ end
22
+
23
+ dummy = Dummy.new
24
+ dummy.hello.should eql 'Hello Nobody'
25
+ dummy.hello('Teja').should eql 'Hello Teja'
26
+ dummy.hello('Teja', 21).should eql 'Hello Teja Age 21'
27
+ end
28
+
29
+ it "makes your code even more magical" do
30
+ class Dummy
31
+ include Loverload
32
+
33
+ def_overload :hello do
34
+ with_params String do |name|
35
+ "Hello Name: #{ name }"
36
+ end
37
+
38
+ with_params Fixnum do |age|
39
+ "Hello Age: #{ age }"
40
+ end
41
+
42
+ with_params String, Fixnum do |name, age|
43
+ "Hello Name: #{ name } Age: #{ age }"
44
+ end
45
+
46
+ with_params Fixnum, String do |age, name|
47
+ "Hello Age: #{ age } Name: #{ name }"
48
+ end
49
+ end
50
+ end
51
+
52
+ dummy = Dummy.new
53
+ dummy.hello('Teja').should eql 'Hello Name: Teja'
54
+ dummy.hello(21).should eql 'Hello Age: 21'
55
+ dummy.hello('Teja', 21).should eql 'Hello Name: Teja Age: 21'
56
+ dummy.hello(21, 'Teja').should eql 'Hello Age: 21 Name: Teja'
57
+ end
58
+
59
+ it "makes you puke rainbow" do
60
+ class Dummy
61
+ include Loverload
62
+
63
+ def_overload :before_save do
64
+ with_params Dummy do |dummy|
65
+ "Puke rainbow"
66
+ end
67
+
68
+ with_params Symbol do |symbol|
69
+ "Puke more rainbow"
70
+ end
71
+
72
+ with_params Proc do |proc|
73
+ "Puke rainbow and leprechaun"
74
+ end
75
+
76
+ with_params String do |string|
77
+ "Puke rainbow, leprechaun, and gold"
78
+ end
79
+ end
80
+ end
81
+
82
+ dummy = Dummy.new
83
+ dummy.before_save(Dummy.new).should eql "Puke rainbow"
84
+ dummy.before_save(:symbol).should eql "Puke more rainbow"
85
+ dummy.before_save(proc{|this| is proc}).should eql "Puke rainbow and leprechaun"
86
+ dummy.before_save('string').should eql "Puke rainbow, leprechaun, and gold"
87
+ end
88
+
89
+ it "can call another method" do
90
+ class Dummy
91
+ include Loverload
92
+
93
+ def another_method
94
+ 'Hello from another method'
95
+ end
96
+
97
+ def_overload :call_another_method do
98
+ with_params do
99
+ another_method
100
+ end
101
+ end
102
+ end
103
+
104
+ dummy = Dummy.new
105
+
106
+ dummy.call_another_method.should eql 'Hello from another method'
107
+ end
108
+
109
+ it "shared state" do
110
+ class Dummy
111
+ include Loverload
112
+
113
+ def initialize
114
+ @hello = 'World'
115
+ end
116
+
117
+ def another_method
118
+ 'Hello from another method'
119
+ end
120
+
121
+ def_overload :call_another_method do
122
+ with_params do
123
+ "#@hello, #{ another_method }"
124
+ end
125
+ end
126
+ end
127
+
128
+ dummy = Dummy.new
129
+
130
+ dummy.call_another_method.should eql 'World, Hello from another method'
131
+ end
132
+
133
+ it "can have two overload methods" do
134
+ class Dummy
135
+ include Loverload
136
+
137
+ def another_method
138
+ 'Hello from another method'
139
+ end
140
+
141
+ def_overload :method_1 do
142
+ with_params do
143
+ 'method_1'
144
+ end
145
+
146
+ with_params do |arg|
147
+ "method_1 with arg"
148
+ end
149
+ end
150
+
151
+ def_overload :method_2 do
152
+ with_params do
153
+ 'method_2'
154
+ end
155
+
156
+ with_params do |arg|
157
+ "method_2 with arg"
158
+ end
159
+ end
160
+ end
161
+
162
+ dummy = Dummy.new
163
+ dummy.method_1.should eql 'method_1'
164
+ dummy.method_1(1).should eql 'method_1 with arg'
165
+ dummy.method_2.should eql 'method_2'
166
+ dummy.method_2(1).should eql 'method_2 with arg'
167
+ end
168
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: loverload
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Teja Sophista V.R.
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ prerelease: false
16
+ type: :development
17
+ name: bundler
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: '1.3'
24
+ requirement: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ prerelease: false
32
+ type: :development
33
+ name: rake
34
+ version_requirements: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ requirement: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ prerelease: false
48
+ type: :development
49
+ name: rspec
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirement: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ prerelease: false
64
+ type: :development
65
+ name: debugger
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirement: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: DSL for building method overloading in Ruby more magical
79
+ email:
80
+ - tejanium@yahoo.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files: []
84
+ files:
85
+ - .gitignore
86
+ - Gemfile
87
+ - LICENSE.txt
88
+ - README.md
89
+ - Rakefile
90
+ - lib/loverload.rb
91
+ - lib/loverload/method.rb
92
+ - lib/loverload/version.rb
93
+ - loverload.gemspec
94
+ - spec/loverload/loverload_spec.rb
95
+ homepage: http://github.com/tejanium/loverload
96
+ licenses:
97
+ - MIT
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 1.8.25
117
+ signing_key:
118
+ specification_version: 3
119
+ summary: DSL for building method overloading in Ruby
120
+ test_files:
121
+ - spec/loverload/loverload_spec.rb