r_spec-clone 1.2.1 → 1.2.2

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: 90252cd64a48b7b40aa2424c1c09c69227e45e414ac5fd8d14a53697c0b1c180
4
- data.tar.gz: 7eb7211ac34e5dfc2f1f74ae17d354f2704feb41e400d5fada1ccaa764912413
3
+ metadata.gz: 7ca7e0d020bebba8aec767197a6c765fa4c0ded5bb96fb58723e5de8321ba1bf
4
+ data.tar.gz: 3e9fd96ec29c5341bb5b8f8a3fb60c9672a816e3dd22e1d80d7593ef78689f74
5
5
  SHA512:
6
- metadata.gz: a7fc657a588d0efd081ead62736ddd0f2595e09f0e4db6df235550503325d46cb4814110e16a4fb55244c07de645878d1e08eab40e5ddcc0226b3a64e318091d
7
- data.tar.gz: ff205ff80822fea221bbcd27bf8a43925617146be2bf48d0c24d525bbe530921ce6f835530bce0cad53ef6f3e694278b6bd9655dbd4506f3691365cb15ce800a
6
+ metadata.gz: 7ae195dc7673cdd06068d376763ca3b67904eb1bea7ec502cdaf74424ffacb2d44c685988e7c22db21e7be2295a9d3de3b93d587e1c0d8696739dfdb8f37216d
7
+ data.tar.gz: 2b3522c31de373f4b9dc3a5d88a9a8e2ec7443d11205d6f93eae91f43a136bead79774333d3d8bac04b96cd07f89eb8c9792c379af0eb380b644da0931d639b4
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,26 @@ 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
+ ```
104
119
 
105
120
  ### Expectations
106
121
 
@@ -237,6 +252,7 @@ __RSpec clone__'s specifications are self-described here: [spec/](https://github
237
252
 
238
253
  * Home page: [https://r-spec.dev/](https://r-spec.dev/)
239
254
  * Cheatsheet: [https://r-spec.dev/cheatsheet.html](https://r-spec.dev/cheatsheet.html)
255
+ * Blog post: [https://batman.buzz/introducing-a-new-rspec-850d48c0f901](https://batman.buzz/introducing-a-new-rspec-850d48c0f901)
240
256
  * Source code: [https://github.com/cyril/r_spec-clone.rb](https://github.com/cyril/r_spec-clone.rb)
241
257
  * API Doc: [https://rubydoc.info/gems/r_spec-clone](https://rubydoc.info/gems/r_spec-clone)
242
258
  * Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
data/lib/r_spec.rb CHANGED
@@ -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
 
@@ -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
@@ -2,15 +2,13 @@
2
2
 
3
3
  require "matchi/rspec"
4
4
 
5
- require_relative File.join("..", "error", "pending_expectation")
6
-
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.
10
+ # This module defines a number of methods to create expectations, which
11
+ # are automatically included into examples.
14
12
  #
15
13
  # It also includes a collection of expectation matchers 🤹
16
14
  #
@@ -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.
@@ -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(isolation: 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.2.2
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-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: expresenter
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 1.1.0
47
+ version: 2.0.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.0.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement