interrobang 1.0.0

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: 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: