spectus 1.1.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +0 -5
  5. data/.travis.yml +12 -3
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.md +17 -18
  9. data/README.md +18 -199
  10. data/VERSION.semver +1 -1
  11. data/bin/console +7 -0
  12. data/bin/setup +5 -0
  13. data/lib/spectus.rb +12 -2
  14. data/lib/spectus/expectation_target.rb +86 -12
  15. data/lib/spectus/requirement_level/high.rb +36 -0
  16. data/lib/spectus/requirement_level/low.rb +22 -0
  17. data/lib/spectus/requirement_level/medium.rb +22 -0
  18. data/lib/spectus/sandbox.rb +31 -0
  19. data/{spectus.pem → spectus-gem-public_cert.pem} +0 -0
  20. data/spectus.gemspec +14 -10
  21. metadata +50 -72
  22. metadata.gz.sig +0 -0
  23. data/.coveralls.yml +0 -1
  24. data/example/duck/README.md +0 -6
  25. data/example/duck/app.rb +0 -3
  26. data/example/duck/lib.rb +0 -13
  27. data/example/duck/test.rb +0 -43
  28. data/lib/spectus/dsl.rb +0 -20
  29. data/lib/spectus/matcher.rb +0 -34
  30. data/lib/spectus/matcher/eql.rb +0 -16
  31. data/lib/spectus/matcher/equal.rb +0 -16
  32. data/lib/spectus/matcher/match.rb +0 -16
  33. data/lib/spectus/matcher/raise_exception.rb +0 -22
  34. data/lib/spectus/version.rb +0 -9
  35. data/test/helper_test.rb +0 -4
  36. data/test/spectus/helper_test.rb +0 -1
  37. data/test/spectus/matcher/built_in/helper_test.rb +0 -1
  38. data/test/spectus/matcher/built_in/test_eql.rb +0 -21
  39. data/test/spectus/matcher/built_in/test_equal.rb +0 -21
  40. data/test/spectus/matcher/built_in/test_match.rb +0 -21
  41. data/test/spectus/matcher/built_in/test_raise_exception.rb +0 -21
  42. data/test/spectus/matcher/custom/be_prime/helper_test.rb +0 -13
  43. data/test/spectus/matcher/custom/be_prime/test_be_prime.rb +0 -21
  44. data/test/spectus/matcher/custom/be_the_answer/helper_test.rb +0 -11
  45. data/test/spectus/matcher/custom/be_the_answer/test_be_the_answer.rb +0 -21
  46. data/test/spectus/matcher/custom/helper_test.rb +0 -1
  47. data/test/spectus/matcher/custom/start_with/helper_test.rb +0 -15
  48. data/test/spectus/matcher/custom/start_with/test_start_with.rb +0 -21
  49. data/test/spectus/matcher/helper_test.rb +0 -1
  50. data/test/spectus/test_dsl.rb +0 -9
  51. data/test/spectus/test_matcher.rb +0 -38
  52. data/test/spectus/test_version.rb +0 -11
  53. data/test/support.rb +0 -3
  54. data/test/support/coverage.rb +0 -11
  55. data/test/support/env.rb +0 -1
  56. data/test/support/immutable.rb +0 -12
  57. data/test/support/presenter.rb +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b29a968ab4babf3a903050203e7deb144040793
4
- data.tar.gz: 88bceace4526d5b32086d8cffc4b0bafe0a63eea
3
+ metadata.gz: 867183006b16f6ab6f0d641efbfd37380a4612b8
4
+ data.tar.gz: a478b86f508003282d7544cfd660a6b811b71cb2
5
5
  SHA512:
6
- metadata.gz: 33c4154ad5a8df2a17a18c150f8f08415cde517314b3b108ae25eb5e2150016d88653ff7a20e0bb0f6dd90e4daa4cdf4d443ec6e96da003cc8d0b5a3874ad506
7
- data.tar.gz: 044277ab6398d8d44b2566b858cb394f22e75c6f8dcd09eae299e3beb3245c7c1304f2fb6966d925feb20f0f119e480b3d1635d5011688fc046c6142176ad660
6
+ metadata.gz: 252c54bd2591df3ff5eb38b27ae5482855d08346c9679901bea0d6fba059134a678d9d79235a621c94de6d970eaf195f96144d52034f42379ce903ce46de92f7
7
+ data.tar.gz: 9576c89c47fa07424278f9bcff57e5fd26cf9075a239fc2e3db2e367eedb696e656296a6a07a4ced7ea923a1fc156f493f62410211970ae10262b69d943ad90c
Binary file
data.tar.gz.sig CHANGED
Binary file
data/.gitignore CHANGED
@@ -7,8 +7,3 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
- *.bundle
11
- *.so
12
- *.o
13
- *.a
14
- mkmf.log
@@ -1,6 +1,15 @@
1
1
  language: ruby
2
- script: 'bundle exec rake test:coverage'
2
+ sudo: false
3
+ cache: bundler
4
+ script: 'bundle exec rake test:coverage --trace'
5
+ before_install:
6
+ - gem install bundler
3
7
  rvm:
4
- - 2.0.0
5
- - 2.1.3
8
+ - 1.9.3
9
+ - 2.0
10
+ - 2.1
11
+ - 2.2
6
12
  - ruby-head
13
+ - jruby
14
+ - jruby-head
15
+ - rbx-2
@@ -0,0 +1,13 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities.
4
+
5
+ We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion.
6
+
7
+ Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct.
8
+
9
+ Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team.
10
+
11
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers.
12
+
13
+ This Code of Conduct is adapted from the [Contributor Covenant](http:contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/)
data/Gemfile CHANGED
@@ -1,2 +1,5 @@
1
1
  source 'https://rubygems.org'
2
+
2
3
  gemspec
4
+
5
+ gem 'rubysl-irb' if RUBY_ENGINE.eql?('rbx')
data/LICENSE.md CHANGED
@@ -1,22 +1,21 @@
1
- Copyright (c) 2014 Cyril Wack
1
+ The MIT License (MIT)
2
2
 
3
- MIT License
3
+ Copyright (c) 2014 Cyril Wack
4
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:
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:
12
11
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
15
14
 
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.
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
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,13 +1,12 @@
1
1
  # Spectus
2
2
 
3
3
  [![Build Status](https://travis-ci.org/fixrb/spectus.svg?branch=master)](https://travis-ci.org/fixrb/spectus)
4
- [![Coverage Status](http://img.shields.io/coveralls/fixrb/spectus.svg?branch=master)](https://coveralls.io/r/fixrb/spectus)
5
4
  [![Dependency Status](https://gemnasium.com/fixrb/spectus.svg)](https://gemnasium.com/fixrb/spectus)
6
5
  [![Gem Version](http://img.shields.io/gem/v/spectus.svg)](https://rubygems.org/gems/spectus)
7
6
  [![Inline docs](http://inch-ci.org/github/fixrb/spectus.svg?branch=master)](http://inch-ci.org/github/fixrb/spectus)
8
7
  [![Documentation](http://img.shields.io/:yard-docs-38c800.svg)](http://rubydoc.info/gems/spectus/frames)
9
8
 
10
- > Expectation library with some built-in matchers for Ruby.
9
+ > Expectation library with [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt)'s requirement levels, and some matchers for Ruby.
11
10
 
12
11
  ## Contact
13
12
 
@@ -17,7 +16,9 @@
17
16
 
18
17
  ## Rubies
19
18
 
20
- __Spectus__ is supported by Ruby (MRI) 2+.
19
+ * [MRI](https://www.ruby-lang.org/)
20
+ * [Rubinius](http://rubini.us/)
21
+ * [JRuby](http://jruby.org/)
21
22
 
22
23
  ## Installation
23
24
 
@@ -29,221 +30,47 @@ gem 'spectus'
29
30
 
30
31
  And then execute:
31
32
 
32
- ```shell
33
- $ bundle
34
- ```
33
+ $ bundle
35
34
 
36
35
  Or install it yourself as:
37
36
 
38
- ```shell
39
- $ gem install spectus
40
- ```
41
-
42
- ## Why would I want this library?
43
-
44
- * It's 143 lines of fast and KISS code.
45
- * Atomic state transitions, unmutated objects, thread-safe.
46
- * Provides a generic and consistent DSL for assertions.
47
-
48
- ## API
49
-
50
- The [Spectus DSL](lib/spectus/dsl.rb) provides the `expect` method.
51
- It takes a block parameter and responds to:
52
-
53
- * `to(definition)`
54
- * `not_to(definition)`
55
-
56
- Then, it returns `true` or `false`; or it raises an exception.
37
+ $ gem install spectus
57
38
 
58
39
  ## Usage
59
40
 
60
- ```ruby
61
- class Duck
62
- def walks
63
- "Klop klop!"
64
- end
65
-
66
- def swims
67
- "Swoosh..."
68
- end
69
-
70
- def quacks
71
- puts "Quaaaaaack!"
72
- end
73
- end
74
-
75
- @bird = Duck.new
76
- ```
77
-
78
- > When I see a `#<Duck:0x007f96b285d6d0>` that ...
41
+ **Absolute requirement** definition:
79
42
 
80
43
  ```ruby
81
- require 'spectus'
82
- extend Spectus::DSL
83
-
84
- # Let's define the custom matcher `capture_stdout`.
85
- require 'stringio'
86
- module Spectus
87
- module Matcher
88
- class CaptureStdout
89
- def initialize expected
90
- @expected = expected
91
- end
92
-
93
- def matches?
94
- begin
95
- orig_std = $stdout
96
- $stdout = StringIO.new
97
- yield
98
- $stdout.string.eql? @expected
99
- ensure
100
- $stdout = orig_std
101
- end
102
- end
103
- end
104
- end
105
- end
106
-
107
- expectation_1 = expect { @bird.walks }.to eql: "Klop klop!"
108
- expectation_2 = expect { @bird.swims }.to eql: "Swoosh..."
109
- expectation_3 = expect { @bird.quacks }.to capture_stdout: "Quaaaaaack!\n"
110
- expectation_4 = expect { @bird.speaks }.to raise_exception: NoMethodError
111
-
112
- case (expectation_1 == true &&
113
- expectation_2 == true &&
114
- expectation_3 == true &&
115
- expectation_4 == true)
116
- when true then puts "I call that #{@bird} a duck."
117
- else abort 'WAT?'
118
- end
44
+ Spectus.this { 'foo'.upcase }.MUST eql: 'FOO' # => true
119
45
  ```
120
46
 
121
- > I call that `#<Duck:0x007f96b285d6d0>` a duck.
122
-
123
- ## Built-in matchers
124
-
125
- ### Equivalence
47
+ **Absolute prohibition** definition:
126
48
 
127
49
  ```ruby
128
- expect { 'foo' }.to eql: 'foo' # => true
50
+ Spectus.this { 'foo'.length }.MUST_NOT equal: 42 # => true
129
51
  ```
130
52
 
131
- ### Identity
53
+ **Recommended** definition:
132
54
 
133
55
  ```ruby
134
- expect { :foo }.to equal: :foo # => true
56
+ Spectus.this { 'foo'.valid_encoding? }.SHOULD equal: true # => true
135
57
  ```
136
58
 
137
- ### Regular expressions
59
+ **Not recommended** definition:
138
60
 
139
61
  ```ruby
140
- expect { 'foo' }.to({match: /^foo$/}) # => true
62
+ Spectus.this { ''.blank? }.SHOULD_NOT raise_exception: NoMethodError # => false
141
63
  ```
142
64
 
143
- ### Expecting errors
144
-
145
- ```ruby
146
- expect { Foo }.to raise_exception: NameError # => true
147
- ```
148
-
149
- ## Custom matchers
150
-
151
- Custom matchers can also be defined for expressing expectations.
152
-
153
- ### Be prime
154
-
155
- The following expression...
65
+ **Optional** definition:
156
66
 
157
67
  ```ruby
158
- require 'prime'
159
- expect { Prime.prime? 42 }.to equal: false # => true
68
+ Spectus.this { 'foo'.bar }.MAY match: /^foo$/ # => true
160
69
  ```
161
70
 
162
- ...could be refactored into:
163
-
164
- ```ruby
165
- expect { 42 }.not_to :be_prime # => true
166
- ```
167
-
168
- It can be done with this custom matcher:
169
-
170
- ```ruby
171
- require 'prime'
172
-
173
- module Spectus
174
- module Matcher
175
- class BePrime
176
- def matches?
177
- Prime.prime? yield
178
- end
179
- end
180
- end
181
- end
182
- ```
183
-
184
- ### Be the answer
185
-
186
- The following expression...
187
-
188
- ```ruby
189
- expect { 42 }.to equal: 42 # => true
190
- ```
191
-
192
- ...could be refactored into:
193
-
194
- ```ruby
195
- expect { 42 }.to :be_the_answer # => true
196
- ```
197
-
198
- It can be done with this custom matcher:
199
-
200
- ```ruby
201
- module Spectus
202
- module Matcher
203
- class BeTheAnswer
204
- def matches?
205
- 42.equal? yield
206
- end
207
- end
208
- end
209
- end
210
- ```
211
-
212
- ### Start with
213
-
214
- The following expression...
215
-
216
- ```ruby
217
- expect { 'foobar' }.to match: /^foo/ # => true
218
- ```
219
-
220
- ...could be refactored into:
221
-
222
- ```ruby
223
- expect { 'foobar' }.to start_with: 'foo' # => true
224
- ```
225
-
226
- It can be done with this custom matcher:
227
-
228
- ```ruby
229
- module Spectus
230
- module Matcher
231
- class StartWith
232
- def initialize expected
233
- @expected = expected
234
- end
235
-
236
- def matches?
237
- !Regexp.new("^#{@expected}").match(yield).nil?
238
- end
239
- end
240
- end
241
- end
242
- ```
243
-
244
- ## Presentations
71
+ ## Versioning
245
72
 
246
- * [こんばんは、条件やビヘイビアテスト](https://speakerdeck.com/cyril/konbanha-tiao-jian-yabiheibiatesuto)
73
+ __Spectus__ follows [Semantic Versioning 2.0](http://semver.org/).
247
74
 
248
75
  ## Contributing
249
76
 
@@ -252,11 +79,3 @@ end
252
79
  3. Commit your changes (`git commit -am 'Add some feature'`)
253
80
  4. Push to the branch (`git push origin my-new-feature`)
254
81
  5. Create a new Pull Request
255
-
256
- ## Versioning
257
-
258
- __Spectus__ follows [Semantic Versioning 2.0](http://semver.org/)
259
-
260
- ## Copyright
261
-
262
- &copy; 2014 [Cyril Wack](https://plus.google.com/+CyrilWack?rel=author)
@@ -1 +1 @@
1
- 1.1.1
1
+ 2.0.0
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'spectus'
5
+
6
+ require 'irb'
7
+ IRB.start
@@ -0,0 +1,5 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
@@ -1,8 +1,18 @@
1
- require_relative File.join 'spectus', 'dsl'
2
- require_relative File.join 'spectus', 'version'
1
+ require_relative File.join 'spectus', 'expectation_target'
3
2
 
4
3
  # Namespace for the Spectus library.
5
4
  #
6
5
  # @api private
7
6
  module Spectus
7
+ # Expectations are built with this method.
8
+ #
9
+ # @api public
10
+ #
11
+ # @example Absolute requirement definition
12
+ # this { 42 }.MUST equal: 42 # => true
13
+ #
14
+ # @return [ExpectationTarget] the expectation target.
15
+ def self.this(&input)
16
+ ExpectationTarget.new(&input)
17
+ end
8
18
  end
@@ -1,32 +1,106 @@
1
- require_relative 'matcher'
1
+ require_relative File.join 'requirement_level', 'high'
2
+ require_relative File.join 'requirement_level', 'medium'
3
+ require_relative File.join 'requirement_level', 'low'
2
4
 
3
5
  module Spectus
4
-
5
6
  # Wraps the target of an expectation.
6
7
  #
7
8
  # @example
8
- # expect { do_something } # => ExpectationTarget wrapping the block
9
+ # this { stuff } # => ExpectationTarget wrapping the block
9
10
  class ExpectationTarget < BasicObject
10
- def initialize &actual
11
+ # Create a new expection target
12
+ #
13
+ def initialize(&actual)
11
14
  @actual = actual
12
15
  end
13
16
 
14
- # Evaluate to a positive assertion.
17
+ # This word, or the terms "REQUIRED" or "SHALL", mean that the
18
+ # definition is an absolute requirement of the specification.
19
+ #
20
+ # @api public
21
+ #
22
+ # @example _Absolute requirement_ definition
23
+ # this { 'foo'.upcase }.MUST eql: 'FOO' # => true
24
+ #
25
+ # @param [Hash] definition
26
+ #
27
+ # @return [Boolean] report if the expectation is true or false.
28
+ def MUST(definition)
29
+ RequirementLevel::High.new(definition).pass?(&@actual)
30
+ end
31
+
32
+ # This phrase, or the phrase "SHALL NOT", mean that the
33
+ # definition is an absolute prohibition of the specification.
15
34
  #
16
35
  # @api public
17
36
  #
18
- # @see Matcher#pass?
19
- def to definition
20
- Matcher.pass? false, definition, &@actual
37
+ # @example _Absolute prohibition_ definition
38
+ # this { 'foo'.length }.MUST_NOT equal: 42 # => true
39
+ #
40
+ # @param [Hash] definition
41
+ #
42
+ # @return [Boolean] report if the expectation is true or false.
43
+ def MUST_NOT(definition)
44
+ RequirementLevel::High.new(definition, true).pass?(&@actual)
21
45
  end
22
46
 
23
- # Evaluate to a negative assertion.
47
+ # This word, or the adjective "RECOMMENDED", mean that there
48
+ # may exist valid reasons in particular circumstances to ignore a
49
+ # particular item, but the full implications must be understood and
50
+ # carefully weighed before choosing a different course.
24
51
  #
25
52
  # @api public
26
53
  #
27
- # @see Matcher#pass?
28
- def not_to definition
29
- Matcher.pass? true, definition, &@actual
54
+ # @example _Recommended_ definition
55
+ # this { 'foo'.valid_encoding? }.SHOULD equal: true # => true
56
+ #
57
+ # @param [Hash] definition
58
+ #
59
+ # @return [Boolean] report if the expectation is true or false.
60
+ def SHOULD(definition)
61
+ RequirementLevel::Medium.new(definition).pass?(&@actual)
62
+ end
63
+
64
+ # This phrase, or the phrase "NOT RECOMMENDED" mean that
65
+ # there may exist valid reasons in particular circumstances when the
66
+ # particular behavior is acceptable or even useful, but the full
67
+ # implications should be understood and the case carefully weighed
68
+ # before implementing any behavior described with this label.
69
+ #
70
+ # @api public
71
+ #
72
+ # @example _Not recommended_ definition
73
+ # this { ''.blank? }.SHOULD_NOT raise_exception: NoMethodError # => false
74
+ #
75
+ # @param [Hash] definition
76
+ #
77
+ # @return [Boolean] report if the expectation is true or false.
78
+ def SHOULD_NOT(definition)
79
+ RequirementLevel::Medium.new(definition, true).pass?(&@actual)
80
+ end
81
+
82
+ # This word, or the adjective "OPTIONAL", mean that an item is
83
+ # truly optional. One vendor may choose to include the item because a
84
+ # particular marketplace requires it or because the vendor feels that
85
+ # it enhances the product while another vendor may omit the same item.
86
+ # An implementation which does not include a particular option MUST be
87
+ # prepared to interoperate with another implementation which does
88
+ # include the option, though perhaps with reduced functionality. In the
89
+ # same vein an implementation which does include a particular option
90
+ # MUST be prepared to interoperate with another implementation which
91
+ # does not include the option (except, of course, for the feature the
92
+ # option provides.)
93
+ #
94
+ # @api public
95
+ #
96
+ # @example _Optional_ definition
97
+ # this { 'foo'.bar }.MAY match: /^foo$/ # => true
98
+ #
99
+ # @param [Hash] definition
100
+ #
101
+ # @return [Boolean] report if the expectation is true or false.
102
+ def MAY(definition)
103
+ RequirementLevel::Low.new(definition).pass?(&@actual)
30
104
  end
31
105
  end
32
106
  end