r_spec-clone 1.2.1 → 1.2.2

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: 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