interrobang 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6095e5897bbea3cff7301fdc71e9957fb8780eab
4
+ data.tar.gz: d1832778b017ca518c234006241e5bbd8406e17b
5
+ SHA512:
6
+ metadata.gz: 60c8312652570cad7ae79b0a0388f84b040bcd4d4cdb0bb9083d3c0283a2a9bd4991eea28f2c4d68cb5eedf3b4b157acdf6f25c93fc9f2fc94bf95a90bf1f3fe
7
+ data.tar.gz: 622daee4c4311256827dea66f1b6251e2f9ddc27129be4e0143e33c409b46ecb0e75eb7d2e480bdce36bceb48a7a5fb2963610e52358026486e799672a6ccd4e
data/.gitignore ADDED
@@ -0,0 +1,14 @@
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
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ script: bundle exec rake test
3
+ rvm:
4
+ - 2.2
5
+ - 2.1
6
+ - 2.0.0
7
+ - ruby-head
8
+ - jruby-head
9
+ - rbx-2
10
+ addons:
11
+ code_climate:
12
+ repo_token: 240d93328887c5936b3af5aadca1900358cb12bdc227831b0577be2e9a89d817
data/.yardopts ADDED
@@ -0,0 +1,6 @@
1
+ --readme README.md
2
+ --plugin tomdoc
3
+ lib
4
+ -
5
+ *.md
6
+ *.txt
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in interrobang.gemspec
4
+ gemspec
5
+
6
+ gem 'codeclimate-test-reporter', group: :test, require: nil
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Faraz Yashar
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,266 @@
1
+ # Interrobang :interrobang:
2
+
3
+ [![Build Status](https://travis-ci.org/fny/interrobang.svg?branch=master)](https://travis-ci.org/fny/interrobang)
4
+ [![Test Coverage](https://codeclimate.com/github/fny/interrobang/badges/coverage.svg)](https://codeclimate.com/github/fny/interrobang)
5
+
6
+ Convert your `predicate_methods?` into `bang_methods!` without abusing `method_missing`.
7
+
8
+ `Interrobang` currently only works with Ruby versions that support keyword arguments.
9
+
10
+ ## Overview
11
+
12
+ Say we have the following class:
13
+
14
+ ```ruby
15
+ class Answer
16
+ # Say these return a boolean.
17
+ def correct?; end
18
+ def is_correct; end
19
+ def is_factual; end
20
+ def is_right; end
21
+ end
22
+ ```
23
+
24
+ `Interrobang` automagically adds corresponding bang methods for any predicate methods that end in a `?`. The bang methods explode when the predicate method returns a falsey value.
25
+
26
+ ```ruby
27
+ Interrobang.bangify(Answer)
28
+ answer = Answer.new # => [:correct!]
29
+ answer.respond_to?(:correct!) # => true (no method missing shenanigans!)
30
+ Answer.new.correct! # => Raises Interrobang::FalsePredicate if `#correct?` is false
31
+ ```
32
+
33
+ You can add prefixes and suffixes to the generated bang method.
34
+
35
+ ```ruby
36
+ Interrobang.bangify(Answer, prefix: 'ensure_', suffix: '_or_else')
37
+ # => [:ensure_correct_or_else!]
38
+ Answer.new.ensure_correct_or_else!
39
+ # => Raises Interrobang::FalsePredicate if `#correct?` is false
40
+ ```
41
+
42
+ Provide your own blocks to execute on failure. You can optionally access the symbol of the predicate method as an argument.
43
+
44
+ ```ruby
45
+ Interrobang.bangify(Answer, prefix: 'ensure_') do |predicate_method|
46
+ raise StandardError, predicate_method
47
+ end # => [:ensure_correct!]
48
+ Answer.new.ensure_correct! # => Raises StandardError if `#correct?` is false
49
+ ```
50
+
51
+ Need to convert a single method? No problem.
52
+
53
+ ```ruby
54
+ Interrobang.bangify_method(Answer, :correct?, prefix: 'ensure_', suffix: '_on_saturday') do
55
+ if Time.now.saturday?
56
+ raise WeekendLaziness
57
+ else
58
+ true
59
+ end
60
+ end # => :ensure_correct_on_saturday!
61
+ ```
62
+
63
+ ### Filters
64
+
65
+ Perhaps you'd like to convert methods that match a different pattern?
66
+
67
+ ```ruby
68
+ Interrobang.bangify(Answer, matching: %r{\Ais_.*\z})
69
+ # => [:is_correct!, :is_factual!, :is_right!]
70
+ ```
71
+
72
+ You can exclude methods that match the pattern with `except`.
73
+
74
+ ```ruby
75
+ Interrobang.bangify(Answer, matching: %r{\Ais_.*\z},
76
+ except: [:is_factual, :is_right])
77
+ # => [:is_correct!]
78
+ ```
79
+
80
+ Maybe you'd like to state the methods to convert explicitly?
81
+
82
+ ```ruby
83
+ Interrobang.bangify(Answer, only: :is_correct) # => [:is_correct!]
84
+ ```
85
+
86
+ You can opt to include methods from parent classes, but proceed with caution...
87
+
88
+ ```ruby
89
+ Interrobang.bangify(Answer, include_super: true, prefix: 'ensure_')
90
+ # => [:ensure_correct!, :ensure_nil!, :ensure_eql!, :ensure_tainted!, :ensure_untrusted!, :ensure_frozen!, :ensure_instance_variable_defined!, :ensure_instance_of!, :ensure_kind_of!, :ensure_is_a!, :ensure_respond_to!, :ensure_equal!]
91
+ Answer.new.ensure_nil! # => Raises Interrobang::FalsePredicate
92
+ ```
93
+
94
+ Too lazy to type `Interrobang`? Just `extend` it. It's methods are `module_function`s!
95
+
96
+ ```ruby
97
+ class Answer
98
+ extend Interrobang
99
+ bangify self
100
+ bangify_method self, :is_special
101
+ end
102
+ ```
103
+
104
+ See `lib/interrobang.rb` for complete documentation and the tests for details.
105
+
106
+ ## Installation
107
+
108
+ Add this line to your application's Gemfile:
109
+
110
+ ```ruby
111
+ gem 'interrobang'
112
+ ```
113
+
114
+ And then execute:
115
+
116
+ $ bundle
117
+
118
+ Or install it yourself as:
119
+
120
+ $ gem install interrobang
121
+
122
+
123
+ ## Example Use Case with Rails
124
+
125
+ `Interrobang` works wonderfully with permission-related objects. Say we have a bangified `Protector` class that defines user permissions in our application:
126
+
127
+ ```ruby
128
+ class Protector
129
+ NotSignedIn = Class.new(Exception)
130
+ Unauthorized = Class.new(Exception)
131
+
132
+ def initialize(user)
133
+ @user = user
134
+ end
135
+
136
+ def signed_in?
137
+ @user.is_a?(User)
138
+ end
139
+
140
+ def admin?
141
+ @user && @user.is_admin
142
+ end
143
+
144
+ def can_edit_user?(other_user)
145
+ @user && (@user.is_admin || @user.id == other_user.id)
146
+ end
147
+
148
+ Interrobang.bangify(self, prefix: 'ensure_') do |predicate_method|
149
+ raise Unauthorized, "#{predicate_method} failed"
150
+ end
151
+
152
+ Interrobang.bangify_method(self, :signed_in?, prefix: 'ensure_') do |predicate_method|
153
+ raise NotSignedIn, "#{predicate_method} failed"
154
+ end
155
+ end
156
+ ```
157
+
158
+ In our controller, we can then define rescue handlers for the those exceptions, and add a method to access a `Protector` instance.
159
+
160
+ ```ruby
161
+ class ApplicationController < ActionController::Base
162
+ def protector
163
+ @protector ||= Protector.new(current_user)
164
+ end
165
+
166
+ rescue_from Protector::NotSignedIn do
167
+ redirect_to sign_in_path, alert: "Please sign in to continue."
168
+ end
169
+
170
+ rescue_from Protector::Unauthorized do
171
+ # Handle as you will
172
+ end
173
+ end
174
+ ```
175
+
176
+ Now we can call `protector.ensure_signed_in!`, `protector.ensure_admin!`, `protector.ensure_can_edit!(other_user)!` from any controller and trigger the errors defined with `Interrobang`.
177
+
178
+ ### Aside: Testing Tricks with Rescue Handlers
179
+
180
+ For tests, we can stub the rescue handlers with methods that expose the original errors so we can check for them directly.
181
+
182
+ ```ruby
183
+ # spec/support/helpers.rb
184
+ def raise_handled_rescues(controller = ApplicationController)
185
+ stubbed_handlers = controller.rescue_handlers.map { |rescue_handler|
186
+ name, proc = rescue_handler
187
+ [ name, -> { raise Kernel.const_get(name) } ]
188
+ }
189
+ allow(controller).to receive(:rescue_handlers).and_return(stubbed_handlers)
190
+ end
191
+ ```
192
+
193
+ This allows us to test that proper errors are being raised independently from testing each error's particular handling.
194
+
195
+ ```ruby
196
+ # spec/controllers/users_controller_spec.rb
197
+ RSpec.describe UsersController, type: :controller do
198
+ before { raise_handled_rescues }
199
+ after { reset_handled_rescues }
200
+ describe "GET index" do
201
+ context "unauthenticated user" do
202
+ it "raises Protector::NotSignedIn" do
203
+ expect { get :index }.to raise_error(Protector::NotSignedIn)
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ # spec/controllers/application_controller_spec.rb
210
+ RSpec.describe ApplicationController, type: :controller do
211
+ describe "Protector::NotSignedIn rescue handler" do
212
+ controller { def index; raise Protector::NotSignedIn; end }
213
+ it "redirects to the sign in page" do
214
+ get :index
215
+ expect(response).to redirect_to sign_in_path
216
+ end
217
+ end
218
+ end
219
+ ```
220
+
221
+ ## What are these predicate methods and bang methods?
222
+
223
+ **Predicate methods** return a Boolean. By Ruby convention, these methods typically end in a `?`. Other languages like [Scheme][scheme-conventions], [C#][csharp-predicates], [Java][java-predicates], support this interface too.
224
+
225
+ **Bang methods** are "dangerous" or modify the receiver. By convention, these methods typically end with a `!`. In the case of `Interrobang`, these methods are considered "dangerous" because they may raise an exception.
226
+
227
+ ### Fun Fact
228
+
229
+ The Ruby conventions for `?` and `!` are borrowed from [Scheme][scheme-conventions]:
230
+
231
+ > 1.3.5 Naming conventions
232
+ >
233
+ >
234
+ > By convention, the names of procedures that always return a boolean value usually end in ``?''. Such procedures are called predicates.
235
+ >
236
+ > By convention, the names of procedures that store values into previously
237
+ > allocated locations (see section 3.4) usually end in ``!''. Such procedures
238
+ > are called mutation procedures. By convention, the value returned by a
239
+ > mutation procedure is unspecified.
240
+
241
+ ## Development
242
+
243
+ Be sure to test all the things. Just `rake test`. You can use `bundle console` to play with things in an IRB session.
244
+
245
+ ## Contributing
246
+
247
+ 1. Fork it ( https://github.com/fny/interrobang/fork )
248
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
249
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
250
+ 4. Push to the branch (`git push origin my-new-feature`)
251
+ 5. Create a new Pull Request
252
+
253
+ ## Special Thanks To...
254
+
255
+ - [Discourse][discourse] for inspiring me to find a `method_missing`-free alternative to its [EnsureMagic][discourse-ensure]
256
+ - [Michael Josephson][josephson] for [pointing me in the right direction][so-question]
257
+ - To all [contributers][github-contributers]! :beers:
258
+
259
+ [csharp-predicates]: https://msdn.microsoft.com/en-us/library/bfcke1bz%28v=vs.110%29.aspx "Predicate<T> Delegate"
260
+ [java-predicates]: https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html "Interface Predicate<T>"
261
+ [scheme-conventions]: http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-4.html#%_sec_1.3.5 "Scheme Naming Conventions"
262
+ [discourse]: http://discourse.org "Discourse"
263
+ [discourse-ensure]: https://github.com/discourse/discourse/blob/ba0084edee8ace004855b987e1661a7eaff60122/lib/guardian/ensure_magic.rb "module EnsureMagic"
264
+ [josephson]: http://www.josephson.org/ "Michael Josephson"
265
+ [so-question]: http://stackoverflow.com/questions/28818193/define-method-based-on-existing-method-in-ruby "Define Method Based on Existing Method in Ruby - Stack Overflow"
266
+ [github-contributers]: https://github.com/fny/interrobang/graphs/contributors "Predicate Bang Contributers - GitHub"
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib/interrobang'
6
+ t.test_files = FileList['test/lib/**/*_test.rb']
7
+ t.verbose = true
8
+ end
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'interrobang/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'interrobang'
8
+ spec.version = Interrobang::VERSION
9
+ spec.authors = ["Faraz Yashar"]
10
+ spec.email = ["faraz.yashar@gmail.com"]
11
+ spec.summary = "Convert your predicate_methods? into bang_methods! without
12
+ abusing method_missing"
13
+ spec.description = "Convert your predicate_methods? into bang_methods! without
14
+ abusing method_missing."
15
+ spec.homepage = 'https://github.com/fny/interrobang'
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ['lib']
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.7'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'minitest', '~> 5.5'
26
+
27
+ spec.required_ruby_version = '>= 2.0.0'
28
+ end
@@ -0,0 +1,103 @@
1
+ require 'interrobang/version'
2
+
3
+ # Convert your `#predicate_methods?` to `#bang_methods!`
4
+ module Interrobang
5
+ # Exception to raise when no block is provided for bangified falsey methods
6
+ FalsePredicate = Class.new(Exception)
7
+
8
+ # Regexp that matches methods that end in question marks.
9
+ DEFAULT_PATTERN = %r{\A[^?]+\?\z}
10
+
11
+ module_function
12
+
13
+ # Converts the specified predicate methods in a class to bang methods.
14
+ #
15
+ # klass - The Class to target for bangification
16
+ # block - An optional block to run if a predicate method returns something falsey
17
+ #
18
+ # Options
19
+ #
20
+ # matching - The Regexp used to match methods that should be bangified; defaults to DEFAULT_PATTERN
21
+ # only - The Symbol or Symbol Array of methods to bangify exclusively
22
+ # except - The Symbol or Symbol Array of methods to ignore when pattern matching
23
+ # prefix - The String prefix to add to front of the bangified method
24
+ # suffix - The String suffix to add to end of the bangified method
25
+ # inlcude_super - The Boolean specifying whether to bangify parent methods
26
+ #
27
+ # Returns the Symbol Array of bangified method names.
28
+ def bangify(klass, matching: DEFAULT_PATTERN, only: [], except: [], prefix: '', suffix: '', include_super: false)
29
+ method_keys = klass.instance_methods(include_super)
30
+ only = [only] unless only.is_a?(Array)
31
+ except = [except] unless except.is_a?(Array)
32
+ if only.empty?
33
+ method_keys.map do |method_key|
34
+ if method_key.to_s =~ matching && !except.include?(method_key)
35
+ if block_given?
36
+ bangify_method(klass, method_key, prefix: prefix, suffix: suffix, &Proc.new)
37
+ else
38
+ bangify_method(klass, method_key, prefix: prefix, suffix: suffix)
39
+ end
40
+ end
41
+ end.compact
42
+ else
43
+ method_keys.map do |method_key|
44
+ if only.include?(method_key)
45
+ if block_given?
46
+ bangify_method(klass, method_key, prefix: prefix, suffix: suffix, &Proc.new)
47
+ else
48
+ bangify_method(klass, method_key, prefix: prefix, suffix: suffix)
49
+ end
50
+ end
51
+ end.compact
52
+ end
53
+ end
54
+
55
+ # Converts the specified predicate method to a bang method.
56
+ #
57
+ # klass - The Class to target for bangification
58
+ # predicate_method - The Symbol of the predicate method
59
+ # block - An optional block to run if a predicate method returns something falsey
60
+ #
61
+ # Options
62
+ #
63
+ # matching - The Regexp used to match methods that should be bangified
64
+ # prefix - The String prefix to add to front of the bangified method
65
+ # suffix - The String suffix to add to end of the bangified method
66
+ #
67
+ # Returns the Symbol name of the bang method created.
68
+ def bangify_method(klass, predicate_method, prefix: '', suffix: '')
69
+ predicate_method_string = predicate_method.to_s
70
+ method_name_base =
71
+ case predicate_method_string[-1]
72
+ when '=', '!'
73
+ return
74
+ when '?'
75
+ predicate_method.to_s[0..-2]
76
+ else
77
+ predicate_method.to_s
78
+ end
79
+
80
+ bang_method = :"#{prefix}#{method_name_base}#{suffix}!"
81
+
82
+ klass.class_eval do
83
+ if block_given?
84
+ define_method(bang_method) do |*args, &block|
85
+ if send(predicate_method, *args, &block)
86
+ true
87
+ else
88
+ yield(predicate_method)
89
+ end
90
+ end
91
+ else
92
+ define_method(bang_method) do |*args, &block|
93
+ if send(predicate_method, *args, &block)
94
+ true
95
+ else
96
+ raise(Interrobang::FalsePredicate, "#{predicate_method} is false")
97
+ end
98
+ end
99
+ end
100
+ end
101
+ bang_method
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module Interrobang
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,189 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ SomeError = Class.new(Exception)
4
+
5
+ def test_class
6
+ Class.new {
7
+ def true?; true; end
8
+ def veritable?; true; end
9
+ def so_true; true; end
10
+ def so_very_true; true; end
11
+ def false?; false; end
12
+ def so_false; false; end
13
+ def assignment=; end
14
+ def bang!; '!'; end
15
+ def with_argument?(bool); bool; end
16
+ }
17
+ end
18
+
19
+ describe Interrobang do
20
+ describe '.bangify_method' do
21
+ describe "with a method that ends in a ?" do
22
+ it "adds a ! method dropping the ?" do
23
+ klass = test_class
24
+ Interrobang.bangify_method(klass, :true?)
25
+ assert klass.new.true!
26
+ end
27
+ it "has no method missing shenanigans" do
28
+ klass = test_class
29
+ Interrobang.bangify_method(klass, :true?)
30
+ assert klass.new.respond_to?(:true!)
31
+ end
32
+ end
33
+
34
+ describe "with a method that does not end in a ?" do
35
+ it "adds a ! method" do
36
+ klass = test_class
37
+ Interrobang.bangify_method(klass, :so_true)
38
+ end
39
+ end
40
+
41
+ it "returns the symbol of the bangified method" do
42
+ klass = test_class
43
+ assert_equal Interrobang.bangify_method(klass, :true?), :true!
44
+ end
45
+
46
+ it "works on methods with arguments" do
47
+ klass = test_class
48
+ Interrobang.bangify_method(klass, :with_argument?)
49
+ assert klass.new.with_argument!(true)
50
+ -> { klass.new.with_argument!(false) }.must_raise Interrobang::FalsePredicate
51
+ end
52
+
53
+ it "does not convert assignment methods" do
54
+ klass = test_class
55
+ Interrobang.bangify_method klass, :assignment_=
56
+ -> { klass.new.assignment_! }.must_raise NoMethodError
57
+ end
58
+
59
+ it "does not convert bang methods" do
60
+ klass = test_class
61
+ Interrobang.bangify_method klass, :bang!
62
+ assert_equal klass.new.bang!, '!'
63
+ end
64
+
65
+ describe "options" do
66
+ it "adds any provided prefix or suffix to the bang method" do
67
+ klass = test_class
68
+ Interrobang.bangify_method(klass, :true?, prefix: 'prefix_', suffix: '_suffix')
69
+ assert klass.new.prefix_true_suffix!
70
+ end
71
+ end
72
+
73
+ describe "falsey predicates" do
74
+ describe "without a custom block" do
75
+ it "raises a FalsePredicate error" do
76
+ klass = test_class
77
+ Interrobang.bangify_method klass, :false?
78
+ err = -> { klass.new.false! }.must_raise Interrobang::FalsePredicate
79
+ assert_equal err.message, 'false? is false'
80
+ end
81
+ end
82
+
83
+ describe "with a provided block" do
84
+ it "performs the provided block for the bang method" do
85
+ klass = test_class
86
+ Interrobang.bangify_method klass, :false? do
87
+ raise SomeError
88
+ end
89
+ -> { klass.new.false! }.must_raise SomeError
90
+ end
91
+
92
+ it "allows the provided block to take the predicate method as an argument" do
93
+ klass = test_class
94
+ Interrobang.bangify_method klass, :false? do |predicate_method|
95
+ raise SomeError, "#{predicate_method} isn't true"
96
+ end
97
+ err = -> { klass.new.false! }.must_raise SomeError
98
+ assert_equal err.message, "false? isn't true"
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ describe '.bangify' do
105
+ it "converts all predicate? methods by default" do
106
+ klass = test_class
107
+ Interrobang.bangify klass
108
+ assert klass.new.true!
109
+ assert klass.new.veritable!
110
+ end
111
+
112
+ it "returns an array of symbols of the bangified methods" do
113
+ klass = test_class
114
+ assert_equal Interrobang.bangify(klass), [:true!, :veritable!, :false!, :with_argument!]
115
+ end
116
+
117
+ it "converts all methods according to the provided prefix and suffix" do
118
+ klass = test_class
119
+ Interrobang.bangify klass, prefix: 'prefix_', suffix: '_suffix'
120
+ assert klass.new.prefix_true_suffix!
121
+ assert klass.new.prefix_veritable_suffix!
122
+ end
123
+
124
+ it "converts all methods that match the provided pattern" do
125
+ klass = test_class
126
+ Interrobang.bangify klass, matching: %r{\Aso_.*\z}
127
+ assert klass.new.so_true!
128
+ assert klass.new.so_very_true!
129
+ -> { klass.new.true! }.must_raise NoMethodError
130
+ end
131
+
132
+ it "converts all methods that match the provided pattern respected except" do
133
+ klass = test_class
134
+ Interrobang.bangify klass, matching: %r{\Aso_.*\z}, except: [:so_very_true]
135
+ assert klass.new.so_true!
136
+ -> { klass.new.so_very_true! }.must_raise NoMethodError
137
+ -> { klass.new.true! }.must_raise NoMethodError
138
+ end
139
+
140
+ it "except option accepts a singular symbol" do
141
+ klass = test_class
142
+ Interrobang.bangify klass, matching: %r{\Aso_.*\z}, except: :so_very_true
143
+ assert klass.new.so_true!
144
+ -> { klass.new.so_very_true! }.must_raise NoMethodError
145
+ -> { klass.new.true! }.must_raise NoMethodError
146
+ end
147
+
148
+ it "converts only the methods specified in the only option" do
149
+ klass = test_class
150
+ Interrobang.bangify klass, only: [:so_true]
151
+ assert klass.new.so_true!
152
+ -> { klass.new.so_very_true! }.must_raise NoMethodError
153
+ -> { klass.new.true! }.must_raise NoMethodError
154
+ end
155
+
156
+ it "except option accepts a singular symbol" do
157
+ klass = test_class
158
+ Interrobang.bangify klass, only: :so_true
159
+ assert klass.new.so_true!
160
+ -> { klass.new.so_very_true! }.must_raise NoMethodError
161
+ -> { klass.new.true! }.must_raise NoMethodError
162
+ end
163
+
164
+ it "converts only the methods specified in the only option with a block" do
165
+ klass = test_class
166
+ Interrobang.bangify klass, only: [:so_false] do
167
+ raise SomeError
168
+ end
169
+ -> { klass.new.so_false! }.must_raise SomeError
170
+ -> { klass.new.so_true! }.must_raise NoMethodError
171
+ -> { klass.new.true! }.must_raise NoMethodError
172
+ end
173
+
174
+ it "performs the provided block for the bang method" do
175
+ klass = test_class
176
+ Interrobang.bangify klass do
177
+ raise SomeError
178
+ end
179
+ assert klass.new.true!
180
+ -> { klass.new.false! }.must_raise SomeError
181
+ end
182
+
183
+ it "converts super methods when specified" do
184
+ klass = test_class
185
+ Interrobang.bangify klass, include_super: true, prefix: 'ensure_'
186
+ -> { klass.new.ensure_nil! }.must_raise Interrobang::FalsePredicate
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,7 @@
1
+ require 'codeclimate-test-reporter'
2
+ CodeClimate::TestReporter.start
3
+
4
+ require 'minitest/autorun'
5
+ require 'minitest/pride'
6
+
7
+ require File.expand_path('../../lib/interrobang', __FILE__)
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: interrobang
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Faraz Yashar
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-27 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.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.5'
55
+ description: |-
56
+ Convert your predicate_methods? into bang_methods! without
57
+ abusing method_missing.
58
+ email:
59
+ - faraz.yashar@gmail.com
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - ".gitignore"
65
+ - ".travis.yml"
66
+ - ".yardopts"
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - interrobang.gemspec
72
+ - lib/interrobang.rb
73
+ - lib/interrobang/version.rb
74
+ - test/lib/predicate_bang_test.rb
75
+ - test/test_helper.rb
76
+ homepage: https://github.com/fny/interrobang
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.0.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.6
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Convert your predicate_methods? into bang_methods! without abusing method_missing
100
+ test_files:
101
+ - test/lib/predicate_bang_test.rb
102
+ - test/test_helper.rb
103
+ has_rdoc: