super_module 1.1.1 → 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.
- checksums.yaml +4 -4
- data/README.md +34 -87
- data/VERSION +1 -1
- data/examples/reddit-readers/banister/foo.rb +1 -2
- data/lib/super_module.rb +41 -26
- data/lib/super_module/v1.rb +37 -0
- data/lib/super_module/v1/module_body_method_call_recorder.rb +42 -0
- data/lib/super_module/v1/singleton_method_definition_store.rb +106 -0
- data/spec/lib/super_module_spec.rb +159 -145
- data/spec/support/baz.rb +1 -3
- data/spec/support/v1.rb +6 -0
- data/spec/support/v1/bar.rb +51 -0
- data/spec/support/v1/baz.rb +28 -0
- data/spec/support/v1/fake_active_model.rb +16 -0
- data/spec/support/v1/foo.rb +87 -0
- data/spec/support/v2.rb +6 -0
- data/spec/support/v2/bar.rb +52 -0
- data/spec/support/v2/baz.rb +27 -0
- data/spec/support/v2/fake_active_model.rb +14 -0
- data/spec/support/v2/foo.rb +87 -0
- data/spec/support/v2_alt.rb +6 -0
- data/spec/support/v2_alt/bar.rb +52 -0
- data/spec/support/v2_alt/baz.rb +27 -0
- data/spec/support/v2_alt/fake_active_model.rb +14 -0
- data/spec/support/v2_alt/foo.rb +87 -0
- data/super_module.gemspec +21 -6
- metadata +20 -5
- data/lib/super_module/module_body_method_call_recorder.rb +0 -40
- data/lib/super_module/singleton_method_definition_store.rb +0 -102
- data/spec/support/support.rb +0 -4
@@ -2,195 +2,209 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe SuperModule do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
class BazActiveRecord < FakeActiveRecord
|
18
|
-
include Baz
|
19
|
-
end
|
20
|
-
|
21
|
-
context "included by a module (Foo) that is included by a class (FooActiveRecord)" do
|
22
|
-
|
23
|
-
subject { FooActiveRecord }
|
24
|
-
|
25
|
-
it 'allows invoking class methods' do
|
26
|
-
expect(subject.validations).to include(['foo', {:presence => true}])
|
5
|
+
['V1',
|
6
|
+
'V2',
|
7
|
+
'V2Alt'
|
8
|
+
].each do |version|
|
9
|
+
Object.send(:remove_const, :SupportVersion) rescue nil
|
10
|
+
SupportVersion = Support.const_get(version)
|
11
|
+
|
12
|
+
Object.send(:remove_const, :FakeActiveRecord) rescue nil
|
13
|
+
class FakeActiveRecord
|
14
|
+
include SupportVersion::FakeActiveModel
|
27
15
|
end
|
28
16
|
|
29
|
-
|
30
|
-
|
17
|
+
Object.send(:remove_const, :FooActiveRecord) rescue nil
|
18
|
+
class FooActiveRecord < FakeActiveRecord
|
19
|
+
include SupportVersion::Foo
|
31
20
|
end
|
32
21
|
|
33
|
-
|
34
|
-
|
22
|
+
Object.send(:remove_const, :BarActiveRecord) rescue nil
|
23
|
+
class BarActiveRecord < FakeActiveRecord
|
24
|
+
include SupportVersion::Bar
|
35
25
|
end
|
36
26
|
|
37
|
-
|
38
|
-
|
27
|
+
Object.send(:remove_const, :BazActiveRecord) rescue nil
|
28
|
+
class BazActiveRecord < FakeActiveRecord
|
29
|
+
include SupportVersion::Baz
|
39
30
|
end
|
31
|
+
|
32
|
+
context version do
|
40
33
|
|
41
|
-
|
42
|
-
formatter = Proc.new {|value| "Block formatted #{value}"}
|
43
|
-
expect(subject.foo_block(&formatter)).to eq('Block formatted self.foo')
|
44
|
-
end
|
34
|
+
context "included by a module (Foo) that is included by a class (FooActiveRecord)" do
|
45
35
|
|
46
|
-
|
47
|
-
formatter = Proc.new {|value, param1| "Block formatted #{value} with #{param1}"}
|
48
|
-
expect(subject.foo_single_param_block('param1_value', &formatter)).to eq('Block formatted self.foo with param1_value')
|
49
|
-
end
|
36
|
+
subject { FooActiveRecord }
|
50
37
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
38
|
+
it 'allows invoking class methods' do
|
39
|
+
expect(subject.validations).to include(['foo', {:presence => true}])
|
40
|
+
end
|
55
41
|
|
56
|
-
|
57
|
-
|
58
|
-
|
42
|
+
it 'includes class method declared via "self.method_name"' do
|
43
|
+
expect(subject.foo).to eq('self.foo')
|
44
|
+
end
|
59
45
|
|
60
|
-
|
61
|
-
|
62
|
-
|
46
|
+
it 'includes class method declared via "self.method_name" taking a single parameter' do
|
47
|
+
expect(subject.foo_single_param('param1_value')).to eq('self.foo(param1_value)')
|
48
|
+
end
|
63
49
|
|
64
|
-
|
65
|
-
|
66
|
-
|
50
|
+
it 'includes class method declared via "self.method_name" taking multiple parameters' do
|
51
|
+
expect(subject.foo_multi_params('param1_value', 'param2_value', 'param3_value')).to eq('self.foo(param1_value,param2_value,param3_value)')
|
52
|
+
end
|
67
53
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
end
|
54
|
+
it 'includes class method declared via "self.method_name" taking a block' do
|
55
|
+
formatter = Proc.new {|value| "Block formatted #{value}"}
|
56
|
+
expect(subject.foo_block(&formatter)).to eq('Block formatted self.foo')
|
57
|
+
end
|
73
58
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
59
|
+
it 'includes class method declared via "self.method_name" taking a single paramter and a block' do
|
60
|
+
formatter = Proc.new {|value, param1| "Block formatted #{value} with #{param1}"}
|
61
|
+
expect(subject.foo_single_param_block('param1_value', &formatter)).to eq('Block formatted self.foo with param1_value')
|
62
|
+
end
|
79
63
|
|
80
|
-
|
81
|
-
|
82
|
-
|
64
|
+
it 'includes class method declared via "self.method_name" taking multiple paramters and a block' do
|
65
|
+
formatter = Proc.new {|value, param1, param2, param3| "Block formatted #{value} with #{param1},#{param2},#{param3}"}
|
66
|
+
expect(subject.foo_multi_params_block('param1_value', 'param2_value', 'param3_value', &formatter)).to eq('Block formatted self.foo with param1_value,param2_value,param3_value')
|
67
|
+
end
|
83
68
|
|
84
|
-
|
85
|
-
|
86
|
-
|
69
|
+
it 'includes class method declared via "self.method_name" on one line' do
|
70
|
+
expect(subject.foo_one_line).to eq('self.foo_one_line')
|
71
|
+
end
|
87
72
|
|
88
|
-
|
89
|
-
|
90
|
-
|
73
|
+
it 'includes class method declared via "class < self"' do
|
74
|
+
expect(subject.foo_class_self).to eq('self.foo_class_self')
|
75
|
+
end
|
91
76
|
|
92
|
-
|
93
|
-
|
94
|
-
|
77
|
+
it 'includes class method declared via "class < self" using define_method' do
|
78
|
+
expect(subject.foo_class_self_define_method).to eq('self.foo_class_self_define_method')
|
79
|
+
end
|
95
80
|
|
96
|
-
|
97
|
-
|
98
|
-
|
81
|
+
it 'includes private class method' do
|
82
|
+
expect{subject.foo_private}.to raise_error
|
83
|
+
expect(subject.private_methods.map(&:to_s)).to include('foo_private')
|
84
|
+
expect(subject.send(:foo_private)).to eq('self.foo_private')
|
85
|
+
end
|
99
86
|
|
100
|
-
|
101
|
-
|
87
|
+
it 'includes protected class method (declared using protected :method_name)' do
|
88
|
+
expect{subject.foo_protected}.to raise_error
|
89
|
+
expect(subject.protected_methods.map(&:to_s)).to include('foo_protected')
|
90
|
+
expect(subject.send(:foo_protected)).to eq('self.foo_protected')
|
91
|
+
end
|
102
92
|
|
103
|
-
|
104
|
-
|
93
|
+
it 'includes empty class method' do
|
94
|
+
expect(subject.empty).to eq(nil)
|
95
|
+
end
|
105
96
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
end
|
97
|
+
it 'includes empty class method with one empty line' do
|
98
|
+
expect(subject.empty_one_empty_line).to eq(nil)
|
99
|
+
end
|
110
100
|
|
111
|
-
|
101
|
+
it 'includes empty class method with comment' do
|
102
|
+
expect(subject.empty_with_comment).to eq(nil)
|
103
|
+
end
|
112
104
|
|
113
|
-
|
105
|
+
it 'includes empty class method one line definition' do
|
106
|
+
expect(subject.empty_one_line_definition).to eq(nil)
|
107
|
+
end
|
114
108
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
end
|
109
|
+
it 'includes empty class method one line definition with spaces' do
|
110
|
+
expect(subject.empty_one_line_definition_with_spaces).to eq(nil)
|
111
|
+
end
|
119
112
|
|
120
|
-
|
121
|
-
|
122
|
-
expect(subject.bar).to eq('self.bar')
|
123
|
-
end
|
113
|
+
it 'includes instance methods' do
|
114
|
+
instance = subject.new
|
124
115
|
|
125
|
-
|
126
|
-
|
116
|
+
expect(instance.foo).to eq('foo')
|
117
|
+
end
|
127
118
|
|
128
|
-
|
129
|
-
|
130
|
-
|
119
|
+
it 'provides class method self as the including base class as in the class method (meh)' do
|
120
|
+
expect(subject.meh).to eq(subject)
|
121
|
+
end
|
122
|
+
end
|
131
123
|
|
132
|
-
|
133
|
-
instance = subject.new
|
134
|
-
expect(instance.length).to eq(3)
|
135
|
-
end
|
124
|
+
context "included by a module (Foo) that is included by a second module (Bar) that is included by a class (BarActiveRecord)" do
|
136
125
|
|
137
|
-
|
138
|
-
expect(subject.barrable).to eq(true)
|
139
|
-
end
|
126
|
+
subject { BarActiveRecord }
|
140
127
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
allow(Time).to receive(:now).and_return(now + 100)
|
146
|
-
instance2 = subject.new
|
128
|
+
it 'allows invoking class methods' do
|
129
|
+
expect(subject.validations).to include(['foo', {:presence => true}])
|
130
|
+
expect(subject.validations).to include(['bar', {:presence => true}])
|
131
|
+
end
|
147
132
|
|
148
|
-
|
149
|
-
|
133
|
+
it 'includes class methods declared via "class << self"' do
|
134
|
+
expect(subject.foo).to eq('self.foo')
|
135
|
+
expect(subject.bar).to eq('self.bar')
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'includes instance methods' do
|
139
|
+
instance = subject.new
|
140
|
+
|
141
|
+
expect(instance.foo).to eq('foo')
|
142
|
+
expect(instance.bar).to eq('bar')
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'can include a basic module (Forwardable) into singleton class by placing in class << self' do
|
146
|
+
instance = subject.new
|
147
|
+
expect(instance.length).to eq(3)
|
148
|
+
end
|
149
|
+
|
150
|
+
it 'applies super module (Bar) class method invocation (make_barrable) on including class (BarActiveRecord), whereby the method that is defined in the same super module that declares it (Bar)' do
|
151
|
+
expect(subject.barrable).to eq(true)
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'can include a basic module (Comparable)' do
|
155
|
+
now = Time.now
|
156
|
+
allow(Time).to receive(:now).and_return(now)
|
157
|
+
instance = subject.new
|
158
|
+
allow(Time).to receive(:now).and_return(now + 100)
|
159
|
+
instance2 = subject.new
|
160
|
+
|
161
|
+
expect(instance2 > instance).to eq(true)
|
162
|
+
end
|
150
163
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
164
|
+
it 'provides class method self as the including base class as in the class method (meh)' do
|
165
|
+
expect(subject.meh).to eq(subject)
|
166
|
+
end
|
167
|
+
end
|
155
168
|
|
156
|
-
|
169
|
+
context "(with SuperModule.define alternate syntax in Baz) included by a module (Foo), included by another module (Bar), included by a third module (Baz) that is included by a class (BazActiveRecord)" do
|
157
170
|
|
158
|
-
|
171
|
+
subject { BazActiveRecord }
|
159
172
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
173
|
+
it 'allows invoking class methods' do
|
174
|
+
expect(subject.validations).to include(['foo', {:presence => true}])
|
175
|
+
expect(subject.validations).to include(['bar', {:presence => true}])
|
176
|
+
expect(subject.validations).to include(['baz', {:presence => true}])
|
177
|
+
end
|
165
178
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
179
|
+
it 'includes class methods declared via "class << self"' do
|
180
|
+
expect(subject.foo).to eq('self.foo')
|
181
|
+
expect(subject.bar).to eq('self.bar')
|
182
|
+
expect(subject.baz).to eq('self.baz')
|
183
|
+
end
|
171
184
|
|
172
|
-
|
173
|
-
|
185
|
+
it 'includes instance methods' do
|
186
|
+
instance = BazActiveRecord.new(100)
|
174
187
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
188
|
+
expect(instance.foo).to eq('foo')
|
189
|
+
expect(instance.bar).to eq('bar')
|
190
|
+
expect(instance.baz).to eq('baz')
|
191
|
+
end
|
179
192
|
|
180
|
-
|
181
|
-
|
182
|
-
|
193
|
+
it 'invokes singleton method (make_barrable) from super module' do
|
194
|
+
expect(subject.barrable).to eq(true)
|
195
|
+
end
|
183
196
|
|
184
|
-
|
185
|
-
|
186
|
-
|
197
|
+
it 'can override super module behavior (<=>)' do
|
198
|
+
instance = subject.new(50)
|
199
|
+
instance2 = subject.new(7)
|
187
200
|
|
188
|
-
|
189
|
-
|
201
|
+
expect(instance2 > instance).to eq(false)
|
202
|
+
end
|
190
203
|
|
191
|
-
|
192
|
-
|
204
|
+
it 'provides class method self as the including base class as in the class method (meh)' do
|
205
|
+
expect(subject.meh).to eq(subject)
|
206
|
+
end
|
207
|
+
end
|
193
208
|
end
|
194
209
|
end
|
195
|
-
|
196
210
|
end
|
data/spec/support/baz.rb
CHANGED
data/spec/support/v1.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Support::V1::Bar
|
4
|
+
include SuperModule
|
5
|
+
include Support::V1::Foo
|
6
|
+
include Comparable
|
7
|
+
validates 'bar', {:presence => true}
|
8
|
+
attr_reader :created_at
|
9
|
+
|
10
|
+
# Defines singleton methods via class << self to provide as a test case for SuperModule
|
11
|
+
class << self
|
12
|
+
include Forwardable
|
13
|
+
|
14
|
+
def barrable
|
15
|
+
@barrable
|
16
|
+
end
|
17
|
+
|
18
|
+
def barrable=(value)
|
19
|
+
@barrable = value
|
20
|
+
end
|
21
|
+
|
22
|
+
def make_barrable
|
23
|
+
self.barrable = true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
make_barrable
|
28
|
+
def_delegators :@bar, :length
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@bar = bar
|
32
|
+
@created_at = Time.now.to_f
|
33
|
+
end
|
34
|
+
|
35
|
+
def bar
|
36
|
+
'bar'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Defines singleton method via a form of eval (class_eval) to provide as a test case for SuperModule
|
40
|
+
class_eval do
|
41
|
+
def self.bar
|
42
|
+
'self.bar'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def <=>(other)
|
47
|
+
created_at <=> other.created_at
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Support::V1::Baz
|
2
|
+
include SuperModule
|
3
|
+
include Support::V1::Bar
|
4
|
+
make_barrable
|
5
|
+
validates 'baz', {:presence => true}
|
6
|
+
attr_reader :baz_factor
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def baz
|
10
|
+
'self.baz'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(baz_factor)
|
15
|
+
super()
|
16
|
+
@baz_factor = baz_factor
|
17
|
+
end
|
18
|
+
|
19
|
+
def baz
|
20
|
+
'baz'
|
21
|
+
end
|
22
|
+
|
23
|
+
def <=>(other)
|
24
|
+
baz_factor <=> other.baz_factor
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|