r_spec-clone 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90252cd64a48b7b40aa2424c1c09c69227e45e414ac5fd8d14a53697c0b1c180
4
- data.tar.gz: 7eb7211ac34e5dfc2f1f74ae17d354f2704feb41e400d5fada1ccaa764912413
3
+ metadata.gz: c8475d853643279af5a0a255bf7b3fd5b4547f4dd596bc044fa37a5ac2d69ff0
4
+ data.tar.gz: 3d22158ee01cb6f0e4924bd57345225e35d40920b2bffaf0cf862575db4b62ca
5
5
  SHA512:
6
- metadata.gz: a7fc657a588d0efd081ead62736ddd0f2595e09f0e4db6df235550503325d46cb4814110e16a4fb55244c07de645878d1e08eab40e5ddcc0226b3a64e318091d
7
- data.tar.gz: ff205ff80822fea221bbcd27bf8a43925617146be2bf48d0c24d525bbe530921ce6f835530bce0cad53ef6f3e694278b6bd9655dbd4506f3691365cb15ce800a
6
+ metadata.gz: 2f6826b996db0d6b3f727a7bc16b7757f7fc1ae350ca2285cf81aaf4ce8bfb15f0c37a8910bb2413800821524109cd6c655275aa2b800f52ba25aba1c31c9ac7
7
+ data.tar.gz: 53b85ef4eb8b249cdf2f717de35a6c29916c65d28a125e28656e300a5bfb7263d62865fba6d53a2517ae035cf64daa0c2b7b04a82ecaca93903502b0f5c2a59d
data/README.md CHANGED
@@ -6,6 +6,7 @@ A minimalist __RSpec clone__ with all the essentials.
6
6
 
7
7
  ## Status
8
8
 
9
+ [![Home](https://img.shields.io/badge/Home-r--spec.dev-00af8b)](https://r-spec.dev/)
9
10
  [![Version](https://img.shields.io/github/v/tag/cyril/r_spec-clone.rb?label=Version&logo=github)](https://github.com/cyril/r_spec-clone.rb/releases)
10
11
  [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/cyril/r_spec-clone.rb/main)
11
12
  [![CI](https://github.com/cyril/r_spec-clone.rb/workflows/CI/badge.svg?branch=main)](https://github.com/cyril/r_spec-clone.rb/actions?query=workflow%3Aci+branch%3Amain)
@@ -23,7 +24,7 @@ A minimalist __RSpec clone__ with all the essentials.
23
24
 
24
25
  * There is no option to activate monkey-patching.
25
26
  * It does not rely on [hacks such as `at_exit` hook](https://blog.arkency.com/2013/06/are-we-abusing-at-exit/) to trigger the tests.
26
- * Built-in matchers [do not trust _actual_](https://asciinema.org/a/29172?autoplay=1&speed=2) and do not send it messages.
27
+ * Malicious _actual values_ cannot [hack results](https://asciinema.org/a/423547?autoplay=1&speed=2).
27
28
  * If no `subject` has been explicitly determined, none is defined.
28
29
  * If no described class is set, `described_class` is undefined instead of `nil`.
29
30
  * Expectations cannot be added inside a `before` block.
@@ -95,12 +96,28 @@ For unit tests, it is recommended to follow the conventions for method names:
95
96
 
96
97
  To establish certain contexts — think _empty array_ versus _array with elements_ — the `context` method may be used to communicate this to the reader.
97
98
 
98
- Finally, each block of code can be run in a subprocess to isolate side effects with the equivalent methods:
99
+ To execute unit tests while isolating side effects in a sub-process, declined methods can be used: `describe!`, `context!`, `it!`, `its!`. Here is an example:
99
100
 
100
- * `describe!`
101
- * `context!`
102
- * `it!`
103
- * `its!`
101
+ ```ruby
102
+ app = "foo"
103
+
104
+ RSpec.describe "Side effects per example" do
105
+ it! "runs the example in isolation" do
106
+ expect { app.gsub!("foo", "bar") }.to eq "bar"
107
+ expect(app).to eq "bar"
108
+ end
109
+
110
+ it "runs the example" do
111
+ expect(app).to eq "foo"
112
+ end
113
+ end
114
+
115
+ # Success: expected to eq "bar".
116
+ # Success: expected to eq "bar".
117
+ # Success: expected to eq "foo".
118
+ ```
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).
104
121
 
105
122
  ### Expectations
106
123
 
@@ -132,13 +149,13 @@ expect(actual).to match(expected) # passes if expected.match?(actual)
132
149
  expect { actual }.to raise_exception(expected) # passes if expected exception is raised
133
150
  ```
134
151
 
135
- #### Truth
152
+ #### True
136
153
 
137
154
  ```ruby
138
155
  expect(actual).to be_true # passes if true.equal?(actual)
139
156
  ```
140
157
 
141
- #### Untruth
158
+ #### False
142
159
 
143
160
  ```ruby
144
161
  expect(actual).to be_false # passes if false.equal?(actual)
@@ -157,6 +174,21 @@ expect(actual).to be_instance_of(expected) # passes if expected.equal?(actual
157
174
  expect(actual).to be_an_instance_of(expected) # passes if expected.equal?(actual.class)
158
175
  ```
159
176
 
177
+ #### Change
178
+
179
+ ```ruby
180
+ expect { object.action }.to change(object, :value).from(old).to(new)
181
+ expect { object.action }.to change(object, :value).by(delta)
182
+ expect { object.action }.to change(object, :value).by_at_least(minimum_delta)
183
+ expect { object.action }.to change(object, :value).by_at_most(maximum_delta)
184
+ ```
185
+
186
+ #### Satisfy
187
+
188
+ ```ruby
189
+ expect(actual).to(satisfy { |value| value == expected })
190
+ ```
191
+
160
192
  ### Running specs
161
193
 
162
194
  By convention, specs live in the `spec/` directory of a project. Spec files should end with `_spec.rb` to be recognizable as such.
@@ -217,17 +249,23 @@ bundle exec rake
217
249
 
218
250
  ## Performance
219
251
 
252
+ The benchmarks compare the performance of [`r_spec-clone`](https://rubygems.org/gems/r_spec-clone) with the following frameworks (in alphabetical order):
253
+
254
+ * [`fix`](https://rubygems.org/gems/fix)
255
+ * [`minitest`](https://rubygems.org/gems/minitest)
256
+ * [`rspec`](https://rubygems.org/gems/rspec)
257
+
220
258
  ### Boot time
221
259
 
222
260
  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).
223
261
 
224
- ![Boot time](https://r-spec.dev/benchmark-boot-time.svg)
262
+ ![Boot time benchmark](https://r-spec.dev/benchmark-boot-time.svg)
225
263
 
226
- ### Run time
264
+ ### Runtime
227
265
 
228
266
  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).
229
267
 
230
- ![Run time](https://r-spec.dev/benchmark-run-time.svg)
268
+ ![Runtime benchmark](https://r-spec.dev/benchmark-run-time.svg)
231
269
 
232
270
  ## Test suite
233
271
 
@@ -237,6 +275,7 @@ __RSpec clone__'s specifications are self-described here: [spec/](https://github
237
275
 
238
276
  * Home page: [https://r-spec.dev/](https://r-spec.dev/)
239
277
  * Cheatsheet: [https://r-spec.dev/cheatsheet.html](https://r-spec.dev/cheatsheet.html)
278
+ * Blog post: [https://batman.buzz/introducing-a-new-rspec-850d48c0f901](https://batman.buzz/introducing-a-new-rspec-850d48c0f901)
240
279
  * Source code: [https://github.com/cyril/r_spec-clone.rb](https://github.com/cyril/r_spec-clone.rb)
241
280
  * API Doc: [https://rubydoc.info/gems/r_spec-clone](https://rubydoc.info/gems/r_spec-clone)
242
281
  * Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
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"
@@ -201,8 +201,8 @@ module RSpec
201
201
  # @param name [String, nil] The name of the spec.
202
202
  # @param block [Proc] An expectation to evaluate.
203
203
  #
204
- # @raise (see RSpec::ExpectationTarget::Base#result)
205
- # @return (see RSpec::ExpectationTarget::Base#result)
204
+ # @raise (see RSpec::Clone::ExpectationTarget::Base#result)
205
+ # @return (see RSpec::Clone::ExpectationTarget::Base#result)
206
206
  def self.it(name = nil, &block)
207
207
  Clone::Dsl.it(name, &block)
208
208
  end
@@ -329,8 +329,7 @@ module RSpec
329
329
  #
330
330
  # @api public
331
331
  def self.it(_name = nil, &block)
332
- example = ::Class.new(self) { include ExpectationHelper::It }.new
333
- run(example, &block)
332
+ run(example_without_attribute.new, &block)
334
333
  end
335
334
 
336
335
  # :nocov:
@@ -417,15 +416,7 @@ module RSpec
417
416
  #
418
417
  # @api public
419
418
  def self.its(attribute, *args, **kwargs, &block)
420
- example = ::Class.new(self) do
421
- include ExpectationHelper::Its
422
-
423
- define_method(:actual) do
424
- subject.public_send(attribute, *args, **kwargs)
425
- end
426
- end.new
427
-
428
- run(example, &block)
419
+ run(example_with_attribute(attribute, *args, **kwargs).new, &block)
429
420
  end
430
421
 
431
422
  # :nocov:
@@ -495,6 +486,25 @@ module RSpec
495
486
  Console.passed_spec Error::PendingExpectation.result(message)
496
487
  end
497
488
 
489
+ # Example class for concrete test case.
490
+ def self.example_without_attribute
491
+ ::Class.new(self) do
492
+ prepend ExpectationHelper::It
493
+ end
494
+ end
495
+
496
+ # Example class for concrete test case that specifies the actual value of
497
+ # an attribute of the subject.
498
+ def self.example_with_attribute(attribute, *args, **kwargs)
499
+ ::Class.new(self) do
500
+ prepend ExpectationHelper::Its
501
+
502
+ define_method(:actual) do
503
+ subject.public_send(attribute, *args, **kwargs)
504
+ end
505
+ end
506
+ end
507
+
498
508
  # Creates a subprocess and runs the block inside.
499
509
  def self.fork!(&block)
500
510
  pid = fork(&block)
@@ -514,7 +524,7 @@ module RSpec
514
524
  example&.send(AFTER_METHOD)
515
525
  end
516
526
 
517
- private_class_method :fork!, :run
527
+ private_class_method :example_without_attribute, :example_with_attribute, :fork!, :run
518
528
 
519
529
  private
520
530
 
@@ -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
@@ -18,8 +18,8 @@ module RSpec
18
18
  # @return [Block, Value] The wrapped target of an expectation.
19
19
  #
20
20
  # @example
21
- # expect("foo") # => #<RSpec::ExpectationTarget::Value:0x00007fb6b823 @actual="foo">
22
- # expect { Boom } # => #<RSpec::ExpectationTarget::Block:0x00007fb6b826 @callable=#<Proc:0x00007fb6b826>>
21
+ # expect("foo") # => #<RSpec::Clone::ExpectationTarget::Value:0x00007f @actual="foo">
22
+ # expect { Boom } # => #<RSpec::Clone::ExpectationTarget::Block:0x00007f @callable=#<Proc:0x00007f>>
23
23
  #
24
24
  # @api public
25
25
  def expect(value = self.class.superclass, &block)
@@ -31,7 +31,7 @@ module RSpec
31
31
  # @return [Block] The wrapped target of an expectation.
32
32
  #
33
33
  # @example
34
- # is_expected # => #<RSpec::ExpectationTarget::Block:0x00007fb6b8263df8 @callable=#<Proc:0x00007fb6b8263e20>>
34
+ # is_expected # => #<RSpec::Clone::ExpectationTarget::Block:0x00007fb6b8 @callable=#<Proc:0x00007fb6b8>>
35
35
  #
36
36
  # @api public
37
37
  def is_expected
@@ -15,7 +15,7 @@ module RSpec
15
15
  # @return [Block] The wrapped target of an expectation.
16
16
  #
17
17
  # @example
18
- # is_expected # => #<RSpec::ExpectationTarget::Block:0x00007fb6b8263df8 @callable=#<Proc:0x00007fb6b8263e20>>
18
+ # is_expected # => #<RSpec::Clone::ExpectationTarget::Block:0x00007f @callable=#<Proc:0x00007f>>
19
19
  #
20
20
  # @api public
21
21
  def is_expected
@@ -1,83 +1,201 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "matchi/rspec"
4
-
5
- require_relative File.join("..", "error", "pending_expectation")
3
+ require "matchi"
6
4
 
7
5
  module RSpec
8
6
  module Clone
9
7
  module ExpectationHelper
10
8
  # Abstract expectation helper base module.
11
9
  #
12
- # This module defines a number of methods to create expectations, which are
13
- # automatically included into examples.
14
- #
15
- # It also includes a collection of expectation matchers 🤹
16
- #
17
- # @example Equivalence matcher
18
- # matcher = eql("foo") # => Matchi::Matcher::Eql.new("foo")
19
- # matcher.matches? { "foo" } # => true
20
- # matcher.matches? { "bar" } # => false
21
- #
22
- # matcher = eq("foo") # => Matchi::Matcher::Eq.new("foo")
23
- # matcher.matches? { "foo" } # => true
24
- # matcher.matches? { "bar" } # => false
25
- #
26
- # @example Identity matcher
27
- # object = "foo"
28
- #
29
- # matcher = equal(object) # => Matchi::Matcher::Equal.new(object)
30
- # matcher.matches? { object } # => true
31
- # matcher.matches? { "foo" } # => false
32
- #
33
- # matcher = be(object) # => Matchi::Matcher::Be.new(object)
34
- # matcher.matches? { object } # => true
35
- # matcher.matches? { "foo" } # => false
36
- #
37
- # @example Regular expressions matcher
38
- # matcher = match(/^foo$/) # => Matchi::Matcher::Match.new(/^foo$/)
39
- # matcher.matches? { "foo" } # => true
40
- # matcher.matches? { "bar" } # => false
41
- #
42
- # @example Expecting errors matcher
43
- # matcher = raise_exception(NameError) # => Matchi::Matcher::RaiseException.new(NameError)
44
- # matcher.matches? { Boom } # => true
45
- # matcher.matches? { true } # => false
46
- #
47
- # @example Truth matcher
48
- # matcher = be_true # => Matchi::Matcher::BeTrue.new
49
- # matcher.matches? { true } # => true
50
- # matcher.matches? { false } # => false
51
- # matcher.matches? { nil } # => false
52
- # matcher.matches? { 4 } # => false
53
- #
54
- # @example Untruth matcher
55
- # matcher = be_false # => Matchi::Matcher::BeFalse.new
56
- # matcher.matches? { false } # => true
57
- # matcher.matches? { true } # => false
58
- # matcher.matches? { nil } # => false
59
- # matcher.matches? { 4 } # => false
60
- #
61
- # @example Nil matcher
62
- # matcher = be_nil # => Matchi::Matcher::BeNil.new
63
- # matcher.matches? { nil } # => true
64
- # matcher.matches? { false } # => false
65
- # matcher.matches? { true } # => false
66
- # matcher.matches? { 4 } # => false
10
+ # This module defines a number of methods to create expectations, which
11
+ # are automatically included into examples.
67
12
  #
68
- # @example Type/class matcher
69
- # matcher = be_instance_of(String) # => Matchi::Matcher::BeInstanceOf.new(String)
70
- # matcher.matches? { "foo" } # => true
71
- # matcher.matches? { 4 } # => false
72
- #
73
- # matcher = be_an_instance_of(String) # => Matchi::Matcher::BeAnInstanceOf.new(String)
74
- # matcher.matches? { "foo" } # => true
75
- # matcher.matches? { 4 } # => false
13
+ # It also includes a collection of expectation matchers.
76
14
  #
77
15
  # @see https://github.com/fixrb/matchi
78
- # @see https://github.com/fixrb/matchi-rspec
79
16
  module Shared
80
- 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
+ # Regular expressions matcher
55
+ #
56
+ # @example
57
+ # matcher = match(/^foo$/)
58
+ # matcher.matches? { "foo" } # => true
59
+ # matcher.matches? { "bar" } # => false
60
+ #
61
+ # @param expected [#match] A regular expression.
62
+ #
63
+ # @return [#matches?] A regular expression matcher.
64
+ #
65
+ # @api public
66
+ def match(expected)
67
+ ::Matchi::Match.new(expected)
68
+ end
69
+
70
+ # Expecting errors matcher
71
+ #
72
+ # @example
73
+ # matcher = raise_exception(NameError)
74
+ # matcher.matches? { Boom } # => true
75
+ # matcher.matches? { true } # => false
76
+ #
77
+ # @param expected [Exception, #to_s] The expected exception name.
78
+ #
79
+ # @return [#matches?] An error matcher.
80
+ #
81
+ # @api public
82
+ def raise_exception(expected)
83
+ ::Matchi::RaiseException.new(expected)
84
+ end
85
+
86
+ # True matcher
87
+ #
88
+ # @example
89
+ # matcher = be_true
90
+ # matcher.matches? { true } # => true
91
+ # matcher.matches? { false } # => false
92
+ # matcher.matches? { nil } # => false
93
+ # matcher.matches? { 4 } # => false
94
+ #
95
+ # @return [#matches?] A `true` matcher.
96
+ #
97
+ # @api public
98
+ def be_true
99
+ be(true)
100
+ end
101
+
102
+ # False matcher
103
+ #
104
+ # @example
105
+ # matcher = be_false
106
+ # matcher.matches? { false } # => true
107
+ # matcher.matches? { true } # => false
108
+ # matcher.matches? { nil } # => false
109
+ # matcher.matches? { 4 } # => false
110
+ #
111
+ # @return [#matches?] A `false` matcher.
112
+ #
113
+ # @api public
114
+ def be_false
115
+ be(false)
116
+ end
117
+
118
+ # Nil matcher
119
+ #
120
+ # @example
121
+ # matcher = be_nil
122
+ # matcher.matches? { nil } # => true
123
+ # matcher.matches? { false } # => false
124
+ # matcher.matches? { true } # => false
125
+ # matcher.matches? { 4 } # => false
126
+ #
127
+ # @return [#matches?] A `nil` matcher.
128
+ #
129
+ # @api public
130
+ def be_nil
131
+ be(nil)
132
+ end
133
+
134
+ # Type/class matcher
135
+ #
136
+ # @example
137
+ # matcher = be_an_instance_of(String)
138
+ # matcher.matches? { "foo" } # => true
139
+ # matcher.matches? { 4 } # => false
140
+ #
141
+ # @param expected [Class, #to_s] The expected class name.
142
+ #
143
+ # @return [#matches?] A type/class matcher.
144
+ #
145
+ # @api public
146
+ def be_an_instance_of(expected)
147
+ ::Matchi::BeAnInstanceOf.new(expected)
148
+ end
149
+
150
+ # Change matcher
151
+ #
152
+ # @example
153
+ # object = []
154
+ # matcher = change(object, :length).by(1)
155
+ # matcher.matches? { object << 1 } # => true
156
+ #
157
+ # object = []
158
+ # matcher = change(object, :length).by_at_least(1)
159
+ # matcher.matches? { object << 1 } # => true
160
+ #
161
+ # object = []
162
+ # matcher = change(object, :length).by_at_most(1)
163
+ # matcher.matches? { object << 1 } # => true
164
+ #
165
+ # object = "foo"
166
+ # matcher = change(object, :to_s).from("foo").to("FOO")
167
+ # matcher.matches? { object.upcase! } # => true
168
+ #
169
+ # object = "foo"
170
+ # matcher = change(object, :to_s).to("FOO")
171
+ # matcher.matches? { object.upcase! } # => true
172
+ #
173
+ # @param object [#object_id] An object.
174
+ # @param method [Symbol] The name of a method.
175
+ # @param args [Array] A list of arguments.
176
+ # @param kwargs [Hash] A list of keyword arguments.
177
+ #
178
+ # @return [#matches?] A change matcher.
179
+ #
180
+ # @api public
181
+ def change(object, method, *args, **kwargs, &block)
182
+ ::Matchi::Change.new(object, method, *args, **kwargs, &block)
183
+ end
184
+
185
+ # Satisfy matcher
186
+ #
187
+ # @example
188
+ # matcher = satisfy { |value| value == 42 }
189
+ # matcher.matches? { 42 } # => true
190
+ #
191
+ # @param expected [Proc] A block of code.
192
+ #
193
+ # @return [#matches?] A satisfy matcher.
194
+ #
195
+ # @api public
196
+ def satisfy(&expected)
197
+ ::Matchi::Satisfy.new(&expected)
198
+ end
81
199
  end
82
200
  end
83
201
  end
@@ -8,8 +8,8 @@ module RSpec
8
8
  # Wraps the target of an expectation.
9
9
  module ExpectationTarget
10
10
  # @param undefined_value A sentinel value to be able to tell when the user
11
- # did not pass an argument. We can't use `nil` for that because `nil` is a
12
- # valid value to pass.
11
+ # did not pass an argument. We can't use `nil` for that because `nil` is
12
+ # a valid value to pass.
13
13
  # @param value [#object_id, nil] An actual value.
14
14
  # @param block [#call, nil] A code to evaluate.
15
15
  #
@@ -10,14 +10,14 @@ module RSpec
10
10
  module ExpectationTarget
11
11
  # Abstract expectation target base class.
12
12
  #
13
- # @note `RSpec::ExpectationTarget::Base` is not intended to be instantiated
14
- # directly by users. Use `expect` instead.
13
+ # @note `RSpec::Clone::ExpectationTarget::Base` is not intended to be
14
+ # instantiated directly by users. Use `expect` instead.
15
15
  class Base
16
16
  # Instantiate a new expectation target.
17
17
  #
18
- # @param actual [#object_id] The actual value of the code to evaluate.
19
- def initialize(actual)
20
- @actual = actual
18
+ # @param input [#object_id, Proc] The code to evaluate.
19
+ def initialize(input)
20
+ @input = input
21
21
  end
22
22
 
23
23
  # Runs the given expectation, passing if `matcher` returns true.
@@ -52,6 +52,36 @@ module RSpec
52
52
 
53
53
  protected
54
54
 
55
+ # @param test [::TestTube::Base] The state of the experiment.
56
+ # @param matcher [#matches?] The matcher.
57
+ # @param negate [Boolean] The assertion is positive or negative.
58
+ #
59
+ # @return [nil] Write a message to STDOUT.
60
+ #
61
+ # @raise [SystemExit] Terminate execution immediately by calling
62
+ # `Kernel.exit(false)` with a failure message written to STDERR.
63
+ def absolute_requirement(test, matcher:, negate:)
64
+ result(
65
+ passed?(test),
66
+ actual: test.actual,
67
+ error: test.error,
68
+ got: test.got,
69
+ matcher: matcher,
70
+ negate: negate
71
+ )
72
+ end
73
+
74
+ # Code experiment result.
75
+ #
76
+ # @param test [::TestTube::Base] The state of the experiment.
77
+ #
78
+ # @see https://github.com/fixrb/test_tube
79
+ #
80
+ # @return [Boolean] The result of the test (passed or failed).
81
+ def passed?(test)
82
+ test.got.equal?(true)
83
+ end
84
+
55
85
  # @param passed [Boolean] The high expectation passed or failed.
56
86
  # @param actual [#object_id] The actual value.
57
87
  # @param error [Exception, nil] Any raised exception.
@@ -65,13 +95,13 @@ module RSpec
65
95
  # `Kernel.exit(false)` with a failure message written to STDERR.
66
96
  def result(passed, actual:, error:, got:, matcher:, negate:)
67
97
  Console.passed_spec ::Expresenter.call(passed).with(
68
- actual: actual,
69
- error: error,
70
- expected: matcher.expected,
71
- got: got,
72
- negate: negate,
73
- matcher: matcher.class.to_sym,
74
- 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
75
105
  )
76
106
  rescue ::Expresenter::Fail => e
77
107
  Console.failed_spec(e)
@@ -16,31 +16,20 @@ module RSpec
16
16
  # # with `not_to`
17
17
  # expect { actual }.not_to be(4)
18
18
  #
19
- # @note `RSpec::ExpectationTarget::Block` is not intended to be instantiated
20
- # directly by users. Use `expect` instead.
19
+ # @note `RSpec::Clone::ExpectationTarget::Block` is not intended to be
20
+ # instantiated directly by users. Use `expect` instead.
21
21
  class Block < Base
22
22
  protected
23
23
 
24
24
  # @param matcher [#matches?] The matcher.
25
25
  # @param negate [Boolean] The assertion is positive or negative.
26
26
  #
27
- # @return [nil] Write a message to STDOUT.
27
+ # @return (see Base#absolute_requirement)
28
28
  #
29
- # @raise [SystemExit] Terminate execution immediately by calling
30
- # `Kernel.exit(false)` with a failure message written to STDERR.
29
+ # @raise (see Base#absolute_requirement)
31
30
  def absolute_requirement(matcher:, negate:)
32
- experiment = ::TestTube.invoke(
33
- @actual,
34
- isolation: false,
35
- matcher: matcher,
36
- negate: negate
37
- )
38
-
39
- result(
40
- experiment.got.equal?(true),
41
- actual: experiment.actual,
42
- error: experiment.error,
43
- got: experiment.got,
31
+ super(
32
+ ::TestTube.invoke(isolate: false, matcher: matcher, negate: negate, &@input),
44
33
  matcher: matcher,
45
34
  negate: negate
46
35
  )
@@ -16,30 +16,20 @@ module RSpec
16
16
  # # with `not_to`
17
17
  # expect(actual).not_to be(4)
18
18
  #
19
- # @note `RSpec::ExpectationTarget::Value` is not intended to be instantiated
20
- # directly by users. Use `expect` instead.
19
+ # @note `RSpec::Clone::ExpectationTarget::Value` is not intended to be
20
+ # instantiated directly by users. Use `expect` instead.
21
21
  class Value < Base
22
22
  protected
23
23
 
24
24
  # @param matcher [#matches?] The matcher.
25
25
  # @param negate [Boolean] The assertion is positive or negative.
26
26
  #
27
- # @return [nil] Write a message to STDOUT.
27
+ # @return (see Base#absolute_requirement)
28
28
  #
29
- # @raise [SystemExit] Terminate execution immediately by calling
30
- # `Kernel.exit(false)` with a failure message written to STDERR.
29
+ # @raise (see Base#absolute_requirement)
31
30
  def absolute_requirement(matcher:, negate:)
32
- experiment = ::TestTube.pass(
33
- @actual,
34
- matcher: matcher,
35
- negate: negate
36
- )
37
-
38
- result(
39
- experiment.got.equal?(true),
40
- actual: experiment.actual,
41
- error: experiment.error,
42
- got: experiment.got,
31
+ super(
32
+ ::TestTube.pass(@input, matcher: matcher, negate: negate),
43
33
  matcher: matcher,
44
34
  negate: negate
45
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.1
4
+ version: 1.3.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-02 00:00:00.000000000 Z
11
+ date: 2021-07-23 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.1.2
33
+ version: 3.1.1
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.1.2
40
+ version: 3.1.1
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: 1.1.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: 1.1.0
54
+ version: 2.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement