up_the_irons-immutable 0.1 → 0.2
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 +36 -8
- data/immutable.gemspec +1 -1
- data/lib/immutable.rb +16 -12
- data/spec/immutable_spec.rb +70 -62
- metadata +1 -1
data/README
CHANGED
@@ -14,7 +14,7 @@ Child classes, however, can still override the method. So this is not like
|
|
14
14
|
Java's "final" method modifier.
|
15
15
|
|
16
16
|
One can argue that in OOP, if you want to reimplement or extend a method, a
|
17
|
-
child class is the only place you should be doing that anyway.
|
17
|
+
child class is the only place where you should be doing that anyway.
|
18
18
|
|
19
19
|
Alpha
|
20
20
|
-----
|
@@ -96,7 +96,6 @@ to immutable.rb and not mess with $RUBYLIB.
|
|
96
96
|
If you installed ``Immutable`` from RubyGems, put::
|
97
97
|
|
98
98
|
require 'rubygems'
|
99
|
-
gem 'up_the_irons-immutable'
|
100
99
|
require 'immutable'
|
101
100
|
|
102
101
|
at the top of your programs.
|
@@ -136,11 +135,41 @@ reimplementing them. So the following:
|
|
136
135
|
end
|
137
136
|
end
|
138
137
|
|
138
|
+
Will raise an error:
|
139
|
+
|
140
|
+
::
|
141
|
+
|
142
|
+
Cannot override the immutable method: foo (Immutable::CannotOverrideMethod)
|
143
|
+
|
144
|
+
There is one option to immutable_method() called :silent. If :silent is true,
|
145
|
+
no exception will be raised. One can then do:
|
146
|
+
|
147
|
+
::
|
148
|
+
|
149
|
+
module Foo
|
150
|
+
include Immutable
|
151
|
+
|
152
|
+
def foo
|
153
|
+
:foo
|
154
|
+
end
|
155
|
+
|
156
|
+
immutable_method :foo, :silent => true
|
157
|
+
end
|
158
|
+
|
159
|
+
module Foo
|
160
|
+
def foo
|
161
|
+
:baz
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
139
165
|
include Foo
|
140
166
|
|
141
167
|
foo # => :foo
|
142
168
|
|
143
|
-
|
169
|
+
foo() returns :foo, not :baz. It did not allow itself to be overriden. Using
|
170
|
+
:silent can bring a great deal of confusion to other developers wondering why
|
171
|
+
their method overrides aren't working. I would consider using :silent bad
|
172
|
+
practice in all but very limited cases. Use with extreme caution.
|
144
173
|
|
145
174
|
There is an alias for immutable_method() called immutable_methods() (plural).
|
146
175
|
Use whichever style you prefer.
|
@@ -148,7 +177,7 @@ Use whichever style you prefer.
|
|
148
177
|
To Do
|
149
178
|
-----
|
150
179
|
|
151
|
-
|
180
|
+
I finished my TODOs, cool.
|
152
181
|
|
153
182
|
Author
|
154
183
|
------
|
@@ -177,17 +206,16 @@ Copyright
|
|
177
206
|
|
178
207
|
Copyright (c) 2008 Garry C. Dolley
|
179
208
|
|
180
|
-
|
209
|
+
Immutable is free software; you can redistribute it and/or modify it under the
|
181
210
|
terms of the GNU General Public License as published by the Free Software
|
182
211
|
Foundation; either version 2 of the License, or (at your option) any later
|
183
212
|
version.
|
184
213
|
|
185
|
-
|
214
|
+
Immutable is distributed in the hope that it will be useful, but WITHOUT ANY
|
186
215
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
187
216
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
188
217
|
details.
|
189
218
|
|
190
219
|
You should have received a copy of the GNU General Public License along with
|
191
|
-
|
220
|
+
Immutable; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
192
221
|
Street, Fifth Floor, Boston, MA 02110-1301, USA
|
193
|
-
|
data/immutable.gemspec
CHANGED
data/lib/immutable.rb
CHANGED
@@ -1,30 +1,34 @@
|
|
1
1
|
module Immutable
|
2
|
+
class CannotOverrideMethod < StandardError; end
|
3
|
+
|
2
4
|
def self.included(mod)
|
3
5
|
mod.extend(ClassMethods)
|
4
6
|
end
|
5
7
|
|
6
8
|
module ClassMethods
|
7
9
|
def immutable_method(*args)
|
10
|
+
opts = args.last.is_a?(Hash) ? args.pop : {}
|
11
|
+
|
8
12
|
args.each do |method|
|
9
13
|
alias_method "orig_#{method}", method
|
10
14
|
end
|
11
15
|
|
12
|
-
@args = args
|
16
|
+
@args = args; @opts = opts
|
13
17
|
module_eval do
|
14
18
|
def self.method_added(sym)
|
15
19
|
if @args
|
16
20
|
@args.each do |method|
|
17
|
-
if method
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
21
|
+
if method && sym == method.to_sym && !called_by_method_added
|
22
|
+
unless @opts[:silent]
|
23
|
+
raise CannotOverrideMethod, "Cannot override the immutable method: #{sym}"
|
24
|
+
end
|
25
|
+
|
26
|
+
self.module_eval <<-"end;"
|
27
|
+
def #{method.to_s}(*args, &block)
|
28
|
+
orig_#{method.to_s}(*args, &block)
|
29
|
+
end
|
30
|
+
end;
|
31
|
+
end
|
28
32
|
end # @args.each
|
29
33
|
end # @args
|
30
34
|
end # def self.method_added()
|
data/spec/immutable_spec.rb
CHANGED
@@ -19,7 +19,7 @@ module Foo
|
|
19
19
|
:fast
|
20
20
|
end
|
21
21
|
|
22
|
-
immutable_method :foo, :bar
|
22
|
+
immutable_method :foo, :bar, :silent => true
|
23
23
|
end
|
24
24
|
|
25
25
|
# Other Foo modules we can screw with, so specs don't step on each other
|
@@ -37,69 +37,49 @@ describe "Module Foo" do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
describe "after redefining" do
|
40
|
-
def redefine(method)
|
41
|
-
Foo.module_eval <<-"end;"
|
42
|
-
def #{method.to_s}
|
43
|
-
:slow
|
44
|
-
end
|
45
|
-
end;
|
46
|
-
end
|
47
|
-
|
48
40
|
it "should not let foo() be redefined" do
|
49
|
-
redefine(:foo)
|
41
|
+
redefine(Foo, :foo)
|
50
42
|
test_it(Foo, :foo)
|
51
43
|
end
|
52
44
|
|
53
45
|
it "should not let foo() be redefined even if we try twice" do
|
54
|
-
redefine(:foo)
|
55
|
-
redefine(:foo)
|
46
|
+
redefine(Foo, :foo)
|
47
|
+
redefine(Foo, :foo)
|
56
48
|
test_it(Foo, :foo)
|
57
49
|
end
|
58
50
|
|
59
51
|
it "should not let bar() be redefined" do
|
60
|
-
redefine(:bar)
|
52
|
+
redefine(Foo, :bar)
|
61
53
|
test_it(Foo, :bar)
|
62
54
|
end
|
63
55
|
|
64
56
|
it "should not let bar() be redefined even if we try twice" do
|
65
|
-
redefine(:bar)
|
66
|
-
redefine(:bar)
|
57
|
+
redefine(Foo, :bar)
|
58
|
+
redefine(Foo, :bar)
|
67
59
|
test_it(Foo, :bar)
|
68
60
|
end
|
69
61
|
end
|
70
62
|
|
71
63
|
describe "after undefining" do
|
72
|
-
def undefine(method)
|
73
|
-
Foo2.module_eval do
|
74
|
-
undef_method(method)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
64
|
it "should not let foo() be undefined" do
|
79
|
-
undefine(:foo)
|
65
|
+
undefine(Foo2, :foo)
|
80
66
|
test_it(Foo2, :foo)
|
81
67
|
end
|
82
68
|
|
83
69
|
it "should not let bar() be undefined" do
|
84
|
-
undefine(:bar)
|
70
|
+
undefine(Foo2, :bar)
|
85
71
|
test_it(Foo2, :bar)
|
86
72
|
end
|
87
73
|
end
|
88
74
|
|
89
75
|
describe "after removing" do
|
90
|
-
def remove(method)
|
91
|
-
Foo3.module_eval do
|
92
|
-
remove_method(method)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
76
|
it "should not let foo() be removed" do
|
97
|
-
remove(:foo)
|
77
|
+
remove(Foo3, :foo)
|
98
78
|
test_it(Foo3, :foo)
|
99
79
|
end
|
100
80
|
|
101
81
|
it "should not let bar() be removed" do
|
102
|
-
remove(:bar)
|
82
|
+
remove(Foo3, :bar)
|
103
83
|
test_it(Foo3, :bar)
|
104
84
|
end
|
105
85
|
end
|
@@ -120,7 +100,7 @@ class Bar
|
|
120
100
|
:fast
|
121
101
|
end
|
122
102
|
|
123
|
-
immutable_method :foo, :bar
|
103
|
+
immutable_method :foo, :bar, :silent => true
|
124
104
|
end
|
125
105
|
|
126
106
|
# Other Bar modules we can screw with, so specs don't step on each other
|
@@ -140,69 +120,49 @@ describe "Class Bar" do
|
|
140
120
|
end
|
141
121
|
|
142
122
|
describe "after redefining" do
|
143
|
-
def redefine(method)
|
144
|
-
Bar.module_eval <<-"end;"
|
145
|
-
def #{method.to_s}
|
146
|
-
:slow
|
147
|
-
end
|
148
|
-
end;
|
149
|
-
end
|
150
|
-
|
151
123
|
it "should not let foo() be redefined" do
|
152
|
-
redefine(:foo)
|
124
|
+
redefine(Bar, :foo)
|
153
125
|
test_it(Bar, :foo)
|
154
126
|
end
|
155
127
|
|
156
128
|
it "should not let foo() be redefined even if we try twice" do
|
157
|
-
redefine(:foo)
|
158
|
-
redefine(:foo)
|
129
|
+
redefine(Bar, :foo)
|
130
|
+
redefine(Bar, :foo)
|
159
131
|
test_it(Bar, :foo)
|
160
132
|
end
|
161
133
|
|
162
134
|
it "should not let bar() be redefined" do
|
163
|
-
redefine(:bar)
|
135
|
+
redefine(Bar, :bar)
|
164
136
|
test_it(Bar, :bar)
|
165
137
|
end
|
166
138
|
|
167
139
|
it "should not let bar() be redefined even if we try twice" do
|
168
|
-
redefine(:bar)
|
169
|
-
redefine(:bar)
|
140
|
+
redefine(Bar, :bar)
|
141
|
+
redefine(Bar, :bar)
|
170
142
|
test_it(Bar, :bar)
|
171
143
|
end
|
172
144
|
end
|
173
145
|
|
174
146
|
describe "after undefining" do
|
175
|
-
def undefine(method)
|
176
|
-
Bar2.module_eval do
|
177
|
-
undef_method(method)
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
147
|
it "should not let foo() be undefined" do
|
182
|
-
undefine(:foo)
|
148
|
+
undefine(Bar2, :foo)
|
183
149
|
test_it(Bar2, :foo)
|
184
150
|
end
|
185
151
|
|
186
152
|
it "should not let bar() be undefined" do
|
187
|
-
undefine(:bar)
|
153
|
+
undefine(Bar2, :bar)
|
188
154
|
test_it(Bar2, :bar)
|
189
155
|
end
|
190
156
|
end
|
191
157
|
|
192
158
|
describe "after removing" do
|
193
|
-
def remove(method)
|
194
|
-
Bar3.module_eval do
|
195
|
-
remove_method(method)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
159
|
it "should not let foo() be removed" do
|
200
|
-
remove(:foo)
|
160
|
+
remove(Bar3, :foo)
|
201
161
|
test_it(Bar3, :foo)
|
202
162
|
end
|
203
163
|
|
204
164
|
it "should not let bar() be removed" do
|
205
|
-
remove(:bar)
|
165
|
+
remove(Bar3, :bar)
|
206
166
|
test_it(Bar3, :bar)
|
207
167
|
end
|
208
168
|
end
|
@@ -213,3 +173,51 @@ describe "Class Bar" do
|
|
213
173
|
end
|
214
174
|
end
|
215
175
|
end
|
176
|
+
|
177
|
+
##############
|
178
|
+
# Exceptions #
|
179
|
+
##############
|
180
|
+
|
181
|
+
module Boo
|
182
|
+
include Immutable
|
183
|
+
|
184
|
+
def boo
|
185
|
+
:fast
|
186
|
+
end
|
187
|
+
|
188
|
+
immutable_method :boo
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "Exceptions" do
|
192
|
+
describe "by default" do
|
193
|
+
it "should raise exception upon override" do
|
194
|
+
lambda do
|
195
|
+
redefine(Boo, :boo)
|
196
|
+
end.should raise_error(Immutable::CannotOverrideMethod, /Cannot override the immutable method: boo$/)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
##################
|
202
|
+
# Helper methods #
|
203
|
+
##################
|
204
|
+
|
205
|
+
def redefine(mod, method)
|
206
|
+
mod.module_eval <<-"end;"
|
207
|
+
def #{method.to_s}
|
208
|
+
:slow
|
209
|
+
end
|
210
|
+
end;
|
211
|
+
end
|
212
|
+
|
213
|
+
def undefine(mod, method)
|
214
|
+
mod.module_eval do
|
215
|
+
undef_method(method)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def remove(mod, method)
|
220
|
+
mod.module_eval do
|
221
|
+
remove_method(method)
|
222
|
+
end
|
223
|
+
end
|