loverload 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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