r_spec 1.0.0.beta7 → 1.0.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: 46557ee64f6cc554942399aa9219e9102879b2b7b113e53dc4ba63d2c0c5c0af
4
- data.tar.gz: a83b773e20cf2db46b28586be6836d7913a4c3b8f9bf2ce747110f2556737374
3
+ metadata.gz: b251a708b0d9e2f0dcc8a17f7ef08cfeeafa6e553446e9a650431c9aaf7b6951
4
+ data.tar.gz: 528cbc2cd07397ba094a5f08703be53467ac04ee85c82f1cd1465e419f4c5c92
5
5
  SHA512:
6
- metadata.gz: b7c89ce9b933e7adcfc26e03c2f4417ed44c423ca56932f173b2161572877967df37d99c9a560e8cf64c58458777842cb0db7eb1396c89a7f052d981b45f9864
7
- data.tar.gz: 51c4b747116d8f1bb3bb2e593b00aa940ec463d1b9a03506984f2b445f3607febd455884051279f73cef2fc2edac7cfe6d9b4de210c1f1cef6402bd501729f6c
6
+ metadata.gz: 7132f226d0510929ec1a466c2c3e9a3c90a654efd399646476eb04b5fbdcad84254791eb270b83ca68e2c17ad06ca98581a79251714ae7032a9eb888f8716db2
7
+ data.tar.gz: 55d0b1f4e98feeca3c875c542529e1ea5a4f43093a30658f56670f380de23f7f5402e562fccfb85e69e234a066f06ec8600493fcdedd871d78183ea419d055f6
data/README.md CHANGED
@@ -6,33 +6,32 @@ A minimalist __[RSpec](https://github.com/rspec/rspec) clone__ with all the esse
6
6
 
7
7
  ## Status
8
8
 
9
- [![Gem Version](https://badge.fury.io/rb/r_spec.svg)](https://badge.fury.io/rb/r_spec)
10
- [![Build Status](https://travis-ci.org/cyril/r_spec.rb.svg?branch=main)](https://travis-ci.org/cyril/r_spec.rb)
11
- [![Inline Docs](https://inch-ci.org/github/cyril/r_spec.rb.svg)](https://inch-ci.org/github/cyril/r_spec.rb)
12
- [![Documentation](https://img.shields.io/:yard-docs-38c800.svg)](https://rubydoc.info/gems/r_spec/frames)
9
+ [![Version](https://img.shields.io/github/v/tag/cyril/r_spec.rb?include_prereleases&label=Version&logo=github&sort=semver)](https://github.com/cyril/r_spec.rb/releases)
10
+ [![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?)](https://rubydoc.info/github/cyril/r_spec.rb/main)
11
+ [![CI](https://github.com/cyril/r_spec.rb/workflows/CI/badge.svg?branch=main)](https://github.com/cyril/r_spec.rb/actions?query=workflow%3Aci+branch%3Amain)
12
+ [![RuboCop](https://github.com/cyril/r_spec.rb/workflows/RuboCop/badge.svg?branch=main)](https://github.com/cyril/r_spec.rb/actions?query=workflow%3Arubocop+branch%3Amain)
13
+ [![License](https://img.shields.io/github/license/cyril/r_spec.rb?label=License&logo=github)](https://github.com/cyril/r_spec.rb/raw/main/LICENSE.md)
13
14
 
14
- ## Project Goals
15
+ ## Project goals
15
16
 
16
17
  * Enforce the guidelines and best practices outlined in the community [RSpec style guide](https://rspec.rubystyle.guide/).
17
- * Provide most of RSpec's DSL to express expected outcomes of a code example without magic power.
18
+ * Provide most of RSpec's DSL to express expected outcomes of a code example with no magical powers.
18
19
 
19
- ## Some Differences
20
+ ## Some differences
20
21
 
21
22
  * Less features and an implementation with much less code complexity.
22
23
  * Spec files can also be executed directly with the `ruby` executable.
23
24
  * There is no option to activate monkey-patching.
24
25
  * It does not rely on hacks such as `at_exit` hook to trigger the tests.
25
- * Built-in matchers do not trust _actual_ and do not send it messages.
26
+ * Built-in matchers [do not trust _actual_](https://asciinema.org/a/29172?autoplay=1&speed=2) and do not send it messages.
26
27
  * If no `subject` has been explicitly determined, none is defined.
27
28
  * If no described class is set, `described_class` is undefined instead of `nil`.
28
29
  * Expectations cannot be added inside a `before` block.
29
30
  * [Arbitrary helper methods](https://relishapp.com/rspec/rspec-core/v/3-10/docs/helper-methods/arbitrary-helper-methods) are not exposed to examples.
30
31
  * The `let` method defines a helper method rather than a memoized helper method.
31
32
  * The one-liner `is_expected` syntax also works with block expectations.
32
- * All `subject` definitions must come _before_ examples.
33
- * All `before` definitions must come _before_ examples.
34
- * All `after` definitions must come _before_ examples.
35
- * All `let` definitions must come _before_ examples.
33
+ * `subject`, `before`, `after` and `let` definitions must come before examples.
34
+ * Each [`context` runs its tests in _isolation_](https://asciinema.org/a/29070?autoplay=1&speed=2) to prevent side effects.
36
35
 
37
36
  ## Important ⚠️
38
37
 
@@ -51,7 +50,7 @@ Following [RubyGems naming conventions](https://guides.rubygems.org/name-your-ge
51
50
  Add this line to your application's Gemfile:
52
51
 
53
52
  ```ruby
54
- gem "r_spec", ">= 1.0.0.beta7"
53
+ gem "r_spec"
55
54
  ```
56
55
 
57
56
  And then execute:
@@ -63,7 +62,7 @@ bundle
63
62
  Or install it yourself as:
64
63
 
65
64
  ```sh
66
- gem install r_spec --pre
65
+ gem install r_spec
67
66
  ```
68
67
 
69
68
  ## Overview
@@ -74,7 +73,7 @@ Inspired by [RSpec](https://rspec.info/), it includes a domain specific language
74
73
 
75
74
  A basic spec looks something like this:
76
75
 
77
- [![Super DRY example](https://asciinema.org/a/418672.svg)](https://asciinema.org/a/418672?autoplay=1)
76
+ [![RSpec clone demo](https://asciinema.org/a/422210.svg)](https://asciinema.org/a/422210?autoplay=1&speed=2)
78
77
 
79
78
  ## Usage
80
79
 
@@ -105,7 +104,8 @@ For unit tests, it is recommended to follow the conventions for method names:
105
104
  * instance methods are prefixed with `#`, class methods with `.`.
106
105
 
107
106
  To establish certain contexts — think _empty array_ versus _array with elements_ — the `context` method may be used to communicate this to the reader.
108
- It has a different name, but behaves exactly like `describe`.
107
+ Its behavior is slightly different from `describe` because each `context` runs its tests in isolation,
108
+ so side effects caused by testing do not propagate out of contexts.
109
109
 
110
110
  `describe` and `context` take an optional description as argument and a block containing the individual specs or nested groupings.
111
111
 
@@ -224,31 +224,28 @@ task default: :test
224
224
 
225
225
  Benchmark against [100 executions of a file containing one expectation](https://github.com/cyril/r_spec.rb/blob/main/benchmark/) (lower is better).
226
226
 
227
- | Framework | Seconds to complete |
228
- |-------------|---------------------|
229
- | `r_spec` | 13.0 |
230
- | `rspec` | 32.2 |
231
- | `minitest` | 17.5 |
232
- | `test-unit` | 20.5 |
227
+ ![Runtime](https://r-spec.dev/benchmark-runtime.png)
233
228
 
234
- ## Test Suite
229
+ ## Test suite
235
230
 
236
231
  __RSpec clone__'s specifications are self-described here: [spec/](https://github.com/cyril/r_spec.rb/blob/main/spec/)
237
232
 
238
233
  ## Contact
239
234
 
240
- * Home page: https://r-spec.dev
241
- * Source code: https://github.com/cyril/r_spec.rb
235
+ * Home page: [https://r-spec.dev/](https://r-spec.dev/)
236
+ * Cheatsheet: [https://r-spec.dev/cheatsheet.html](https://r-spec.dev/cheatsheet.html)
237
+ * Source code: [https://github.com/cyril/r_spec.rb](https://github.com/cyril/r_spec.rb)
238
+ * API Doc: [https://rubydoc.info/gems/r_spec](https://rubydoc.info/gems/r_spec)
242
239
  * Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
243
240
 
244
- ## Special Thanks ❤️
241
+ ## Special thanks ❤️
245
242
 
246
243
  I would like to thank the whole [RSpec team](https://rspec.info/about/) for all their work.
247
244
  It's a great framework and it's a pleasure to work with every day.
248
245
 
249
246
  Without RSpec, this clone would not have been possible.
250
247
 
251
- ## Buy me a Coffee
248
+ ## Buy me a coffee
252
249
 
253
250
  If you like this project please consider making a small donation.
254
251
 
@@ -260,4 +257,12 @@ __RSpec clone__ follows [Semantic Versioning 2.0](https://semver.org/).
260
257
 
261
258
  ## License
262
259
 
263
- The [gem](https://rubygems.org/gems/r_spec) is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
260
+ The [gem](https://rubygems.org/gems/r_spec) is available as open source under the terms of the [MIT License](https://github.com/cyril/r_spec.rb/raw/main/LICENSE.md).
261
+
262
+ ## One more thing
263
+
264
+ Under the hood, __RSpec clone__ is largely animated by [a collection of testing libraries designed to make programmers happy](https://github.com/fixrb/).
265
+
266
+ It's a living example of what we can do combining small libraries together that can boost the fun of programming.
267
+
268
+ ![Fix testing tools logo for Ruby](https://github.com/cyril/r_spec.rb/raw/main/img/fixrb.svg)
data/lib/r_spec.rb CHANGED
@@ -65,7 +65,46 @@ require_relative File.join("r_spec", "dsl")
65
65
  #
66
66
  # @api public
67
67
  module RSpec
68
- # Specs are built with this method.
68
+ # Defines an example group that establishes a specific context, like _empty
69
+ # array_ versus _array with elements_.
70
+ #
71
+ # Unlike {.describe}, the block is evaluated in isolation in order to scope
72
+ # possible side effects inside its context.
73
+ #
74
+ # @example
75
+ # require "r_spec"
76
+ #
77
+ # RSpec.context "when divided by zero" do
78
+ # subject { 42 / 0 }
79
+ #
80
+ # it { is_expected.to raise_exception ZeroDivisionError }
81
+ # end
82
+ #
83
+ # # Output to the console
84
+ # # Success: divided by 0.
85
+ #
86
+ # @param description [String] A description that usually begins with "when",
87
+ # "with" or "without".
88
+ # @param block [Proc] The block to define the specs.
89
+ #
90
+ # @api public
91
+ def self.context(description, &block)
92
+ Dsl.context(description, &block)
93
+ end
94
+
95
+ # Defines an example group that describes a unit to be tested.
96
+ #
97
+ # @example
98
+ # require "r_spec"
99
+ #
100
+ # RSpec.describe String do
101
+ # describe "+" do
102
+ # it("concats") { expect("foo" + "bar").to eq "foobar" }
103
+ # end
104
+ # end
105
+ #
106
+ # # Output to the console
107
+ # # Success: expected to eq "foobar".
69
108
  #
70
109
  # @param const [Module, String] A module to include in block context.
71
110
  # @param block [Proc] The block to define the specs.
@@ -74,4 +113,58 @@ module RSpec
74
113
  def self.describe(const, &block)
75
114
  Dsl.describe(const, &block)
76
115
  end
116
+
117
+ # Defines a concrete test case.
118
+ #
119
+ # The test is performed by the block supplied to &block.
120
+ #
121
+ # @example The integer after 41
122
+ # require "r_spec"
123
+ #
124
+ # RSpec.it { expect(41.next).to be 42 }
125
+ #
126
+ # # Output to the console
127
+ # # Success: expected to be 42.
128
+ #
129
+ # It is usually used inside a {Dsl.describe} or {Dsl.context} section.
130
+ #
131
+ # @param name [String, nil] The name of the spec.
132
+ # @param block [Proc] An expectation to evaluate.
133
+ #
134
+ # @raise (see RSpec::ExpectationTarget::Base#result)
135
+ # @return (see RSpec::ExpectationTarget::Base#result)
136
+ #
137
+ # @api public
138
+ def self.it(name = nil, &block)
139
+ Dsl.it(name, &block)
140
+ end
141
+
142
+ # Defines a pending test case.
143
+ #
144
+ # `&block` is never evaluated. It can be used to describe behaviour that is
145
+ # not yet implemented.
146
+ #
147
+ # @example
148
+ # require "r_spec"
149
+ #
150
+ # RSpec.pending "is implemented but waiting" do
151
+ # expect something to be finished
152
+ # end
153
+ #
154
+ # RSpec.pending "is not yet implemented and waiting"
155
+ #
156
+ # # Output to the console
157
+ # # Warning: is implemented but waiting.
158
+ # # Warning: is not yet implemented and waiting.
159
+ #
160
+ # It is usually used inside a {Dsl.describe} or {Dsl.context} section.
161
+ #
162
+ # @param message [String] The reason why the example is pending.
163
+ #
164
+ # @return [nil] Write a message to STDOUT.
165
+ #
166
+ # @api public
167
+ def self.pending(message)
168
+ Dsl.pending(message)
169
+ end
77
170
  end
data/lib/r_spec/dsl.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "aw"
4
+
3
5
  require_relative "console"
4
6
  require_relative "error"
5
7
  require_relative "expectation_helper"
@@ -155,7 +157,8 @@ module RSpec
155
157
  # Defines an example group that establishes a specific context, like _empty
156
158
  # array_ versus _array with elements_.
157
159
  #
158
- # It is functionally equivalent to {.describe}.
160
+ # Unlike {.describe}, the block is evaluated in isolation in order to scope
161
+ # possible side effects inside its context.
159
162
  #
160
163
  # @example
161
164
  # require "r_spec"
@@ -177,9 +180,9 @@ module RSpec
177
180
  # @param _description [String] A description that usually begins with
178
181
  # "when", "with" or "without".
179
182
  # @param block [Proc] The block to define the specs.
180
- def self.context(_description = nil, &block)
183
+ def self.context(_description, &block)
181
184
  desc = ::Class.new(self)
182
- desc.instance_eval(&block)
185
+ ::Aw.fork! { desc.instance_eval(&block) }
183
186
  end
184
187
 
185
188
  # Defines a concrete test case.
@@ -230,7 +233,7 @@ module RSpec
230
233
 
231
234
  exit false
232
235
  ensure
233
- example.send(AFTER_METHOD)
236
+ example&.send(AFTER_METHOD)
234
237
  end
235
238
 
236
239
  # Use the {.its} method to define a single spec that specifies the actual
@@ -295,7 +298,7 @@ module RSpec
295
298
 
296
299
  exit false
297
300
  ensure
298
- example.send(AFTER_METHOD)
301
+ example&.send(AFTER_METHOD)
299
302
  end
300
303
 
301
304
  # Defines a pending test case.
@@ -19,8 +19,7 @@ module RSpec
19
19
  got: false,
20
20
  matcher: :raise_exception,
21
21
  negate: true,
22
- level: :SHOULD,
23
- valid: false
22
+ level: :SHOULD
24
23
  )
25
24
  end
26
25
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "expresenter"
4
+ require "test_tube"
4
5
 
5
6
  require_relative File.join("..", "console")
6
7
 
@@ -50,12 +51,12 @@ module RSpec
50
51
 
51
52
  protected
52
53
 
54
+ # @param passed [Boolean] The high expectation passed or failed.
53
55
  # @param actual [#object_id] The actual value.
54
56
  # @param error [Exception, nil] Any raised exception.
55
57
  # @param got [Boolean, nil] Any returned value.
56
58
  # @param matcher [#matches?] The matcher.
57
59
  # @param negate [Boolean] The assertion is positive or negative.
58
- # @param valid [Boolean] The result of an expectation.
59
60
  #
60
61
  # @return [nil] Write a message to STDOUT.
61
62
  #
@@ -63,14 +64,13 @@ module RSpec
63
64
  # `Kernel.exit(false)` with a failure message written to STDERR.
64
65
  #
65
66
  # @api private
66
- def result(actual:, error:, got:, matcher:, negate:, valid:)
67
- Console.passed_spec ::Expresenter.call(valid).with(
67
+ def result(passed, actual:, error:, got:, matcher:, negate:)
68
+ Console.passed_spec ::Expresenter.call(passed).with(
68
69
  actual: actual,
69
70
  error: error,
70
71
  expected: matcher.expected,
71
72
  got: got,
72
73
  negate: negate,
73
- valid: valid,
74
74
  matcher: matcher.class.to_sym,
75
75
  level: :MUST
76
76
  )
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spectus/exam"
4
-
5
3
  require_relative "base"
6
4
 
7
5
  module RSpec
@@ -30,20 +28,20 @@ module RSpec
30
28
  # @raise [SystemExit] Terminate execution immediately by calling
31
29
  # `Kernel.exit(false)` with a failure message written to STDERR.
32
30
  def absolute_requirement(matcher:, negate:)
33
- exam = ::Spectus::Exam.new(
34
- callable: @actual,
31
+ experiment = ::TestTube.invoke(
32
+ @actual,
35
33
  isolation: false,
36
- negate: negate,
37
- matcher: matcher
34
+ matcher: matcher,
35
+ negate: negate
38
36
  )
39
37
 
40
38
  result(
41
- actual: exam.actual,
42
- error: exam.exception,
43
- got: exam.got,
39
+ experiment.got.equal?(true),
40
+ actual: experiment.actual,
41
+ error: experiment.error,
42
+ got: experiment.got,
44
43
  matcher: matcher,
45
- negate: negate,
46
- valid: exam.valid?
44
+ negate: negate
47
45
  )
48
46
  end
49
47
  end
@@ -28,15 +28,19 @@ module RSpec
28
28
  # @raise [SystemExit] Terminate execution immediately by calling
29
29
  # `Kernel.exit(false)` with a failure message written to STDERR.
30
30
  def absolute_requirement(matcher:, negate:)
31
- valid = negate ^ matcher.matches? { @actual }
31
+ experiment = ::TestTube.pass(
32
+ @actual,
33
+ matcher: matcher,
34
+ negate: negate
35
+ )
32
36
 
33
37
  result(
34
- actual: @actual,
35
- error: nil,
36
- got: valid,
38
+ experiment.got.equal?(true),
39
+ actual: experiment.actual,
40
+ error: experiment.error,
41
+ got: experiment.got,
37
42
  matcher: matcher,
38
- negate: negate,
39
- valid: valid
43
+ negate: negate
40
44
  )
41
45
  end
42
46
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta7
4
+ version: 1.0.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-06-16 00:00:00.000000000 Z
11
+ date: 2021-06-24 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aw
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.12
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.12
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: expresenter
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: 1.2.1
33
+ version: 1.3.0
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: 1.2.1
40
+ version: 1.3.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: matchi-rspec
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -39,19 +53,19 @@ dependencies:
39
53
  - !ruby/object:Gem::Version
40
54
  version: 1.1.2
41
55
  - !ruby/object:Gem::Dependency
42
- name: spectus
56
+ name: test_tube
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: 3.3.4
61
+ version: 1.1.0
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: 3.3.4
68
+ version: 1.1.0
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -221,9 +235,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
221
235
  version: 2.7.0
222
236
  required_rubygems_version: !ruby/object:Gem::Requirement
223
237
  requirements:
224
- - - ">"
238
+ - - ">="
225
239
  - !ruby/object:Gem::Version
226
- version: 1.3.1
240
+ version: '0'
227
241
  requirements: []
228
242
  rubygems_version: 3.1.6
229
243
  signing_key: