r_spec 1.0.0.beta5 → 1.0.0.beta10

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: 5df8b9cdb685bc7388fdbdbc0a7de755a3c5c2426e5c6f8346c464562ed16e30
4
- data.tar.gz: 9b22d8599741dd00b0a812931cbf4c575acf948b0e4914dd662decc23fd8eea6
3
+ metadata.gz: ba07a04820e5602fb73f32e7b265ef6cc755a54c396a7c9419fc97c8125d2fb1
4
+ data.tar.gz: 2330fe89b377b2f0cf13aaf6d325bf0b4f1c1fff5a409b8feba2f24f39e040a2
5
5
  SHA512:
6
- metadata.gz: 27938ad6a4ab512ef8c564402064188c67bfb40430897f14be5cbd07eefae04bce7bf5709b5a4fbb11f82b4e51b9aaaaa36278ad3ff34cc829fd54a76d643660
7
- data.tar.gz: b2ee9bccf5f59bb9d1a0a03d800a8824f643b5875854e57465c640d5eacce8a1ae86a45ccfe42c968921c6587a07d973b1e622bf19ac9e19eee22d906d396f16
6
+ metadata.gz: 76a062afb51273f181f86db0fd85eb342fe6404f832e6facba450607f32f6b8555057ffa9918379ae30a8a63548c0911378348318ddba64be5bf94a14ecad8c1
7
+ data.tar.gz: 0d90f7fd0f0b94f40d28d4cb4c6dfcf82047830067881b0a8fef8108eb8cf4704b1542589023d91aed0f3814bbc10a5b7652269ac67ab7477a8a1c2231dc3383
data/README.md CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  A minimalist __[RSpec](https://github.com/rspec/rspec) clone__ with all the essentials.
4
4
 
5
- ![What did you RSpec?](https://github.com/cyril/r_spec.rb/raw/main/img/what-did-you-rspec.svg)
5
+ ![What did you RSpec?](https://github.com/cyril/r_spec.rb/raw/main/img/what-did-you-rspec.jpg)
6
6
 
7
7
  ## Status
8
8
 
9
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)
10
+ [![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
11
  [![Documentation](https://img.shields.io/:yard-docs-38c800.svg)](https://rubydoc.info/gems/r_spec/frames)
13
12
 
14
- ## Goal
13
+ ## Project goals
15
14
 
16
- This clone attempts to provide most of RSpec's DSL to express expected outcomes of a code example without magic power.
15
+ * Enforce the guidelines and best practices outlined in the community [RSpec style guide](https://rspec.rubystyle.guide/).
16
+ * Provide most of RSpec's DSL to express expected outcomes of a code example without magic power.
17
17
 
18
18
  ## Some differences
19
19
 
@@ -28,6 +28,7 @@ This clone attempts to provide most of RSpec's DSL to express expected outcomes
28
28
  * [Arbitrary helper methods](https://relishapp.com/rspec/rspec-core/v/3-10/docs/helper-methods/arbitrary-helper-methods) are not exposed to examples.
29
29
  * The `let` method defines a helper method rather than a memoized helper method.
30
30
  * The one-liner `is_expected` syntax also works with block expectations.
31
+ * `subject`, `before`, `after` and `let` definitions must come before examples.
31
32
 
32
33
  ## Important ⚠️
33
34
 
@@ -46,7 +47,7 @@ Following [RubyGems naming conventions](https://guides.rubygems.org/name-your-ge
46
47
  Add this line to your application's Gemfile:
47
48
 
48
49
  ```ruby
49
- gem "r_spec", ">= 1.0.0.beta5"
50
+ gem "r_spec", ">= 1.0.0.beta10"
50
51
  ```
51
52
 
52
53
  And then execute:
@@ -81,16 +82,15 @@ Many projects use a custom spec helper which organizes these includes.
81
82
  Concrete test cases are defined in `it` blocks.
82
83
  An optional descriptive string states it's purpose and a block contains the main logic performing the test.
83
84
 
85
+ Test cases that have been defined or outlined but are not yet expected to work can be defined using `pending` instead of `it`. They will not be run but show up in the spec report as pending.
86
+
84
87
  An `it` block contains an example that should invoke the code to be tested and define what is expected of it.
85
88
  Each example can contain multiple expectations, but it should test only one specific behaviour.
86
89
 
87
- To express an expectation, wrap an object or block in `expect`, call `to` or `not_to` and pass it a matcher object.
88
-
90
+ To express an expectation, wrap an object or block in `expect`, call `to` (or `not_to`) and pass it a matcher object.
89
91
  If the expectation is met, code execution continues.
90
92
  Otherwise the example has _failed_ and other code will not be executed.
91
93
 
92
- Test cases that have been defined or outlined but are not yet expected to work can be defined using `pending` instead of `expect`. They will not be run but show up in the spec report as pending.
93
-
94
94
  In test files, specs are structured by example groups which are defined by `describe` and `context` sections.
95
95
  Typically a top level `describe` defines the outer unit (such as a class) to be tested by the spec.
96
96
  Further `describe` sections can be nested within the outer unit to specify smaller units under test (such as individual methods).
@@ -100,7 +100,7 @@ For unit tests, it is recommended to follow the conventions for method names:
100
100
  * outer `describe` is the name of the class, inner `describe` targets methods;
101
101
  * instance methods are prefixed with `#`, class methods with `.`.
102
102
 
103
- To establish certain contexts - think _empty array_ versus _array with elements_ - the `context` method may be used to communicate this to the reader.
103
+ To establish certain contexts think _empty array_ versus _array with elements_ the `context` method may be used to communicate this to the reader.
104
104
  It has a different name, but behaves exactly like `describe`.
105
105
 
106
106
  `describe` and `context` take an optional description as argument and a block containing the individual specs or nested groupings.
@@ -214,6 +214,19 @@ task spec: :test
214
214
  task default: :test
215
215
  ```
216
216
 
217
+ ## Performance
218
+
219
+ ### Runtime
220
+
221
+ Benchmark against [100 executions of a file containing one expectation](https://github.com/cyril/r_spec.rb/blob/main/benchmark/) (lower is better).
222
+
223
+ | Framework | Seconds to complete |
224
+ |-------------|---------------------|
225
+ | `r_spec` | 13.0 |
226
+ | `rspec` | 32.2 |
227
+ | `minitest` | 17.5 |
228
+ | `test-unit` | 20.5 |
229
+
217
230
  ## Test suite
218
231
 
219
232
  __RSpec clone__'s specifications are self-described here: [spec/](https://github.com/cyril/r_spec.rb/blob/main/spec/)
@@ -224,10 +237,6 @@ __RSpec clone__'s specifications are self-described here: [spec/](https://github
224
237
  * Source code: https://github.com/cyril/r_spec.rb
225
238
  * Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
226
239
 
227
- ## Versioning
228
-
229
- __RSpec clone__ follows [Semantic Versioning 2.0](https://semver.org/).
230
-
231
240
  ## Special thanks ❤️
232
241
 
233
242
  I would like to thank the whole [RSpec team](https://rspec.info/about/) for all their work.
@@ -241,6 +250,18 @@ If you like this project please consider making a small donation.
241
250
 
242
251
  [![Donate with Ethereum](https://github.com/cyril/r_spec.rb/raw/main/img/donate-eth.svg)](https://etherscan.io/address/0x834b5c1feaff5aebf9cd0f25dc38e741d65ab773)
243
252
 
253
+ ## Versioning
254
+
255
+ __RSpec clone__ follows [Semantic Versioning 2.0](https://semver.org/).
256
+
244
257
  ## License
245
258
 
246
259
  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
+
261
+ ## One more thing
262
+
263
+ Under the hood, __RSpec clone__ is largely animated by [a collection of testing libraries designed to make programmers happy](https://github.com/fixrb/).
264
+
265
+ It's a living example of what we can do combining small libraries together that can boost the fun of programming.
266
+
267
+ ![Fix testing tools logo for Ruby](https://github.com/cyril/r_spec.rb/raw/main/img/fixrb.svg)
data/lib/r_spec.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("r_spec", "dsl")
4
+
3
5
  # Top level namespace for the RSpec clone.
4
6
  #
5
7
  # @example The true from the false
6
8
  # require "r_spec"
7
9
  #
8
- # RSpec.describe do
10
+ # RSpec.describe "The true from the false" do
9
11
  # it { expect(false).not_to be true }
10
12
  # end
11
13
  #
@@ -69,9 +71,61 @@ module RSpec
69
71
  # @param block [Proc] The block to define the specs.
70
72
  #
71
73
  # @api public
72
- def self.describe(const = nil, &block)
74
+ def self.describe(const, &block)
73
75
  Dsl.describe(const, &block)
74
76
  end
75
- end
76
77
 
77
- require_relative File.join("r_spec", "dsl")
78
+ # Defines a concrete test case.
79
+ #
80
+ # The test is performed by the block supplied to &block.
81
+ #
82
+ # @example The integer after 41
83
+ # require "r_spec"
84
+ #
85
+ # RSpec.it { expect(41.next).to be 42 }
86
+ #
87
+ # # Output to the console
88
+ # # Success: expected to be 42.
89
+ #
90
+ # It is usually used inside a {Dsl.describe} or {Dsl.context} section.
91
+ #
92
+ # @param name [String, nil] The name of the spec.
93
+ # @param block [Proc] An expectation to evaluate.
94
+ #
95
+ # @raise (see RSpec::ExpectationTarget::Base#result)
96
+ # @return (see RSpec::ExpectationTarget::Base#result)
97
+ #
98
+ # @api public
99
+ def self.it(name = nil, &block)
100
+ Dsl.it(name, &block)
101
+ end
102
+
103
+ # Defines a pending test case.
104
+ #
105
+ # `&block` is never evaluated. It can be used to describe behaviour that is
106
+ # not yet implemented.
107
+ #
108
+ # @example
109
+ # require "r_spec"
110
+ #
111
+ # RSpec.pending "is implemented but waiting" do
112
+ # expect something to be finished
113
+ # end
114
+ #
115
+ # RSpec.pending "is not yet implemented and waiting"
116
+ #
117
+ # # Output to the console
118
+ # # Warning: is implemented but waiting.
119
+ # # Warning: is not yet implemented and waiting.
120
+ #
121
+ # It is usually used inside a {Dsl.describe} or {Dsl.context} section.
122
+ #
123
+ # @param message [String] The reason why the example is pending.
124
+ #
125
+ # @return [nil] Write a message to STDOUT.
126
+ #
127
+ # @api public
128
+ def self.pending(message)
129
+ Dsl.pending(message)
130
+ end
131
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec
4
+ # Send log messages to the console.
5
+ #
6
+ # @api private
7
+ module Console
8
+ # @param report [::Expresenter::Pass] Passed expectation result presenter.
9
+ #
10
+ # @see https://github.com/fixrb/expresenter
11
+ #
12
+ # @return [nil] Add a colored message to `$stdout`.
13
+ def self.passed_spec(report)
14
+ puts report.colored_string
15
+ end
16
+
17
+ # @param report [::Expresenter::Fail] Failed expectation result presenter.
18
+ #
19
+ # @see https://github.com/fixrb/expresenter
20
+ #
21
+ # @raise [SystemExit] Terminate execution immediately with colored message.
22
+ def self.failed_spec(report)
23
+ abort report.colored_string
24
+ end
25
+
26
+ # The Ruby source filename and line number containing this method or nil if
27
+ # this method was not defined in Ruby (i.e. native).
28
+ #
29
+ # @param filename [String, nil] The Ruby source filename.
30
+ # @param line [Integer, nil] The Ruby source line number.
31
+ #
32
+ # @return [String] The Ruby source filename and line number associated with
33
+ # the evaluated spec.
34
+ def self.source(filename, line)
35
+ puts [filename, line].compact.join(":")
36
+ end
37
+ end
38
+ end
data/lib/r_spec/dsl.rb CHANGED
@@ -1,60 +1,190 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "securerandom"
3
+ require_relative "console"
4
+ require_relative "error"
5
+ require_relative "expectation_helper"
4
6
 
5
7
  module RSpec
6
8
  # Abstract class for handling the domain-specific language.
7
9
  class Dsl
8
- # Instructs the spec runner to execute the given block before each spec in
9
- # the spec suite.
10
+ BEFORE_METHOD = :initialize
11
+ AFTER_METHOD = :terminate
12
+
13
+ private_constant :BEFORE_METHOD, :AFTER_METHOD
14
+
15
+ # Executes the given block before each spec in the current context runs.
16
+ #
17
+ # @example
18
+ # require "r_spec"
19
+ #
20
+ # RSpec.describe Integer do
21
+ # before do
22
+ # @value = 123
23
+ # end
24
+ #
25
+ # it { expect(@value).to be 123 }
26
+ #
27
+ # describe "nested" do
28
+ # before do
29
+ # @value -= 81
30
+ # end
31
+ #
32
+ # it { expect(@value).to be 42 }
33
+ # end
34
+ #
35
+ # it { expect(@value).to be 123 }
36
+ # end
37
+ #
38
+ # # Output to the console
39
+ # # Success: expected to be 123.
40
+ # # Success: expected to be 42.
41
+ # # Success: expected to be 123.
10
42
  #
11
43
  # @param block [Proc] The content to execute at the class initialization.
12
44
  def self.before(&block)
13
- define_method(:initialize) do |*args, **kwargs|
45
+ define_method(BEFORE_METHOD) do
14
46
  super()
15
- instance_exec(*args, **kwargs, &block)
47
+ instance_eval(&block)
16
48
  end
49
+
50
+ private BEFORE_METHOD
51
+ end
52
+
53
+ # Executes the given block after each spec in the current context runs.
54
+ #
55
+ # @example
56
+ # require "r_spec"
57
+ #
58
+ # RSpec.describe Integer do
59
+ # after do
60
+ # puts "That is the answer to everything."
61
+ # end
62
+ #
63
+ # it { expect(42).to be 42 }
64
+ # end
65
+ #
66
+ # # Output to the console
67
+ # # Success: expected to be 42.
68
+ # # That is the answer to everything.
69
+ #
70
+ # @param block [Proc] The content to execute at the class initialization.
71
+ def self.after(&block)
72
+ define_method(AFTER_METHOD) do
73
+ instance_exec(&block)
74
+ super()
75
+ end
76
+
77
+ private AFTER_METHOD
17
78
  end
18
79
 
19
80
  # Sets a user-defined property.
20
81
  #
82
+ # @example
83
+ # require "r_spec"
84
+ #
85
+ # RSpec.describe "Name stories" do
86
+ # let(:name) { "Bob" }
87
+ #
88
+ # it { expect(name).to eq "Bob" }
89
+ #
90
+ # context "with last name" do
91
+ # let(:name) { "#{super()} Smith" }
92
+ #
93
+ # it { expect(name).to eq "Bob Smith" }
94
+ # end
95
+ # end
96
+ #
97
+ # # Output to the console
98
+ # # Success: expected to eq "Bob".
99
+ # # Success: expected to eq "Bob Smith".
100
+ #
21
101
  # @param name [String, Symbol] The name of the property.
22
102
  # @param block [Proc] The content of the method to define.
23
103
  #
24
- # @return [Symbol] A protected method that define the block content.
104
+ # @return [Symbol] A private method that define the block content.
25
105
  def self.let(name, *args, **kwargs, &block)
26
- protected define_method(name.to_sym, *args, **kwargs, &block)
106
+ raise Error::ReservedMethod if [BEFORE_METHOD, AFTER_METHOD].include?(name.to_sym)
107
+
108
+ private define_method(name, *args, **kwargs, &block)
27
109
  end
28
110
 
29
- # Sets a user-defined property named `subject`.
111
+ # Sets a user-defined property named {#subject}.
112
+ #
113
+ # @example
114
+ # require "r_spec"
115
+ #
116
+ # RSpec.describe Array do
117
+ # subject { [1, 2, 3] }
118
+ #
119
+ # it "has the prescribed elements" do
120
+ # expect(subject).to eq([1, 2, 3])
121
+ # end
122
+ # end
123
+ #
124
+ # # Output to the console
125
+ # # Success: expected to eq [1, 2, 3].
30
126
  #
31
127
  # @param block [Proc] The subject to set.
32
- # @return [Symbol] A `subject` method that define the block content.
128
+ # @return [Symbol] A {#subject} method that define the block content.
33
129
  def self.subject(&block)
34
130
  let(__method__, &block)
35
131
  end
36
132
 
37
- # Create a group of specs.
133
+ # Defines an example group that describes a unit to be tested.
38
134
  #
39
- # @param const [Module, #object_id] A module to include in block context.
135
+ # @example
136
+ # require "r_spec"
137
+ #
138
+ # RSpec.describe String do
139
+ # describe "+" do
140
+ # it("concats") { expect("foo" + "bar").to eq "foobar" }
141
+ # end
142
+ # end
143
+ #
144
+ # # Output to the console
145
+ # # Success: expected to eq "foobar".
146
+ #
147
+ # @param const [Module, String] A module to include in block context.
40
148
  # @param block [Proc] The block to define the specs.
41
- def self.describe(const = nil, &block)
42
- desc = Sandbox.const_set(random_test_const_name, ::Class.new(self))
43
-
44
- if const.is_a?(::Module)
45
- desc.define_method(:described_class) { const }
46
- desc.send(:protected, :described_class)
47
- end
48
-
149
+ def self.describe(const, &block)
150
+ desc = ::Class.new(self)
151
+ desc.let(:described_class) { const } if const.is_a?(::Module)
49
152
  desc.instance_eval(&block)
50
- desc
51
153
  end
52
154
 
53
- # Add `context` to the DSL.
54
- singleton_class.send(:alias_method, :context, :describe)
155
+ # Defines an example group that establishes a specific context, like _empty
156
+ # array_ versus _array with elements_.
157
+ #
158
+ # It is functionally equivalent to {.describe}.
159
+ #
160
+ # @example
161
+ # require "r_spec"
162
+ #
163
+ # RSpec.describe "web resource" do
164
+ # context "when resource is not found" do
165
+ # pending "responds with 404"
166
+ # end
167
+ #
168
+ # context "when resource is found" do
169
+ # pending "responds with 200"
170
+ # end
171
+ # end
172
+ #
173
+ # # Output to the console
174
+ # # Warning: responds with 404.
175
+ # # Warning: responds with 200.
176
+ #
177
+ # @param _description [String] A description that usually begins with
178
+ # "when", "with" or "without".
179
+ # @param block [Proc] The block to define the specs.
180
+ def self.context(_description = nil, &block)
181
+ desc = ::Class.new(self)
182
+ desc.instance_eval(&block)
183
+ end
55
184
 
56
- # Use the `it` method to define a single spec. A spec should contain one or
57
- # more expectations that test the state of the code.
185
+ # Defines a concrete test case.
186
+ #
187
+ # The test is performed by the block supplied to `&block`.
58
188
  #
59
189
  # @example The integer after 41
60
190
  # require "r_spec"
@@ -83,22 +213,29 @@ module RSpec
83
213
  # # Success: expected 41 to be an instance of Integer.
84
214
  # # Success: divided by 0.
85
215
  #
216
+ # It can be used inside a {.describe} or {.context} section.
217
+ #
86
218
  # @param _name [String, nil] The name of the spec.
87
219
  # @param block [Proc] An expectation to evaluate.
88
220
  #
89
221
  # @raise (see ExpectationTarget::Base#result)
90
222
  # @return (see ExpectationTarget::Base#result)
91
223
  def self.it(_name = nil, &block)
92
- raise ::ArgumentError, "Missing block" unless block
224
+ raise ::ArgumentError, "Missing example block" unless block
93
225
 
94
- puts "\e[37m#{block.source_location.join(':')}\e[0m"
226
+ example = ::Class.new(self) { include ExpectationHelper::It }.new
227
+ example.instance_eval(&block)
228
+ rescue ::SystemExit
229
+ Console.source(*block.source_location)
95
230
 
96
- i = it_example.new
97
- i.instance_eval(&block)
231
+ exit false
232
+ ensure
233
+ example&.send(AFTER_METHOD)
98
234
  end
99
235
 
100
- # Use the `its` method to define a single spec that specifies the actual
101
- # value of an attribute of the subject using `is_expected`.
236
+ # Use the {.its} method to define a single spec that specifies the actual
237
+ # value of an attribute of the subject using
238
+ # {ExpectationHelper::Its#is_expected}.
102
239
  #
103
240
  # @example The integer after 41
104
241
  # require "r_spec"
@@ -142,43 +279,55 @@ module RSpec
142
279
  # @raise (see ExpectationTarget::Base#result)
143
280
  # @return (see ExpectationTarget::Base#result)
144
281
  def self.its(attribute, *args, **kwargs, &block)
145
- raise ::ArgumentError, "Missing block" unless block
282
+ raise ::ArgumentError, "Missing example block" unless block
146
283
 
147
- puts "\e[37m#{block.source_location.join(':')}\e[0m"
284
+ example = ::Class.new(self) do
285
+ include ExpectationHelper::Its
148
286
 
149
- i = its_example.new
287
+ define_method(:actual) do
288
+ subject.public_send(attribute, *args, **kwargs)
289
+ end
290
+ end.new
150
291
 
151
- i.define_singleton_method(:actual) do
152
- subject.public_send(attribute, *args, **kwargs)
153
- end
292
+ example.instance_eval(&block)
293
+ rescue ::SystemExit
294
+ Console.source(*block.source_location)
154
295
 
155
- i.instance_eval(&block)
296
+ exit false
297
+ ensure
298
+ example&.send(AFTER_METHOD)
156
299
  end
157
300
 
158
- # @private
301
+ # Defines a pending test case.
159
302
  #
160
- # @return [Class<Dsl>] The class of the example to be tested.
161
- def self.it_example
162
- ::Class.new(self) { include ExpectationHelper::It }
163
- end
164
-
165
- # @private
303
+ # `&block` is never evaluated. It can be used to describe behaviour that is
304
+ # not yet implemented.
166
305
  #
167
- # @return [Class<Dsl>] The class of the example to be tested.
168
- def self.its_example
169
- ::Class.new(self) { include ExpectationHelper::Its }
170
- end
171
-
172
- # @private
306
+ # @example
307
+ # require "r_spec"
308
+ #
309
+ # RSpec.describe "an example" do
310
+ # pending "is implemented but waiting" do
311
+ # expect something to be finished
312
+ # end
173
313
  #
174
- # @return [String] A random constant name for a test class.
175
- def self.random_test_const_name
176
- "Test#{::SecureRandom.hex(4).to_i(16)}"
314
+ # pending "is not yet implemented and waiting"
315
+ # end
316
+ #
317
+ # # Output to the console
318
+ # # Warning: is implemented but waiting.
319
+ # # Warning: is not yet implemented and waiting.
320
+ #
321
+ # @param message [String] The reason why the example is pending.
322
+ #
323
+ # @return [nil] Write a message to STDOUT.
324
+ #
325
+ # @api public
326
+ def self.pending(message)
327
+ Console.passed_spec Error::PendingExpectation.result(message)
177
328
  end
178
329
 
179
- private_class_method :it_example, :its_example, :random_test_const_name
180
-
181
- protected
330
+ private
182
331
 
183
332
  def described_class
184
333
  raise Error::UndefinedDescribedClass,
@@ -188,9 +337,9 @@ module RSpec
188
337
  def subject
189
338
  raise Error::UndefinedSubject, "subject not explicitly defined"
190
339
  end
340
+
341
+ define_method(AFTER_METHOD) do
342
+ # do nothing by default
343
+ end
191
344
  end
192
345
  end
193
-
194
- require_relative "error"
195
- require_relative "expectation_helper"
196
- require_relative "sandbox"
data/lib/r_spec/error.rb CHANGED
@@ -1,5 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("error", "pending_expectation")
4
+ require_relative File.join("error", "reserved_method")
5
+ require_relative File.join("error", "undefined_described_class")
6
+ require_relative File.join("error", "undefined_subject")
7
+
3
8
  module RSpec
4
9
  # Namespace for exceptions.
5
10
  #
@@ -7,7 +12,3 @@ module RSpec
7
12
  module Error
8
13
  end
9
14
  end
10
-
11
- require_relative File.join("error", "pending_expectation")
12
- require_relative File.join("error", "undefined_described_class")
13
- require_relative File.join("error", "undefined_subject")
@@ -12,16 +12,15 @@ module RSpec
12
12
  #
13
13
  # @return [nil] Write a pending expectation to STDOUT.
14
14
  def self.result(message)
15
- warn " " + ::Expresenter.call(true).with(
15
+ ::Expresenter.call(true).with(
16
16
  actual: new(message),
17
17
  error: nil,
18
18
  expected: self,
19
19
  got: false,
20
20
  matcher: :raise_exception,
21
21
  negate: true,
22
- level: :SHOULD,
23
- valid: false
24
- ).colored_string
22
+ level: :SHOULD
23
+ )
25
24
  end
26
25
  end
27
26
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec
4
+ module Error
5
+ # Exception for reserved methods.
6
+ #
7
+ # @api private
8
+ class ReservedMethod < ::RuntimeError
9
+ end
10
+ end
11
+ end
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("expectation_helper", "it")
4
+ require_relative File.join("expectation_helper", "its")
5
+
3
6
  module RSpec
4
- # Namespace for `it` and `its` helper modules.
7
+ # Namespace for {Dsl.it} and {Dsl.its}'s helper modules.
5
8
  module ExpectationHelper
6
9
  end
7
10
  end
8
-
9
- require_relative File.join("expectation_helper", "it")
10
- require_relative File.join("expectation_helper", "its")
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "base"
3
+ require_relative "shared"
4
4
  require_relative File.join("..", "expectation_target")
5
5
 
6
6
  module RSpec
7
7
  module ExpectationHelper
8
- # `it` expectation helper module.
8
+ # {RSpec::Dsl.it}'s expectation helper module.
9
9
  module It
10
- include Base
10
+ include Shared
11
11
 
12
12
  # Create an expectation for a spec.
13
13
  #
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "base"
3
+ require_relative "shared"
4
4
  require_relative File.join("..", "expectation_target", "block")
5
5
 
6
6
  module RSpec
7
7
  module ExpectationHelper
8
- # `its` expectation helper module.
8
+ # {RSpec::Dsl.its}'s expectation helper module.
9
9
  module Its
10
- include Base
10
+ include Shared
11
11
 
12
12
  # Wraps the target of an expectation with the actual value.
13
13
  #
@@ -9,7 +9,7 @@ module RSpec
9
9
  # Abstract expectation helper base module.
10
10
  #
11
11
  # This module defines a number of methods to create expectations, which are
12
- # automatically included into example namespaces.
12
+ # automatically included into examples.
13
13
  #
14
14
  # It also includes a collection of expectation matchers 🤹
15
15
  #
@@ -75,25 +75,8 @@ module RSpec
75
75
  #
76
76
  # @see https://github.com/fixrb/matchi
77
77
  # @see https://github.com/fixrb/matchi-rspec
78
- module Base
78
+ module Shared
79
79
  include ::Matchi::Helper
80
-
81
- # Mark a spec as pending, expectation results will be ignored.
82
- #
83
- # @param description [String] The reason why the example is pending.
84
- #
85
- # @return [nil] Write a message to STDOUT.
86
- #
87
- # @example Output a message to the console and return nil
88
- # pending("something else getting finished") # => nil
89
- #
90
- # # Output to the console
91
- # # Warning: something else getting finished.
92
- #
93
- # @api public
94
- def pending(description)
95
- Error::PendingExpectation.result(description)
96
- end
97
80
  end
98
81
  end
99
82
  end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative File.join("expectation_target", "block")
4
+ require_relative File.join("expectation_target", "value")
5
+
3
6
  module RSpec
4
7
  # Wraps the target of an expectation.
5
8
  #
@@ -25,6 +28,3 @@ module RSpec
25
28
  end
26
29
  end
27
30
  end
28
-
29
- require_relative File.join("expectation_target", "block")
30
- require_relative File.join("expectation_target", "value")
@@ -1,6 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "expresenter"
4
+ require "test_tube"
5
+
6
+ require_relative File.join("..", "console")
4
7
 
5
8
  module RSpec
6
9
  module ExpectationTarget
@@ -9,6 +12,13 @@ module RSpec
9
12
  # @note `RSpec::ExpectationTarget::Base` is not intended to be instantiated
10
13
  # directly by users. Use `expect` instead.
11
14
  class Base
15
+ # Instantiate a new expectation target.
16
+ #
17
+ # @param actual [#object_id] The actual value of the code to evaluate.
18
+ def initialize(actual)
19
+ @actual = actual
20
+ end
21
+
12
22
  # Runs the given expectation, passing if `matcher` returns true.
13
23
  #
14
24
  # @example _Absolute requirement_ definition
@@ -41,12 +51,12 @@ module RSpec
41
51
 
42
52
  protected
43
53
 
54
+ # @param passed [Boolean] The high expectation passed or failed.
44
55
  # @param actual [#object_id] The actual value.
45
56
  # @param error [Exception, nil] Any raised exception.
46
57
  # @param got [Boolean, nil] Any returned value.
47
58
  # @param matcher [#matches?] The matcher.
48
59
  # @param negate [Boolean] The assertion is positive or negative.
49
- # @param valid [Boolean] The result of an expectation.
50
60
  #
51
61
  # @return [nil] Write a message to STDOUT.
52
62
  #
@@ -54,19 +64,18 @@ module RSpec
54
64
  # `Kernel.exit(false)` with a failure message written to STDERR.
55
65
  #
56
66
  # @api private
57
- def result(actual:, error:, got:, matcher:, negate:, valid:)
58
- puts " " + ::Expresenter.call(valid).with(
67
+ def result(passed, actual:, error:, got:, matcher:, negate:)
68
+ Console.passed_spec ::Expresenter.call(passed).with(
59
69
  actual: actual,
60
70
  error: error,
61
71
  expected: matcher.expected,
62
72
  got: got,
63
73
  negate: negate,
64
- valid: valid,
65
74
  matcher: matcher.class.to_sym,
66
75
  level: :MUST
67
- ).colored_string
76
+ )
68
77
  rescue ::Expresenter::Fail => e
69
- abort " #{e.colored_string}"
78
+ Console.failed_spec(e)
70
79
  end
71
80
  end
72
81
  end
@@ -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
@@ -20,15 +18,6 @@ module RSpec
20
18
  # @note `RSpec::ExpectationTarget::Block` is not intended to be instantiated
21
19
  # directly by users. Use `expect` instead.
22
20
  class Block < Base
23
- # Instantiate a new expectation target.
24
- #
25
- # @param block [#call] The code to evaluate.
26
- def initialize(block)
27
- super()
28
-
29
- @callable = block
30
- end
31
-
32
21
  protected
33
22
 
34
23
  # @param matcher [#matches?] The matcher.
@@ -39,20 +28,20 @@ module RSpec
39
28
  # @raise [SystemExit] Terminate execution immediately by calling
40
29
  # `Kernel.exit(false)` with a failure message written to STDERR.
41
30
  def absolute_requirement(matcher:, negate:)
42
- exam = ::Spectus::Exam.new(
43
- callable: @callable,
31
+ experiment = ::TestTube.invoke(
32
+ @actual,
44
33
  isolation: false,
45
- negate: negate,
46
- matcher: matcher
34
+ matcher: matcher,
35
+ negate: negate
47
36
  )
48
37
 
49
38
  result(
50
- actual: exam.actual,
51
- error: exam.exception,
52
- got: exam.got,
39
+ experiment.got.equal?(true),
40
+ actual: experiment.actual,
41
+ error: experiment.error,
42
+ got: experiment.got,
53
43
  matcher: matcher,
54
- negate: negate,
55
- valid: exam.valid?
44
+ negate: negate
56
45
  )
57
46
  end
58
47
  end
@@ -18,15 +18,6 @@ module RSpec
18
18
  # @note `RSpec::ExpectationTarget::Value` is not intended to be instantiated
19
19
  # directly by users. Use `expect` instead.
20
20
  class Value < Base
21
- # Instantiate a new expectation target.
22
- #
23
- # @param actual [#object_id] The actual value.
24
- def initialize(actual)
25
- super()
26
-
27
- @actual = actual
28
- end
29
-
30
21
  protected
31
22
 
32
23
  # @param matcher [#matches?] The matcher.
@@ -37,15 +28,19 @@ module RSpec
37
28
  # @raise [SystemExit] Terminate execution immediately by calling
38
29
  # `Kernel.exit(false)` with a failure message written to STDERR.
39
30
  def absolute_requirement(matcher:, negate:)
40
- valid = negate ^ matcher.matches? { @actual }
31
+ experiment = ::TestTube.pass(
32
+ @actual,
33
+ matcher: matcher,
34
+ negate: negate
35
+ )
41
36
 
42
37
  result(
43
- actual: @actual,
44
- error: nil,
45
- got: valid,
38
+ experiment.got.equal?(true),
39
+ actual: experiment.actual,
40
+ error: experiment.error,
41
+ got: experiment.got,
46
42
  matcher: matcher,
47
- negate: negate,
48
- valid: valid
43
+ negate: negate
49
44
  )
50
45
  end
51
46
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: r_spec
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta5
4
+ version: 1.0.0.beta10
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-10 00:00:00.000000000 Z
11
+ date: 2021-06-21 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.2.1
19
+ version: 1.3.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.2.1
26
+ version: 1.3.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: matchi-rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.1.1
33
+ version: 1.1.2
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.1
40
+ version: 1.1.2
41
41
  - !ruby/object:Gem::Dependency
42
- name: spectus
42
+ name: test_tube
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.3.3
47
+ version: 1.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: 3.3.3
54
+ version: 1.1.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -187,20 +187,21 @@ files:
187
187
  - LICENSE.md
188
188
  - README.md
189
189
  - lib/r_spec.rb
190
+ - lib/r_spec/console.rb
190
191
  - lib/r_spec/dsl.rb
191
192
  - lib/r_spec/error.rb
192
193
  - lib/r_spec/error/pending_expectation.rb
194
+ - lib/r_spec/error/reserved_method.rb
193
195
  - lib/r_spec/error/undefined_described_class.rb
194
196
  - lib/r_spec/error/undefined_subject.rb
195
197
  - lib/r_spec/expectation_helper.rb
196
- - lib/r_spec/expectation_helper/base.rb
197
198
  - lib/r_spec/expectation_helper/it.rb
198
199
  - lib/r_spec/expectation_helper/its.rb
200
+ - lib/r_spec/expectation_helper/shared.rb
199
201
  - lib/r_spec/expectation_target.rb
200
202
  - lib/r_spec/expectation_target/base.rb
201
203
  - lib/r_spec/expectation_target/block.rb
202
204
  - lib/r_spec/expectation_target/value.rb
203
- - lib/r_spec/sandbox.rb
204
205
  homepage: https://r-spec.dev/
205
206
  licenses:
206
207
  - MIT
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RSpec
4
- # Namespace to collect test classes.
5
- #
6
- # @api private
7
- module Sandbox
8
- end
9
- end