retroactive_module_inclusion 1.1.0 → 1.2.0
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/.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
|