bang 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []