r_spec-clone 1.2.3 → 1.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5c76f25e186a2f835a2a006e3b3add6c7b94d4b070bd3a81b866747edff8291f
4
- data.tar.gz: e9203508514fde39e690e145172dd417d2dcd20eb6badc44a1cb34fc3dc7335a
3
+ metadata.gz: ef1c79c6783a2aace9f035ef5935bb556828731501ce7b92f86dcedf58e18d90
4
+ data.tar.gz: 615131453af20ba74f436f0569db9f429af2bd18589de5ee132ef69af8cd09d8
5
5
  SHA512:
6
- metadata.gz: 30681f5232bef7c695e05b169ce5fcf3882277bf981174898d586a01c756b0eec3ca88c9eecf6c02c3deae7d515e84f3bbd404202cb1aef59f63b70fa901f6ca
7
- data.tar.gz: 0e4e21aa8f6aa8d6f281ce99add7018ea6d163fab13fd8cd04863104884244a74566b11d665d3e7a7e5c0e683e474b479d18383b0cf8e7f192b7986cd7947d26
6
+ metadata.gz: bbaa63b25dc7a3d98810d686d5fb4a5cacec5a74ac04d1aab01f86dfc886ef57cf9b9ae20201aaf3a43e95bb626ce363bfe62190142904ceef8526d1d34ef9ab
7
+ data.tar.gz: e6b4d19ef401aa923f31739ab5ee5289929309d762113f82d361f52859c17f24739e18f8236e93db6d47f428e1f09a6aa4c6beabfb5ea938f0fa1f6769cf4835
data/README.md CHANGED
@@ -117,6 +117,8 @@ end
117
117
  # Success: expected to eq "foo".
118
118
  ```
119
119
 
120
+ Note: if you are wondering what the Ruby code generated by using the DSL might look like, an article presents the correspondence between each method via simple examples, available in [English](https://dev.to/cyri_/what-ruby-code-to-expect-from-a-testing-dsl-4oe1), [Chinese](https://ruby-china.org/topics/41441) and [Japanese](https://qiita.com/cyril/items/17ee758e162bae144a07).
121
+
120
122
  ### Expectations
121
123
 
122
124
  Expectations define if the value being tested (_actual_) matches a certain value or specific criteria.
@@ -135,6 +137,12 @@ expect(actual).to equal(expected) # passes if expected.equal?(actual)
135
137
  expect(actual).to be(expected) # passes if expected.equal?(actual)
136
138
  ```
137
139
 
140
+ #### Comparisons
141
+
142
+ ```ruby
143
+ expect(actual).to be_within(delta).of(expected) # passes if (expected - actual).abs <= delta
144
+ ```
145
+
138
146
  #### Regular expressions
139
147
 
140
148
  ```ruby
@@ -147,13 +155,13 @@ expect(actual).to match(expected) # passes if expected.match?(actual)
147
155
  expect { actual }.to raise_exception(expected) # passes if expected exception is raised
148
156
  ```
149
157
 
150
- #### Truth
158
+ #### True
151
159
 
152
160
  ```ruby
153
161
  expect(actual).to be_true # passes if true.equal?(actual)
154
162
  ```
155
163
 
156
- #### Untruth
164
+ #### False
157
165
 
158
166
  ```ruby
159
167
  expect(actual).to be_false # passes if false.equal?(actual)
@@ -172,6 +180,36 @@ expect(actual).to be_instance_of(expected) # passes if expected.equal?(actual
172
180
  expect(actual).to be_an_instance_of(expected) # passes if expected.equal?(actual.class)
173
181
  ```
174
182
 
183
+ #### Predicate
184
+
185
+ ```ruby
186
+ expect(actual).to be_xxx # passes if actual.xxx?
187
+ expect(actual).to be_have_xxx(:yyy) # passes if actual.has_xxx?(:yyy)
188
+ ```
189
+
190
+ ##### Examples
191
+
192
+ ```ruby
193
+ expect([]).to be_empty
194
+ expect(foo: 1).to have_key(:foo)
195
+ ```
196
+
197
+ #### Change
198
+
199
+ ```ruby
200
+ expect { object.action }.to change(object, :value).to(new)
201
+ expect { object.action }.to change(object, :value).from(old).to(new)
202
+ expect { object.action }.to change(object, :value).by(delta)
203
+ expect { object.action }.to change(object, :value).by_at_least(minimum_delta)
204
+ expect { object.action }.to change(object, :value).by_at_most(maximum_delta)
205
+ ```
206
+
207
+ #### Satisfy
208
+
209
+ ```ruby
210
+ expect(actual).to(satisfy { |value| value == expected })
211
+ ```
212
+
175
213
  ### Running specs
176
214
 
177
215
  By convention, specs live in the `spec/` directory of a project. Spec files should end with `_spec.rb` to be recognizable as such.
@@ -232,17 +270,23 @@ bundle exec rake
232
270
 
233
271
  ## Performance
234
272
 
273
+ The benchmarks compare the performance of [`r_spec-clone`](https://rubygems.org/gems/r_spec-clone) with the following frameworks (in alphabetical order):
274
+
275
+ * [`fix`](https://rubygems.org/gems/fix)
276
+ * [`minitest`](https://rubygems.org/gems/minitest)
277
+ * [`rspec`](https://rubygems.org/gems/rspec)
278
+
235
279
  ### Boot time
236
280
 
237
281
  Benchmark against [100 executions of a file containing 1 expectation](https://github.com/cyril/r_spec-clone.rb/blob/main/benchmark/boot_time/) (lower is better).
238
282
 
239
- ![Boot time](https://r-spec.dev/benchmark-boot-time.svg)
283
+ ![Boot time benchmark](https://r-spec.dev/benchmark-boot-time.svg)
240
284
 
241
- ### Run time
285
+ ### Runtime
242
286
 
243
- Benchmark against [1 execution of a file containing 1,000,000 expectations](https://github.com/cyril/r_spec-clone.rb/blob/main/benchmark/run_time/) (lower is better).
287
+ Benchmark against [1 execution of a file containing 100,000 expectations](https://github.com/cyril/r_spec-clone.rb/blob/main/benchmark/run_time/) (lower is better).
244
288
 
245
- ![Run time](https://r-spec.dev/benchmark-run-time.svg)
289
+ ![Runtime benchmark](https://r-spec.dev/benchmark-run-time.svg)
246
290
 
247
291
  ## Test suite
248
292
 
data/lib/r_spec.rb CHANGED
@@ -37,8 +37,8 @@ require_relative File.join("r_spec", "clone", "dsl")
37
37
  #
38
38
  # # Output to the console
39
39
  # # Success: expected to eq 3.
40
- # # Success: expected true to be true.
41
- # # Success: expected false to be false.
40
+ # # Success: expected to be true.
41
+ # # Success: expected to be false.
42
42
  #
43
43
  # @example An inherited definition of let
44
44
  # require "r_spec"
@@ -12,13 +12,13 @@ module RSpec
12
12
  # @return [nil] Write a pending expectation to STDOUT.
13
13
  def self.result(message)
14
14
  ::Expresenter.call(true).with(
15
- actual: new(message),
16
- error: nil,
17
- expected: self,
18
- got: false,
19
- matcher: :raise_exception,
20
- negate: true,
21
- level: :SHOULD
15
+ actual: new(message),
16
+ definition: "raise exception #{self}",
17
+ error: nil,
18
+ expected: self,
19
+ got: false,
20
+ negate: true,
21
+ level: :SHOULD
22
22
  )
23
23
  end
24
24
  end
@@ -19,7 +19,7 @@ module RSpec
19
19
  #
20
20
  # @example
21
21
  # expect("foo") # => #<RSpec::Clone::ExpectationTarget::Value:0x00007f @actual="foo">
22
- # expect { Boom } # => #<RSpec::Clone::ExpectationTarget::Block:0x00007f @callable=#<Proc:0x00007f>>
22
+ # expect { RSpec::Clone::Boom! } # => #<RSpec::Clone::ExpectationTarget::Block:0x... @callable=#<Proc:0x...>>
23
23
  #
24
24
  # @api public
25
25
  def expect(value = self.class.superclass, &block)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "matchi/rspec"
4
- require "matchi/helper"
3
+ require "matchi"
5
4
 
6
5
  module RSpec
7
6
  module Clone
@@ -11,72 +10,240 @@ module RSpec
11
10
  # This module defines a number of methods to create expectations, which
12
11
  # are automatically included into examples.
13
12
  #
14
- # It also includes a collection of expectation matchers 🤹
15
- #
16
- # @example Equivalence matcher
17
- # matcher = eql("foo") # => Matchi::Matcher::Eql.new("foo")
18
- # matcher.matches? { "foo" } # => true
19
- # matcher.matches? { "bar" } # => false
20
- #
21
- # matcher = eq("foo") # => Matchi::Matcher::Eq.new("foo")
22
- # matcher.matches? { "foo" } # => true
23
- # matcher.matches? { "bar" } # => false
24
- #
25
- # @example Identity matcher
26
- # object = "foo"
27
- #
28
- # matcher = equal(object) # => Matchi::Matcher::Equal.new(object)
29
- # matcher.matches? { object } # => true
30
- # matcher.matches? { "foo" } # => false
31
- #
32
- # matcher = be(object) # => Matchi::Matcher::Be.new(object)
33
- # matcher.matches? { object } # => true
34
- # matcher.matches? { "foo" } # => false
35
- #
36
- # @example Regular expressions matcher
37
- # matcher = match(/^foo$/) # => Matchi::Matcher::Match.new(/^foo$/)
38
- # matcher.matches? { "foo" } # => true
39
- # matcher.matches? { "bar" } # => false
40
- #
41
- # @example Expecting errors matcher
42
- # matcher = raise_exception(NameError) # => Matchi::Matcher::RaiseException.new(NameError)
43
- # matcher.matches? { Boom } # => true
44
- # matcher.matches? { true } # => false
45
- #
46
- # @example Truth matcher
47
- # matcher = be_true # => Matchi::Matcher::BeTrue.new
48
- # matcher.matches? { true } # => true
49
- # matcher.matches? { false } # => false
50
- # matcher.matches? { nil } # => false
51
- # matcher.matches? { 4 } # => false
52
- #
53
- # @example Untruth matcher
54
- # matcher = be_false # => Matchi::Matcher::BeFalse.new
55
- # matcher.matches? { false } # => true
56
- # matcher.matches? { true } # => false
57
- # matcher.matches? { nil } # => false
58
- # matcher.matches? { 4 } # => false
59
- #
60
- # @example Nil matcher
61
- # matcher = be_nil # => Matchi::Matcher::BeNil.new
62
- # matcher.matches? { nil } # => true
63
- # matcher.matches? { false } # => false
64
- # matcher.matches? { true } # => false
65
- # matcher.matches? { 4 } # => false
66
- #
67
- # @example Type/class matcher
68
- # matcher = be_instance_of(String) # => Matchi::Matcher::BeInstanceOf.new(String)
69
- # matcher.matches? { "foo" } # => true
70
- # matcher.matches? { 4 } # => false
71
- #
72
- # matcher = be_an_instance_of(String) # => Matchi::Matcher::BeAnInstanceOf.new(String)
73
- # matcher.matches? { "foo" } # => true
74
- # matcher.matches? { 4 } # => false
13
+ # It also includes a collection of expectation matchers.
75
14
  #
76
15
  # @see https://github.com/fixrb/matchi
77
- # @see https://github.com/fixrb/matchi-rspec
78
16
  module Shared
79
- include ::Matchi::Helper
17
+ # Equivalence matcher
18
+ #
19
+ # @example
20
+ # matcher = eq("foo")
21
+ # matcher.matches? { "foo" } # => true
22
+ # matcher.matches? { "bar" } # => false
23
+ #
24
+ # @param expected [#eql?] An expected equivalent object.
25
+ #
26
+ # @return [#matches?] An equivalence matcher.
27
+ #
28
+ # @api public
29
+ def eq(expected)
30
+ ::Matchi::Eq.new(expected)
31
+ end
32
+
33
+ alias eql eq
34
+
35
+ # Identity matcher
36
+ #
37
+ # @example
38
+ # object = "foo"
39
+ # matcher = be(object)
40
+ # matcher.matches? { object } # => true
41
+ # matcher.matches? { "foo" } # => false
42
+ #
43
+ # @param expected [#equal?] The expected identical object.
44
+ #
45
+ # @return [#matches?] An identity matcher.
46
+ #
47
+ # @api public
48
+ def be(expected)
49
+ ::Matchi::Be.new(expected)
50
+ end
51
+
52
+ alias equal be
53
+
54
+ # Comparisons matcher
55
+ #
56
+ # @example
57
+ # matcher = be_within(1).of(41)
58
+ # matcher.matches? { 42 } # => true
59
+ # matcher.matches? { 43 } # => false
60
+ #
61
+ # @param delta [Numeric] A numeric value.
62
+ #
63
+ # @return [#matches?] A comparison matcher.
64
+ #
65
+ # @api public
66
+ def be_within(delta)
67
+ ::Matchi::BeWithin.new(delta)
68
+ end
69
+
70
+ # Regular expressions matcher
71
+ #
72
+ # @example
73
+ # matcher = match(/^foo$/)
74
+ # matcher.matches? { "foo" } # => true
75
+ # matcher.matches? { "bar" } # => false
76
+ #
77
+ # @param expected [#match] A regular expression.
78
+ #
79
+ # @return [#matches?] A regular expression matcher.
80
+ #
81
+ # @api public
82
+ def match(expected)
83
+ ::Matchi::Match.new(expected)
84
+ end
85
+
86
+ # Expecting errors matcher
87
+ #
88
+ # @example
89
+ # matcher = raise_exception(NameError)
90
+ # matcher.matches? { RSpec::Clone::Boom! } # => true
91
+ # matcher.matches? { true } # => false
92
+ #
93
+ # @param expected [Exception, #to_s] The expected exception name.
94
+ #
95
+ # @return [#matches?] An error matcher.
96
+ #
97
+ # @api public
98
+ def raise_exception(expected)
99
+ ::Matchi::RaiseException.new(expected)
100
+ end
101
+
102
+ # True matcher
103
+ #
104
+ # @example
105
+ # matcher = be_true
106
+ # matcher.matches? { true } # => true
107
+ # matcher.matches? { false } # => false
108
+ # matcher.matches? { nil } # => false
109
+ # matcher.matches? { 4 } # => false
110
+ #
111
+ # @return [#matches?] A `true` matcher.
112
+ #
113
+ # @api public
114
+ def be_true
115
+ be(true)
116
+ end
117
+
118
+ # False matcher
119
+ #
120
+ # @example
121
+ # matcher = be_false
122
+ # matcher.matches? { false } # => true
123
+ # matcher.matches? { true } # => false
124
+ # matcher.matches? { nil } # => false
125
+ # matcher.matches? { 4 } # => false
126
+ #
127
+ # @return [#matches?] A `false` matcher.
128
+ #
129
+ # @api public
130
+ def be_false
131
+ be(false)
132
+ end
133
+
134
+ # Nil matcher
135
+ #
136
+ # @example
137
+ # matcher = be_nil
138
+ # matcher.matches? { nil } # => true
139
+ # matcher.matches? { false } # => false
140
+ # matcher.matches? { true } # => false
141
+ # matcher.matches? { 4 } # => false
142
+ #
143
+ # @return [#matches?] A `nil` matcher.
144
+ #
145
+ # @api public
146
+ def be_nil
147
+ be(nil)
148
+ end
149
+
150
+ # Type/class matcher
151
+ #
152
+ # @example
153
+ # matcher = be_an_instance_of(String)
154
+ # matcher.matches? { "foo" } # => true
155
+ # matcher.matches? { 4 } # => false
156
+ #
157
+ # @param expected [Class, #to_s] The expected class name.
158
+ #
159
+ # @return [#matches?] A type/class matcher.
160
+ #
161
+ # @api public
162
+ def be_an_instance_of(expected)
163
+ ::Matchi::BeAnInstanceOf.new(expected)
164
+ end
165
+
166
+ # Change matcher
167
+ #
168
+ # @example
169
+ # object = []
170
+ # matcher = change(object, :length).by(1)
171
+ # matcher.matches? { object << 1 } # => true
172
+ #
173
+ # object = []
174
+ # matcher = change(object, :length).by_at_least(1)
175
+ # matcher.matches? { object << 1 } # => true
176
+ #
177
+ # object = []
178
+ # matcher = change(object, :length).by_at_most(1)
179
+ # matcher.matches? { object << 1 } # => true
180
+ #
181
+ # object = "foo"
182
+ # matcher = change(object, :to_s).from("foo").to("FOO")
183
+ # matcher.matches? { object.upcase! } # => true
184
+ #
185
+ # object = "foo"
186
+ # matcher = change(object, :to_s).to("FOO")
187
+ # matcher.matches? { object.upcase! } # => true
188
+ #
189
+ # @param object [#object_id] An object.
190
+ # @param method [Symbol] The name of a method.
191
+ # @param args [Array] A list of arguments.
192
+ # @param kwargs [Hash] A list of keyword arguments.
193
+ #
194
+ # @return [#matches?] A change matcher.
195
+ #
196
+ # @api public
197
+ def change(object, method, *args, **kwargs, &block)
198
+ ::Matchi::Change.new(object, method, *args, **kwargs, &block)
199
+ end
200
+
201
+ # Satisfy matcher
202
+ #
203
+ # @example
204
+ # matcher = satisfy { |value| value == 42 }
205
+ # matcher.matches? { 42 } # => true
206
+ #
207
+ # @param expected [Proc] A block of code.
208
+ #
209
+ # @return [#matches?] A satisfy matcher.
210
+ #
211
+ # @api public
212
+ def satisfy(&expected)
213
+ ::Matchi::Satisfy.new(&expected)
214
+ end
215
+
216
+ private
217
+
218
+ # Predicate matcher, or default method missing behavior.
219
+ #
220
+ # @example Empty predicate matcher
221
+ # matcher = be_empty
222
+ # matcher.matches? { [] } # => true
223
+ # matcher.matches? { [4] } # => false
224
+ def method_missing(name, *args, **kwargs, &block)
225
+ return super unless predicate_matcher_name?(name)
226
+
227
+ ::Matchi::Predicate.new(name, *args, **kwargs, &block)
228
+ end
229
+
230
+ # :nocov:
231
+
232
+ # Hook method to return whether the obj can respond to id method or not.
233
+ def respond_to_missing?(name, include_private = false)
234
+ predicate_matcher_name?(name) || super
235
+ end
236
+
237
+ # :nocov:
238
+
239
+ # Predicate matcher name detector.
240
+ #
241
+ # @param name [Array, Symbol] The name of a potential predicate matcher.
242
+ #
243
+ # @return [Boolean] Indicates if it is a predicate matcher name or not.
244
+ def predicate_matcher_name?(name)
245
+ name.start_with?("be_", "have_") && !name.end_with?("!", "?")
246
+ end
80
247
  end
81
248
  end
82
249
  end
@@ -95,13 +95,13 @@ module RSpec
95
95
  # `Kernel.exit(false)` with a failure message written to STDERR.
96
96
  def result(passed, actual:, error:, got:, matcher:, negate:)
97
97
  Console.passed_spec ::Expresenter.call(passed).with(
98
- actual: actual,
99
- error: error,
100
- expected: matcher.expected,
101
- got: got,
102
- negate: negate,
103
- matcher: matcher.class.to_sym,
104
- level: :MUST
98
+ actual: actual,
99
+ definition: matcher.to_s,
100
+ error: error,
101
+ expected: matcher.expected,
102
+ got: got,
103
+ negate: negate,
104
+ level: :MUST
105
105
  )
106
106
  rescue ::Expresenter::Fail => e
107
107
  Console.failed_spec(e)
@@ -29,7 +29,7 @@ module RSpec
29
29
  # @raise (see Base#absolute_requirement)
30
30
  def absolute_requirement(matcher:, negate:)
31
31
  super(
32
- ::TestTube.invoke(isolation: false, matcher: matcher, negate: negate, &@input),
32
+ ::TestTube.invoke(isolate: false, matcher: matcher, negate: negate, &@input),
33
33
  matcher: matcher,
34
34
  negate: negate
35
35
  )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r_spec-clone
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.5.0
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-07-15 00:00:00.000000000 Z
11
+ date: 2021-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: expresenter
@@ -16,42 +16,42 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.3.0
19
+ version: 1.4.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.3.0
26
+ version: 1.4.0
27
27
  - !ruby/object:Gem::Dependency
28
- name: matchi-rspec
28
+ name: matchi
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2.0
33
+ version: 3.3.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.2.0
40
+ version: 3.3.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: test_tube
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.0.0
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.0
54
+ version: 2.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement