r_spec 0.3.1 → 1.0.0.beta3
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 +5 -5
- data/LICENSE.md +1 -1
- data/README.md +240 -78
- data/lib/r_spec.rb +15 -22
- data/lib/r_spec/dsl.rb +124 -0
- data/lib/r_spec/expectation_target.rb +28 -0
- data/lib/r_spec/expectation_target/base.rb +66 -0
- data/lib/r_spec/expectation_target/block.rb +62 -0
- data/lib/r_spec/expectation_target/value.rb +55 -0
- data/lib/r_spec/log.rb +24 -0
- data/lib/r_spec/pending.rb +24 -0
- data/lib/r_spec/test.rb +7 -0
- metadata +96 -78
- data/.gitignore +0 -11
- data/.travis.yml +0 -29
- data/.yardopts +0 -1
- data/CODE_OF_CONDUCT.md +0 -13
- data/Gemfile +0 -3
- data/Rakefile +0 -20
- data/VERSION.semver +0 -1
- data/bin/console +0 -7
- data/bin/setup +0 -5
- data/certs/gem-cyril-public_cert.pem +0 -21
- data/checksum/r_spec-0.1.0.gem.sha512 +0 -1
- data/checksum/r_spec-0.1.1.gem.sha512 +0 -1
- data/checksum/r_spec-0.2.0.gem.sha512 +0 -1
- data/checksum/r_spec-0.3.0.gem.sha512 +0 -1
- data/lib/fix/it.rb +0 -10
- data/lib/fix/on.rb +0 -43
- data/pkg_checksum +0 -11
- data/r_spec.gemspec +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7baead9bb63726ef4e29f1ae2df0ff2584177377d1ddda34377d0fb37503ec64
|
4
|
+
data.tar.gz: 52ebf75f1e76d238ffc7592fd624e6af5bc2eed3423d5742accfcb3222555560
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 985f437d4b2a9ffa63a1a14f9d588ba44bea017e5374ec50ba718c41497a0e91cc41ea7705928c7d7b38b3bbc11f6b6f114929d2e81ba1191be02b248b7e43bf
|
7
|
+
data.tar.gz: c525c43c2259150b9122bbf6a84bf61cbcd6323109992a7ce9ddd2248143788cbc6c15bf4b4f231648aadba29a8e1fed80dc068d9e2462a2b903299ec9c1c174
|
data/LICENSE.md
CHANGED
data/README.md
CHANGED
@@ -1,136 +1,298 @@
|
|
1
|
-
#
|
1
|
+
# RSpec clone
|
2
2
|
|
3
|
-
[
|
4
|
-
[][codeclimate]
|
5
|
-
[][gemnasium]
|
6
|
-
[][gem]
|
7
|
-
[][inchpages]
|
8
|
-
[][rubydoc]
|
3
|
+
A minimalist [RSpec](https://github.com/rspec/rspec) clone with all the essentials.
|
9
4
|
|
10
|
-
|
5
|
+

|
11
6
|
|
12
|
-
|
7
|
+
## Status
|
13
8
|
|
14
|
-
|
9
|
+
[](https://badge.fury.io/rb/r_spec)
|
10
|
+
[](https://travis-ci.org/cyril/r_spec.rb)
|
11
|
+
[](https://inch-ci.org/github/cyril/r_spec.rb)
|
15
12
|
|
16
|
-
|
13
|
+
## Goal
|
17
14
|
|
18
|
-
This
|
15
|
+
This clone attempts to provide most of RSpec's DSL without magic power.
|
19
16
|
|
20
|
-
|
17
|
+
## Some differences
|
21
18
|
|
22
|
-
|
19
|
+
* Less features and an implementation with much less code complexity.
|
20
|
+
* Spec files can also be executed directly with the `ruby` executable.
|
21
|
+
* There is no option to activate monkey-patching.
|
22
|
+
* Does not rely on hacks such as `at_exit` hook to trigger the tests.
|
23
|
+
* Built-in matchers do not trust _actual_ and do not send it any message.
|
24
|
+
* The subject must be explicitly defined, otherwise it is not implemented.
|
23
25
|
|
24
|
-
##
|
26
|
+
## Important ⚠️
|
25
27
|
|
26
|
-
|
27
|
-
* Bugs/issues: https://github.com/cyril/r_spec/issues
|
28
|
+
To avoid confusion in the community, please note that:
|
28
29
|
|
29
|
-
|
30
|
+
- the gem of this project is **not [`rspec`](https://rubygems.org/gems/rspec)**,
|
31
|
+
it is **[`r_spec`](https://rubygems.org/gems/r_spec)**;
|
32
|
+
- this project is totally independent of [rspec.info](https://rspec.info/).
|
30
33
|
|
31
|
-
|
32
|
-
* [Rubinius](http://rubini.us/)
|
33
|
-
* [JRuby](http://jruby.org/)
|
34
|
+
### Note
|
34
35
|
|
35
|
-
|
36
|
+
Following [RubyGems naming conventions](https://guides.rubygems.org/name-your-gem/#use-underscores-for-multiple-words), the module name for this project is `RSpec`.
|
36
37
|
|
37
|
-
|
38
|
+
## Installation
|
38
39
|
|
39
|
-
|
40
|
+
Add this line to your application's Gemfile:
|
40
41
|
|
41
|
-
|
42
|
+
```ruby
|
43
|
+
gem "r_spec", ">= 1.0.0.beta2"
|
44
|
+
```
|
42
45
|
|
43
|
-
|
46
|
+
And then execute:
|
44
47
|
|
45
|
-
|
48
|
+
```sh
|
49
|
+
bundle
|
50
|
+
```
|
46
51
|
|
47
|
-
|
52
|
+
Or install it yourself as:
|
48
53
|
|
49
|
-
|
54
|
+
```sh
|
55
|
+
gem install r_spec --pre
|
56
|
+
```
|
50
57
|
|
51
|
-
##
|
58
|
+
## Usage
|
52
59
|
|
53
|
-
|
60
|
+
To understand how the framework builds and runs tests, here are some correspondences between the DSL syntax and the generated Ruby code.
|
54
61
|
|
55
|
-
|
62
|
+
### `describe` method
|
56
63
|
|
57
|
-
|
58
|
-
$ gem install r_spec -P HighSecurity
|
64
|
+
Example of specification content:
|
59
65
|
|
60
|
-
|
66
|
+
```ruby
|
67
|
+
RSpec.describe String do
|
68
|
+
end
|
69
|
+
```
|
61
70
|
|
62
|
-
|
71
|
+
Corresponding Ruby code:
|
63
72
|
|
64
73
|
```ruby
|
65
|
-
|
74
|
+
module RSpec::Test
|
75
|
+
class Test3582143298
|
76
|
+
protected
|
77
|
+
|
78
|
+
def described_class
|
79
|
+
String
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
66
83
|
```
|
67
84
|
|
68
|
-
|
85
|
+
### `context` method
|
69
86
|
|
70
|
-
|
87
|
+
The behavior of the `context` method is exactly the same as `describe`.
|
71
88
|
|
72
|
-
|
89
|
+
### `subject` method
|
73
90
|
|
74
|
-
|
91
|
+
Example of specification content:
|
75
92
|
|
76
93
|
```ruby
|
77
|
-
|
94
|
+
RSpec.describe "Subject" do
|
95
|
+
subject do
|
96
|
+
:foo
|
97
|
+
end
|
98
|
+
end
|
99
|
+
```
|
78
100
|
|
79
|
-
|
101
|
+
Corresponding Ruby code:
|
80
102
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
103
|
+
```ruby
|
104
|
+
module RSpec::Test
|
105
|
+
class Test3582143298
|
106
|
+
protected
|
107
|
+
|
108
|
+
def subject
|
109
|
+
:foo
|
110
|
+
end
|
85
111
|
end
|
112
|
+
end
|
113
|
+
```
|
114
|
+
|
115
|
+
### Embedded `describe` method
|
116
|
+
|
117
|
+
Example of specification content:
|
86
118
|
|
87
|
-
|
88
|
-
|
89
|
-
|
119
|
+
```ruby
|
120
|
+
RSpec.describe "Describe" do
|
121
|
+
# main describe block
|
122
|
+
|
123
|
+
describe "Embedded describe" do
|
124
|
+
# embedded describe block
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
Corresponding Ruby code:
|
130
|
+
|
131
|
+
```ruby
|
132
|
+
module RSpec::Test
|
133
|
+
class Test3582143298
|
134
|
+
# main describe block
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
module RSpec::Test
|
139
|
+
class Test198623541 < RSpec::Test::Test3582143298
|
140
|
+
# embedded describe block
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
### `let` method
|
146
|
+
|
147
|
+
Example of specification content:
|
148
|
+
|
149
|
+
```ruby
|
150
|
+
RSpec.describe do
|
151
|
+
let(:var0) { 42 }
|
152
|
+
let(:var1) { 42 + var3 }
|
153
|
+
let(:var3) { 42 }
|
154
|
+
end
|
155
|
+
```
|
156
|
+
|
157
|
+
Corresponding Ruby code:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
module RSpec::Test
|
161
|
+
class Test3582143298
|
162
|
+
protected
|
163
|
+
|
164
|
+
def var0
|
165
|
+
42
|
166
|
+
end
|
167
|
+
|
168
|
+
def var1
|
169
|
+
42 + var3
|
170
|
+
end
|
171
|
+
|
172
|
+
def var3
|
173
|
+
42
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
### `before` method
|
180
|
+
|
181
|
+
Example of specification content:
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
RSpec.describe do
|
185
|
+
before do
|
186
|
+
puts "hello"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
```
|
190
|
+
|
191
|
+
Corresponding Ruby code:
|
192
|
+
|
193
|
+
```ruby
|
194
|
+
module RSpec::Test
|
195
|
+
class Test3582143298
|
196
|
+
def initialize
|
197
|
+
puts "hello"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
```
|
202
|
+
|
203
|
+
### `expect` method
|
204
|
+
|
205
|
+
Example of specification content:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
RSpec.describe do
|
209
|
+
it { expect(41.next).to be(42) }
|
210
|
+
end
|
211
|
+
```
|
212
|
+
|
213
|
+
Corresponding Ruby code:
|
214
|
+
|
215
|
+
```ruby
|
216
|
+
module RSpec::Test
|
217
|
+
class Test3582143298
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
example_class = Class.new(RSpec::Test::Test3582143298) do
|
222
|
+
include Matchi::Helper
|
223
|
+
|
224
|
+
# Declaration of private methods (`expect`, `is_expected`, `log`, `pending`).
|
225
|
+
end
|
226
|
+
|
227
|
+
example_class.new.instance_eval do
|
228
|
+
ExpectationTarget::Value.new(41.next).to be(42)
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
232
|
+
Success: expected to be 42.
|
233
|
+
|
234
|
+
## Example
|
235
|
+
|
236
|
+
Let's test an array:
|
237
|
+
|
238
|
+
```ruby
|
239
|
+
# array_spec.rb
|
240
|
+
|
241
|
+
require "r_spec"
|
242
|
+
|
243
|
+
RSpec.describe Array do
|
244
|
+
before do
|
245
|
+
@elements = described_class.new
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "#count" do
|
249
|
+
subject do
|
250
|
+
@elements.count
|
251
|
+
end
|
252
|
+
|
253
|
+
it { is_expected.to be 0 }
|
254
|
+
|
255
|
+
context "when a new element is added" do
|
256
|
+
before do
|
257
|
+
@elements << 1
|
258
|
+
end
|
259
|
+
|
260
|
+
it { is_expected.to be 1 }
|
261
|
+
end
|
90
262
|
end
|
91
263
|
end
|
92
264
|
```
|
93
265
|
|
94
266
|
It can be tested in the console with the command:
|
95
267
|
|
96
|
-
|
97
|
-
|
268
|
+
```sh
|
269
|
+
ruby array_spec.rb
|
270
|
+
```
|
98
271
|
|
99
|
-
|
100
|
-
|
272
|
+
array_spec.rb:15 Success: expected to be 0.
|
273
|
+
array_spec.rb:22 Success: expected to be 1.
|
101
274
|
|
102
|
-
##
|
275
|
+
## Test suite
|
103
276
|
|
104
|
-
|
105
|
-
every Gem release. These checksums can be found in the `checksum/` directory.
|
106
|
-
Although these checksums do not prevent malicious users from tampering with a
|
107
|
-
built Gem they can be used for basic integrity verification purposes.
|
277
|
+
__RSpec clone__'s specifications are self-described here: [spec/](https://github.com/cyril/r_spec.rb/blob/main/spec/)
|
108
278
|
|
109
|
-
|
110
|
-
example:
|
279
|
+
## Contact
|
111
280
|
|
112
|
-
|
113
|
-
|
281
|
+
* Home page: https://r-spec.dev
|
282
|
+
* Source code: https://github.com/cyril/r_spec.rb
|
283
|
+
* Twitter: [https://twitter.com/cyri\_](https://twitter.com/cyri\_)
|
114
284
|
|
115
285
|
## Versioning
|
116
286
|
|
117
|
-
|
287
|
+
__RSpec clone__ follows [Semantic Versioning 2.0](https://semver.org/).
|
118
288
|
|
119
|
-
##
|
289
|
+
## Special thanks
|
120
290
|
|
121
|
-
|
122
|
-
|
123
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
124
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
125
|
-
5. Create a new Pull Request
|
291
|
+
I would like to thank the whole [RSpec team](https://rspec.info/about/) for all their work.
|
292
|
+
It's a great framework and it's a pleasure to work with every day.
|
126
293
|
|
127
|
-
|
294
|
+
Without RSpec, this clone would not have been possible. ❤️
|
128
295
|
|
129
|
-
|
296
|
+
## License
|
130
297
|
|
131
|
-
[gem]
|
132
|
-
[travis]: https://travis-ci.org/cyril/r_spec
|
133
|
-
[codeclimate]: https://codeclimate.com/github/cyril/r_spec
|
134
|
-
[gemnasium]: https://gemnasium.com/cyril/r_spec
|
135
|
-
[inchpages]: http://inch-ci.org/github/cyril/r_spec
|
136
|
-
[rubydoc]: http://rubydoc.info/gems/r_spec/frames
|
298
|
+
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).
|
data/lib/r_spec.rb
CHANGED
@@ -1,32 +1,25 @@
|
|
1
|
-
|
2
|
-
require 'fix/expect'
|
3
|
-
require 'fix/its'
|
4
|
-
require 'fix/let'
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
#
|
3
|
+
# Top level namespace for the RSpec clone.
|
7
4
|
#
|
8
|
-
# @
|
5
|
+
# @example
|
6
|
+
# require "r_spec"
|
7
|
+
#
|
8
|
+
# RSpec.describe Integer do
|
9
|
+
# it { expect(41.next).to be 42 }
|
10
|
+
# end
|
9
11
|
#
|
12
|
+
# @api public
|
10
13
|
module RSpec
|
11
14
|
# Specs are built with this method.
|
12
15
|
#
|
13
|
-
# @
|
14
|
-
#
|
15
|
-
# it { expect(42).to be 42 }
|
16
|
-
# end
|
16
|
+
# @param const [Module, String] A module to include in block context.
|
17
|
+
# @param block [Proc] The block to define the specs.
|
17
18
|
#
|
18
|
-
# @
|
19
|
-
|
20
|
-
|
21
|
-
#
|
22
|
-
# @raise [SystemExit] The result of the test.
|
23
|
-
def self.describe(front_object, options = {}, &specs)
|
24
|
-
t = ::Fix::Test.new(front_object, options, &specs)
|
25
|
-
|
26
|
-
print t.report.to_s if options.fetch(:verbose, true)
|
27
|
-
exit t.pass?
|
19
|
+
# @api public
|
20
|
+
def self.describe(const, &block)
|
21
|
+
DSL.describe(const, &block)
|
28
22
|
end
|
29
23
|
end
|
30
24
|
|
31
|
-
require_relative File.join
|
32
|
-
require_relative File.join 'fix', 'on'
|
25
|
+
require_relative File.join("r_spec", "dsl")
|
data/lib/r_spec/dsl.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "matchi/rspec"
|
4
|
+
require "securerandom"
|
5
|
+
|
6
|
+
module RSpec
|
7
|
+
# Abstract class for handling the domain-specific language.
|
8
|
+
class DSL
|
9
|
+
# @param block [Proc] The content to execute at the class initialization.
|
10
|
+
def self.before(&block)
|
11
|
+
define_method(:initialize) do |*args, **kwargs|
|
12
|
+
super()
|
13
|
+
instance_exec(*args, **kwargs, &block)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param block [Proc] The content of the method to define.
|
18
|
+
# @return [Symbol] A protected method that define the block content.
|
19
|
+
def self.let(name, &block)
|
20
|
+
protected define_method(name.to_sym, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @param block [Proc] The subject to set.
|
24
|
+
# @return [Symbol] A `subject` method that define the block content.
|
25
|
+
def self.subject(&block)
|
26
|
+
let(__method__, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Describe a set of expectations.
|
30
|
+
#
|
31
|
+
# @param const [Module, #object_id] A module to include in block context.
|
32
|
+
# @param block [Proc] The block to define the specs.
|
33
|
+
def self.describe(const, &block)
|
34
|
+
desc = Test.const_set(random_test_const_name, ::Class.new(self))
|
35
|
+
|
36
|
+
if const.is_a?(::Module)
|
37
|
+
desc.define_method(:described_class) { const }
|
38
|
+
desc.send(:protected, :described_class)
|
39
|
+
end
|
40
|
+
|
41
|
+
desc.instance_eval(&block)
|
42
|
+
desc
|
43
|
+
end
|
44
|
+
|
45
|
+
# Add `context` to the DSL.
|
46
|
+
singleton_class.send(:alias_method, :context, :describe)
|
47
|
+
|
48
|
+
# Evaluate an expectation.
|
49
|
+
#
|
50
|
+
# @param block [Proc] An expectation to evaluate.
|
51
|
+
#
|
52
|
+
# @raise (see ExpectationTarget::Base#result)
|
53
|
+
# @return (see ExpectationTarget::Base#result)
|
54
|
+
def self.it(_name = nil, &block)
|
55
|
+
raise ::ArgumentError, "Missing block" unless block
|
56
|
+
|
57
|
+
puts "\e[37m#{block.source_location.join(':')}\e[0m"
|
58
|
+
|
59
|
+
i = example.new
|
60
|
+
i.instance_eval(&block)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @private
|
64
|
+
#
|
65
|
+
# @return [Class<DSL>] The class of the example to be tested.
|
66
|
+
def self.example
|
67
|
+
# Dynamic creation of an example class.
|
68
|
+
::Class.new(self) do
|
69
|
+
# Include a collection of matchers.
|
70
|
+
include ::Matchi::Helper
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
# Wraps the target of an expectation with the actual value.
|
75
|
+
#
|
76
|
+
# @param actual [#object_id] The actual value.
|
77
|
+
#
|
78
|
+
# @return [ExpectationTarget] The target of the expectation.
|
79
|
+
def expect(actual = self.class.superclass, &block)
|
80
|
+
ExpectationTarget.call(self.class.superclass, actual, block)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Wraps the target of an expectation with the subject as actual value.
|
84
|
+
#
|
85
|
+
# @return [ExpectationTarget] (see #expect)
|
86
|
+
def is_expected
|
87
|
+
expect(subject)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Output a message to the console.
|
91
|
+
#
|
92
|
+
# @param message [String] The string to be notified about.
|
93
|
+
#
|
94
|
+
# @return [nil] Write a message to STDOUT.
|
95
|
+
def log(message)
|
96
|
+
Log.result(message)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Indicate that an example is disabled pending some action.
|
100
|
+
#
|
101
|
+
# @param description [String] The reason why the example is pending.
|
102
|
+
#
|
103
|
+
# @return [nil] Write a message to STDOUT.
|
104
|
+
def pending(description)
|
105
|
+
Pending.result(description)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# @private
|
111
|
+
#
|
112
|
+
# @return [String] A random constant name for a test class.
|
113
|
+
def self.random_test_const_name
|
114
|
+
"Test#{::SecureRandom.hex(4).to_i(16)}"
|
115
|
+
end
|
116
|
+
|
117
|
+
private_class_method :example, :random_test_const_name
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
require_relative "expectation_target"
|
122
|
+
require_relative "log"
|
123
|
+
require_relative "pending"
|
124
|
+
require_relative "test"
|