super_module 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 80fcc01874eafdb2bf870cd3e06f55a135d830d1
4
- data.tar.gz: 7c9b6e1a8b5f16b19ff60755c2258b3e67da3484
2
+ SHA256:
3
+ metadata.gz: 70513ad566652aaf58d9da92fe22c598be383f3df25700a25245b0862e9b5580
4
+ data.tar.gz: 3002cb8ce8d0e853b1228f29f952034a7f9c2520c9635806860bde0959fe448b
5
5
  SHA512:
6
- metadata.gz: e0f9ac72e8ae4aaf4fee64d9aaae54a996de85d7e18b3f5de523bef20bc0b1362bca31bc3317888fe1de405468cc43ef117de47098792ffbb98642deb42de3d5
7
- data.tar.gz: 9e0dd6a4468c5719a99197a2136c4a9b5078009c2b78aa5fb0feb5674f322b2020648658fa279bd43caad6b68074f32eeb2e2836c23927d61c428dcd4985b9d3
6
+ metadata.gz: e20a35408bb4be154120310d932fe679d0ddc1224817886c1235cfdcb89750a6fd9655d9b0432e9f5441504122d714042da22527ac8ebb1316f3f3e6b1359021
7
+ data.tar.gz: 04db18d5c5991a8342d868a56aa8143b71b4775dd7f7f4a4cb919f9fb0c1073775602441fe41e0d19630bac5f690f52ce9c4cca5170d58bc3af1fafda87a862e
@@ -0,0 +1,35 @@
1
+ # Change Log
2
+
3
+ ## 1.3.0
4
+
5
+ - Dropped support for SuperModule 2 Beta syntax, reverting to V1 syntax as the default
6
+ - Added `included_super_module` method to allow modules to call it if they need to redefine `self.included` for meta-programming.
7
+
8
+ ## 1.2.2
9
+
10
+ * Relaxed dependency on `method_source` gem version
11
+
12
+ ## v2 Beta (v1.2.1)
13
+
14
+ * Standalone super module usage (e.g. direct class method invocation)
15
+
16
+ ## v2 Beta (v1.2.0)
17
+
18
+ * New `super_module(name)` syntax
19
+ * Much simpler implementation with guaranteed correctness and no performance hit
20
+ * Less memory footprint by not requiring method_source Ruby gem for v2 syntax
21
+ * Backwards compatibility with v1 syntax
22
+
23
+ ## v1.1.1
24
+
25
+ * Added support for private and protected methods
26
+ * Added many more RSpec test cases, including testing of empty and comment containing singleton methods
27
+
28
+ ## v1.1.0
29
+
30
+ * Brand new `self`-friendly algorithm that ensures true mixing of super module singleton methods into the including base class or module, thus always returning the actual base class or module `self` when invoking a super module inherited singleton method (thanks to [Banister](https://github.com/banister) for [reporting previous limitation on Reddit and providing suggestions](http://www.reddit.com/r/ruby/comments/30j66y/step_aside_activesupportconcern_supermodule_is/))
31
+ * New `included_super_modules` inherited singleton method that provides developer with a list of all included super modules similar to the Ruby `included_modules` method.
32
+ * No more use for method_missing (Thanks to Marc-André Lafortune for bringing up as a previous limitation in [AirPair article reviews](https://www.airpair.com/ruby/posts/step-aside-activesupportconcern-supermodule-is-the-new-sheriff-in-town))
33
+ * New dependency on [Banister](https://github.com/banister)'s [method_source](https://github.com/banister/method_source) library to have the self-friendly algorithm eval inherited class method sources into the including base class or module.
34
+ * Refactorings, including break-up of the original SuperModule into 3 modules in separate files
35
+ * More RSpec test coverage, including additional method definition scenarios, such as when adding dynamically via `class_eval` and `define_method`
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
- # <img src="https://raw.githubusercontent.com/AndyObtiva/super_module/master/SuperModule.jpg" alt="SuperModule" align="left" height="50" /> &nbsp; SuperModule 2 Beta
1
+ # <img src="https://raw.githubusercontent.com/AndyObtiva/super_module/master/SuperModule.jpg" alt="SuperModule" align="left" height="50" /> &nbsp; SuperModule 1.3
2
2
  [![Gem Version](https://badge.fury.io/rb/super_module.svg)](http://badge.fury.io/rb/super_module)
3
+ [![Build Status](https://api.travis-ci.org/AndyObtiva/super_module.svg?branch=master)](https://travis-ci.org/AndyObtiva/super_module)
3
4
  [![Coverage Status](https://coveralls.io/repos/AndyObtiva/super_module/badge.svg?branch=master)](https://coveralls.io/r/AndyObtiva/super_module?branch=master)
4
5
  [![Code Climate](https://codeclimate.com/github/AndyObtiva/super_module.svg)](https://codeclimate.com/github/AndyObtiva/super_module)
5
6
 
@@ -9,7 +10,9 @@ Ruby offers one workaround in the form of implementing the hook method [`Module.
9
10
 
10
11
  Another workaround is [`ActiveSupport::Concern`](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html), a Rails library that attempts to ease some of the boilerplate pain by offering a [DSL](http://www.infoq.com/news/2007/06/dsl-or-not) layer on top of [`Module.included(base)`](http://ruby-doc.org/core-2.2.1/Module.html#method-i-included). Unfortunately, while it helps improve readability a bit, it adds even more boilerplate idiom cruft, thus feeling no more than putting a band-aid on the problem.
11
12
 
12
- But do not fear, [SuperModule](https://rubygems.org/gems/super_module) comes to the rescue! By declaring your module as a `super_module`, it will simply behave as one would expect and automatically include class methods along with instance methods, without any further work needed.
13
+ But do not fear, [SuperModule](https://rubygems.org/gems/super_module) comes to the rescue! By declaring your module as a SuperModule, it will simply behave as one would expect and automatically include class methods along with instance methods, without any further work needed.
14
+
15
+ Used in my other project: [Glimmer](https://github.com/AndyObtiva/Glimmer) (Ruby Desktop GUI Library)
13
16
 
14
17
  ## Introductory Comparison
15
18
 
@@ -73,7 +76,8 @@ A step forward that addresses the boiler-plate repetitive code concern, but is o
73
76
  #### 3) [SuperModule](https://github.com/AndyObtiva/super_module)
74
77
 
75
78
  ```ruby
76
- super_module :UserIdentifiable do
79
+ module UserIdentifiable
80
+ include SuperModule
77
81
  include ActiveModel::Model
78
82
 
79
83
  belongs_to :user
@@ -88,28 +92,19 @@ super_module :UserIdentifiable do
88
92
  end
89
93
  end
90
94
  ```
91
- Using `super_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.
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.
92
96
 
93
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.
94
98
 
95
99
  In other words, [SuperModule](https://rubygems.org/gems/super_module) furthers Ruby's goal of making programmers happy.
96
100
 
97
- By the way, SuperModule 2 Beta supports an alternate syntax as well:
98
-
99
- ```ruby
100
- UserIdentifiable = super_module do
101
- end
102
- ```
103
-
104
-
105
-
106
101
  ## Instructions
107
102
 
108
103
  #### 1) Install and require gem
109
104
 
110
105
  <b>Using [Bundler](http://bundler.io/)</b>
111
106
 
112
- Add the following to Gemfile: <pre>gem 'super_module', '1.2.2'</pre>
107
+ Add the following to Gemfile: <pre>gem 'super_module', '1.3.0'</pre>
113
108
 
114
109
  And run the following command: <pre>bundle</pre>
115
110
 
@@ -123,10 +118,11 @@ Run the following command: <pre>gem install super_module</pre>
123
118
 
124
119
  Add the following at the top of your [Ruby](https://www.ruby-lang.org/en/) file: <pre>require 'super_module'</pre>
125
120
 
126
- #### 2) Call `super_module(name)` and pass it the super module body in a block
121
+ #### 2) Simply include SuperModule in your module (just like you would do any other Ruby module)
127
122
 
128
123
  ```ruby
129
- super_module :UserIdentifiable do
124
+ module UserIdentifiable
125
+ include SuperModule
130
126
  include ActiveModel::Model
131
127
 
132
128
  belongs_to :user
@@ -151,7 +147,8 @@ end
151
147
  class CourseEnrollment < ActiveRecord::Base
152
148
  include UserIdentifiable
153
149
  end
154
- super_module :Accountable do
150
+ module Accountable
151
+ include SuperModule
155
152
  include UserIdentifiable
156
153
  end
157
154
  class Activity < ActiveRecord::Base
@@ -194,7 +191,8 @@ Create a ruby file called super_module_irb_example.rb with the following content
194
191
  require 'rubygems' # to be backwards compatible with Ruby 1.8.7
195
192
  require 'super_module'
196
193
 
197
- super_module :RequiresAttributes do
194
+ module RequiresAttributes
195
+ include SuperModule
198
196
 
199
197
  def self.requires(*attributes)
200
198
  attributes.each {|attribute| required_attributes << attribute}
@@ -267,58 +265,35 @@ V2 has a much simpler algorithm than V1 that goes as follows:
267
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
268
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`
269
267
 
270
- ## Limitations and Caveats
268
+ ## Warnings
269
+
270
+ 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.
271
271
 
272
- * [SuperModule](https://rubygems.org/gems/super_module) has been designed to be used only in the initial code definition of a module (not supporting later re-opening of the module.)
272
+ 2) Given [SuperModule](https://rubygems.org/gems/super_module)'s implementation relies on `self.included(base)`, sub-modules must not hook into it.
273
273
 
274
- * Given [SuperModule](https://rubygems.org/gems/super_module)'s implementation relies on `self.included(base)`, if an including super module (or a super module including another super module) must hook into <code>self.included(base)</code> for meta-programming cases that require it, such as conditional `include` statements or method definitions, it would have to alias <code>self.included(base)</code> and then invoke the aliased version in every super module that needs it like in this example:
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
275
  ```ruby
276
- super_module :AdminIdentifiable do
276
+ module AdminIdentifiable
277
+ include SuperModule
277
278
  include UserIdentifiable
278
279
 
279
280
  class << self
280
- alias included_super_module included
281
281
  def included(base)
282
282
  included_super_module(base)
283
- # do some extra work
283
+ # do some extra rare meta-programming work
284
284
  # like conditional inclusion of other modules
285
285
  # or conditional definition of methods
286
286
  end
287
287
  end
288
288
  end
289
289
  ```
290
- In the future, [SuperModule](https://rubygems.org/gems/super_module) could perhaps provide robust built-in facilities for allowing super modules to easily hook into <code>self.included(base)</code> without interfering with [SuperModule](https://rubygems.org/gems/super_module) behavior.
290
+ This does not work for all cases (like multiple levels of super module nesting), and is not recommended, likely causing problems.
291
291
 
292
- ## What's New?
292
+ Avoid hooking into `self.included(base)` at all costs.
293
293
 
294
- ### v2 Beta (v1.2.2)
294
+ ## Change Log
295
295
 
296
- * Relaxed dependency on `method_source` gem version
297
-
298
- ### v2 Beta (v1.2.1)
299
-
300
- * Standalone super module usage (e.g. direct class method invocation)
301
-
302
- ### v2 Beta (v1.2.0)
303
-
304
- * New `super_module(name)` syntax
305
- * Much simpler implementation with guaranteed correctness and no performance hit
306
- * Less memory footprint by not requiring method_source Ruby gem for v2 syntax
307
- * Backwards compatibility with v1 syntax
308
-
309
- ### v1.1.1
310
-
311
- * Added support for private and protected methods
312
- * Added many more RSpec test cases, including testing of empty and comment containing singleton methods
313
-
314
- ### v1.1.0
315
-
316
- * Brand new `self`-friendly algorithm that ensures true mixing of super module singleton methods into the including base class or module, thus always returning the actual base class or module `self` when invoking a super module inherited singleton method (thanks to [Banister](https://github.com/banister) for [reporting previous limitation on Reddit and providing suggestions](http://www.reddit.com/r/ruby/comments/30j66y/step_aside_activesupportconcern_supermodule_is/))
317
- * New `included_super_modules` inherited singleton method that provides developer with a list of all included super modules similar to the Ruby `included_modules` method.
318
- * No more use for method_missing (Thanks to Marc-André Lafortune for bringing up as a previous limitation in [AirPair article reviews](https://www.airpair.com/ruby/posts/step-aside-activesupportconcern-supermodule-is-the-new-sheriff-in-town))
319
- * New dependency on [Banister](https://github.com/banister)'s [method_source](https://github.com/banister/method_source) library to have the self-friendly algorithm eval inherited class method sources into the including base class or module.
320
- * Refactorings, including break-up of the original SuperModule into 3 modules in separate files
321
- * More RSpec test coverage, including additional method definition scenarios, such as when adding dynamically via `class_eval` and `define_method`
296
+ [CHANGELOG.md](https://raw.githubusercontent.com/AndyObtiva/super_module/master/CHANGELOG.md)
322
297
 
323
298
  ## Feedback and Contribution
324
299
 
@@ -332,6 +307,11 @@ The library is quite new and can use all the feedback and help it can get. So, p
332
307
  * 2015-03-27 - [AirPair](http://www.airpair.com) Article: [Step aside ActiveSupport::Concern. SuperModule is the new sheriff in town!](https://www.airpair.com/ruby/posts/step-aside-activesupportconcern-supermodule-is-the-new-sheriff-in-town)
333
308
  * 2014-03-27 - [Code Painter](http://andymaleh.blogspot.com) Blog Post: [Ruby SuperModule Comes To The Rescue!!](http://andymaleh.blogspot.ca/2014/03/ruby-supermodule-comes-to-rescue.html)
334
309
 
310
+ ## TODO
311
+
312
+ - Fix issue where class methods cannot get called from super_module directly (when used with "CONSTANT = super_module do" approach)
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
314
+
335
315
  ## Copyright
336
316
 
337
317
  Copyright (c) 2014-2016 Andy Maleh. See LICENSE.txt for
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.2.2
1
+ 1.3.0
@@ -8,50 +8,12 @@
8
8
 
9
9
  # Avoiding require_relative for backwards compatibility with Ruby 1.8.7
10
10
 
11
+ require_relative 'super_module/v1'
12
+
11
13
  module SuperModule
12
14
  class << self
13
- V1_LIBRARY = File.expand_path(File.join(File.dirname(__FILE__), 'super_module', 'v1'))
14
-
15
- attr_accessor :super_module_body
16
-
17
- def define(&super_module_body)
18
- clone.tap { |super_module| super_module.super_module_body = super_module_body }
19
- end
20
-
21
15
  def included(original_base)
22
- if super_module_body
23
- original_base.class_eval(&super_module_body)
24
- else
25
- require V1_LIBRARY
26
- original_base.send(:include, SuperModule::V1)
27
- end
28
- end
29
-
30
- def __super_module_parent(name, ancestor)
31
- name_tokens = name.to_s.split('::')
32
- name_token_count = name_tokens.size
33
- if name_token_count == 1
34
- ancestor
35
- else
36
- top_ancestor = ancestor.const_get(name_tokens.first)
37
- sub_module_name = name_tokens[1, name_token_count].join('::')
38
- __super_module_parent(sub_module_name, top_ancestor)
39
- end
40
- end
41
-
42
- end
43
-
44
- end
45
-
46
- def super_module(name=nil, &super_module_body)
47
- initial_ancestor = self.class == Object ? Object : self
48
- SuperModule.define(&super_module_body).tap do |new_super_module|
49
- if name
50
- parent = SuperModule.__super_module_parent(name, initial_ancestor)
51
- module_name = name.to_s.split('::').last
52
- parent.const_set(module_name, new_super_module)
53
- super_module_body = new_super_module.super_module_body
54
- new_super_module.class_eval(&super_module_body)
16
+ original_base.send(:include, SuperModule::V1)
55
17
  end
56
18
  end
57
19
  end
@@ -28,10 +28,10 @@ module SuperModule
28
28
  __define_super_module_singleton_methods(base)
29
29
  __invoke_module_body_method_calls(base)
30
30
  end
31
+ alias included_super_module included
31
32
  end
32
33
  end
33
34
  end
34
35
  end
35
36
  end
36
37
  end
37
-
@@ -26,7 +26,8 @@ module SuperModule
26
26
  :dbg_print, #debugger library friendly exclusion
27
27
  :dbg_puts, #debugger library friendly exclusion
28
28
  :define,
29
- :included,
29
+ :included,
30
+ :included_super_module,
30
31
  :included_super_modules,
31
32
  :singleton_method_added,
32
33
  :super_module_body
@@ -36,7 +37,7 @@ module SuperModule
36
37
  def __super_module_singleton_methods
37
38
  @__super_module_singleton_methods ||= []
38
39
  end
39
-
40
+
40
41
  def __singleton_method_body_for(super_module, method_name)
41
42
  super_module.__super_module_singleton_methods.detect {|sm_method_name, sm_method_body| sm_method_name == method_name}[1]
42
43
  end
@@ -78,7 +79,7 @@ module SuperModule
78
79
 
79
80
  def __singleton_method_body(method_name)
80
81
  super_module_having_method = __super_module_having_method(method_name)
81
- super_module_having_method ? __singleton_method_body_for(super_module_having_method, method_name) : __build_singleton_method_body_source(method_name)
82
+ super_module_having_method ? __singleton_method_body_for(super_module_having_method, method_name) : __build_singleton_method_body_source(method_name)
82
83
  end
83
84
 
84
85
  def __overwrite_singleton_method_from_current_super_module(method_name, method_body)
@@ -91,7 +92,7 @@ module SuperModule
91
92
  def singleton_method_added(method_name)
92
93
  unless __super_module_singleton_methods_excluded_from_base_definition.include?(method_name)
93
94
  method_body = __singleton_method_body(method_name)
94
- __super_module_singleton_methods << [method_name, method_body]
95
+ __super_module_singleton_methods << [method_name, method_body]
95
96
  __overwrite_singleton_method_from_current_super_module(method_name, method_body)
96
97
  end
97
98
  end
@@ -1,219 +1,256 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe SuperModule do
3
+ class V1::FakeActiveRecord
4
+ include ::V1::FakeActiveModel
5
+ end
4
6
 
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
15
- end
7
+ class V1::FooActiveRecord < V1::FakeActiveRecord
8
+ include ::V1::Foo
9
+ end
16
10
 
17
- Object.send(:remove_const, :FooActiveRecord) rescue nil
18
- class FooActiveRecord < FakeActiveRecord
19
- include SupportVersion::Foo
20
- end
11
+ class V1::BarActiveRecord < V1::FakeActiveRecord
12
+ include ::V1::Bar
13
+ end
14
+
15
+ class V1::BazActiveRecord < V1::FakeActiveRecord
16
+ include ::V1::Baz
17
+ end
18
+
19
+ module V1::SummarizedActiveModel
20
+ include SuperModule
21
21
 
22
- Object.send(:remove_const, :BarActiveRecord) rescue nil
23
- class BarActiveRecord < FakeActiveRecord
24
- include SupportVersion::Bar
22
+ def self.included(klass)
23
+ included_super_module(klass)
24
+ if klass.name.split(/::/).last.start_with?('Fake')
25
+ klass.extend(FakeClassMethods)
25
26
  end
27
+ end
28
+
29
+ def self.validates(attribute, options)
30
+ super # test that singleton class inheritance works
31
+ end
32
+
33
+ def self.validations
34
+ super # test that singleton class inheritance works
35
+ end
36
+
37
+ def self.summary
38
+ validations.flatten.map(&:to_s).join("/")
39
+ end
26
40
 
27
- Object.send(:remove_const, :BazActiveRecord) rescue nil
28
- class BazActiveRecord < FakeActiveRecord
29
- include SupportVersion::Baz
41
+ module FakeClassMethods
42
+ def fake_summary
43
+ 'This is a fake summary.'
30
44
  end
45
+ end
46
+ end
31
47
 
32
- context version do
48
+ class V1::SummarizedActiveRecord < V1::FakeActiveRecord
49
+ include ::V1::SummarizedActiveModel
50
+ end
33
51
 
34
- context "standalone module usage" do
35
- subject { Support::V2::FakeActiveModel }
52
+ class V1::FakeSummarizedActiveRecord < V1::FakeActiveRecord
53
+ include ::V1::SummarizedActiveModel
54
+ end
36
55
 
37
- it 'allows invoking class methods' do
38
- subject.validates 'foo', {:presence => true}
39
- expect(subject.validations).to include(['foo', {:presence => true}])
40
- end
56
+ describe SuperModule do
57
+ context V1 do
58
+ context "standalone module usage" do
59
+ subject { V1::FakeActiveModel }
41
60
 
61
+ it 'allows invoking class methods' do
62
+ subject.validates 'foo', {:presence => true}
63
+ expect(subject.validations).to include(['foo', {:presence => true}])
42
64
  end
65
+ end
43
66
 
44
- context "included by a module (Foo) that is included by a class (FooActiveRecord)" do
67
+ context "included by a module (Foo) that is included by a class (FooActiveRecord)" do
45
68
 
46
- subject { FooActiveRecord }
69
+ subject { V1::FooActiveRecord }
47
70
 
48
- it 'allows invoking class methods' do
49
- expect(subject.validations).to include(['foo', {:presence => true}])
50
- end
71
+ it 'allows invoking class methods' do
72
+ expect(subject.validations).to include(['foo', {:presence => true}])
73
+ end
51
74
 
52
- it 'includes class method declared via "self.method_name"' do
53
- expect(subject.foo).to eq('self.foo')
54
- end
75
+ it 'includes class method declared via "self.method_name"' do
76
+ expect(subject.foo).to eq('self.foo')
77
+ end
55
78
 
56
- it 'includes class method declared via "self.method_name" taking a single parameter' do
57
- expect(subject.foo_single_param('param1_value')).to eq('self.foo(param1_value)')
58
- end
79
+ it 'includes class method declared via "self.method_name" taking a single parameter' do
80
+ expect(subject.foo_single_param('param1_value')).to eq('self.foo(param1_value)')
81
+ end
59
82
 
60
- it 'includes class method declared via "self.method_name" taking multiple parameters' do
61
- expect(subject.foo_multi_params('param1_value', 'param2_value', 'param3_value')).to eq('self.foo(param1_value,param2_value,param3_value)')
62
- end
83
+ it 'includes class method declared via "self.method_name" taking multiple parameters' do
84
+ expect(subject.foo_multi_params('param1_value', 'param2_value', 'param3_value')).to eq('self.foo(param1_value,param2_value,param3_value)')
85
+ end
63
86
 
64
- it 'includes class method declared via "self.method_name" taking a block' do
65
- formatter = Proc.new {|value| "Block formatted #{value}"}
66
- expect(subject.foo_block(&formatter)).to eq('Block formatted self.foo')
67
- end
87
+ it 'includes class method declared via "self.method_name" taking a block' do
88
+ formatter = Proc.new {|value| "Block formatted #{value}"}
89
+ expect(subject.foo_block(&formatter)).to eq('Block formatted self.foo')
90
+ end
68
91
 
69
- it 'includes class method declared via "self.method_name" taking a single paramter and a block' do
70
- formatter = Proc.new {|value, param1| "Block formatted #{value} with #{param1}"}
71
- expect(subject.foo_single_param_block('param1_value', &formatter)).to eq('Block formatted self.foo with param1_value')
72
- end
92
+ it 'includes class method declared via "self.method_name" taking a single paramter and a block' do
93
+ formatter = Proc.new {|value, param1| "Block formatted #{value} with #{param1}"}
94
+ expect(subject.foo_single_param_block('param1_value', &formatter)).to eq('Block formatted self.foo with param1_value')
95
+ end
73
96
 
74
- it 'includes class method declared via "self.method_name" taking multiple paramters and a block' do
75
- formatter = Proc.new {|value, param1, param2, param3| "Block formatted #{value} with #{param1},#{param2},#{param3}"}
76
- 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')
77
- end
97
+ it 'includes class method declared via "self.method_name" taking multiple paramters and a block' do
98
+ formatter = Proc.new {|value, param1, param2, param3| "Block formatted #{value} with #{param1},#{param2},#{param3}"}
99
+ 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')
100
+ end
78
101
 
79
- it 'includes class method declared via "self.method_name" on one line' do
80
- expect(subject.foo_one_line).to eq('self.foo_one_line')
81
- end
102
+ it 'includes class method declared via "self.method_name" on one line' do
103
+ expect(subject.foo_one_line).to eq('self.foo_one_line')
104
+ end
82
105
 
83
- it 'includes class method declared via "class < self"' do
84
- expect(subject.foo_class_self).to eq('self.foo_class_self')
85
- end
106
+ it 'includes class method declared via "class < self"' do
107
+ expect(subject.foo_class_self).to eq('self.foo_class_self')
108
+ end
86
109
 
87
- it 'includes class method declared via "class < self" using define_method' do
88
- expect(subject.foo_class_self_define_method).to eq('self.foo_class_self_define_method')
89
- end
110
+ it 'includes class method declared via "class < self" using define_method' do
111
+ expect(subject.foo_class_self_define_method).to eq('self.foo_class_self_define_method')
112
+ end
90
113
 
91
- it 'includes private class method' do
92
- expect{subject.foo_private}.to raise_error
93
- expect(subject.private_methods.map(&:to_s)).to include('foo_private')
94
- expect(subject.send(:foo_private)).to eq('self.foo_private')
95
- end
114
+ it 'includes private class method' do
115
+ expect{subject.foo_private}.to raise_error
116
+ expect(subject.private_methods.map(&:to_s)).to include('foo_private')
117
+ expect(subject.send(:foo_private)).to eq('self.foo_private')
118
+ end
96
119
 
97
- it 'includes protected class method (declared using protected :method_name)' do
98
- expect{subject.foo_protected}.to raise_error
99
- expect(subject.protected_methods.map(&:to_s)).to include('foo_protected')
100
- expect(subject.send(:foo_protected)).to eq('self.foo_protected')
101
- end
120
+ it 'includes protected class method (declared using protected :method_name)' do
121
+ expect{subject.foo_protected}.to raise_error
122
+ expect(subject.protected_methods.map(&:to_s)).to include('foo_protected')
123
+ expect(subject.send(:foo_protected)).to eq('self.foo_protected')
124
+ end
102
125
 
103
- it 'includes empty class method' do
104
- expect(subject.empty).to eq(nil)
105
- end
126
+ it 'includes empty class method' do
127
+ expect(subject.empty).to eq(nil)
128
+ end
106
129
 
107
- it 'includes empty class method with one empty line' do
108
- expect(subject.empty_one_empty_line).to eq(nil)
109
- end
130
+ it 'includes empty class method with one empty line' do
131
+ expect(subject.empty_one_empty_line).to eq(nil)
132
+ end
110
133
 
111
- it 'includes empty class method with comment' do
112
- expect(subject.empty_with_comment).to eq(nil)
113
- end
134
+ it 'includes empty class method with comment' do
135
+ expect(subject.empty_with_comment).to eq(nil)
136
+ end
114
137
 
115
- it 'includes empty class method one line definition' do
116
- expect(subject.empty_one_line_definition).to eq(nil)
117
- end
138
+ it 'includes empty class method one line definition' do
139
+ expect(subject.empty_one_line_definition).to eq(nil)
140
+ end
118
141
 
119
- it 'includes empty class method one line definition with spaces' do
120
- expect(subject.empty_one_line_definition_with_spaces).to eq(nil)
121
- end
142
+ it 'includes empty class method one line definition with spaces' do
143
+ expect(subject.empty_one_line_definition_with_spaces).to eq(nil)
144
+ end
122
145
 
123
- it 'includes instance methods' do
124
- instance = subject.new
146
+ it 'includes instance methods' do
147
+ instance = subject.new
125
148
 
126
- expect(instance.foo).to eq('foo')
127
- end
149
+ expect(instance.foo).to eq('foo')
150
+ end
128
151
 
129
- it 'provides class method self as the including base class as in the class method (meh)' do
130
- expect(subject.meh).to eq(subject)
131
- end
152
+ it 'provides class method self as the including base class as in the class method (meh)' do
153
+ expect(subject.meh).to eq(subject)
132
154
  end
155
+ end
133
156
 
134
- context "included by a module (Foo) that is included by a second module (Bar) that is included by a class (BarActiveRecord)" do
157
+ context "included by a module (Foo) that is included by a second module (Bar) that is included by a class (BarActiveRecord)" do
135
158
 
136
- subject { BarActiveRecord }
159
+ subject { V1::BarActiveRecord }
137
160
 
138
- it 'allows invoking class methods' do
139
- expect(subject.validations).to include(['foo', {:presence => true}])
140
- expect(subject.validations).to include(['bar', {:presence => true}])
141
- end
161
+ it 'allows invoking class methods' do
162
+ expect(subject.validations).to include(['foo', {:presence => true}])
163
+ expect(subject.validations).to include(['bar', {:presence => true}])
164
+ end
142
165
 
143
- it 'includes class methods declared via "class << self"' do
144
- expect(subject.foo).to eq('self.foo')
145
- expect(subject.bar).to eq('self.bar')
146
- end
166
+ it 'includes class methods declared via "class << self"' do
167
+ expect(subject.foo).to eq('self.foo')
168
+ expect(subject.bar).to eq('self.bar')
169
+ end
147
170
 
148
- it 'includes instance methods' do
149
- instance = subject.new
171
+ it 'includes instance methods' do
172
+ instance = subject.new
150
173
 
151
- expect(instance.foo).to eq('foo')
152
- expect(instance.bar).to eq('bar')
153
- end
174
+ expect(instance.foo).to eq('foo')
175
+ expect(instance.bar).to eq('bar')
176
+ end
154
177
 
155
- it 'can include a basic module (Forwardable) into singleton class by placing in class << self' do
156
- instance = subject.new
157
- expect(instance.length).to eq(3)
158
- end
178
+ it 'can include a basic module (Forwardable) into singleton class by placing in class << self' do
179
+ instance = subject.new
180
+ expect(instance.length).to eq(3)
181
+ end
159
182
 
160
- 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
161
- expect(subject.barrable).to eq(true)
162
- end
183
+ 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
184
+ expect(subject.barrable).to eq(true)
185
+ end
163
186
 
164
- it 'can include a basic module (Comparable)' do
165
- now = Time.now
166
- allow(Time).to receive(:now).and_return(now)
167
- instance = subject.new
168
- allow(Time).to receive(:now).and_return(now + 100)
169
- instance2 = subject.new
187
+ it 'can include a basic module (Comparable)' do
188
+ now = Time.now
189
+ allow(Time).to receive(:now).and_return(now)
190
+ instance = subject.new
191
+ allow(Time).to receive(:now).and_return(now + 100)
192
+ instance2 = subject.new
170
193
 
171
- expect(instance2 > instance).to eq(true)
172
- end
194
+ expect(instance2 > instance).to eq(true)
195
+ end
173
196
 
174
- it 'provides class method self as the including base class as in the class method (meh)' do
175
- expect(subject.meh).to eq(subject)
176
- end
197
+ it 'provides class method self as the including base class as in the class method (meh)' do
198
+ expect(subject.meh).to eq(subject)
177
199
  end
200
+ end
201
+
202
+ 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
178
203
 
179
- 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
204
+ subject { V1::BazActiveRecord }
180
205
 
181
- subject { BazActiveRecord }
206
+ it 'allows invoking class methods' do
207
+ expect(subject.validations).to include(['foo', {:presence => true}])
208
+ expect(subject.validations).to include(['bar', {:presence => true}])
209
+ expect(subject.validations).to include(['baz', {:presence => true}])
210
+ end
182
211
 
183
- it 'allows invoking class methods' do
184
- expect(subject.validations).to include(['foo', {:presence => true}])
185
- expect(subject.validations).to include(['bar', {:presence => true}])
186
- expect(subject.validations).to include(['baz', {:presence => true}])
187
- end
212
+ it 'includes class methods declared via "class << self"' do
213
+ expect(subject.foo).to eq('self.foo')
214
+ expect(subject.bar).to eq('self.bar')
215
+ expect(subject.baz).to eq('self.baz')
216
+ end
188
217
 
189
- it 'includes class methods declared via "class << self"' do
190
- expect(subject.foo).to eq('self.foo')
191
- expect(subject.bar).to eq('self.bar')
192
- expect(subject.baz).to eq('self.baz')
193
- end
218
+ it 'includes instance methods' do
219
+ instance = subject.new(100)
194
220
 
195
- it 'includes instance methods' do
196
- instance = BazActiveRecord.new(100)
221
+ expect(instance.foo).to eq('foo')
222
+ expect(instance.bar).to eq('bar')
223
+ expect(instance.baz).to eq('baz')
224
+ end
197
225
 
198
- expect(instance.foo).to eq('foo')
199
- expect(instance.bar).to eq('bar')
200
- expect(instance.baz).to eq('baz')
201
- end
226
+ it 'invokes singleton method (make_barrable) from super module' do
227
+ expect(subject.barrable).to eq(true)
228
+ end
202
229
 
203
- it 'invokes singleton method (make_barrable) from super module' do
204
- expect(subject.barrable).to eq(true)
205
- end
230
+ it 'can override super module behavior (<=>)' do
231
+ instance = subject.new(50)
232
+ instance2 = subject.new(7)
206
233
 
207
- it 'can override super module behavior (<=>)' do
208
- instance = subject.new(50)
209
- instance2 = subject.new(7)
234
+ expect(instance2 > instance).to eq(false)
235
+ end
210
236
 
211
- expect(instance2 > instance).to eq(false)
212
- end
237
+ it 'provides class method self as the including base class as in the class method (meh)' do
238
+ expect(subject.meh).to eq(subject)
239
+ end
240
+ end
213
241
 
214
- it 'provides class method self as the including base class as in the class method (meh)' do
215
- expect(subject.meh).to eq(subject)
216
- end
242
+ context 'meta-programming included' do
243
+ it 'returns summary' do
244
+ V1::SummarizedActiveRecord.validates 'foo', {:presence => true}
245
+ V1::SummarizedActiveRecord.validates 'bar', {:presence => true}
246
+ expect(V1::SummarizedActiveRecord.summary).to eq('foo/{:presence=>true}/bar/{:presence=>true}')
247
+ expect{V1::SummarizedActiveRecord.fake_summary}.to raise_error
248
+ end
249
+ it 'returns fake summary' do
250
+ V1::FakeSummarizedActiveRecord.validates 'foo', {:presence => true}
251
+ V1::FakeSummarizedActiveRecord.validates 'bar', {:presence => true}
252
+ expect(V1::FakeSummarizedActiveRecord.summary).to eq('foo/{:presence=>true}/bar/{:presence=>true}')
253
+ expect(V1::FakeSummarizedActiveRecord.fake_summary).to eq('This is a fake summary.')
217
254
  end
218
255
  end
219
256
  end