subclass_must_implement 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: be7eacd344df936c6557036eed810d353b476445
4
+ data.tar.gz: f7c20318294fc06bb3ff92a2776d81f7cc8fb5d6
5
+ SHA512:
6
+ metadata.gz: 5de082a47ac63d76765acfa7bbb2777c7a067ba91861903862dd4b2430b380fd0addbe3d79bdf809780861b124cbbc8f9d3043dce4b8cc3814cd23925a91ebeb
7
+ data.tar.gz: 3aec63e7c84a7983315504ff8e0fefd81ade0bc02bf4555f2f81891e5b4ee4e97dda9a2a2157b71a36f571c2580b778aa56b80cca191c2e2a1a9ec13567e2af2
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .ruby-version
24
+
data/.rspec ADDED
@@ -0,0 +1,5 @@
1
+ --color
2
+ --profile
3
+ --backtrace
4
+ --format documentation
5
+ --require spec_helper
@@ -0,0 +1 @@
1
+ subclass_must_implement
@@ -0,0 +1,35 @@
1
+ require "simplecov-rcov-text"
2
+ require "colorize"
3
+
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new([
5
+ SimpleCov::Formatter::RcovTextFormatter,
6
+ SimpleCov::Formatter::HTMLFormatter
7
+ ])
8
+
9
+ SimpleCov.start do
10
+ add_filter "/spec/"
11
+
12
+ # Fail the build when coverage is < 100%:
13
+ at_exit do
14
+ SimpleCov.result.format!
15
+ actual = SimpleCov.result.covered_percent
16
+ if actual < 100 then # FAIL
17
+ msg = "\nLow coverage: "
18
+ msg << "#{actual}%".colorize(:red)
19
+ msg << " is " << "under".colorize(:red) << " the threshold: "
20
+ msg << "#{100}%.".colorize(:green)
21
+ msg << "\n"
22
+ $stderr.puts msg
23
+ exit 1
24
+ else # PASS
25
+ # Precision: three decimal places:
26
+ actual_trunc = (actual * 1000).floor / 1000.0
27
+ msg = "\nCoverage: "
28
+ msg << "#{actual}%".colorize(:green)
29
+ msg << " is " << "at".colorize(:green) << " the threshold: "
30
+ msg << "#{100}%.".colorize(:green)
31
+ msg << "\n"
32
+ $stdout.puts msg
33
+ end
34
+ end
35
+ end
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 HornsAndHooves
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,75 @@
1
+ # SubclassMustImplement
2
+
3
+ There are circumstances when it is desirable to specify certain methods as abstract, i.e. it is the responsibility of any subclass to implement them.
4
+ Getting a `MethodMIssing` is not helpful; an error that explicitly explains that the missing method is required by contract will save much time.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'subclass_must_implement'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install yourself as:
17
+
18
+ $ gem install subclass_must_implement
19
+
20
+ ## Usage
21
+
22
+ Either `include SubclassMustImplement` or `extend SubclassMustImplement` in your base class.
23
+ Then call `subclass_must_implement` with a list of required method names as symbols.
24
+ You can optionally pass in a custom error message using the `err_message` named argument.
25
+
26
+ Example 1:
27
+
28
+ ```ruby
29
+ class BaseFoo
30
+ include SubclassMustImplement
31
+
32
+ subclass_must_implement :foo, :bar, :baz
33
+ end
34
+
35
+ class Foo < BaseFoo
36
+ def foo
37
+ :foo
38
+ end
39
+ end
40
+
41
+ f = Foo.new
42
+ f.foo # returns :foo
43
+ f.bar # raises a NotImplementedError that "bar" must be implemented in the subclass
44
+ f.baz # raises a NotImplementedError that "baz" must be implemented in the subclass
45
+ f.qux # raises a MethodMissing
46
+ ```
47
+
48
+ Example 2:
49
+
50
+ ```ruby
51
+ class BaseBar
52
+ extend SubclassMustImplement
53
+
54
+ subclass_must_implement :foo, :bar, err_message: "Version expected!!!"
55
+ end
56
+
57
+ class Bar < BaseBar
58
+ def bar
59
+ :bar
60
+ end
61
+ end
62
+
63
+ b = Bar.new
64
+ b.bar # return :bar
65
+ b.foo # raises a NotImplementedError with the specified error message "Version expected!!!"
66
+ ```
67
+
68
+ ## Contributing
69
+
70
+ 1. Fork it ( https://github.com/[my-github-username]/subclass_must_implement/fork )
71
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
72
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
73
+ 4. Push to the branch (`git push origin my-new-feature`)
74
+ 5. Create a new Pull Request
75
+ 6. Make sure all the test pass and your changes have test coverage!
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ rescue LoadError
7
+ end
@@ -0,0 +1,74 @@
1
+ # Either `include SubclassMustImplement` or `extend SubclassMustImplement` in your base class.
2
+ # Then call `subclass_must_implement` with a list of required method names as symbols.
3
+ # You can optionally pass in a custom error message using the `err_message` named argument.
4
+ #
5
+ # Example 1:
6
+ #
7
+ # class BaseFoo
8
+ # include SubclassMustImplement
9
+ #
10
+ # subclass_must_implement :foo, :bar, :baz
11
+ # end
12
+ #
13
+ # class Foo < BaseFoo
14
+ # def foo
15
+ # :foo
16
+ # end
17
+ # end
18
+ #
19
+ # f = Foo.new
20
+ # f.foo # returns :foo
21
+ # f.bar # raises a NotImplementedError that "bar" must be implemented in the subclass
22
+ # f.baz # raises a NotImplementedError that "baz" must be implemented in the subclass
23
+ # f.qux # raises a MethodMissing
24
+ #
25
+ # Example 2:
26
+ #
27
+ # class BaseBar
28
+ # extend SubclassMustImplement
29
+ #
30
+ # subclass_must_implement :foo, :bar, err_message: "Version expected!!!"
31
+ # end
32
+ #
33
+ # class Bar < BaseBar
34
+ # def bar
35
+ # :bar
36
+ # end
37
+ # end
38
+ #
39
+ # b = Bar.new
40
+ # b.bar # return :bar
41
+ # b.foo # raises a NotImplementedError with the specified error message "Version expected!!!"
42
+ #
43
+ module SubclassMustImplement
44
+
45
+ # Injects the `subclass_must_implement` macro
46
+ def self.included(base)
47
+ base.extend ClassMethods
48
+ end
49
+
50
+ # Injects the `subclass_must_implement` macro
51
+ def self.extended(base)
52
+ base.extend ClassMethods
53
+ end
54
+
55
+ # Returns the Gem version as a string
56
+ def self.version
57
+ "0.0.1"
58
+ end
59
+
60
+ # The class level macros are defined here.
61
+ module ClassMethods
62
+
63
+ # Defines a method for each method name that raises a NotImplementedError when called.
64
+ # Pass in a custom error message if desired using the err_message named argument.
65
+ def subclass_must_implement(*method_names, err_message: nil)
66
+ method_names.each do |method_name|
67
+ err = err_message.nil? ? "`#{method_name}` must be implemented in a subclass." : "#{err_message}"
68
+ define_method method_name do |*_|
69
+ raise NotImplementedError, err
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,89 @@
1
+ require 'simplecov'
2
+ SimpleCov.start
3
+
4
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
5
+ RSpec.configure do |config|
6
+ # rspec-expectations config goes here. You can use an alternate
7
+ # assertion/expectation library such as wrong or the stdlib/minitest
8
+ # assertions if you prefer.
9
+ config.expect_with :rspec do |expectations|
10
+ # This option will default to `true` in RSpec 4. It makes the `description`
11
+ # and `failure_message` of custom matchers include text for helper methods
12
+ # defined using `chain`, e.g.:
13
+ # be_bigger_than(2).and_smaller_than(4).description
14
+ # # => "be bigger than 2 and smaller than 4"
15
+ # ...rather than:
16
+ # # => "be bigger than 2"
17
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
18
+ end
19
+
20
+ # rspec-mocks config goes here. You can use an alternate test double
21
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
22
+ config.mock_with :rspec do |mocks|
23
+ # Prevents you from mocking or stubbing a method that does not exist on
24
+ # a real object. This is generally recommended, and will default to
25
+ # `true` in RSpec 4.
26
+ mocks.verify_partial_doubles = true
27
+ end
28
+
29
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
30
+ # have no way to turn it off -- the option exists only for backwards
31
+ # compatibility in RSpec 3). It causes shared context metadata to be
32
+ # inherited by the metadata hash of host groups and examples, rather than
33
+ # triggering implicit auto-inclusion in groups with matching metadata.
34
+ config.shared_context_metadata_behavior = :apply_to_host_groups
35
+
36
+ # The settings below are suggested to provide a good initial experience
37
+ # with RSpec, but feel free to customize to your heart's content.
38
+ =begin
39
+ # This allows you to limit a spec run to individual examples or groups
40
+ # you care about by tagging them with `:focus` metadata. When nothing
41
+ # is tagged with `:focus`, all examples get run. RSpec also provides
42
+ # aliases for `it`, `describe`, and `context` that include `:focus`
43
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
44
+ config.filter_run_when_matching :focus
45
+
46
+ # Allows RSpec to persist some state between runs in order to support
47
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
48
+ # you configure your source control system to ignore this file.
49
+ config.example_status_persistence_file_path = "spec/examples.txt"
50
+
51
+ # Limits the available syntax to the non-monkey patched syntax that is
52
+ # recommended. For more details, see:
53
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
54
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
55
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
56
+ config.disable_monkey_patching!
57
+
58
+ # This setting enables warnings. It's recommended, but in some cases may
59
+ # be too noisy due to issues in dependencies.
60
+ config.warnings = true
61
+
62
+ # Many RSpec users commonly either run the entire suite or an individual
63
+ # file, and it's useful to allow more verbose output when running an
64
+ # individual spec file.
65
+ if config.files_to_run.one?
66
+ # Use the documentation formatter for detailed output,
67
+ # unless a formatter has already been configured
68
+ # (e.g. via a command-line flag).
69
+ config.default_formatter = "doc"
70
+ end
71
+
72
+ # Print the 10 slowest examples and example groups at the
73
+ # end of the spec run, to help surface which specs are running
74
+ # particularly slow.
75
+ config.profile_examples = 10
76
+
77
+ # Run specs in random order to surface order dependencies. If you find an
78
+ # order dependency and want to debug it, you can fix the order by providing
79
+ # the seed, which is printed after each run.
80
+ # --seed 1234
81
+ config.order = :random
82
+
83
+ # Seed global randomization in this process using the `--seed` CLI option.
84
+ # Setting this allows you to use `--seed` to deterministically reproduce
85
+ # test failures related to randomization by passing the same `--seed` value
86
+ # as the one that triggered the failure.
87
+ Kernel.srand config.seed
88
+ =end
89
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SubclassMustImplement do
4
+
5
+ class BaseFoo
6
+ include SubclassMustImplement
7
+
8
+ subclass_must_implement :foo, :bar, :baz
9
+ end
10
+
11
+ class Foo < BaseFoo
12
+ def foo
13
+ :foo
14
+ end
15
+ end
16
+
17
+ class BaseBar
18
+ extend SubclassMustImplement
19
+
20
+ subclass_must_implement :version, :sub_version, err_message: "Version expected!!!"
21
+ end
22
+
23
+ class Bar < BaseBar
24
+ def version
25
+ SubclassMustImplement.version
26
+ end
27
+ end
28
+
29
+ let(:foo) { Foo.new }
30
+ let(:bar) { Bar.new }
31
+
32
+ context "module included" do
33
+ it "will raise a not implemented error if any required method is not implemented in the subclass" do
34
+ expect { foo.bar }.to raise_error(NotImplementedError, "`bar` must be implemented in a subclass.")
35
+ expect { foo.baz }.to raise_error(NotImplementedError, "`baz` must be implemented in a subclass.")
36
+ end
37
+
38
+ it "will not raise an error if a requred method is implemented by the subclass" do
39
+ expect(foo.foo).to eq(:foo)
40
+ end
41
+ end
42
+
43
+ context "module extended" do
44
+ it "will raise a not implemented error if any required method is not implemented in the subclass" do
45
+ expect { bar.sub_version }.to raise_error(NotImplementedError, "Version expected!!!")
46
+ end
47
+
48
+ it "will not raise an error if a requred method is implemented by the subclass" do
49
+ expect(bar.version).to eq(described_class.version)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'subclass_must_implement'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "subclass_must_implement"
8
+ spec.version = SubclassMustImplement.version
9
+ spec.authors = ["Arthur Shagall"]
10
+ spec.email = ["arthur.shagall@gmail.com"]
11
+ spec.summary = %q{Make abstract methods explicit.}
12
+ spec.description = %q{Auto-generate abstract method stubs to mark them as required to be implemented in subclasses.}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.15"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ spec.add_development_dependency "simplecov"
25
+ spec.add_development_dependency "simplecov-rcov-text"
26
+ spec.add_development_dependency "colorize"
27
+ end
metadata ADDED
@@ -0,0 +1,143 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: subclass_must_implement
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Arthur Shagall
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.15'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.15'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: simplecov
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov-rcov-text
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: colorize
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Auto-generate abstract method stubs to mark them as required to be implemented
98
+ in subclasses.
99
+ email:
100
+ - arthur.shagall@gmail.com
101
+ executables: []
102
+ extensions: []
103
+ extra_rdoc_files: []
104
+ files:
105
+ - ".gitignore"
106
+ - ".rspec"
107
+ - ".ruby-gemset"
108
+ - ".simplecov"
109
+ - Gemfile
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - lib/subclass_must_implement.rb
114
+ - spec/spec_helper.rb
115
+ - spec/subclass_must_implement_spec.rb
116
+ - subclass_must_implement.gemspec
117
+ homepage: ''
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.6.14
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Make abstract methods explicit.
141
+ test_files:
142
+ - spec/spec_helper.rb
143
+ - spec/subclass_must_implement_spec.rb