retroactive_module_inclusion 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +0 -1
- data/History.rdoc +12 -1
- data/README.rdoc +17 -2
- data/Rakefile +1 -1
- data/lib/retroactive_module_inclusion.rb +20 -14
- data/test/test_retroactive_module_inclusion.rb +35 -11
- data.tar.gz.sig +0 -0
- metadata +5 -9
- metadata.gz.sig +0 -0
data/.yardopts
CHANGED
data/History.rdoc
CHANGED
@@ -1,9 +1,20 @@
|
|
1
|
+
=== 1.2.0 / 2011-01-23
|
2
|
+
|
3
|
+
* 2 minor enhancements
|
4
|
+
|
5
|
+
* Chaged #retroactively_include visibility to public and updated tests accordingly
|
6
|
+
* motivated by this discussion {this discussion}[https://github.com/lsegal/yard/issues/issue/242/] with Loren Segal
|
7
|
+
|
8
|
+
* Better documentation:
|
9
|
+
* many README and History fixes and improvements
|
10
|
+
* code documentation enhanced with YARD tags
|
11
|
+
|
1
12
|
=== 1.1.0 / 2011-01-22
|
2
13
|
|
3
14
|
* 2 minor enhancements
|
4
15
|
|
5
16
|
* Refactored retroactively_include method from ::Module to
|
6
|
-
CoreExt::Module::RetroactiveModuleInclusion, after Ola Bini suggested
|
17
|
+
CoreExt::Module::RetroactiveModuleInclusion, after what Ola Bini suggested
|
7
18
|
in his post {SAFE(R) MONKEY PATCHING}[http://olabini.com/blog/2011/01/safeer-monkey-patching/]
|
8
19
|
|
9
20
|
* Finally, managed to make yard document the retroactively_include method:
|
data/README.rdoc
CHANGED
@@ -39,7 +39,7 @@ included Enumerable (e.g., the Range class). Unfortunately, this is not the case
|
|
39
39
|
(1..2).mean #=> NoMethodError: undefined method `mean' for 1..2:Range
|
40
40
|
|
41
41
|
Surely this behaviour does not conform to the least surprise principle.
|
42
|
-
In fact, this inconsistency stems from
|
42
|
+
In fact, this inconsistency stems from efficienty concerns
|
43
43
|
and characterize a limitation in Ruby's object model (see {Dynamic Module Include Problem}[http://eigenclass.org/hiki/The+double+inclusion+problem]).
|
44
44
|
|
45
45
|
In face of that, one has basically two possible solutions. The first is to give up Stats and define the method directly inside Enumerable
|
@@ -53,8 +53,19 @@ In face of that, one has basically two possible solutions. The first is to give
|
|
53
53
|
|
54
54
|
The second, more concise and elegant, is to use this gem
|
55
55
|
|
56
|
+
Enumerable.retroactively_include Stats
|
57
|
+
|
58
|
+
Note that the method retroactively_include, which was private in early
|
59
|
+
versions, became public in v1.2.0. Nevertheless, one can still call
|
60
|
+
|
56
61
|
Enumerable.module_eval { retroactively_include Stats }
|
57
62
|
|
63
|
+
or
|
64
|
+
|
65
|
+
Enumerable.send :retroactively_include, Stats
|
66
|
+
|
67
|
+
to the same effect.
|
68
|
+
|
58
69
|
== FEATURES:
|
59
70
|
|
60
71
|
* Tested on all major Ruby interpreters (100% coverage, 0% failure):
|
@@ -67,9 +78,13 @@ The second, more concise and elegant, is to use this gem
|
|
67
78
|
== SYNOPSIS:
|
68
79
|
|
69
80
|
SomeModule.module_eval { retroactively_include AnotherModule }
|
70
|
-
|
81
|
+
|
71
82
|
or equivalently
|
72
83
|
|
84
|
+
SomeModule.send :retroactively_include, AnotherModule
|
85
|
+
|
86
|
+
or still
|
87
|
+
|
73
88
|
module SomeModule
|
74
89
|
retroactively_include AnotherModule
|
75
90
|
end
|
data/Rakefile
CHANGED
@@ -2,12 +2,10 @@ module CoreExt
|
|
2
2
|
module Module
|
3
3
|
module RetroactiveModuleInclusion
|
4
4
|
|
5
|
-
private
|
6
|
-
|
7
5
|
# Includes +mod+ retroactively, i.e., extending to all classes and modules which
|
8
6
|
# had included +self+ _beforehand_.
|
9
7
|
#
|
10
|
-
#
|
8
|
+
# @example Retroactively include a module in Enumerable.
|
11
9
|
#
|
12
10
|
# module Stats
|
13
11
|
# def mean
|
@@ -19,17 +17,23 @@ module CoreExt
|
|
19
17
|
#
|
20
18
|
# (1..2).mean #=> 1.5
|
21
19
|
#
|
22
|
-
|
20
|
+
# @return self
|
21
|
+
#
|
22
|
+
def retroactively_include(mod)
|
23
23
|
raise TypeError, "wrong argument type #{mod.class} (expected Module)" unless mod.is_a? ::Module # ::Module would in general be equivalent to Object::Module and simply Module would mean CoreExt::Module in this context
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
24
|
+
|
25
|
+
pseudo_descendants.each do |pd|
|
26
|
+
pd.module_eval { include mod }
|
27
|
+
end
|
28
|
+
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
# @return [Array] All modules and classes which have self in its ancestors tree, including self itself.
|
35
|
+
#
|
36
|
+
def pseudo_descendants
|
33
37
|
# JRuby (at least up to version 1.5.6) has ObjectSpace disabled by default,
|
34
38
|
# thus it must be enabled manually ([reference][2]).
|
35
39
|
#
|
@@ -42,14 +46,16 @@ module CoreExt
|
|
42
46
|
prev_jruby_objectspace_state = JRuby.objectspace
|
43
47
|
JRuby.objectspace = true
|
44
48
|
end
|
49
|
+
result = []
|
45
50
|
ObjectSpace.each_object(::Module) do |m|
|
46
51
|
if m <= self # equiv. to "if m.include?(self) || m == self"
|
47
|
-
|
52
|
+
result << m
|
48
53
|
end
|
49
54
|
end
|
50
55
|
if defined?(RUBY_DESCRIPTION) && RUBY_DESCRIPTION =~ /jruby/i
|
51
56
|
JRuby.objectspace = prev_jruby_objectspace_state
|
52
57
|
end
|
58
|
+
result
|
53
59
|
end
|
54
60
|
|
55
61
|
::Module.class_eval { include CoreExt::Module::RetroactiveModuleInclusion }
|
@@ -1,10 +1,14 @@
|
|
1
1
|
require "test/unit"
|
2
2
|
require File.expand_path("../../lib/retroactive_module_inclusion", __FILE__)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
[1,2].each do |n|
|
5
|
+
eval <<-EOS
|
6
|
+
module Stats#{n}
|
7
|
+
def mean#{n}
|
8
|
+
inject(&:+) / count.to_f
|
9
|
+
end
|
10
|
+
end
|
11
|
+
EOS
|
8
12
|
end
|
9
13
|
|
10
14
|
class TestRetroactiveInclude < Test::Unit::TestCase
|
@@ -18,13 +22,33 @@ class TestRetroactiveInclude < Test::Unit::TestCase
|
|
18
22
|
type_ok(Numeric, Math)
|
19
23
|
end
|
20
24
|
|
21
|
-
def
|
22
|
-
assert_raise(NoMethodError) { (1..2).
|
23
|
-
Enumerable.module_eval { include
|
24
|
-
assert_raise(NoMethodError, 'include should not work retroactively ') { (1..2).
|
25
|
-
Enumerable.module_eval { retroactively_include
|
26
|
-
assert_nothing_raised('retroactively_include should do the job') { (1..2).
|
27
|
-
assert_equal 1.5, (1..2).
|
25
|
+
def test_retroactively_include_private
|
26
|
+
assert_raise(NoMethodError) { (1..2).mean1 }
|
27
|
+
Enumerable.module_eval { include Stats1 }
|
28
|
+
assert_raise(NoMethodError, 'include should not work retroactively ') { (1..2).mean1 }
|
29
|
+
Enumerable.module_eval { retroactively_include Stats1 }
|
30
|
+
assert_nothing_raised('retroactively_include should do the job') { (1..2).mean1 }
|
31
|
+
assert_equal 1.5, (1..2).mean1
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_retroactively_include_public
|
35
|
+
assert_raise(NoMethodError) { (1..2).mean2 }
|
36
|
+
Enumerable.module_eval { include Stats2 }
|
37
|
+
assert_raise(NoMethodError, 'include should not work retroactively ') { (1..2).mean2 }
|
38
|
+
Enumerable.module_eval { retroactively_include Stats2 }
|
39
|
+
assert_nothing_raised('retroactively_include should do the job') { (1..2).mean2 }
|
40
|
+
assert_equal 1.5, (1..2).mean2
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_jruby_object_space_prev_state
|
44
|
+
if defined?(RUBY_DESCRIPTION) && RUBY_DESCRIPTION =~ /jruby/i
|
45
|
+
require 'jruby'
|
46
|
+
[true, false].each do |prev_state|
|
47
|
+
JRuby.objectspace = prev_state
|
48
|
+
Enumerable.module_eval { include Stats1 }
|
49
|
+
assert_equal prev_state, JRuby.objectspace
|
50
|
+
end
|
51
|
+
end
|
28
52
|
end
|
29
53
|
|
30
54
|
private
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: retroactive_module_inclusion
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
4
|
+
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
|
-
-
|
7
|
+
- 2
|
9
8
|
- 0
|
10
|
-
version: 1.
|
9
|
+
version: 1.2.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Adriano Mitre
|
@@ -36,7 +35,7 @@ cert_chain:
|
|
36
35
|
9u8N6mQNneIVRh6Xfdko/Q==
|
37
36
|
-----END CERTIFICATE-----
|
38
37
|
|
39
|
-
date: 2011-01-
|
38
|
+
date: 2011-01-23 00:00:00 -02:00
|
40
39
|
default_executable:
|
41
40
|
dependencies:
|
42
41
|
- !ruby/object:Gem::Dependency
|
@@ -47,7 +46,6 @@ dependencies:
|
|
47
46
|
requirements:
|
48
47
|
- - ">="
|
49
48
|
- !ruby/object:Gem::Version
|
50
|
-
hash: 47
|
51
49
|
segments:
|
52
50
|
- 2
|
53
51
|
- 8
|
@@ -98,7 +96,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
96
|
requirements:
|
99
97
|
- - ">="
|
100
98
|
- !ruby/object:Gem::Version
|
101
|
-
hash: 3
|
102
99
|
segments:
|
103
100
|
- 0
|
104
101
|
version: "0"
|
@@ -107,14 +104,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
104
|
requirements:
|
108
105
|
- - ">="
|
109
106
|
- !ruby/object:Gem::Version
|
110
|
-
hash: 3
|
111
107
|
segments:
|
112
108
|
- 0
|
113
109
|
version: "0"
|
114
110
|
requirements: []
|
115
111
|
|
116
112
|
rubyforge_project: retroactive_module_inclusion
|
117
|
-
rubygems_version: 1.
|
113
|
+
rubygems_version: 1.3.7
|
118
114
|
signing_key:
|
119
115
|
specification_version: 3
|
120
116
|
summary: This gem circumvents the "dynamic module include" (aka "double inclusion") problem, which is the fact that M.module_eval { include N } does not make the methods of module N available to modules and classes which had included module M beforehand, only to the ones that include it thereafter
|
metadata.gz.sig
CHANGED
Binary file
|