spectus 3.3.3 → 3.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99e857c2dbe2b02d961770b40bd9119fa115665105c99f0a6eb813266e9b72be
4
- data.tar.gz: 6f54bf36215f3f662257cffd68e420051f83f6de13d15d9dca60ffb7e89b9c0f
3
+ metadata.gz: 8767313f403c0f015d1316eabbf06f124ef4ecb136f8edf3529d533602622a8c
4
+ data.tar.gz: 419a5c0e93edac33135d305e9e384fea7d6ca305d68f9bd268f89d4ead020d3c
5
5
  SHA512:
6
- metadata.gz: 5d6b1e7a99bc5d6b52760a8f5fa37f58d485bda7fbf08d9790f78944375d46807366cc9c0232f5f0bb25940b668f89b8a153b78940204ee8e0c54cdc371dacd4
7
- data.tar.gz: 658aaa685fe75ea3fd06c92b0ddca3066efb841cf3c0aa4b252f7d2a9f797ea9f44791ff441bc72bfc76f95fd3f3c532a8b4a1b74e40ea832f6c72ffcbff9b3d
6
+ metadata.gz: 368fb8f488627e6c5b225bd66416ce4a3c8f61aaab0ce0a68ec6d2f354978393299399ccc4f9ea2c8e719b336764b9b7cededa4f6f237a7e5ad9a1495deb47ef
7
+ data.tar.gz: a5e56d1e3c6058f6df75bea0b5d564b0eb2cb6eea620ac9d445bea29a0a45e17302cdddf7cb9b5f7d18609c0b1334527f2495eef264bfb5d9041da453ec1055e
data/README.md CHANGED
@@ -1,11 +1,10 @@
1
1
  # Spectus
2
2
 
3
- [![Build Status](https://api.travis-ci.org/fixrb/spectus.svg?branch=main)][travis]
4
- [![Gem Version](https://badge.fury.io/rb/spectus.svg)][gem]
5
- [![Inline docs](https://inch-ci.org/github/fixrb/spectus.svg?branch=main)][inchpages]
6
- [![Documentation](https://img.shields.io/:yard-docs-38c800.svg)][rubydoc]
3
+ [![Build Status](https://api.travis-ci.org/fixrb/spectus.svg?branch=main)](https://travis-ci.org/fixrb/spectus)
4
+ [![Gem Version](https://badge.fury.io/rb/spectus.svg)](https://rubygems.org/gems/spectus)
5
+ [![Documentation](https://img.shields.io/:yard-docs-38c800.svg)](https://rubydoc.info/gems/spectus/frames)
7
6
 
8
- > Expectation library with [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt)'s requirement levels 🚥
7
+ > Expectation library with [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt) requirement levels 🚥
9
8
 
10
9
  ## Installation
11
10
 
@@ -27,19 +26,102 @@ Or install it yourself as:
27
26
  gem install spectus
28
27
  ```
29
28
 
29
+ ## Overview
30
+
31
+ Assuming that an expectation is an assertion that is either `true` or `false`,
32
+ qualifying it with `MUST`, `SHOULD` and `MAY`, we can draw up several scenarios:
33
+
34
+ | Requirement levels | **MUST** | **SHOULD** | **MAY** |
35
+ | ------------------------- | -------- | ---------- | ------- |
36
+ | Implemented & Matched | `true` | `true` | `true` |
37
+ | Implemented & Not matched | `false` | `true` | `false` |
38
+ | Implemented & Exception | `false` | `false` | `false` |
39
+ | Not implemented | `false` | `false` | `true` |
40
+
41
+ When an expectation is evaluated by Spectus,
42
+
43
+ * in case of a _passed_ expectation, a `Spectus::Result::Pass` instance is _returned_;
44
+ * in case of a _failed_ expectation, a `Spectus::Result::Fail` exception is _raised_.
45
+
30
46
  ## Usage
31
47
 
32
- To begin with, let's include __Spectus__:
48
+ The __Spectus__ library is basically a module containing an `it` instance method that accept a block representing the actual value to be evaluated through an expectation.
49
+
50
+ The `Spectus` module can be included inside a class and used as follows:
33
51
 
34
52
  ```ruby
35
- include Spectus
53
+ require "spectus"
54
+
55
+ class Spec
56
+ include ::Spectus
57
+
58
+ attr_reader :subject
59
+
60
+ def initialize(subject)
61
+ @subject = subject
62
+ end
63
+
64
+ def test_a
65
+ it { subject.upcase }.MUST eql "FOO"
66
+ end
67
+
68
+ def test_b
69
+ it { subject.blank? }.MAY be_true
70
+ end
71
+
72
+ def test_c
73
+ it { subject.length }.SHOULD equal 42
74
+ end
75
+ end
36
76
  ```
37
77
 
78
+ ```ruby
79
+ t = Spec.new("foo")
80
+
81
+ t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
82
+
83
+ t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY, valid: false)
84
+
85
+ t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
86
+ ```
87
+
88
+ ```ruby
89
+ t = Spec.new(4)
90
+
91
+ t.test_a # => raises an exception:
92
+ # Traceback (most recent call last):
93
+ # 6: from ./bin/console:8:in `<main>'
94
+ # 5: from (irb):23
95
+ # 4: from (irb):11:in `test_a'
96
+ # 3: from /Users/cyril/github/fixrb/spectus/lib/spectus/expectation_target.rb:34:in `MUST'
97
+ # 2: from /Users/cyril/github/fixrb/spectus/lib/spectus/requirement_level/base.rb:38:in `call'
98
+ # 1: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/expresenter-1.2.1/lib/expresenter/fail.rb:19:in `with'
99
+ # Spectus::Result::Fail (NoMethodError: undefined method `upcase' for 4:Integer)
100
+
101
+ t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for 4:Integer>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY, valid: false)
102
+
103
+ t.test_c # => raises an exception:
104
+ # Traceback (most recent call last):
105
+ # 6: from ./bin/console:8:in `<main>'
106
+ # 5: from (irb):25
107
+ # 4: from (irb):19:in `test_c'
108
+ # 3: from /Users/cyril/github/fixrb/spectus/lib/spectus/expectation_target.rb:100:in `SHOULD'
109
+ # 2: from /Users/cyril/github/fixrb/spectus/lib/spectus/requirement_level/base.rb:38:in `call'
110
+ # 1: from /Users/cyril/.rbenv/versions/2.7.3/lib/ruby/gems/2.7.0/gems/expresenter-1.2.1/lib/expresenter/fail.rb:19:in `with'
111
+ # Spectus::Result::Fail (NoMethodError: undefined method `length' for 4:Integer.)
112
+ ```
113
+
114
+ ## More examples
115
+
38
116
  ### Absolute Requirement
39
117
 
40
118
  Given the "`ルビー`" object, when it receives `valid_encoding?` method, then it **MUST** be `true`:
41
119
 
42
120
  ```ruby
121
+ require "spectus"
122
+
123
+ include Spectus
124
+
43
125
  it { "ルビー".valid_encoding? }.MUST be_true
44
126
  # => Spectus::Result::Pass(actual: true, error: nil, expected: nil, got: true, matcher: :be_true, negate: false, level: :MUST, valid: true)
45
127
  ```
@@ -51,6 +133,10 @@ The result of the test shows that the spec passed.
51
133
  Given the "`foo`" object, when it receives `length` method, then it **MUST NOT** raise the `NoMethodError` exception:
52
134
 
53
135
  ```ruby
136
+ require "spectus"
137
+
138
+ include Spectus
139
+
54
140
  it { "foo".length }.MUST_NOT raise_exception NoMethodError
55
141
  # => Spectus::Result::Pass(actual: 3, error: nil, expected: NoMethodError, got: true, matcher: :raise_exception, negate: true, level: :MUST, valid: true)
56
142
  ```
@@ -62,6 +148,10 @@ The result of the test shows that the spec passed.
62
148
  Given the `BasicObject` object, when it receives `superclass` method, then it **SHOULD** return the explicit blank class `NilClass`:
63
149
 
64
150
  ```ruby
151
+ require "spectus"
152
+
153
+ include Spectus
154
+
65
155
  it { BasicObject.superclass }.SHOULD equal NilClass
66
156
  # => Spectus::Result::Pass(actual: nil, error: nil, expected: NilClass, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
67
157
  ```
@@ -74,6 +164,10 @@ However, because there isn't any exception, the result of the test shows that th
74
164
  Given the "`1`" object, when it receives `+(1)` method, then it **SHOULD NOT** return the "`11`" value:
75
165
 
76
166
  ```ruby
167
+ require "spectus"
168
+
169
+ include Spectus
170
+
77
171
  it { "1" + 1 }.SHOULD_NOT eql "11"
78
172
  # raise Spectus::Result::Fail(actual: nil, error: #<TypeError: no implicit conversion of Integer into String>, expected: "11", got: nil, matcher: :eql, negate: true, level: :SHOULD, valid: false)
79
173
  ```
@@ -85,17 +179,16 @@ There was a `TypeError` exception, the result of the test shows that the spec fa
85
179
  Given the "`foo`" object, when it receives `blank?` method, then it **MAY** be `false`:
86
180
 
87
181
  ```ruby
182
+ require "spectus"
183
+
184
+ include Spectus
185
+
88
186
  it { "foo".blank? }.MAY be_false
89
187
  # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_false, negate: false, level: :MAY, valid: false)
90
188
  ```
91
189
 
92
190
  The optional `blank?` method is not implemented (unlike in [Ruby on Rails](https://api.rubyonrails.org/classes/Object.html#method-i-blank-3F), for instance), so the result of the test shows that the spec passed.
93
191
 
94
- ### More Examples
95
-
96
- A full list of unit tests can be viewed (and executed) here:
97
- [./test.rb](https://github.com/fixrb/spectus/blob/main/test.rb)
98
-
99
192
  ## Code Isolation
100
193
 
101
194
  When executing expectations, side-effects may occur.
@@ -107,7 +200,10 @@ Because they may or may not be desired, each requirement level has 2 versions:
107
200
  Example of test without isolation:
108
201
 
109
202
  ```ruby
203
+ require "spectus"
204
+
110
205
  include Spectus
206
+
111
207
  greeting = "Hello, world!"
112
208
  it { greeting.gsub!("world", "Alice") }.MUST eql "Hello, Alice!"
113
209
  # => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
@@ -117,7 +213,10 @@ greeting # => "Hello, Alice!"
117
213
  Example of test in isolation:
118
214
 
119
215
  ```ruby
216
+ require "spectus"
217
+
120
218
  include Spectus
219
+
121
220
  greeting = "Hello, world!"
122
221
  it { greeting.gsub!("world", "Alice") }.MUST! eql "Hello, Alice!"
123
222
  # => Spectus::Result::Pass(actual: "Hello, Alice!", error: nil, expected: "Hello, Alice!", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
@@ -145,8 +244,3 @@ The [gem](https://rubygems.org/gems/spectus) is available as open source under t
145
244
  src="https://github.com/fixrb/spectus/raw/main/img/sashite.png"
146
245
  alt="Sashite" /></a>
147
246
  </p>
148
-
149
- [gem]: https://rubygems.org/gems/spectus
150
- [travis]: https://travis-ci.org/fixrb/spectus
151
- [inchpages]: https://inch-ci.org/github/fixrb/spectus
152
- [rubydoc]: https://rubydoc.info/gems/spectus/frames
data/lib/spectus.rb CHANGED
@@ -2,11 +2,101 @@
2
2
 
3
3
  require "matchi/helper"
4
4
 
5
+ require_relative File.join("spectus", "expectation_target")
6
+
5
7
  # Namespace for the Spectus library.
6
8
  #
7
- # @example It MUST equal 42.
9
+ # This module defines the {#it} method to create expectations, which can be
10
+ # automatically included into classes.
11
+ #
12
+ # @example
13
+ # class Spec
14
+ # include ::Spectus
15
+ #
16
+ # attr_reader :subject
17
+ #
18
+ # def initialize(subject)
19
+ # @subject = subject
20
+ # end
21
+ #
22
+ # def test_a
23
+ # it { subject.upcase }.MUST eql "FOO"
24
+ # end
25
+ #
26
+ # def test_b
27
+ # it { subject.blank? }.MAY be_true
28
+ # end
29
+ #
30
+ # def test_c
31
+ # it { subject.length }.SHOULD equal 42
32
+ # end
33
+ # end
34
+ #
35
+ # t = Spec.new("foo")
36
+ # t.test_a # => Spectus::Result::Pass(actual: "FOO", error: nil, expected: "FOO", got: true, matcher: :eql, negate: false, level: :MUST, valid: true)
37
+ # t.test_b # => Spectus::Result::Pass(actual: nil, error: #<NoMethodError: undefined method `blank?' for "foo":String>, expected: nil, got: nil, matcher: :be_true, negate: false, level: :MAY, valid: false)
38
+ # t.test_c # => Spectus::Result::Pass(actual: 3, error: nil, expected: 42, got: false, matcher: :equal, negate: false, level: :SHOULD, valid: false)
39
+ #
40
+ # Or even directly used like this.
41
+ #
42
+ # @example
8
43
  # require 'spectus'
44
+ #
45
+ # include Spectus
46
+ #
9
47
  # it { 42 }.MUST equal 42 # => #<Spectus::Result::Pass...>
48
+ #
49
+ # It also includes a collection of expectation matchers 🤹
50
+ #
51
+ # @example Equivalence matcher
52
+ # matcher = eql("foo") # => Matchi::Matcher::Eql.new("foo")
53
+ # matcher.matches? { "foo" } # => true
54
+ # matcher.matches? { "bar" } # => false
55
+ #
56
+ # @example Identity matcher
57
+ # object = "foo"
58
+ #
59
+ # matcher = equal(object) # => Matchi::Matcher::Equal.new(object)
60
+ # matcher.matches? { object } # => true
61
+ # matcher.matches? { "foo" } # => false
62
+ #
63
+ # @example Regular expressions matcher
64
+ # matcher = match(/^foo$/) # => Matchi::Matcher::Match.new(/^foo$/)
65
+ # matcher.matches? { "foo" } # => true
66
+ # matcher.matches? { "bar" } # => false
67
+ #
68
+ # @example Expecting errors matcher
69
+ # matcher = raise_exception(NameError) # => Matchi::Matcher::RaiseException.new(NameError)
70
+ # matcher.matches? { Boom } # => true
71
+ # matcher.matches? { true } # => false
72
+ #
73
+ # @example Truth matcher
74
+ # matcher = be_true # => Matchi::Matcher::BeTrue.new
75
+ # matcher.matches? { true } # => true
76
+ # matcher.matches? { false } # => false
77
+ # matcher.matches? { nil } # => false
78
+ # matcher.matches? { 4 } # => false
79
+ #
80
+ # @example Untruth matcher
81
+ # matcher = be_false # => Matchi::Matcher::BeFalse.new
82
+ # matcher.matches? { false } # => true
83
+ # matcher.matches? { true } # => false
84
+ # matcher.matches? { nil } # => false
85
+ # matcher.matches? { 4 } # => false
86
+ #
87
+ # @example Nil matcher
88
+ # matcher = be_nil # => Matchi::Matcher::BeNil.new
89
+ # matcher.matches? { nil } # => true
90
+ # matcher.matches? { false } # => false
91
+ # matcher.matches? { true } # => false
92
+ # matcher.matches? { 4 } # => false
93
+ #
94
+ # @example Type/class matcher
95
+ # matcher = be_an_instance_of(String) # => Matchi::Matcher::BeAnInstanceOf.new(String)
96
+ # matcher.matches? { "foo" } # => true
97
+ # matcher.matches? { 4 } # => false
98
+ #
99
+ # @see https://github.com/fixrb/matchi
10
100
  module Spectus
11
101
  include ::Matchi::Helper
12
102
 
@@ -22,5 +112,3 @@ module Spectus
22
112
  ExpectationTarget.new(&input)
23
113
  end
24
114
  end
25
-
26
- require_relative File.join("spectus", "expectation_target")
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("requirement_level", "must")
4
+ require_relative File.join("requirement_level", "should")
5
+ require_relative File.join("requirement_level", "may")
6
+
3
7
  module Spectus
4
8
  # Wraps the target of an expectation.
5
9
  #
@@ -196,7 +200,3 @@ module Spectus
196
200
  attr_reader :callable
197
201
  end
198
202
  end
199
-
200
- require_relative File.join("requirement_level", "must")
201
- require_relative File.join("requirement_level", "should")
202
- require_relative File.join("requirement_level", "may")
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("..", "exam")
4
+ require_relative File.join("..", "result")
5
+
3
6
  module Spectus
4
7
  # Namespace for the requirement levels.
5
8
  module RequirementLevel
@@ -32,8 +35,8 @@ module Spectus
32
35
 
33
36
  # The result of the expectation.
34
37
  #
35
- # @raise [Spectus::Result::Fail] The expectation is `false`.
36
- # @return [Spectus::Result::Pass] The expectation is `true`.
38
+ # @raise [Spectus::Result::Fail] The expectation failed.
39
+ # @return [Spectus::Result::Pass] The expectation passed.
37
40
  def call
38
41
  Result.call(pass?).with(
39
42
  actual: exam.actual,
@@ -64,6 +67,3 @@ module Spectus
64
67
  end
65
68
  end
66
69
  end
67
-
68
- require_relative File.join("..", "exam")
69
- require_relative File.join("..", "result")
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("result", "fail")
4
+ require_relative File.join("result", "pass")
5
+
3
6
  module Spectus
4
7
  # Namespace for the results.
5
8
  module Result
@@ -13,6 +16,3 @@ module Spectus
13
16
  end
14
17
  end
15
18
  end
16
-
17
- require_relative File.join("result", "fail")
18
- require_relative File.join("result", "pass")
@@ -5,6 +5,8 @@ require "expresenter/fail"
5
5
  module Spectus
6
6
  module Result
7
7
  # The class that is responsible for reporting that the expectation is false.
8
+ #
9
+ # @see https://github.com/fixrb/expresenter/blob/v1.2.1/lib/expresenter/fail.rb
8
10
  class Fail < ::Expresenter::Fail
9
11
  end
10
12
  end
@@ -5,6 +5,8 @@ require "expresenter/pass"
5
5
  module Spectus
6
6
  module Result
7
7
  # The class that is responsible for reporting that the expectation is true.
8
+ #
9
+ # @see https://github.com/fixrb/expresenter/blob/v1.2.1/lib/expresenter/pass.rb
8
10
  class Pass < ::Expresenter::Pass
9
11
  end
10
12
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spectus
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.3.3
4
+ version: 3.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyril Kato
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-10 00:00:00.000000000 Z
11
+ date: 2021-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: defi
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.0.2
47
+ version: 2.1.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.0.2
54
+ version: 2.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: brutal
57
57
  requirement: !ruby/object:Gem::Requirement