overider 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.
@@ -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: []