up_the_irons-immutable 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README +12 -4
- data/immutable.gemspec +9 -10
- data/lib/immutable.rb +36 -16
- data/spec/immutable_spec.rb +74 -9
- metadata +6 -4
data/README
CHANGED
@@ -3,8 +3,8 @@ Immutable
|
|
3
3
|
=========
|
4
4
|
|
5
5
|
:Author: Garry Dolley
|
6
|
-
:Date: 09-
|
7
|
-
:Version: v0.
|
6
|
+
:Date: 09-21-2008
|
7
|
+
:Version: v0.2
|
8
8
|
|
9
9
|
The ``Immutable`` module provides a method (immutable_method) that let's one
|
10
10
|
declare method(s) as immutable. That is, other code will not be able to
|
@@ -22,7 +22,12 @@ Alpha
|
|
22
22
|
This code is very new and despite a pretty comprehensive spec, I'm sure there's
|
23
23
|
cases where someone can figure out how to defeat this. So be it. :)
|
24
24
|
|
25
|
-
|
25
|
+
This code has been tested on the following systems:
|
26
|
+
|
27
|
+
* GNU/Linux (Ubuntu 8.04.1) with Ruby 1.8.6
|
28
|
+
* FreeBSD 7.0 with Ruby 1.8.6
|
29
|
+
* OpenBSD 4.3 with Ruby 1.8.6
|
30
|
+
* Mac OS X 10.5 with Ruby 1.8.6
|
26
31
|
|
27
32
|
Please see the Author section below and report any problems.
|
28
33
|
|
@@ -177,6 +182,9 @@ Use whichever style you prefer.
|
|
177
182
|
To Do
|
178
183
|
-----
|
179
184
|
|
185
|
+
Make method_added immutable, as well as immutable_method. Write tests to try
|
186
|
+
to "defeat" an immutable method, see if we can prevent it.
|
187
|
+
|
180
188
|
I finished my TODOs, cool.
|
181
189
|
|
182
190
|
Author
|
@@ -204,7 +212,7 @@ look like markup, even though it is.
|
|
204
212
|
Copyright
|
205
213
|
---------
|
206
214
|
|
207
|
-
Copyright (c) 2008 Garry C. Dolley
|
215
|
+
Copyright (c) 2008,2009 Garry C. Dolley
|
208
216
|
|
209
217
|
Immutable is free software; you can redistribute it and/or modify it under the
|
210
218
|
terms of the GNU General Public License as published by the Free Software
|
data/immutable.gemspec
CHANGED
@@ -1,12 +1,11 @@
|
|
1
1
|
spec = Gem::Specification.new do |s|
|
2
|
-
s.name
|
3
|
-
s.version
|
4
|
-
s.
|
5
|
-
s.email
|
6
|
-
s.homepage
|
7
|
-
s.
|
8
|
-
s.summary
|
9
|
-
|
10
|
-
s.
|
11
|
-
s.has_rdoc = false
|
2
|
+
s.name = "immutable"
|
3
|
+
s.version = "0.3"
|
4
|
+
s.authors = ["Garry Dolley", "Lucas de Castro"]
|
5
|
+
s.email = "gdolley@ucla.edu"
|
6
|
+
s.homepage = "http://github.com/up_the_irons/immutable/tree/master"
|
7
|
+
s.description = "Declare methods as immutable."
|
8
|
+
s.summary = "Declare methods as immutable, somewhat like Java's 'final' keyword but still allowing child classes to override."
|
9
|
+
s.files = ['lib/immutable.rb', 'spec/immutable_spec.rb', 'immutable.gemspec', 'README', 'COPYING']
|
10
|
+
s.has_rdoc = false
|
12
11
|
end
|
data/lib/immutable.rb
CHANGED
@@ -1,36 +1,50 @@
|
|
1
1
|
module Immutable
|
2
2
|
class CannotOverrideMethod < StandardError; end
|
3
3
|
|
4
|
+
# Random ID changed at each interpreter load
|
5
|
+
UNIQ = "_#{object_id.abs}"
|
6
|
+
|
4
7
|
def self.included(mod)
|
5
8
|
mod.extend(ClassMethods)
|
6
9
|
end
|
7
10
|
|
8
11
|
module ClassMethods
|
9
12
|
def immutable_method(*args)
|
13
|
+
# Initialize variables
|
14
|
+
@immutable_methods = [] if @immutable_methods.nil?
|
15
|
+
@silent_immutable_methods = [] if @silent_immutable_methods.nil?
|
16
|
+
instance_variable_set("@#{UNIQ}_in_method_added", false)
|
17
|
+
|
10
18
|
opts = args.last.is_a?(Hash) ? args.pop : {}
|
11
19
|
|
12
20
|
args.each do |method|
|
13
|
-
alias_method "
|
21
|
+
alias_method "#{UNIQ}_old_#{method}", method
|
14
22
|
end
|
23
|
+
|
24
|
+
# Build list of immutable methods
|
25
|
+
@immutable_methods += args
|
26
|
+
@silent_immutable_methods += args if opts[:silent]
|
15
27
|
|
16
|
-
@
|
28
|
+
@opts = opts
|
17
29
|
module_eval do
|
18
30
|
def self.method_added(sym)
|
19
|
-
if @
|
20
|
-
@
|
21
|
-
if method && sym == method.to_sym && !
|
22
|
-
unless @
|
31
|
+
if @immutable_methods
|
32
|
+
@immutable_methods.each do |method|
|
33
|
+
if method && sym == method.to_sym && !in_method_added?
|
34
|
+
unless @silent_immutable_methods.include?(method)
|
23
35
|
raise CannotOverrideMethod, "Cannot override the immutable method: #{sym}"
|
24
36
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
|
38
|
+
allow_method_override do
|
39
|
+
self.module_eval <<-"end;"
|
40
|
+
def #{method}(*args, &block)
|
41
|
+
#{UNIQ}_old_#{method}(*args, &block)
|
42
|
+
end
|
43
|
+
end;
|
44
|
+
end
|
31
45
|
end
|
32
46
|
end # @args.each
|
33
|
-
end # @
|
47
|
+
end # @immutable_methods
|
34
48
|
end # def self.method_added()
|
35
49
|
|
36
50
|
def self.method_undefined(sym)
|
@@ -42,9 +56,15 @@ module Immutable
|
|
42
56
|
end
|
43
57
|
end # module_eval
|
44
58
|
|
45
|
-
def self.
|
46
|
-
|
47
|
-
|
59
|
+
def self.allow_method_override
|
60
|
+
instance_variable_set("@#{UNIQ}_in_method_added", true)
|
61
|
+
yield
|
62
|
+
ensure
|
63
|
+
instance_variable_set("@#{UNIQ}_in_method_added", false)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.in_method_added?
|
67
|
+
instance_variable_get("@#{UNIQ}_in_method_added")
|
48
68
|
end
|
49
69
|
end # def immutable_method()
|
50
70
|
|
data/spec/immutable_spec.rb
CHANGED
@@ -27,15 +27,6 @@ Foo2 = Foo.clone
|
|
27
27
|
Foo3 = Foo.clone
|
28
28
|
|
29
29
|
describe "Module Foo" do
|
30
|
-
def test_it(mod, method)
|
31
|
-
@value = Object.instance_eval do
|
32
|
-
include mod
|
33
|
-
send(method)
|
34
|
-
end
|
35
|
-
|
36
|
-
@value.should == :fast
|
37
|
-
end
|
38
|
-
|
39
30
|
describe "after redefining" do
|
40
31
|
it "should not let foo() be redefined" do
|
41
32
|
redefine(Foo, :foo)
|
@@ -185,6 +176,11 @@ module Boo
|
|
185
176
|
:fast
|
186
177
|
end
|
187
178
|
|
179
|
+
def boofoo
|
180
|
+
:boofoo_fast
|
181
|
+
end
|
182
|
+
|
183
|
+
immutable_method :boofoo, :silent => true
|
188
184
|
immutable_method :boo
|
189
185
|
end
|
190
186
|
|
@@ -196,6 +192,66 @@ describe "Exceptions" do
|
|
196
192
|
end.should raise_error(Immutable::CannotOverrideMethod, /Cannot override the immutable method: boo$/)
|
197
193
|
end
|
198
194
|
end
|
195
|
+
|
196
|
+
it "should not raise if :silent => true" do
|
197
|
+
redefine(Boo, :boofoo)
|
198
|
+
test_it(Boo, :boofoo, :boofoo_fast)
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
#########
|
203
|
+
# Other #
|
204
|
+
#########
|
205
|
+
|
206
|
+
module Bear
|
207
|
+
include Immutable
|
208
|
+
|
209
|
+
def foo
|
210
|
+
:foo_fast
|
211
|
+
end
|
212
|
+
|
213
|
+
def bar
|
214
|
+
:bar_fast
|
215
|
+
end
|
216
|
+
|
217
|
+
def baz
|
218
|
+
:baz_fast
|
219
|
+
end
|
220
|
+
|
221
|
+
def boo
|
222
|
+
:boo_fast
|
223
|
+
end
|
224
|
+
|
225
|
+
# Make sure we can make independent calls to immutable_method
|
226
|
+
immutable_method :foo
|
227
|
+
immutable_method :bar
|
228
|
+
immutable_method :baz, :silent => true
|
229
|
+
immutable_method :boo
|
230
|
+
end
|
231
|
+
|
232
|
+
describe "Multiple independent calls to immutable_method()" do
|
233
|
+
it "should still recognize foo() is immutable" do
|
234
|
+
lambda do
|
235
|
+
redefine(Bear, :foo)
|
236
|
+
end.should raise_error(Immutable::CannotOverrideMethod, /Cannot override the immutable method: foo$/)
|
237
|
+
end
|
238
|
+
|
239
|
+
it "should still recognize bar() is immutable" do
|
240
|
+
lambda do
|
241
|
+
redefine(Bear, :bar)
|
242
|
+
end.should raise_error(Immutable::CannotOverrideMethod, /Cannot override the immutable method: bar$/)
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should still recognize baz() is immutable" do
|
246
|
+
redefine(Bear, :baz)
|
247
|
+
test_it(Bear, :baz, :baz_fast)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should still recognize boo() is immutable" do
|
251
|
+
lambda do
|
252
|
+
redefine(Bear, :boo)
|
253
|
+
end.should raise_error(Immutable::CannotOverrideMethod, /Cannot override the immutable method: boo$/)
|
254
|
+
end
|
199
255
|
end
|
200
256
|
|
201
257
|
##################
|
@@ -221,3 +277,12 @@ def remove(mod, method)
|
|
221
277
|
remove_method(method)
|
222
278
|
end
|
223
279
|
end
|
280
|
+
|
281
|
+
def test_it(mod, method, value = :fast)
|
282
|
+
@value = Object.instance_eval do
|
283
|
+
include mod
|
284
|
+
send(method)
|
285
|
+
end
|
286
|
+
|
287
|
+
@value.should == value
|
288
|
+
end
|
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: up_the_irons-immutable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: "0.
|
4
|
+
version: "0.3"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Garry Dolley
|
8
|
+
- Lucas de Castro
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
12
|
|
12
|
-
date:
|
13
|
+
date: 2009-05-16 00:00:00 -07:00
|
13
14
|
default_executable:
|
14
15
|
dependencies: []
|
15
16
|
|
16
|
-
description:
|
17
|
+
description: Declare methods as immutable.
|
17
18
|
email: gdolley@ucla.edu
|
18
19
|
executables: []
|
19
20
|
|
@@ -29,6 +30,7 @@ files:
|
|
29
30
|
- COPYING
|
30
31
|
has_rdoc: false
|
31
32
|
homepage: http://github.com/up_the_irons/immutable/tree/master
|
33
|
+
licenses:
|
32
34
|
post_install_message:
|
33
35
|
rdoc_options: []
|
34
36
|
|
@@ -49,7 +51,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
51
|
requirements: []
|
50
52
|
|
51
53
|
rubyforge_project:
|
52
|
-
rubygems_version: 1.
|
54
|
+
rubygems_version: 1.3.5
|
53
55
|
signing_key:
|
54
56
|
specification_version: 2
|
55
57
|
summary: Declare methods as immutable, somewhat like Java's 'final' keyword but still allowing child classes to override.
|