r_spec 1.0.0.beta7 → 1.0.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: 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: