bang 0.1.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.
@@ -0,0 +1,36 @@
1
+ # COPYRIGHT
2
+
3
+ ## NOTICES
4
+
5
+ ### Assay
6
+
7
+ | Project | Bang |
8
+ |-----------|-----------------------------------|
9
+ | Copyright | (c) 2012 Rubyworks |
10
+ | License | (r) BSD-2-Clause |
11
+ | Website | http://rubyworks.github.com/bang |
12
+
13
+ ## LICENSES
14
+
15
+ ### BSD-2-Clause License
16
+
17
+ Redistribution and use in source and binary forms, with or without
18
+ modification, are permitted provided that the following conditions are met:
19
+
20
+ 1. Redistributions of source code must retain the above copyright notice,
21
+ this list of conditions and the following disclaimer.
22
+
23
+ 2. Redistributions in binary form must reproduce the above copyright
24
+ notice, this list of conditions and the following disclaimer in the
25
+ documentation and/or other materials provided with the distribution.
26
+
27
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
28
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
29
+ FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
30
+ COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
31
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
34
+ OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
36
+ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,10 @@
1
+ # HISTORY
2
+
3
+ ## 0.1.0 | 2012-02-09
4
+
5
+ This is the initial release of Bang.
6
+
7
+ Changes:
8
+
9
+ * Happy Birthday!
10
+
@@ -0,0 +1,63 @@
1
+ # Bang! Bang!
2
+
3
+ [Website](http://rubyworks.github.com/bang) /
4
+ [Report Issue](http://github.com/rubyworks/bang/issues) /
5
+ [Mailing List](http://groups.google.com/groups/rubyworks-mailinglist) /
6
+ [Source Code](http://github.com/rubyworks/bang) /
7
+ IRC #rubyworks
8
+
9
+ [![Build Status](https://secure.travis-ci.org/rubyworks/bang.png)](http://travis-ci.org/rubyworks/bang)
10
+
11
+
12
+ ## Description
13
+
14
+ Bang! Bang! is an assertions framework with a very clever design that translates
15
+ any bang call, e.g. `#foo!` into an assertion based on the corresponding query
16
+ call, `#foo?` (if it exists). In practice the framework is similar to MiniTest's
17
+ spec expectation methods, e.g. `#must_equal`, but the dynamic nature of Bang!
18
+ Bang! makes it much more flexible, as it is not limited to a finite set of
19
+ assertion methods.
20
+
21
+ It's also pretty interesting idea that bang methods are asseriton methods.
22
+ In usual Ruby code, bang methods ususually aren't particularly necessary and
23
+ could just as well be handled by non-bang methods, e.g. `#update` vs `#merge!`.
24
+
25
+
26
+ ## Instruction
27
+
28
+ Usage is pretty straight forward.
29
+
30
+ require 'bang'
31
+
32
+ "This string".equals!("That string") #=> raises Bang::Assertion
33
+
34
+ To use Bang! Bang! most effectively with common test frameworks, you may need
35
+ to load an adapter to ensure the framework recognizes the assertions as
36
+ such rather than as ordinary errors.
37
+
38
+ For MiniTest use:
39
+
40
+ require 'bang/minitest'`
41
+
42
+ For TestUnit use:
43
+
44
+ require 'bang/testunit'
45
+
46
+ An RSpec adapter is in the works.
47
+
48
+ Cucumber does not require an adapter as it does not differntiate errors
49
+ from assertions.
50
+
51
+ Note, these adapters simply require the `brass/adapters/minitest` and
52
+ `brass/adapters/testunit` respecitvely along with `bang`. So that's another
53
+ way to do it too.
54
+
55
+
56
+ ## Copyrights
57
+
58
+ Bang Bang is Copyright (c) 2012 Rubyworks
59
+
60
+ You can redistribute it in accordance to the *BSD-2-Clause* license.
61
+
62
+ Please see the included COPYING.md file for license details.
63
+
@@ -0,0 +1,350 @@
1
+ module Bang
2
+
3
+ if RUBY_VERSION < '1.9'
4
+ require 'bang/version'
5
+ else
6
+ require_relative 'bang/version'
7
+ end
8
+
9
+ # Bang's assertion class. Follows standard set by Brass project,
10
+ # defining `#assertion?` method which return `true`.
11
+ #
12
+ class Assertion < ::Exception
13
+
14
+ #
15
+ # Price together an Assetion error give the message used to
16
+ # cause the assertion failure.
17
+ #
18
+ # @return [Assertion] Assertion instance.
19
+ #
20
+ def self.piece(s, a, b, t)
21
+ e = new(message(s, *a, &b))
22
+ e.set_backtrace(t)
23
+ e
24
+ end
25
+
26
+ #
27
+ # Put together an error message representive of the assertion made.
28
+ #
29
+ # @todo Imporve this to better handle operators.
30
+ #
31
+ # @return [String] Failed assertion message.
32
+ #
33
+ def self.message(s, *a, &b)
34
+ "#{s}(%s)" % a.map{ |e| e.inspect }.join(',')
35
+ end
36
+
37
+ #
38
+ # Bang::Assertion is alwasy an assertion.
39
+ #
40
+ # @return [true] Always true.
41
+ #
42
+ def assertion?
43
+ true
44
+ end
45
+ end
46
+
47
+ # Mixin of Object class, will take any undefined bang method, e.g. `foo!`
48
+ # and if there is a corresponding query method, e.g. `foo?`, then it will
49
+ # utilize the query method to make an assertion.
50
+ #
51
+ module MethodMissing
52
+
53
+ #
54
+ # If missing method is a bang method, see if there is a corresponding query
55
+ # method and use that to make an assertion. Will also recognize the same
56
+ # prefixed by `not_`, e.g. `not_equal_to?`.
57
+ #
58
+ def method_missing(s, *a, &b)
59
+ return super(s, *a, &b) unless s.to_s.end_with?('!')
60
+
61
+ neg = false
62
+ name = s.to_s.chomp('!')
63
+
64
+ if name.start_with?('not_')
65
+ neg = true
66
+ name = name[4..-1]
67
+ end
68
+
69
+ meth = method("#{name}?") rescue nil
70
+
71
+ return super(s, *a, &b) unless meth
72
+
73
+ result = meth.call(*a, &b)
74
+
75
+ if !(neg ^ result)
76
+ raise Bang::Assertion.piece(s, a, b, caller)
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ # Mixin for Object class that adds some very useful query methods.
83
+ #
84
+ module ObjectMixin
85
+
86
+ #
87
+ # Is `self` identical with `other`? In other words, do two variables
88
+ # reference the one and the same object.
89
+ #
90
+ # @return [true,false] Whether `self` is identical to `other`.
91
+ #
92
+ def identical?(other)
93
+ other.object_id == object_id
94
+ end
95
+
96
+ #
97
+ # Query method for `#==`. We have to use the `_to` suffix becuase Ruby
98
+ # already defines the prepositionless term as a synonym for `#identical?`.
99
+ # (Hopefully that will change one day.)
100
+ #
101
+ # @return [true,false] Whether `self` is equal to `other`.
102
+ #
103
+ def equal_to?
104
+ other == self
105
+ end
106
+
107
+ #
108
+ # Until we can use `#equal?`, lets make the best of it and offer
109
+ # the plural form as well.
110
+ #
111
+ alias :equals? :equal_to?
112
+
113
+ #
114
+ # Test whether `self` is like `other`. Like is broad equality
115
+ # measure testing `identical?`, `eql?`, `==` and `===`.
116
+ #
117
+ # @todo Should `like?` this include `=~` also?
118
+ #
119
+ # @return [true,false] Whether `self` is like `other`.
120
+ #
121
+ def like?(other)
122
+ other.identical?(self) ||
123
+ other.eql?(self) ||
124
+ other.==(self) ||
125
+ other.===(self)
126
+ end
127
+
128
+ #
129
+ # Test whether `other` is a case of `self` via `#===` method.
130
+ #
131
+ # @return [true,false] Whether `other` is a case of `self`.
132
+ #
133
+ def case?(other)
134
+ other === self
135
+ end
136
+
137
+ #
138
+ # Test whether `self` matches `other` via `#=~` method.
139
+ #
140
+ # @return [true,false] Whether `self` matches `other`.
141
+ #
142
+ def match?(other)
143
+ other =~ self
144
+ end
145
+
146
+ #
147
+ # Test whether `self` is the `true` instance.
148
+ #
149
+ # @return [true,false] Whether `self` is `true`.
150
+ #
151
+ def true?
152
+ TrueClass === self
153
+ end
154
+
155
+ #
156
+ # Test whether `self` is the `false` instance.
157
+ #
158
+ # @return [true,false] Whether `self` is `false`.
159
+ #
160
+ def false?
161
+ FalseClass === self
162
+ end
163
+
164
+ #
165
+ # Yield the given block and return `true` if the `self` is throw,
166
+ # otherwise `false`.
167
+ #
168
+ # @return [true,false] Whether `self` was thrown.
169
+ #
170
+ def thrown?(&block)
171
+ pass = true
172
+ catch(self) do
173
+ begin
174
+ yield
175
+ rescue ArgumentError => err # 1.9 exception
176
+ #msg += ", not #{err.message.split(/ /).last}"
177
+ rescue NameError => err # 1.8 exception
178
+ #msg += ", not #{err.name.inspect}"
179
+ end
180
+ pass = false
181
+ end
182
+ pass
183
+ end
184
+
185
+ #
186
+ # Yield block and return true if it runs without exception and does not
187
+ # return `nil` or `false`.
188
+ #
189
+ # @return [true,false] True if block succeeds, otherwise false.
190
+ #
191
+ def satisfy?(&block)
192
+ begin
193
+ block.call(self)
194
+ rescue
195
+ false
196
+ end
197
+ end
198
+
199
+ end
200
+
201
+ # Mixin for Numeric class that adds `#within?` and `#close?`.
202
+ #
203
+ module NumericMixin
204
+
205
+ #
206
+ # Is this value within a given absolute `delta` of another?
207
+ #
208
+ # @return [true,false] True if within absolute delta, otherwise false.
209
+ #
210
+ def within?(other, delta)
211
+ a, b, d = self.to_f, other.to_f, delta.to_f
212
+
213
+ (b - d) <= a && (b + d) >= a
214
+ end
215
+
216
+ #
217
+ # Is this value within a given relative `epsilon` of another?
218
+ #
219
+ # @return [true,false] True if within relative epsilon, otherwise false.
220
+ #
221
+ def close?(other, epsilon)
222
+ a, b, e = self.to_f, other.to_f, epsilon.to_f
223
+
224
+ d = b * e
225
+
226
+ (b - d) <= a && (b + d) >= a
227
+ end
228
+
229
+ end
230
+
231
+ # Mixin for Proc class that adds `#raises?`, `#rescues?` and `#throws?`.
232
+ #
233
+ module ProcMixin
234
+
235
+ #
236
+ # Execute this procedure and return `true` if the specific given `exception`
237
+ # is raised, otherwise `false`.
238
+ #
239
+ # @return [true,false] Whether exception was raised.
240
+ #
241
+ def raises?(exception)
242
+ begin
243
+ call
244
+ false
245
+ rescue exception => err
246
+ exception == err.class
247
+ rescue Exception => err
248
+ false
249
+ end
250
+ end
251
+
252
+ #
253
+ # Execute this procedure and return `true` if the given `exception`,
254
+ # or subclass there-of is raised, otherwise `false`.
255
+ #
256
+ # @return [true,false] Whether exception was rescued.
257
+ #
258
+ def rescues?(exception)
259
+ begin
260
+ call
261
+ false
262
+ rescue exception => err
263
+ true
264
+ rescue Exception => err
265
+ false
266
+ end
267
+ end
268
+
269
+ #
270
+ # Execute this procedure and return `true` if the given `object`,
271
+ # is thrown, otherwise `false`.
272
+ #
273
+ # @return [true,false] Whether object was thrown.
274
+ #
275
+ def throws?(object)
276
+ pass = true
277
+ catch(object) do
278
+ begin
279
+ call
280
+ rescue ArgumentError => err # 1.9 exception
281
+ #msg += ", not #{err.message.split(/ /).last}"
282
+ rescue NameError => err # 1.8 exception
283
+ #msg += ", not #{err.name.inspect}"
284
+ end
285
+ pass = false
286
+ end
287
+ pass
288
+ end
289
+
290
+ end
291
+
292
+ # Class-level extension for Exception class that adds `#raised?` and `#rescued?`.
293
+ #
294
+ module ExceptionExtension
295
+
296
+ #
297
+ # Yield a given block and return `true` if this exception specifically
298
+ # is raised, otherwise `false`.
299
+ #
300
+ # @return [true,false] Whether exception is raised.
301
+ #
302
+ def raised? #:yield:
303
+ begin
304
+ yield
305
+ false
306
+ rescue self => err
307
+ self == err.class
308
+ rescue Exception
309
+ false
310
+ end
311
+ end
312
+
313
+ #
314
+ # Yield a given block and return `true` if this exception, or a sub-class
315
+ # there-of is raised, otherwise `false`.
316
+ #
317
+ # @return [true,false] Whether exception is rescued.
318
+ #
319
+ def rescued? #:yield:
320
+ begin
321
+ yield
322
+ false
323
+ rescue self
324
+ true
325
+ rescue Exception
326
+ false
327
+ end
328
+ end
329
+
330
+ end
331
+
332
+ end
333
+
334
+ class Object
335
+ include Bang::MethodMissing
336
+ include Bang::ObjectMixin
337
+ end
338
+
339
+ class Proc
340
+ include Bang::ProcMixin
341
+ end
342
+
343
+ class Numeric
344
+ include Bang::NumericMixin
345
+ end
346
+
347
+ class Exception
348
+ extend Bang::ExceptionExtension
349
+ end
350
+
@@ -0,0 +1,2 @@
1
+ require 'brass/adapters/minitest'
2
+ require 'bang'
@@ -0,0 +1,2 @@
1
+ require 'brass/adapters/testunit'
2
+ require 'bang'
@@ -0,0 +1,2 @@
1
+ require 'brass'
2
+ require 'brass/expect'
metadata ADDED
@@ -0,0 +1,90 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bang
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Thomas Sawyer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-02-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: brass
16
+ requirement: &23786500 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *23786500
25
+ - !ruby/object:Gem::Dependency
26
+ name: detroit
27
+ requirement: &23785960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *23785960
36
+ - !ruby/object:Gem::Dependency
37
+ name: qed
38
+ requirement: &23785460 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *23785460
47
+ description: Bang! Bang! provides a dynamic assertions framework utlizing bang methods
48
+ and built to BRASS standards.
49
+ email:
50
+ - transfire@gmail.com
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files:
54
+ - COPYING.md
55
+ - HISTORY.md
56
+ - README.md
57
+ files:
58
+ - lib/bang/minitest.rb
59
+ - lib/bang/testunit.rb
60
+ - lib/bang.rb
61
+ - spec/applique/brass.rb
62
+ - COPYING.md
63
+ - HISTORY.md
64
+ - README.md
65
+ homepage: http://rubyworks.github.com/bang
66
+ licenses:
67
+ - BSD-2-Clause
68
+ post_install_message:
69
+ rdoc_options: []
70
+ require_paths:
71
+ - lib
72
+ required_ruby_version: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ required_rubygems_version: !ruby/object:Gem::Requirement
79
+ none: false
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.11
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Bang methods for assertions!
90
+ test_files: []