super_module 1.3.1 → 1.4.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/CHANGELOG.md +5 -0
- data/README.md +138 -57
- data/VERSION +1 -1
- data/lib/super_module/v1.rb +15 -1
- data/lib/super_module/v1/module_body_method_call_recorder.rb +1 -2
- data/lib/super_module/v1/singleton_method_definition_store.rb +11 -6
- data/spec/lib/super_module_spec.rb +72 -13
- data/super_module.gemspec +6 -6
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4faa73d0b49aef392b5dd1c26df10e4fc7ae5f9c528284503cd68df38c2381b
|
4
|
+
data.tar.gz: 9c48055a31b17ae2cdd554314cc3dbbf4d10e6eb2a93d4f21636663ce0f0a6c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37e9470e3ebe8977cf24425169ac7976304ba4d4eb1c0ca8069fa761813184d24e182235cc57ae01674f09189e22fe2681bd0b3a580e23aff50e323cc47ef435
|
7
|
+
data.tar.gz: 998e4a95be965413b20f49d2dad072a3458b61fd13e34eb33db601bd96ee3f7581c015ccb0e8872b8f3ef329a585dea902cccc165ac7921e58c503a6b2396892
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -94,7 +94,7 @@ end
|
|
94
94
|
```
|
95
95
|
By including `SuperModule` (following Ruby's basic convention of relying on a module), developers can directly add class method invocations and definitions inside the module's body, and [`SuperModule`](https://github.com/AndyObtiva/super_module) takes care of automatically mixing them into classes that include the module.
|
96
96
|
|
97
|
-
As a result, [SuperModule](https://rubygems.org/gems/super_module) collapses the difference between extending a super class and including a super module, thus encouraging developers to write simpler code while making better Object-Oriented Design decisions.
|
97
|
+
As a result, [SuperModule](https://rubygems.org/gems/super_module) collapses the difference between extending a super class and including a [super module](#glossary-and-definitions), thus encouraging developers to write simpler code while making better Object-Oriented Design decisions.
|
98
98
|
|
99
99
|
In other words, [SuperModule](https://rubygems.org/gems/super_module) furthers Ruby's goal of making programmers happy.
|
100
100
|
|
@@ -104,7 +104,7 @@ In other words, [SuperModule](https://rubygems.org/gems/super_module) furthers R
|
|
104
104
|
|
105
105
|
<b>Using [Bundler](http://bundler.io/)</b>
|
106
106
|
|
107
|
-
Add the following to Gemfile: <pre>gem 'super_module', '1.
|
107
|
+
Add the following to Gemfile: <pre>gem 'super_module', '1.4.0'</pre>
|
108
108
|
|
109
109
|
And run the following command: <pre>bundle</pre>
|
110
110
|
|
@@ -118,7 +118,7 @@ Run the following command: <pre>gem install super_module</pre>
|
|
118
118
|
|
119
119
|
Add the following at the top of your [Ruby](https://www.ruby-lang.org/en/) file: <pre>require 'super_module'</pre>
|
120
120
|
|
121
|
-
#### 2) Simply include SuperModule
|
121
|
+
#### 2) Simply include SuperModule at the top of your module definition before anything else.
|
122
122
|
|
123
123
|
```ruby
|
124
124
|
module UserIdentifiable
|
@@ -138,7 +138,9 @@ module UserIdentifiable
|
|
138
138
|
end
|
139
139
|
```
|
140
140
|
|
141
|
-
|
141
|
+
Note: Even if you are including another [super module](#glossary-and-definitions) in your new [super module](#glossary-and-definitions), you must `include SuperModule` at the top of your module definition before anything else.
|
142
|
+
|
143
|
+
#### 3) Mix newly defined module into a class or another [super module](#glossary-and-definitions)
|
142
144
|
|
143
145
|
```ruby
|
144
146
|
class ClubParticipation < ActiveRecord::Base
|
@@ -166,22 +168,21 @@ ClubParticipation.create(club_id: club.id, user_id: user.id).slug
|
|
166
168
|
CourseEnrollment.new(course_id: course.id).valid?
|
167
169
|
```
|
168
170
|
|
169
|
-
##
|
171
|
+
## Usage Notes
|
170
172
|
|
171
|
-
* SuperModule
|
172
|
-
*
|
173
|
-
*
|
174
|
-
* Singleton method: an instance method defined on an object's singleton class. Often used to refer to a class or module method defined on the [Ruby class object or module object singleton class](http://ruby-doc.com/docs/ProgrammingRuby/html/classes.html) via `def self.method_name(...)` or `class << self` enclosing `def method_name(...)`
|
175
|
-
* Class method invocation: Inherited Ruby class or module method invoked in the body of a class or module (e.g. <code>validates :username, presence: true</code>)
|
176
|
-
* Code-time: Time of writing code in a Ruby file as opposed to Run-time
|
177
|
-
* Run-time: Time of executing Ruby code
|
173
|
+
* SuperModule must always be included at the top of a module's body at [code-time](#glossary-and-definitions)
|
174
|
+
* SuperModule inclusion can be optionally followed by other basic or [super module](#glossary-and-definitions) inclusions
|
175
|
+
* A [super module](#glossary-and-definitions) can only be included in a class or another [super module](#glossary-and-definitions)
|
178
176
|
|
179
|
-
##
|
177
|
+
## Glossary and Definitions
|
180
178
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
179
|
+
* SuperModule: name of the library and Ruby module that provides functionality via mixin
|
180
|
+
* Super module: any Ruby module that mixes in SuperModule
|
181
|
+
* Singleton class: also known as the [metaclass](https://rubymonk.com/learning/books/4-ruby-primer-ascent/chapters/39-ruby-s-object-model/lessons/131-singleton-methods-and-metaclasses) or [eigenclass](http://eigenjoy.com/2008/05/29/railsconf08-meta-programming-ruby-for-fun-and-profit/), it is the object-instance-associated class copy available to every object in Ruby (e.g. every `Object.new` instance has a singleton class that is a copy of the `Object` class, which can house instance-specific behavior if needed)
|
182
|
+
* Singleton method: an instance method defined on an object's singleton class. Often used to refer to a class or module method defined on the [Ruby class object or module object singleton class](http://ruby-doc.com/docs/ProgrammingRuby/html/classes.html) via `def self.method_name(...)` or `class << self` enclosing `def method_name(...)`
|
183
|
+
* Class method invocation: Inherited Ruby class or module method invoked in the body of a class or module (e.g. <code>validates :username, presence: true</code>)
|
184
|
+
* Code-time: Time of writing code in a Ruby file as opposed to Run-time
|
185
|
+
* Run-time: Time of executing Ruby code
|
185
186
|
|
186
187
|
## IRB Example
|
187
188
|
|
@@ -192,25 +193,25 @@ require 'rubygems' # to be backwards compatible with Ruby 1.8.7
|
|
192
193
|
require 'super_module'
|
193
194
|
|
194
195
|
module RequiresAttributes
|
195
|
-
|
196
|
+
include SuperModule
|
196
197
|
|
197
|
-
|
198
|
-
|
199
|
-
|
198
|
+
def self.requires(*attributes)
|
199
|
+
attributes.each {|attribute| required_attributes << attribute}
|
200
|
+
end
|
200
201
|
|
201
|
-
|
202
|
-
|
203
|
-
|
202
|
+
def self.required_attributes
|
203
|
+
@required_attributes ||= []
|
204
|
+
end
|
204
205
|
|
205
|
-
|
206
|
-
|
207
|
-
|
206
|
+
def requirements_satisfied?
|
207
|
+
!!self.class.required_attributes.reduce(true) { |result, required_attribute| result && send(required_attribute) }
|
208
|
+
end
|
208
209
|
end
|
209
210
|
|
210
211
|
class MediaAuthorization
|
211
|
-
|
212
|
-
|
213
|
-
|
212
|
+
include RequiresAttributes
|
213
|
+
attr_accessor :user_id, :credit_card_id
|
214
|
+
requires :user_id, :credit_card_id
|
214
215
|
end
|
215
216
|
```
|
216
217
|
|
@@ -256,40 +257,121 @@ media_authorization.requirements_satisfied?
|
|
256
257
|
```
|
257
258
|
=> true
|
258
259
|
|
259
|
-
##
|
260
|
-
|
261
|
-
V2 has a much simpler algorithm than V1 that goes as follows:
|
260
|
+
## Overriding `self.included(base)`
|
262
261
|
|
263
|
-
|
264
|
-
2. Clone `SuperModule` and store in it the passed in `super_module_body` block
|
265
|
-
3. Assign the cloned `SuperModule` to a new constant as defined by name (e.g. 'Utilities::Printer') under a class, module, or the top-level Ruby scope
|
266
|
-
4. When calling `include` on the module later on, its stored super_module_body attribute is retrieved and run in the including class or module body via `class_eval`
|
262
|
+
With `SuperModule`, hooking into `self.included(base)` is no longer needed for most cases. Still, there rare exceptions where that might be needed to execute some meta-programmatic logic. Fortunately, `SuperModule` offers a mechanism to do so.
|
267
263
|
|
268
|
-
|
264
|
+
`SuperModule` relies on `self.included(base)`, so modules mixing it in must refrain from implementing `self.included(base)` directly (`SuperModule` will automatically prevent that by providing instructions should one attempt to do so).
|
269
265
|
|
270
|
-
|
266
|
+
In order for a [super module](#glossary-and-definitions) to hook into `self.included(base)` and add extra logic, it must do so via `super_module_included {|base| ... }` instead, which safely appends that logic to the work of `SuperModule` as well as other nested [super module](#glossary-and-definitions)s.
|
271
267
|
|
272
|
-
|
268
|
+
Example:
|
273
269
|
|
274
|
-
In very rare occasions when an including module needs to redefine <code>self.included(base)</code> for meta-programming purposes, you may do so at your own peril by first invoking <code>self.included_super_module(base)</code> like in this example:
|
275
270
|
```ruby
|
276
|
-
module
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
271
|
+
module V1::SummarizedActiveModel
|
272
|
+
include SuperModule
|
273
|
+
|
274
|
+
super_module_included do |klass|
|
275
|
+
if klass.name.split(/::/).last.start_with?('Fake')
|
276
|
+
klass.extend(FakeClassMethods1)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
module FakeClassMethods1
|
281
|
+
def fake_summary
|
282
|
+
'This is a fake summary.'
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
class << self
|
287
|
+
def self.validates(attribute, options = {})
|
288
|
+
validations << [attribute, options]
|
289
|
+
end
|
290
|
+
|
291
|
+
def self.validations
|
292
|
+
@validations ||= []
|
293
|
+
end
|
294
|
+
|
295
|
+
def summary
|
296
|
+
validations.flatten.map(&:to_s).join("/")
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
module V1::ExtraSummarizedActiveModel
|
302
|
+
include SuperModule
|
303
|
+
|
304
|
+
include ::V1::SummarizedActiveModel
|
305
|
+
|
306
|
+
super_module_included do |klass|
|
307
|
+
if klass.name.split(/::/).last.start_with?('Fake')
|
308
|
+
klass.extend(FakeClassMethods2)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
module FakeClassMethods2
|
313
|
+
def fake_extra
|
314
|
+
'This is fake extra.'
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
class << self
|
319
|
+
def extra
|
320
|
+
"This is extra."
|
287
321
|
end
|
322
|
+
end
|
288
323
|
end
|
324
|
+
|
325
|
+
class V1::SummarizedActiveRecord
|
326
|
+
include ::V1::SummarizedActiveModel
|
327
|
+
end
|
328
|
+
|
329
|
+
class V1::FakeSummarizedActiveRecord
|
330
|
+
include ::V1::SummarizedActiveModel
|
331
|
+
end
|
332
|
+
|
333
|
+
class V1::ExtraSummarizedActiveRecord
|
334
|
+
include ::V1::ExtraSummarizedActiveModel
|
335
|
+
end
|
336
|
+
|
337
|
+
class V1::FakeExtraSummarizedActiveRecord
|
338
|
+
include ::V1::ExtraSummarizedActiveModel
|
339
|
+
end
|
340
|
+
|
341
|
+
V1::SummarizedActiveRecord.validates 'foo', {:presence => true}
|
342
|
+
V1::SummarizedActiveRecord.validates 'bar', {:presence => true}
|
343
|
+
puts V1::SummarizedActiveRecord.summary
|
344
|
+
# prints 'foo/{:presence=>true}/bar/{:presence=>true}'
|
345
|
+
|
346
|
+
V1::FakeSummarizedActiveRecord.validates 'foo', {:presence => true}
|
347
|
+
V1::FakeSummarizedActiveRecord.validates 'bar', {:presence => true}
|
348
|
+
puts V1::FakeSummarizedActiveRecord.summary
|
349
|
+
# prints 'foo/{:presence=>true}/bar/{:presence=>true}'
|
350
|
+
puts V1::FakeSummarizedActiveRecord.fake_summary
|
351
|
+
# prints 'This is a fake summary.'
|
352
|
+
|
353
|
+
V1::ExtraSummarizedActiveRecord.validates 'foo', {:presence => true}
|
354
|
+
V1::ExtraSummarizedActiveRecord.validates 'bar', {:presence => true}
|
355
|
+
puts V1::ExtraSummarizedActiveRecord.summary
|
356
|
+
# prints 'foo/{:presence=>true}/bar/{:presence=>true}'
|
357
|
+
puts V1::ExtraSummarizedActiveRecord.extra
|
358
|
+
# prints 'This is extra.'
|
359
|
+
|
360
|
+
V1::FakeExtraSummarizedActiveRecord.validates 'foo', {:presence => true}
|
361
|
+
V1::FakeExtraSummarizedActiveRecord.validates 'bar', {:presence => true}
|
362
|
+
puts V1::FakeExtraSummarizedActiveRecord.summary
|
363
|
+
# prints 'foo/{:presence=>true}/bar/{:presence=>true}'
|
364
|
+
puts V1::FakeExtraSummarizedActiveRecord.fake_summary
|
365
|
+
# prints 'This is a fake summary.'
|
366
|
+
puts V1::FakeExtraSummarizedActiveRecord.extra
|
367
|
+
# prints 'This is extra.'
|
368
|
+
puts V1::FakeExtraSummarizedActiveRecord.fake_extra
|
369
|
+
# prints 'This is fake extra.'
|
289
370
|
```
|
290
|
-
This does not work for all cases (like multiple levels of super module nesting), and is not recommended, likely causing problems.
|
291
371
|
|
292
|
-
|
372
|
+
## Limitations
|
373
|
+
|
374
|
+
1) [SuperModule](https://rubygems.org/gems/super_module) by definition has been designed to be used only in the initial code declaration of a module, not later mixing or re-opening of a module.
|
293
375
|
|
294
376
|
## Change Log
|
295
377
|
|
@@ -309,10 +391,9 @@ The library is quite new and can use all the feedback and help it can get. So, p
|
|
309
391
|
|
310
392
|
## TODO
|
311
393
|
|
312
|
-
|
313
|
-
- Fix issue where a super module (declared with super_module) can get included in one class only where class methods work, but the next class that includes the super module does not have class methods work
|
394
|
+
None
|
314
395
|
|
315
396
|
## Copyright
|
316
397
|
|
317
|
-
Copyright (c) 2014-
|
398
|
+
Copyright (c) 2014-2020 Andy Maleh. See LICENSE.txt for
|
318
399
|
further details.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/lib/super_module/v1.rb
CHANGED
@@ -5,6 +5,7 @@ module SuperModule
|
|
5
5
|
module V1
|
6
6
|
class << self
|
7
7
|
def included(original_base)
|
8
|
+
# TODO maybe avoid class_eval by extending/including instead
|
8
9
|
original_base.class_eval do
|
9
10
|
extend SuperModule::V1::ModuleBodyMethodCallRecorder
|
10
11
|
extend SuperModule::V1::SingletonMethodDefinitionStore
|
@@ -27,8 +28,21 @@ module SuperModule
|
|
27
28
|
def included(base)
|
28
29
|
__define_super_module_singleton_methods(base)
|
29
30
|
__invoke_module_body_method_calls(base)
|
31
|
+
super_module_included.each {|block| block.call(base)}
|
32
|
+
if base.ancestors.include?(SuperModule) && !base.is_a?(Class)
|
33
|
+
super_module_included.reverse.each do |block|
|
34
|
+
base.super_module_included.unshift(block)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def super_module_included(&block)
|
40
|
+
if block_given?
|
41
|
+
super_module_included << block
|
42
|
+
else
|
43
|
+
@super_module_included_blocks ||= []
|
44
|
+
end
|
30
45
|
end
|
31
|
-
alias included_super_module included
|
32
46
|
end
|
33
47
|
end
|
34
48
|
end
|
@@ -4,7 +4,7 @@ module SuperModule
|
|
4
4
|
def __super_module_singleton_methods_excluded_from_call_recording
|
5
5
|
@__super_module_singleton_methods_excluded_from_call_recording ||= [
|
6
6
|
:__record_method_call,
|
7
|
-
:__method_signature
|
7
|
+
:__method_signature,
|
8
8
|
]
|
9
9
|
end
|
10
10
|
|
@@ -16,7 +16,6 @@ module SuperModule
|
|
16
16
|
"#{method_name}(#{args.to_a.map(&:to_s).join(",")})"
|
17
17
|
end
|
18
18
|
|
19
|
-
#TODO handle case of a method call being passed a block (e.g. validates do custom validator end )
|
20
19
|
def __record_method_call(method_name, *args, &block)
|
21
20
|
return if self.is_a?(Class)
|
22
21
|
__module_body_method_calls << [method_name, args, block]
|
@@ -27,10 +27,9 @@ module SuperModule
|
|
27
27
|
:dbg_puts, #debugger library friendly exclusion
|
28
28
|
:define,
|
29
29
|
:included,
|
30
|
-
:
|
30
|
+
:super_module_included,
|
31
31
|
:included_super_modules,
|
32
32
|
:singleton_method_added,
|
33
|
-
:super_module_body
|
34
33
|
]
|
35
34
|
end
|
36
35
|
|
@@ -70,11 +69,14 @@ module SuperModule
|
|
70
69
|
end
|
71
70
|
|
72
71
|
def __build_singleton_method_body_source(method_name)
|
73
|
-
|
74
|
-
|
72
|
+
the_method = self.method(method_name)
|
73
|
+
method_body = the_method.source
|
74
|
+
method_original_name = the_method.original_name
|
75
|
+
aliased = method_original_name != method_name
|
76
|
+
method_args = __singleton_method_args(method_original_name, method_body)
|
75
77
|
method_body = "def #{method_name}\n#{method_body}\nend" if method_args.nil?
|
76
78
|
class_self_method_def_enclosure = "class << self\n#{__singleton_method_access_level(method_name)}\ndef #{method_name}(#{method_args})\n#{__singleton_method_call_recorder(method_name, method_args)}\n"
|
77
|
-
method_body.sub(__singleton_method_definition_regex(
|
79
|
+
method_body.sub(__singleton_method_definition_regex(method_original_name), class_self_method_def_enclosure) + "\nend\n"
|
78
80
|
end
|
79
81
|
|
80
82
|
def __singleton_method_body(method_name)
|
@@ -90,6 +92,9 @@ module SuperModule
|
|
90
92
|
end
|
91
93
|
|
92
94
|
def singleton_method_added(method_name)
|
95
|
+
if method_name.to_s == 'included' && !method(method_name).source_location.first.include?('super_module/v1')
|
96
|
+
raise 'Do not implement "self.included(base)" hook for a super module! Use "super_module_included {|base| ... }" instead.'
|
97
|
+
end
|
93
98
|
unless __super_module_singleton_methods_excluded_from_base_definition.include?(method_name)
|
94
99
|
method_body = __singleton_method_body(method_name)
|
95
100
|
__super_module_singleton_methods << [method_name, method_body]
|
@@ -98,7 +103,7 @@ module SuperModule
|
|
98
103
|
end
|
99
104
|
|
100
105
|
def self.extended(base)
|
101
|
-
base.extend(SuperModule::ModuleBodyMethodCallRecorder) unless base.
|
106
|
+
base.extend(SuperModule::V1::ModuleBodyMethodCallRecorder) unless base.is_a?(SuperModule::V1::ModuleBodyMethodCallRecorder)
|
102
107
|
base.singleton_method_added(:__method_signature)
|
103
108
|
base.singleton_method_added(:__record_method_call)
|
104
109
|
end
|
@@ -19,28 +19,53 @@ end
|
|
19
19
|
module V1::SummarizedActiveModel
|
20
20
|
include SuperModule
|
21
21
|
|
22
|
-
|
23
|
-
included_super_module(klass)
|
22
|
+
super_module_included do |klass|
|
24
23
|
if klass.name.split(/::/).last.start_with?('Fake')
|
25
|
-
klass.extend(
|
24
|
+
klass.extend(FakeClassMethods1)
|
26
25
|
end
|
27
26
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
|
28
|
+
module FakeClassMethods1
|
29
|
+
def fake_summary
|
30
|
+
'This is a fake summary.'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
def validates(attribute, options)
|
36
|
+
super # test that singleton class inheritance works
|
37
|
+
end
|
38
|
+
|
39
|
+
def validations
|
40
|
+
super # test that singleton class inheritance works
|
41
|
+
end
|
42
|
+
|
43
|
+
def summary
|
44
|
+
validations.flatten.map(&:to_s).join("/")
|
45
|
+
end
|
31
46
|
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module V1::ExtraSummarizedActiveModel
|
50
|
+
include SuperModule
|
32
51
|
|
33
|
-
|
34
|
-
|
52
|
+
include ::V1::SummarizedActiveModel
|
53
|
+
|
54
|
+
super_module_included do |klass|
|
55
|
+
if klass.name.split(/::/).last.start_with?('Fake')
|
56
|
+
klass.extend(FakeClassMethods2)
|
57
|
+
end
|
35
58
|
end
|
36
59
|
|
37
|
-
|
38
|
-
|
60
|
+
module FakeClassMethods2
|
61
|
+
def fake_extra
|
62
|
+
'This is fake extra.'
|
63
|
+
end
|
39
64
|
end
|
40
65
|
|
41
|
-
|
42
|
-
def
|
43
|
-
|
66
|
+
class << self
|
67
|
+
def extra
|
68
|
+
"This is extra."
|
44
69
|
end
|
45
70
|
end
|
46
71
|
end
|
@@ -53,6 +78,14 @@ class V1::FakeSummarizedActiveRecord < V1::FakeActiveRecord
|
|
53
78
|
include ::V1::SummarizedActiveModel
|
54
79
|
end
|
55
80
|
|
81
|
+
class V1::ExtraSummarizedActiveRecord < V1::FakeActiveRecord
|
82
|
+
include ::V1::ExtraSummarizedActiveModel
|
83
|
+
end
|
84
|
+
|
85
|
+
class V1::FakeExtraSummarizedActiveRecord < V1::FakeActiveRecord
|
86
|
+
include ::V1::ExtraSummarizedActiveModel
|
87
|
+
end
|
88
|
+
|
56
89
|
describe SuperModule do
|
57
90
|
context V1 do
|
58
91
|
context "standalone module usage" do
|
@@ -62,6 +95,16 @@ describe SuperModule do
|
|
62
95
|
subject.validates 'foo', {:presence => true}
|
63
96
|
expect(subject.validations).to include(['foo', {:presence => true}])
|
64
97
|
end
|
98
|
+
|
99
|
+
it 'raises error if super module implements self.included(base)' do
|
100
|
+
expect do
|
101
|
+
module SomeSuperModule
|
102
|
+
include SuperModule
|
103
|
+
def self.included(base)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end.to raise_error('Do not implement "self.included(base)" hook for a super module! Use "super_module_included {|base| ... }" instead.')
|
107
|
+
end
|
65
108
|
end
|
66
109
|
|
67
110
|
context "included by a module (Foo) that is included by a class (FooActiveRecord)" do
|
@@ -252,6 +295,22 @@ describe SuperModule do
|
|
252
295
|
expect(V1::FakeSummarizedActiveRecord.summary).to eq('foo/{:presence=>true}/bar/{:presence=>true}')
|
253
296
|
expect(V1::FakeSummarizedActiveRecord.fake_summary).to eq('This is a fake summary.')
|
254
297
|
end
|
298
|
+
it 'returns extra' do
|
299
|
+
V1::ExtraSummarizedActiveRecord.validates 'foo', {:presence => true}
|
300
|
+
V1::ExtraSummarizedActiveRecord.validates 'bar', {:presence => true}
|
301
|
+
expect(V1::ExtraSummarizedActiveRecord.summary).to eq('foo/{:presence=>true}/bar/{:presence=>true}')
|
302
|
+
expect{V1::ExtraSummarizedActiveRecord.fake_summary}.to raise_error
|
303
|
+
expect(V1::ExtraSummarizedActiveRecord.extra).to eq('This is extra.')
|
304
|
+
expect{V1::ExtraSummarizedActiveRecord.fake_extra}.to raise_error
|
305
|
+
end
|
306
|
+
it 'returns fake extra' do
|
307
|
+
V1::FakeExtraSummarizedActiveRecord.validates 'foo', {:presence => true}
|
308
|
+
V1::FakeExtraSummarizedActiveRecord.validates 'bar', {:presence => true}
|
309
|
+
expect(V1::FakeExtraSummarizedActiveRecord.summary).to eq('foo/{:presence=>true}/bar/{:presence=>true}')
|
310
|
+
expect(V1::FakeExtraSummarizedActiveRecord.fake_summary).to eq('This is a fake summary.')
|
311
|
+
expect(V1::FakeExtraSummarizedActiveRecord.extra).to eq('This is extra.')
|
312
|
+
expect(V1::FakeExtraSummarizedActiveRecord.fake_extra).to eq('This is fake extra.')
|
313
|
+
end
|
255
314
|
end
|
256
315
|
end
|
257
316
|
end
|
data/super_module.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: super_module 1.
|
5
|
+
# stub: super_module 1.4.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "super_module".freeze
|
9
|
-
s.version = "1.
|
9
|
+
s.version = "1.4.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib".freeze]
|
13
13
|
s.authors = ["Andy Maleh".freeze]
|
14
|
-
s.date = "2020-
|
14
|
+
s.date = "2020-04-06"
|
15
15
|
s.description = "SuperModule allows defining class methods and method invocations the same way a super class does without using def included(base). This also succeeds ActiveSupport::Concern by offering lighter syntax".freeze
|
16
16
|
s.extra_rdoc_files = [
|
17
17
|
"CHANGELOG.md",
|
@@ -46,7 +46,7 @@ Gem::Specification.new do |s|
|
|
46
46
|
s.specification_version = 4
|
47
47
|
|
48
48
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
49
|
-
s.add_runtime_dependency(%q<method_source>.freeze, [">= 0.8.2"])
|
49
|
+
s.add_runtime_dependency(%q<method_source>.freeze, [">= 0.8.2", "< 1.1.0"])
|
50
50
|
s.add_development_dependency(%q<jeweler>.freeze, ["~> 2.3.0"])
|
51
51
|
s.add_development_dependency(%q<rdoc>.freeze, ["~> 4.2.0"])
|
52
52
|
s.add_development_dependency(%q<rspec>.freeze, ["~> 3.2.0"])
|
@@ -57,7 +57,7 @@ Gem::Specification.new do |s|
|
|
57
57
|
s.add_development_dependency(%q<tins>.freeze, ["~> 1.6.0"])
|
58
58
|
s.add_development_dependency(%q<term-ansicolor>.freeze, ["~> 1.3.2"])
|
59
59
|
else
|
60
|
-
s.add_dependency(%q<method_source>.freeze, [">= 0.8.2"])
|
60
|
+
s.add_dependency(%q<method_source>.freeze, [">= 0.8.2", "< 1.1.0"])
|
61
61
|
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.0"])
|
62
62
|
s.add_dependency(%q<rdoc>.freeze, ["~> 4.2.0"])
|
63
63
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.2.0"])
|
@@ -69,7 +69,7 @@ Gem::Specification.new do |s|
|
|
69
69
|
s.add_dependency(%q<term-ansicolor>.freeze, ["~> 1.3.2"])
|
70
70
|
end
|
71
71
|
else
|
72
|
-
s.add_dependency(%q<method_source>.freeze, [">= 0.8.2"])
|
72
|
+
s.add_dependency(%q<method_source>.freeze, [">= 0.8.2", "< 1.1.0"])
|
73
73
|
s.add_dependency(%q<jeweler>.freeze, ["~> 2.3.0"])
|
74
74
|
s.add_dependency(%q<rdoc>.freeze, ["~> 4.2.0"])
|
75
75
|
s.add_dependency(%q<rspec>.freeze, ["~> 3.2.0"])
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: super_module
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Maleh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: method_source
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 0.8.2
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.1.0
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 0.8.2
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.0
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: jeweler
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|