overider 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in overider.gemspec
4
+ gemspec
@@ -0,0 +1,50 @@
1
+ # Overider
2
+
3
+ ## Background
4
+ Despite Ruby's clean design and flexibility, the language has no native feature
5
+ that allows one to over-ride a method without irrevocably losing the original binding
6
+ of the method name.
7
+ `alias` is a well-worn idiom that circumvents this limitation,
8
+ but blogger Jay Fields wrote an [interesting post](http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html)
9
+ that reminds us that `alias` comes with some less-than-desireable side-effects
10
+ that may not be significant in small scripts and projects
11
+ but may become a problem for larger projects.
12
+
13
+ In the [same post](http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html),
14
+ Jay offered an interesting alternative to `alias`,
15
+ using instead `Module#instance_method` and `Module#define_method`.
16
+ This is much better,
17
+ but I'm not a Ruby ninja yet,
18
+ and I would rather not have to remember the Baroque syntax in `x = self.instance_method(:on!)`
19
+ and `x.bind(self).call` every time I want to do this,
20
+ let alone what they mean when I look at my code several weeks later.
21
+
22
+ So I thought about how I could take Jay's example one step further
23
+ and after some trial and lots of error came up with this.
24
+
25
+ ## Description
26
+ A mix-in module that allows for super-clean method over-riding without resorting to `alias`
27
+ or making unbound methods visible.
28
+
29
+ ## Synopsis
30
+ class A
31
+ def hello
32
+ "hello"
33
+ end
34
+ end
35
+
36
+ # Later, I want to overide class A methods
37
+
38
+ class A
39
+ extend Overider
40
+
41
+ overide (:hello) do |*a|
42
+ overiden(*a) + " overide"
43
+ end
44
+ end
45
+
46
+ puts A.new.hello # ==> "hello overide"
47
+
48
+ ## See also
49
+ * [Ruby: Alias method alternative, Jay Fields](http://blog.jayfields.com/2006/12/ruby-alias-method-alternative.html)
50
+ * <https://github.com/soveran/override>
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,28 @@
1
+ require "overider/version"
2
+
3
+ module Overider
4
+ def overide(sym, &pr)
5
+ orig_unbound_method = self.instance_method(sym)
6
+
7
+ define_method(sym) do |*a, &blk|
8
+ orig_self = self
9
+ obj = Object.new
10
+
11
+ obj.define_singleton_method(:overiden) do |*a, &blk|
12
+ orig_bound_method = orig_unbound_method.bind(orig_self)
13
+
14
+ if !!blk then
15
+ orig_bound_method.call *a, &blk
16
+ else
17
+ orig_bound_method.call *a
18
+ end
19
+ end
20
+
21
+ if !!blk then
22
+ obj.instance_exec(*a, blk, &pr)
23
+ else
24
+ obj.instance_exec(*a, &pr)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,3 @@
1
+ module Overider
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,45 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "overider/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "overider"
7
+ s.version = Overider::VERSION
8
+ s.authors = ["Larry Siden, Westside Consulting LLC"]
9
+ s.email = ["lsiden@westside-consulting.com"]
10
+ s.homepage = "https://github.com/lsiden/overider"
11
+ s.summary = %q{
12
+ A mix-in module that allows for super-clean method over-riding without resorting to =alias=
13
+ or making unbound methods visible.
14
+ }
15
+ s.description = %q{
16
+ class A
17
+ def hello
18
+ "hello"
19
+ end
20
+ end
21
+
22
+ # Later, I want to overide class A methods
23
+
24
+ class A
25
+ extend Overider
26
+
27
+ overide (:hello) do |*a|
28
+ overiden(*a) + " overide"
29
+ end
30
+ end
31
+
32
+ A.new.hello # ==> "hello overide"
33
+ }
34
+
35
+ s.rubyforge_project = "overider"
36
+
37
+ s.files = `git ls-files`.split("\n")
38
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
39
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
40
+ s.require_paths = ["lib"]
41
+
42
+ # specify any dependencies here; for example:
43
+ s.add_development_dependency "rspec"
44
+ # s.add_runtime_dependency "rest-client"
45
+ end
@@ -0,0 +1,156 @@
1
+ require 'rspec'
2
+ require 'overider'
3
+
4
+ describe Overider do
5
+ it 'over-rides method names while allowing access to original method with name "overiden"' do
6
+
7
+ class A
8
+ def hello
9
+ "hello"
10
+ end
11
+ end
12
+
13
+ # Later, I want to overide class A methods
14
+
15
+ class A
16
+ extend Overider
17
+
18
+ overide (:hello) do |*a|
19
+ overiden(*a) + " overide"
20
+ end
21
+ end
22
+
23
+ a = A.new
24
+ a.hello.should == "hello overide"
25
+ end
26
+
27
+ it 'the name "overiden" is not overiden!' do
28
+
29
+ class A
30
+ def hello
31
+ "hello"
32
+ end
33
+
34
+ def goodby
35
+ "goodby"
36
+ end
37
+ end
38
+
39
+ # Later, I want to overide class A methods
40
+
41
+ class A
42
+ extend Overider
43
+
44
+ overide (:hello) do |*a|
45
+ overiden(*a) + " overide"
46
+ end
47
+
48
+ overide (:goodby) do |*a|
49
+ overiden(*a) + " overide"
50
+ end
51
+ end
52
+
53
+ a = A.new
54
+ a.hello.should == "hello overide"
55
+ a.goodby.should == "goodby overide"
56
+ a.hello.should == "hello overide" # "overiden" overiden!
57
+ end
58
+
59
+ it 'works with inheritance' do
60
+
61
+ class B < A
62
+ extend Overider
63
+
64
+ overide :hello do |*a|
65
+ overiden(*a) + " B then A"
66
+ end
67
+ end
68
+
69
+ B.new.hello.should == "hello overide B then A"
70
+ end
71
+
72
+ it 'works with modules' do
73
+ module HelloModule
74
+ def hello
75
+ "hello"
76
+ end
77
+ end
78
+
79
+ class C
80
+ include HelloModule
81
+ extend Overider
82
+
83
+ overide :hello do |*a|
84
+ overiden(*a) + " C"
85
+ end
86
+ end
87
+
88
+ C.new.hello.should == "hello C"
89
+ end
90
+
91
+ it 'works with args' do
92
+ module HelloWithArgs
93
+ def hello(a, b, c)
94
+ "hello #{a}, #{b}, #{c}"
95
+ end
96
+ end
97
+
98
+ class D
99
+ include HelloWithArgs
100
+ extend Overider
101
+
102
+ overide :hello do |a, b, c|
103
+ overiden(a, b, c) + " D"
104
+ end
105
+ end
106
+
107
+ result = D.new.hello 1, 2, 3
108
+ result.should == "hello 1, 2, 3 D"
109
+ end
110
+
111
+ it 'plays nice with blocks' do
112
+ module HelloModule
113
+ def hello(&blk)
114
+ "hello " + blk.call
115
+ end
116
+ end
117
+
118
+ class E
119
+ include HelloModule
120
+ extend Overider
121
+
122
+ # In the overide block, we have to declare blk as a normal block arg, not &blk.
123
+ # It must be a Proc or lambda
124
+ overide :hello do |blk|
125
+ overiden { blk.call } + " in E"
126
+ end
127
+ end
128
+
129
+ result = E.new.hello do
130
+ "block"
131
+ end
132
+ result.should == "hello block in E"
133
+ end
134
+
135
+ it 'plays nice with lambda' do
136
+ module HelloModule
137
+ def hello(&blk)
138
+ "hello " + blk.call
139
+ end
140
+ end
141
+
142
+ class F
143
+ include HelloModule
144
+ extend Overider
145
+
146
+ # In the overide block, we have to declare blk as a normal block arg, not &blk.
147
+ # It must be a Proc or lambda
148
+ overide :hello do |blk|
149
+ overiden { blk.call } + " in F"
150
+ end
151
+ end
152
+
153
+ result = F.new.hello ->{ "block" }
154
+ result.should == "hello block in F"
155
+ end
156
+ end
metadata ADDED
@@ -0,0 +1,68 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: overider
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Larry Siden, Westside Consulting LLC
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-23 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &76593190 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *76593190
25
+ description: ! "\n class A\n def hello\n \"hello\"\n end\n end\n\n
26
+ \ # Later, I want to overide class A methods\n\n class A\n extend Overider\n\n
27
+ \ overide (:hello) do |*a|\n overiden(*a) + \" overide\"\n end\n
28
+ \ end\n\n A.new.hello # ==> \"hello overide\"\n "
29
+ email:
30
+ - lsiden@westside-consulting.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - .gitignore
36
+ - Gemfile
37
+ - README.mkd
38
+ - Rakefile
39
+ - lib/overider.rb
40
+ - lib/overider/version.rb
41
+ - overider.gemspec
42
+ - spec/overider_spec.rb
43
+ homepage: https://github.com/lsiden/overider
44
+ licenses: []
45
+ post_install_message:
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ requirements: []
62
+ rubyforge_project: overider
63
+ rubygems_version: 1.8.10
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: A mix-in module that allows for super-clean method over-riding without resorting
67
+ to =alias= or making unbound methods visible.
68
+ test_files: []