extensible 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 77a0368abe54f48d7dce5ffbbea97d6b932578d3
4
+ data.tar.gz: f297fa02fd05537287e1473f5758f25041df0c85
5
+ SHA512:
6
+ metadata.gz: cc7f44628796c89d5ce517d0606542189681d6213232d1be546832da17b7c9a1cb869f48e1d948e40372442fa14c80a65ef9952a30a57b53d76efe2511d79b7a
7
+ data.tar.gz: d165a474bc6fa83f98a0b5691e028504b31bf764a498d5814359e39b8c500fc3863834ea959b0b34b6dfce7abb30600f36a6439e29c19bf21475c249b7237e51
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .buildpath
16
+ .project
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ Metrics/LineLength:
2
+ Max: 120
3
+ Style/AndOr:
4
+ EnforcedStyle: conditionals
5
+ Style/HashSyntax:
6
+ EnforcedStyle: ruby19
7
+ Style/SpaceInsideBlockBraces:
8
+ SpaceBeforeBlockParameters: false
9
+ Style/StringLiterals:
10
+ EnforcedStyle: double_quotes
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.2.0
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ rvm:
3
+ - ruby-head
4
+ - 2.2
5
+ - 2.1
6
+ - 2.0
7
+ - 1.9.3
8
+ - 1.9.2
9
+ - jruby-head
10
+ - jruby-1.7
11
+ - rbx
12
+ bundler_args: "--without development"
13
+ addons:
14
+ code_climate:
15
+ repo_token:
16
+ secure: E3bOUINqN9inAqw0EsziZGyTzwThdrVrPuiRN6LQYIc7tHWkJBY0UO+tNvpj0tQcF3ViBy8Lbi26W2Fy+y0FWR163AXxQ8wu6Tu21es+sIPUxxnr/WFbVc7CEsE68ExsfNUciHHa82xnHECYaSqpR7gLHeMW7wFksdQvcnNMr38=
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
4
+ group :development do
5
+ gem "byebug", "~> 3.5.1"
6
+ gem "guard-rspec", "~> 4.5.0"
7
+ gem "guard-rubocop", "~> 1.2.0"
8
+ gem "libnotify", "~> 0.9.1"
9
+ gem "pry", "~> 0.10.1"
10
+ gem "rubocop", "~> 0.29.0"
11
+ end
12
+
13
+ group :development, :test do
14
+ gem "codeclimate-test-reporter", "~> 0.4.6"
15
+ gem "rake", "~> 10.4.2"
16
+ gem "rspec", "~> 3.2.0"
17
+ gem "simplecov", "~> 0.9.1"
18
+ end
data/Guardfile ADDED
@@ -0,0 +1,12 @@
1
+ guard :rubocop, all_on_start: false do
2
+ watch(/^.+\.rb$/)
3
+ watch(/^(?:.+\/)?\.rubocop\.yml$/) {|m| File.dirname(m[0]) }
4
+ watch(/^(?:.+\/)?.+\.gemspec$/)
5
+ watch(/^(?:.+\/)?(?:Gem|Rake)file$/)
6
+ end
7
+
8
+ guard :rspec, cmd: "bundle exec rspec -fd" do
9
+ watch(/^spec\/.+_spec\.rb$/)
10
+ watch(/^lib\/(.+)\.rb$/) {|m| "spec/lib/#{m[1]}_spec.rb" }
11
+ watch("spec/spec_helper.rb") { "spec" }
12
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Gabriel de Oliveira
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # Extensible
2
+
3
+ [![Gem Version](http://img.shields.io/gem/v/extensible.svg)][gem]
4
+ [![Build Status](http://img.shields.io/travis/gdeoliveira/extensible.svg)][travis]
5
+ [![Code Climate](http://img.shields.io/codeclimate/github/gdeoliveira/extensible.svg)][codeclimate]
6
+ [![Test Coverage](http://img.shields.io/codeclimate/coverage/github/gdeoliveira/extensible.svg)][codeclimate]
7
+ [![Dependency Status](http://img.shields.io/gemnasium/gdeoliveira/extensible.svg)][gemnasium]
8
+ [![Inline docs](http://inch-ci.org/github/gdeoliveira/extensible.svg?branch=master)][inch-ci]
9
+
10
+ [gem]: https://rubygems.org/gems/extensible
11
+ [travis]: http://travis-ci.org/gdeoliveira/extensible
12
+ [codeclimate]: https://codeclimate.com/github/gdeoliveira/extensible
13
+ [gemnasium]: https://gemnasium.com/gdeoliveira/extensible#development-dependencies
14
+ [inch-ci]: http://inch-ci.org/github/gdeoliveira/extensible
15
+
16
+ Use Extensible on your custom extensions in order to get the following set of advantages over traditional extensions that override the `Module#extended` method directly:
17
+
18
+ - Calls to `super` are handled internally to ensure all your _extensible_ extensions are properly initialized.
19
+ - Your _extensible_ extensions will be automatically able to become the base of other, more specific extensions while proper initialization is maintained by simply including them.
20
+ - Bundle several _extensible_ extensions in a single module by including them and they will all be correctly initialized when extending the bundler module.
21
+
22
+ Specific examples for each of these scenarios can be found in the [usage](#usage) section.
23
+
24
+ ## Installation
25
+
26
+ Add this line to your application's Gemfile:
27
+
28
+ ```ruby
29
+ gem "extensible"
30
+ ```
31
+
32
+ And then execute:
33
+
34
+ $ bundle
35
+
36
+ Or install it yourself as:
37
+
38
+ $ gem install extensible
39
+
40
+ ## When should I use Extensible?
41
+
42
+ You should use Extensible every time you're implementing a module that is intended to be used as an extension for a module or a class **and** that extension needs to have some initialization code.
43
+
44
+ In short: if you are going to override `Module#extended`, use Extensible instead.
45
+
46
+ ## <a name="usage"></a>Usage
47
+
48
+ #### Basic
49
+
50
+ Creating an _extensible_ extension module is, arguably, simpler than creating a traditional extension that overrides `Module#extended`. Note that we do not need to call `super` within the code block since it will be called "under the hood" _before_ the code is executed:
51
+
52
+ ```ruby
53
+ module MyExtension
54
+ extend Extensible
55
+ when_extended {|m| puts "#{self} has extended #{m}." }
56
+ end
57
+ ```
58
+
59
+ As you would expect, this is what happens when you use your _extensible_ extension in a class (or module):
60
+
61
+ ```ruby
62
+ class MyClass
63
+ extend MyExtension
64
+ end #=> MyExtension has extended MyClass.
65
+ ```
66
+
67
+ #### Extending extensions
68
+
69
+ The extensions you create using Extensible are "extensible" in the sense that you (or someone else) can use them as the base for other, more specific extensions. The best bit is you get this at no additional cost. Simply include them and extend away!
70
+
71
+ Suppose we have a base extension that sets an instance variable that holds the reversed name of the module or class extending it:
72
+
73
+ ```ruby
74
+ module MyBaseExtension
75
+ extend Extensible
76
+ when_extended do |m|
77
+ m.instance_variable_set(:@reversed_name, m.to_s.reverse)
78
+ end
79
+ end
80
+ ```
81
+
82
+ Now we can use `MyBaseExtension` on its own, but we can also _extend_ it to, for example, create a reader method for the `@reversed_name` variable by including it on our more specific `MySubExtension`:
83
+
84
+ ```ruby
85
+ module MySubExtension
86
+ include MyBaseExtension
87
+ attr_reader :reversed_name
88
+ end
89
+ ```
90
+
91
+ We can now extend `MySubExtension` ensuring that the initialization routine of `MyBaseExtension` is executed as expected:
92
+
93
+ ```ruby
94
+ class MyClass
95
+ extend MySubExtension
96
+ end
97
+
98
+ MyClass.reversed_name #=> "ssalCyM"
99
+ ```
100
+
101
+ Note: `MySubExtension` could have (if needed) extended Extensible to provide its own initialization routine. In this case both initialization routines (the one for `MyBaseExtension` and the one for `MySubExtension`) would have been executed when `MyClass` extended it.
102
+
103
+ #### Bundling extensions
104
+
105
+ Traditional extensions that override the `Module#extended` method work correctly as long as they are explicitly extended in the module or class that will ultimately use them. This can become really cumbersome really fast when you want to apply several extensions to a set of different modules or classes.
106
+
107
+ Using _extensible_ extensions you can bundle many of them within a single module, and then extend all of them at the same time by extending the bundler module.
108
+
109
+ Suppose you have two extensions (`A` and `B`) that you want to bundle together:
110
+
111
+ ```ruby
112
+ module A
113
+ extend Extensible
114
+ when_extended { puts "A was extended!" }
115
+ end
116
+
117
+ module B
118
+ extend Extensible
119
+ when_extended { puts "B was extended!" }
120
+ end
121
+ ```
122
+
123
+ Simply include them in your bundler module:
124
+
125
+ ```ruby
126
+ module Bundle
127
+ include A
128
+ include B
129
+ end
130
+ ```
131
+
132
+ And extend it!
133
+
134
+ ```ruby
135
+ module MyClass
136
+ extend Bundle
137
+ end #=> A was extended!
138
+ #=> B was extended!
139
+ ```
140
+
141
+ ## Contributing
142
+
143
+ 1. Fork it ( https://github.com/gdeoliveira/extensible/fork )
144
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
145
+ 3. Commit your changes (`git commit -am "Add some feature"`)
146
+ 4. Push to the branch (`git push origin my-new-feature`)
147
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ Dir[File.join(File.dirname(__FILE__), "tasks", "**", "*.rb")].each do |file|
5
+ require file
6
+ end
7
+
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task default: :coverage
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "extensible/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "extensible"
8
+ spec.version = Extensible::VERSION
9
+ spec.authors = ["Gabriel de Oliveira"]
10
+ spec.email = ["deoliveira.gab@gmail.com"]
11
+ spec.summary = "Ruby extensions made easy."
12
+ spec.description = "Use Extensible on your custom extensions in order to get the following set of advantages over" \
13
+ "traditional extensions that override the `Module#extended` method directly:\n\n" \
14
+ "- Calls to `super` are handled internally to ensure all your _extensible_ extensions are" \
15
+ "properly initialized.\n" \
16
+ "- Your _extensible_ extensions will be automatically able to become the base of other, more" \
17
+ "specific extensions while proper initialization is maintained by simply including them.\n" \
18
+ "- Bundle several _extensible_ extensions in a single module by including them and they will all" \
19
+ "be correctly initialized when extending the bundler module."
20
+ spec.homepage = "https://github.com/gdeoliveira/extensible"
21
+ spec.license = "MIT"
22
+ spec.files = `git ls-files -z`.split("\x0")
23
+ spec.test_files = spec.files.grep(/^spec\//)
24
+ spec.require_paths = ["lib"]
25
+ spec.rdoc_options << "--title=Extensible"
26
+ end
@@ -0,0 +1,9 @@
1
+ module Extensible
2
+ ##
3
+ # Contains error message constants.
4
+ module Error
5
+ ##
6
+ # Describes calling a method that expects a code block but isn't provided one.
7
+ BLOCK_NOT_GIVEN = "code block was expected".freeze
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ require "extensible/extension_kernel_template"
2
+
3
+ module Extensible # rubocop:disable Style/Documentation
4
+ ##
5
+ # A custom ExtensionKernelTemplate clone that is extended by Extensible to make it, well, extensible.
6
+ ExtensionKernel = ExtensionKernelTemplate.clone.module_eval do
7
+ private # rubocop:disable Style/EmptyLinesAroundAccessModifier
8
+
9
+ def extended(submodule)
10
+ super
11
+
12
+ unless submodule.const_defined?(:ExtensionKernel, false)
13
+ kernel = ExtensionKernelTemplate.clone
14
+ submodule.const_set(:ExtensionKernel, kernel)
15
+ submodule.extend kernel
16
+ end
17
+
18
+ self
19
+ end
20
+
21
+ self
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ module Extensible
2
+ ##
3
+ # ExtensionKernelTemplate serves as the initial template for all extension kernels that are used internally by
4
+ # Extensible. Each extensible module will extend a clone of ExtensionKernelTemplate that will allow it to execute
5
+ # its own initialization code.
6
+ module ExtensionKernelTemplate
7
+ class << self
8
+ private
9
+
10
+ ##
11
+ # call-seq:
12
+ # initialize_copy(_source) => extension_kernel_template
13
+ #
14
+ # Passes +_source+ to +super+ and overrides the <tt>Module#included</tt> method in order to extend self on
15
+ # including modules.
16
+ #
17
+ # Returns self object.
18
+ def initialize_copy(_source)
19
+ super
20
+
21
+ this_kernel = self
22
+
23
+ define_method :included do |submodule|
24
+ super submodule
25
+ submodule.extend this_kernel
26
+ self
27
+ end
28
+
29
+ private :included
30
+
31
+ self
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,39 @@
1
+ ##
2
+ # Use Extensible on your custom extensions in order to get a set of advantages over traditional extensions that override
3
+ # the <tt>Module#extended</tt> method directly. When _extending_ Extensible you will be able to define your
4
+ # initialization code (similar to using <tt>Module#extended</tt>) via the when_extended method.
5
+ #
6
+ # module MyExtension
7
+ # extend Extensible
8
+ # when_extended {|m| puts "#{self} has extended #{m}." }
9
+ # end
10
+ #
11
+ # class MyClass
12
+ # extend MyExtension
13
+ # end #=> MyExtension has extended MyClass.
14
+ #
15
+ # Extensible is, itself, extensible. This means that you will be able to extend it further or bundle it together with
16
+ # other extensible modules by _including_ it in your module.
17
+ #
18
+ # module MyExtensibleExtension
19
+ # include Extensible
20
+ #
21
+ # def custom_when_extended(&block)
22
+ # puts "Defining initialization code..."
23
+ # when_extended &block
24
+ # end
25
+ # end
26
+ #
27
+ # module MyExtension
28
+ # extend MyExtensibleExtension
29
+ # custom_when_extended {|m| puts "#{self} has extended #{m}." }
30
+ # end #=> Defining initialization code...
31
+ #
32
+ # class MyClass
33
+ # extend MyExtension
34
+ # end #=> MyExtension has extended MyClass.
35
+ module Extensible
36
+ ##
37
+ # Current version of Extensible.
38
+ VERSION = "0.0.1".freeze
39
+ end
data/lib/extensible.rb ADDED
@@ -0,0 +1,35 @@
1
+ require "extensible/constants"
2
+ require "extensible/extension_kernel"
3
+ require "extensible/version"
4
+
5
+ module Extensible # rubocop:disable Style/Documentation
6
+ extend ExtensionKernel
7
+
8
+ private
9
+
10
+ ##
11
+ # call-seq:
12
+ # when_extended() {|module| ... } => self
13
+ #
14
+ # The +when_extended+ method accepts a code block that will be executed every time this module is extended in a
15
+ # manner similar to <tt>Module#extended</tt>. The code block will be passed a +module+ parameter containing the module
16
+ # that is being extended. There is no need to make explicit calls to +super+ as those will be made internally by
17
+ # Extensible.
18
+ #
19
+ # Returns self object.
20
+ def when_extended(&b)
21
+ fail(ArgumentError, Error::BLOCK_NOT_GIVEN) unless block_given?
22
+
23
+ self::ExtensionKernel.module_eval do
24
+ define_method :extended do |submodule|
25
+ super submodule
26
+ b.call submodule
27
+ self
28
+ end
29
+
30
+ private :extended
31
+ end
32
+
33
+ self
34
+ end
35
+ end
data/spec/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ inherit_from:
2
+ - ../.rubocop.yml
3
+ Metrics/LineLength:
4
+ Max: 140
@@ -0,0 +1,7 @@
1
+ require "spec_helper"
2
+
3
+ describe Extensible::Error do
4
+ subject { described_class.constants.map {|c| described_class.const_get c } }
5
+
6
+ it { is_expected.to all(be_frozen) }
7
+ end
@@ -0,0 +1,5 @@
1
+ require "spec_helper"
2
+
3
+ describe Extensible::VERSION do
4
+ it { is_expected.not_to be_nil }
5
+ end
@@ -0,0 +1,195 @@
1
+ require "spec_helper"
2
+
3
+ describe Extensible do
4
+ context "#when_extended" do
5
+ it "raises an error if code block is not provided" do
6
+ m = Module.new
7
+
8
+ expect do
9
+ m.module_eval do
10
+ extend Extensible
11
+ when_extended
12
+ end
13
+ end.to raise_error(ArgumentError)
14
+ end
15
+ end
16
+
17
+ context "hierarchy" do
18
+ let(:extensible_base_extension_1) do
19
+ Module.new.tap do |m|
20
+ m.module_eval do
21
+ include Extensible
22
+ end
23
+ end
24
+ end
25
+
26
+ let(:extensible_base_extension_2) do
27
+ Module.new.tap do |m|
28
+ m.module_eval do
29
+ include Extensible
30
+ extend Extensible
31
+ when_extended do |sm|
32
+ sm.const_set(:EBE_2_CALLED, true)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ let(:extensible_sub_extension) do
39
+ ebe_1 = extensible_base_extension_1
40
+ ebe_2 = extensible_base_extension_2
41
+ Module.new.tap do |m|
42
+ m.module_eval do
43
+ include ebe_1
44
+ include ebe_2
45
+ end
46
+ end
47
+ end
48
+
49
+ let(:base_extension_1) do
50
+ ese = extensible_sub_extension
51
+ Module.new.tap do |m|
52
+ m.module_eval do
53
+ extend ese
54
+ when_extended do |sm|
55
+ sm.const_set(:BE_1_CALLED, true)
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ let(:base_extension_2) do
62
+ ebe_1 = extensible_base_extension_1
63
+ Module.new.tap do |m|
64
+ m.module_eval do
65
+ extend ebe_1
66
+ when_extended do |sm|
67
+ sm.const_set(:BE_2_CALLED, true)
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ let(:sub_extension) do
74
+ be_1 = base_extension_1
75
+ be_2 = base_extension_2
76
+ Module.new.tap do |m|
77
+ m.module_eval do
78
+ include be_1
79
+ include be_2
80
+ end
81
+ end
82
+ end
83
+
84
+ subject do
85
+ se = sub_extension
86
+ Class.new.tap do |c|
87
+ c.class_eval do
88
+ extend se
89
+ end
90
+ end
91
+ end
92
+
93
+ def extension_ids(mod)
94
+ mod.singleton_class.ancestors.map(&:object_id)
95
+ end
96
+
97
+ it "adds the extensible extension kernel to all extensible extensions" do
98
+ expect(extension_ids(Extensible)).to include(Extensible::ExtensionKernel.object_id)
99
+ expect(extension_ids(extensible_base_extension_1)).to include(Extensible::ExtensionKernel.object_id)
100
+ expect(extension_ids(extensible_base_extension_2)).to include(Extensible::ExtensionKernel.object_id)
101
+ expect(extension_ids(extensible_sub_extension)).to include(Extensible::ExtensionKernel.object_id)
102
+ end
103
+
104
+ it "does not add the extensible extension kernel to non-extensible extensions" do
105
+ expect(extension_ids(base_extension_1)).not_to include(Extensible::ExtensionKernel.object_id)
106
+ expect(extension_ids(base_extension_2)).not_to include(Extensible::ExtensionKernel.object_id)
107
+ expect(extension_ids(sub_extension)).not_to include(Extensible::ExtensionKernel.object_id)
108
+ expect(extension_ids(subject)).not_to include(Extensible::ExtensionKernel.object_id)
109
+ end
110
+
111
+ it "adds the `extensible_base_extension_2` extension kernel to modules that include it" do
112
+ expect(extension_ids(extensible_base_extension_2)).to include(extensible_base_extension_2::ExtensionKernel.object_id)
113
+ expect(extension_ids(extensible_sub_extension)).to include(extensible_base_extension_2::ExtensionKernel.object_id)
114
+ end
115
+
116
+ it "does not add the `extensible_base_extension_2` extension kernel to modules that do not include it" do
117
+ expect(extension_ids(Extensible)).not_to include(extensible_base_extension_2::ExtensionKernel.object_id)
118
+ expect(extension_ids(extensible_base_extension_1)).not_to include(extensible_base_extension_2::ExtensionKernel.object_id)
119
+ expect(extension_ids(base_extension_1)).not_to include(extensible_base_extension_2::ExtensionKernel.object_id)
120
+ expect(extension_ids(base_extension_2)).not_to include(extensible_base_extension_2::ExtensionKernel.object_id)
121
+ expect(extension_ids(sub_extension)).not_to include(extensible_base_extension_2::ExtensionKernel.object_id)
122
+ expect(extension_ids(subject)).not_to include(extensible_base_extension_2::ExtensionKernel.object_id)
123
+ end
124
+
125
+ it "adds the `base_extension_1` extension kernel to modules that include it" do
126
+ expect(extension_ids(base_extension_1)).to include(base_extension_1::ExtensionKernel.object_id)
127
+ expect(extension_ids(sub_extension)).to include(base_extension_1::ExtensionKernel.object_id)
128
+ end
129
+
130
+ it "does not add the `base_extension_1` extension kernel to modules that do not include it" do
131
+ expect(extension_ids(Extensible)).not_to include(base_extension_1::ExtensionKernel.object_id)
132
+ expect(extension_ids(extensible_base_extension_1)).not_to include(base_extension_1::ExtensionKernel.object_id)
133
+ expect(extension_ids(extensible_base_extension_2)).not_to include(base_extension_1::ExtensionKernel.object_id)
134
+ expect(extension_ids(extensible_sub_extension)).not_to include(base_extension_1::ExtensionKernel.object_id)
135
+ expect(extension_ids(base_extension_2)).not_to include(base_extension_1::ExtensionKernel.object_id)
136
+ expect(extension_ids(subject)).not_to include(base_extension_1::ExtensionKernel.object_id)
137
+ end
138
+
139
+ it "adds the `base_extension_2` extension kernel to modules that include it" do
140
+ expect(extension_ids(base_extension_2)).to include(base_extension_2::ExtensionKernel.object_id)
141
+ expect(extension_ids(sub_extension)).to include(base_extension_2::ExtensionKernel.object_id)
142
+ end
143
+
144
+ it "does not add the `base_extension_2` extension kernel to modules that do not include it" do
145
+ expect(extension_ids(Extensible)).not_to include(base_extension_2::ExtensionKernel.object_id)
146
+ expect(extension_ids(extensible_base_extension_1)).not_to include(base_extension_2::ExtensionKernel.object_id)
147
+ expect(extension_ids(extensible_base_extension_2)).not_to include(base_extension_2::ExtensionKernel.object_id)
148
+ expect(extension_ids(extensible_sub_extension)).not_to include(base_extension_2::ExtensionKernel.object_id)
149
+ expect(extension_ids(base_extension_1)).not_to include(base_extension_2::ExtensionKernel.object_id)
150
+ expect(extension_ids(subject)).not_to include(base_extension_2::ExtensionKernel.object_id)
151
+ end
152
+
153
+ it "executes the `extensible_base_extension_2` extension code on modules that extend it" do
154
+ expect(base_extension_1.const_defined?(:EBE_2_CALLED, false)).to be(true)
155
+ end
156
+
157
+ it "does not execute `extensible_base_extension_2` extension code on modules that do not extend it" do
158
+ expect(Extensible.const_defined?(:EBE_2_CALLED, false)).to be(false)
159
+ expect(extensible_base_extension_1.const_defined?(:EBE_2_CALLED, false)).to be(false)
160
+ expect(extensible_base_extension_2.const_defined?(:EBE_2_CALLED, false)).to be(false)
161
+ expect(extensible_sub_extension.const_defined?(:EBE_2_CALLED, false)).to be(false)
162
+ expect(base_extension_2.const_defined?(:EBE_2_CALLED, false)).to be(false)
163
+ expect(sub_extension.const_defined?(:EBE_2_CALLED, false)).to be(false)
164
+ expect(subject.const_defined?(:EBE_2_CALLED, false)).to be(false)
165
+ end
166
+
167
+ it "executes the `base_extension_1` extension code on modules that extend it" do
168
+ expect(subject.const_defined?(:BE_1_CALLED, false)).to be(true)
169
+ end
170
+
171
+ it "does not execute `base_extension_1` extension code on modules that do not extend it" do
172
+ expect(Extensible.const_defined?(:BE_1_CALLED, false)).to be(false)
173
+ expect(extensible_base_extension_1.const_defined?(:BE_1_CALLED, false)).to be(false)
174
+ expect(extensible_base_extension_2.const_defined?(:BE_1_CALLED, false)).to be(false)
175
+ expect(extensible_sub_extension.const_defined?(:BE_1_CALLED, false)).to be(false)
176
+ expect(base_extension_1.const_defined?(:BE_1_CALLED, false)).to be(false)
177
+ expect(base_extension_2.const_defined?(:BE_1_CALLED, false)).to be(false)
178
+ expect(sub_extension.const_defined?(:BE_1_CALLED, false)).to be(false)
179
+ end
180
+
181
+ it "executes the `base_extension_2` extension code on modules that extend it" do
182
+ expect(subject.const_defined?(:BE_2_CALLED, false)).to be(true)
183
+ end
184
+
185
+ it "does not execute `base_extension_2` extension code on modules that do not extend it" do
186
+ expect(Extensible.const_defined?(:BE_2_CALLED, false)).to be(false)
187
+ expect(extensible_base_extension_1.const_defined?(:BE_2_CALLED, false)).to be(false)
188
+ expect(extensible_base_extension_2.const_defined?(:BE_2_CALLED, false)).to be(false)
189
+ expect(extensible_sub_extension.const_defined?(:BE_2_CALLED, false)).to be(false)
190
+ expect(base_extension_1.const_defined?(:BE_2_CALLED, false)).to be(false)
191
+ expect(base_extension_2.const_defined?(:BE_2_CALLED, false)).to be(false)
192
+ expect(sub_extension.const_defined?(:BE_2_CALLED, false)).to be(false)
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,21 @@
1
+ unless ENV["COVERAGE"].nil?
2
+ require "codeclimate-test-reporter"
3
+ SimpleCov.start do
4
+ formatter SimpleCov::Formatter::MultiFormatter[
5
+ SimpleCov::Formatter::HTMLFormatter,
6
+ CodeClimate::TestReporter::Formatter
7
+ ]
8
+ add_filter "/spec/"
9
+ end
10
+ end
11
+
12
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
13
+ require "extensible"
14
+
15
+ RSpec.configure do |config|
16
+ config.color = true
17
+ config.order = :rand
18
+ config.expect_with :rspec do |c|
19
+ c.syntax = :expect
20
+ end
21
+ end
data/tasks/console.rb ADDED
@@ -0,0 +1,25 @@
1
+ desc "Open a console with the #{Bundler::GemHelper.gemspec.name} gem loaded"
2
+ task :console do
3
+ require Bundler::GemHelper.gemspec.name
4
+
5
+ if RUBY_VERSION >= "2"
6
+ begin
7
+ require "byebug"
8
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
9
+ end
10
+ else
11
+ begin
12
+ require "debugger"
13
+ rescue LoadError # rubocop:disable Lint/HandleExceptions
14
+ end
15
+ end
16
+
17
+ begin
18
+ require "pry"
19
+ Pry.start
20
+ rescue LoadError
21
+ require "irb"
22
+ ARGV.clear
23
+ IRB.start
24
+ end
25
+ end
data/tasks/coverage.rb ADDED
@@ -0,0 +1,5 @@
1
+ desc "Run tests and generate coverage report"
2
+ task :coverage do
3
+ ENV["COVERAGE"] = "true"
4
+ Rake::Task[:spec].invoke
5
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: extensible
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Gabriel de Oliveira
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-10 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: |-
14
+ Use Extensible on your custom extensions in order to get the following set of advantages overtraditional extensions that override the `Module#extended` method directly:
15
+
16
+ - Calls to `super` are handled internally to ensure all your _extensible_ extensions areproperly initialized.
17
+ - Your _extensible_ extensions will be automatically able to become the base of other, morespecific extensions while proper initialization is maintained by simply including them.
18
+ - Bundle several _extensible_ extensions in a single module by including them and they will allbe correctly initialized when extending the bundler module.
19
+ email:
20
+ - deoliveira.gab@gmail.com
21
+ executables: []
22
+ extensions: []
23
+ extra_rdoc_files: []
24
+ files:
25
+ - ".gitignore"
26
+ - ".rubocop.yml"
27
+ - ".ruby-version"
28
+ - ".travis.yml"
29
+ - Gemfile
30
+ - Guardfile
31
+ - LICENSE.txt
32
+ - README.md
33
+ - Rakefile
34
+ - extensible.gemspec
35
+ - lib/extensible.rb
36
+ - lib/extensible/constants.rb
37
+ - lib/extensible/extension_kernel.rb
38
+ - lib/extensible/extension_kernel_template.rb
39
+ - lib/extensible/version.rb
40
+ - spec/.rubocop.yml
41
+ - spec/lib/extensible/constants_spec.rb
42
+ - spec/lib/extensible/version_spec.rb
43
+ - spec/lib/extensible_spec.rb
44
+ - spec/spec_helper.rb
45
+ - tasks/console.rb
46
+ - tasks/coverage.rb
47
+ homepage: https://github.com/gdeoliveira/extensible
48
+ licenses:
49
+ - MIT
50
+ metadata: {}
51
+ post_install_message:
52
+ rdoc_options:
53
+ - "--title=Extensible"
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.4.5
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Ruby extensions made easy.
72
+ test_files:
73
+ - spec/.rubocop.yml
74
+ - spec/lib/extensible/constants_spec.rb
75
+ - spec/lib/extensible/version_spec.rb
76
+ - spec/lib/extensible_spec.rb
77
+ - spec/spec_helper.rb