fix 1.0.0.beta5 → 1.0.0.beta6
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 +4 -4
- data/README.md +13 -10
- data/lib/fix.rb +2 -1
- data/lib/fix/console.rb +2 -10
- data/lib/fix/dsl.rb +75 -79
- data/lib/fix/test.rb +29 -22
- data/lib/kernel.rb +6 -4
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 361429a943a5149aeea4da4dd83150360db392275ec4d9d98e76969e60768dce
|
4
|
+
data.tar.gz: 6df8aaff424652d4e73cb163cc1dfd973c9a4a03ec2e2d6e351db5f87b0674a8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24a1c58a8e0db0ef62d97881eabc8a4ff0596d82c96f1dee40fc68edffdc17f0206c6d45aa11040e3b11af35038df58ee7bca1f6190330f91b1b384304dcc304
|
7
|
+
data.tar.gz: 0a5ff783abf6bce80c8ff4a3e3f2e938c004bf5cd02e8300f56650e6312638e911638ed41c9293047aa757ae73048cd412bae5b6cc031e43bab82a2f4b92e41c
|
data/README.md
CHANGED
@@ -7,6 +7,8 @@
|
|
7
7
|
[](https://github.com/fixrb/fix/actions?query=workflow%3Arubocop+branch%3Amain)
|
8
8
|
[](https://github.com/fixrb/fix/raw/main/LICENSE.md)
|
9
9
|
|
10
|
+
⚠️ This project is still in the experimental phase. May be used at your own risk.
|
11
|
+
|
10
12
|

|
11
13
|
|
12
14
|
## Installation
|
@@ -14,7 +16,7 @@
|
|
14
16
|
Add this line to your application's Gemfile:
|
15
17
|
|
16
18
|
```ruby
|
17
|
-
gem "fix", ">= 1.0.0.
|
19
|
+
gem "fix", ">= 1.0.0.beta6"
|
18
20
|
```
|
19
21
|
|
20
22
|
And then execute:
|
@@ -58,16 +60,18 @@ And this fixed behavior:
|
|
58
60
|
relative "fix"
|
59
61
|
|
60
62
|
Fix :Duck do
|
63
|
+
it MUST be_an_instance_of :Duck
|
64
|
+
|
61
65
|
on :swims do
|
62
|
-
it
|
66
|
+
it MUST eql "Swoosh..."
|
63
67
|
end
|
64
68
|
|
65
69
|
on :speaks do
|
66
|
-
it
|
70
|
+
it MUST raise_exception NoMethodError
|
67
71
|
end
|
68
72
|
|
69
73
|
on :sings do
|
70
|
-
it
|
74
|
+
it MAY eql "♪... ♫..."
|
71
75
|
end
|
72
76
|
end
|
73
77
|
```
|
@@ -80,7 +84,7 @@ When I run this test:
|
|
80
84
|
require_relative "app"
|
81
85
|
require_relative "fix"
|
82
86
|
|
83
|
-
Fix[:Duck].
|
87
|
+
Fix[:Duck].test { Duck.new }
|
84
88
|
```
|
85
89
|
|
86
90
|
```sh
|
@@ -90,15 +94,14 @@ ruby examples/duck/test.rb
|
|
90
94
|
I should see this output:
|
91
95
|
|
92
96
|
```txt
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
- Success: undefined method `speaks' for #<Duck:0x00007fc5289bcf68>.
|
97
|
+
NoMethodError: undefined method `sings' for #<Duck:0x00007fc5289bcf68>.
|
98
|
+
Success: expected to eql "Swoosh...".
|
99
|
+
Success: undefined method `speaks' for #<Duck:0x00007fc5289bcf68>.
|
97
100
|
```
|
98
101
|
|
99
102
|
## Test suite
|
100
103
|
|
101
|
-
__Fix__'s specifications
|
104
|
+
__Fix__'s specifications will be [fixed here](https://github.com/fixrb/fix/blob/main/fix/) and will be tested against __Fix__'s codebase executing [test/*](https://github.com/fixrb/fix/blob/main/test/)'s files.
|
102
105
|
|
103
106
|
## Contact
|
104
107
|
|
data/lib/fix.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative File.join("fix", "doc")
|
3
4
|
require_relative File.join("fix", "test")
|
4
5
|
|
5
6
|
require_relative "kernel"
|
@@ -18,6 +19,6 @@ module Fix
|
|
18
19
|
#
|
19
20
|
# @return [::Fix::Dsl] The specification document.
|
20
21
|
def self.[](name)
|
21
|
-
Test.new(name)
|
22
|
+
Test.new(*Doc.const_get(name).const_get(:CONTEXTS))
|
22
23
|
end
|
23
24
|
end
|
data/lib/fix/console.rb
CHANGED
@@ -3,21 +3,13 @@
|
|
3
3
|
module Fix
|
4
4
|
# Send log messages to the console.
|
5
5
|
module Console
|
6
|
-
# @param name [String, Symbol] The name of the specification document.
|
7
|
-
# @param subject [#object_id] The front object to be tested.
|
8
|
-
#
|
9
|
-
# @return [nil] Add a message to `$stdout`.
|
10
|
-
def self.title(name, subject)
|
11
|
-
puts "Run #{name} specs against #{subject.inspect}:"
|
12
|
-
end
|
13
|
-
|
14
6
|
# @param report [::Expresenter::Pass] Passed expectation result presenter.
|
15
7
|
#
|
16
8
|
# @see https://github.com/fixrb/expresenter
|
17
9
|
#
|
18
10
|
# @return [nil] Add a colored message to `$stdout`.
|
19
11
|
def self.passed_spec(report)
|
20
|
-
puts
|
12
|
+
puts report.colored_string
|
21
13
|
end
|
22
14
|
|
23
15
|
# @param report [::Expresenter::Fail] Failed expectation result presenter.
|
@@ -26,7 +18,7 @@ module Fix
|
|
26
18
|
#
|
27
19
|
# @raise [SystemExit] Terminate execution immediately with colored message.
|
28
20
|
def self.failed_spec(report)
|
29
|
-
abort
|
21
|
+
abort report.colored_string
|
30
22
|
end
|
31
23
|
end
|
32
24
|
end
|
data/lib/fix/dsl.rb
CHANGED
@@ -4,7 +4,7 @@ require "defi"
|
|
4
4
|
require "matchi/helper"
|
5
5
|
require "spectus"
|
6
6
|
|
7
|
-
require_relative "
|
7
|
+
require_relative "test"
|
8
8
|
|
9
9
|
module Fix
|
10
10
|
# Abstract class for handling the domain-specific language.
|
@@ -16,22 +16,10 @@ module Fix
|
|
16
16
|
# @example
|
17
17
|
# require "fix"
|
18
18
|
#
|
19
|
-
# Fix
|
19
|
+
# Fix do
|
20
20
|
# let(:name) { "Bob" }
|
21
|
-
#
|
22
|
-
# it { expect(name).to eq "Bob" }
|
23
|
-
#
|
24
|
-
# context "with last name" do
|
25
|
-
# let(:name) { "#{super()} Smith" }
|
26
|
-
#
|
27
|
-
# it { expect(name).to eq "Bob Smith" }
|
28
|
-
# end
|
29
21
|
# end
|
30
22
|
#
|
31
|
-
# # Output to the console
|
32
|
-
# # Success: expected to eq "Bob".
|
33
|
-
# # Success: expected to eq "Bob Smith".
|
34
|
-
#
|
35
23
|
# @param name [String, Symbol] The name of the property.
|
36
24
|
# @param block [Proc] The content of the method to define.
|
37
25
|
#
|
@@ -39,11 +27,28 @@ module Fix
|
|
39
27
|
#
|
40
28
|
# @api public
|
41
29
|
def self.let(name, &block)
|
42
|
-
|
30
|
+
private define_method(name, &block)
|
43
31
|
end
|
44
32
|
|
33
|
+
# Defines an example group with user-defined properties that describes a
|
34
|
+
# unit to be tested.
|
35
|
+
#
|
36
|
+
# @example
|
37
|
+
# require "fix"
|
38
|
+
#
|
39
|
+
# Fix do
|
40
|
+
# with :password, "secret" do
|
41
|
+
# it MUST equal true
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# @param kwargs [Hash] The list of propreties.
|
46
|
+
# @param block [Proc] The block to define the specs.
|
47
|
+
#
|
48
|
+
# @api public
|
45
49
|
def self.with(**kwargs, &block)
|
46
50
|
klass = ::Class.new(self)
|
51
|
+
klass.const_get(:CONTEXTS) << klass
|
47
52
|
kwargs.each { |name, value| klass.let(name) { value } }
|
48
53
|
klass.instance_eval(&block)
|
49
54
|
klass
|
@@ -54,115 +59,106 @@ module Fix
|
|
54
59
|
# @example
|
55
60
|
# require "fix"
|
56
61
|
#
|
57
|
-
# Fix
|
58
|
-
# on
|
59
|
-
# it
|
62
|
+
# Fix do
|
63
|
+
# on :+, 2 do
|
64
|
+
# it MUST be 42
|
60
65
|
# end
|
61
66
|
# end
|
62
67
|
#
|
63
|
-
#
|
64
|
-
# # Success: expected to eq "foobar".
|
65
|
-
#
|
66
|
-
# @param const [Module, String] A module to include in block context.
|
68
|
+
# @param method_name [String, Symbol] The method to send to the subject.
|
67
69
|
# @param block [Proc] The block to define the specs.
|
68
70
|
#
|
69
71
|
# @api public
|
70
72
|
def self.on(method_name, *args, **kwargs, &block)
|
71
73
|
klass = ::Class.new(self)
|
72
|
-
klass.const_get(:
|
74
|
+
klass.const_get(:CONTEXTS) << klass
|
75
|
+
|
73
76
|
const_set("Child#{block.object_id}", klass)
|
74
77
|
|
75
78
|
klass.define_singleton_method(:challenges) do
|
76
79
|
super() + [::Defi.send(method_name, *args, **kwargs)]
|
77
80
|
end
|
78
81
|
|
82
|
+
def klass.initialize
|
83
|
+
if subject.raised?
|
84
|
+
subject
|
85
|
+
else
|
86
|
+
challenge = ::Defi.send(method_name, *args, **kwargs)
|
87
|
+
challenge.to(subject.call)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
79
91
|
klass.instance_eval(&block)
|
80
92
|
klass
|
81
93
|
end
|
82
94
|
|
83
|
-
# Defines a concrete
|
95
|
+
# Defines a concrete spec definition.
|
84
96
|
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# @example The integer after 41
|
88
|
-
# require "fix"
|
89
|
-
#
|
90
|
-
# Fix(:AnswerToEverything) { it { MUST be 42 } }.call(42)
|
91
|
-
#
|
92
|
-
# # Output to the console
|
93
|
-
# # Success: expected to be 42.
|
94
|
-
#
|
95
|
-
# @example A division by zero
|
97
|
+
# @example
|
96
98
|
# require "fix"
|
97
99
|
#
|
98
|
-
# Fix
|
99
|
-
# it { MUST be_an_instance_of Integer }
|
100
|
-
#
|
101
|
-
# on :/, 0 do
|
102
|
-
# it { MUST raise_exception ZeroDivisionError }
|
103
|
-
# end
|
104
|
-
# end
|
105
|
-
#
|
106
|
-
# Fix[:Integer].call(41)
|
107
|
-
#
|
108
|
-
# # Output to the console
|
109
|
-
# # Success: expected 41 to be an instance of Integer.
|
110
|
-
# # Success: divided by 0.
|
111
|
-
#
|
112
|
-
# It can be used inside a {.describe} or {.context} section.
|
113
|
-
#
|
114
|
-
# @param block [Proc] An expectation to evaluate.
|
115
|
-
#
|
116
|
-
# @raise (see ExpectationTarget::Base#result)
|
117
|
-
# @return (see ExpectationTarget::Base#result)
|
100
|
+
# Fix { it MUST equal 42 }
|
118
101
|
#
|
119
102
|
# @api public
|
120
|
-
def self.it(
|
121
|
-
define_method("test_#{
|
103
|
+
def self.it(requirement)
|
104
|
+
define_method("test_#{requirement.object_id}") { requirement }
|
122
105
|
end
|
123
106
|
|
124
|
-
|
107
|
+
# @todo Move this method inside "fix-its" gem.
|
108
|
+
def self.its(method_name, requirement)
|
125
109
|
klass = ::Class.new(self)
|
126
|
-
klass.const_get(:
|
127
|
-
|
110
|
+
klass.const_get(:CONTEXTS) << klass
|
111
|
+
|
112
|
+
const_set("Child#{requirement.object_id}", klass)
|
128
113
|
|
129
114
|
klass.define_singleton_method(:challenges) do
|
130
|
-
super() + [::Defi.send(method_name
|
115
|
+
super() + [::Defi.send(method_name)]
|
131
116
|
end
|
132
117
|
|
133
|
-
klass.
|
118
|
+
def klass.initialize
|
119
|
+
if subject.raised?
|
120
|
+
subject
|
121
|
+
else
|
122
|
+
challenge = ::Defi.send(method_name, *args, **kwargs)
|
123
|
+
challenge.to(subject.call)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
klass.it(requirement)
|
134
128
|
end
|
135
129
|
|
136
130
|
def self.challenges
|
137
131
|
[]
|
138
132
|
end
|
139
133
|
|
134
|
+
def self.test(&subject)
|
135
|
+
Test.new(self).test(&subject)
|
136
|
+
end
|
137
|
+
|
140
138
|
private_class_method :challenges
|
141
139
|
|
142
140
|
private
|
143
141
|
|
144
|
-
|
145
|
-
@subject = subject
|
146
|
-
end
|
142
|
+
attr_reader :subject
|
147
143
|
|
148
|
-
|
149
|
-
|
150
|
-
::Spectus.public_send(method_name, matcher).call do
|
151
|
-
self.class.send(:challenges).inject(@subject) do |object, challenge|
|
152
|
-
challenge.to(object).call
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
144
|
+
def initialize(&subject)
|
145
|
+
@subject = ::Defi::Value.new(&subject)
|
156
146
|
end
|
157
147
|
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
148
|
+
::Matchi::Matcher.constants.each do |matcher_const|
|
149
|
+
next if matcher_const.equal?(:Base)
|
150
|
+
|
151
|
+
matcher_klass = ::Matchi::Matcher.const_get(matcher_const)
|
152
|
+
|
153
|
+
define_singleton_method(matcher_klass.to_sym) do |*args|
|
154
|
+
matcher_klass.new(*args)
|
155
|
+
end
|
162
156
|
end
|
163
157
|
|
164
|
-
|
165
|
-
|
158
|
+
::Spectus.methods(false).each do |method_name|
|
159
|
+
define_singleton_method(method_name.upcase) do |matcher|
|
160
|
+
::Spectus.public_send(method_name, matcher)
|
161
|
+
end
|
166
162
|
end
|
167
163
|
end
|
168
164
|
end
|
data/lib/fix/test.rb
CHANGED
@@ -8,37 +8,44 @@ require_relative "doc"
|
|
8
8
|
module Fix
|
9
9
|
# Module for testing spec documents.
|
10
10
|
class Test
|
11
|
-
attr_reader :
|
11
|
+
attr_reader :contexts
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@
|
13
|
+
def initialize(*contexts)
|
14
|
+
@contexts = contexts
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
|
19
|
-
requirements(subject).each { |requirement| test(requirement) }
|
17
|
+
def test(&block)
|
18
|
+
requirements(&block)
|
20
19
|
exit(true)
|
21
20
|
end
|
22
21
|
|
23
22
|
private
|
24
23
|
|
25
|
-
def requirements(
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
def requirements(&block)
|
25
|
+
contexts.flat_map do |context|
|
26
|
+
sandbox = context.new
|
27
|
+
sandbox.public_methods(false).shuffle.map do |public_method|
|
28
|
+
definition = sandbox.public_send(public_method)
|
29
|
+
|
30
|
+
report = begin
|
31
|
+
definition.call do
|
32
|
+
front_object = instance_eval(&block)
|
33
|
+
|
34
|
+
context.send(:challenges).inject(front_object) do |object, challenge|
|
35
|
+
challenge.to(object).call
|
36
|
+
end
|
37
|
+
end
|
38
|
+
rescue ::Expresenter::Fail => e
|
39
|
+
e
|
40
|
+
end
|
41
|
+
|
42
|
+
if report.passed?
|
43
|
+
Console.passed_spec report
|
44
|
+
else
|
45
|
+
Console.failed_spec report
|
46
|
+
end
|
30
47
|
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def specs
|
35
|
-
Doc.const_get(name).const_get(:SPECS)
|
36
|
-
end
|
37
|
-
|
38
|
-
def test(requirement)
|
39
|
-
Console.passed_spec requirement.call
|
40
|
-
rescue ::Expresenter::Fail => e
|
41
|
-
Console.failed_spec e
|
48
|
+
end
|
42
49
|
end
|
43
50
|
end
|
44
51
|
end
|
data/lib/kernel.rb
CHANGED
@@ -19,12 +19,14 @@ module Kernel
|
|
19
19
|
# @return [Class] The specification document.
|
20
20
|
#
|
21
21
|
# rubocop:disable Naming/MethodName
|
22
|
-
def Fix(name, &block)
|
22
|
+
def Fix(name = nil, &block)
|
23
23
|
klass = ::Class.new(::Fix::Dsl)
|
24
|
-
klass.const_set(:
|
24
|
+
klass.const_set(:CONTEXTS, [klass])
|
25
25
|
klass.instance_eval(&block)
|
26
|
-
|
27
|
-
::Fix::
|
26
|
+
|
27
|
+
::Fix::Doc.const_set(name, klass) unless name.nil?
|
28
|
+
|
29
|
+
::Fix::Test.new(*klass.const_get(:CONTEXTS))
|
28
30
|
end
|
29
31
|
# rubocop:enable Naming/MethodName
|
30
32
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.
|
4
|
+
version: 1.0.0.beta6
|
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-
|
11
|
+
date: 2021-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: defi
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 2.
|
33
|
+
version: 2.2.0
|
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: 2.
|
40
|
+
version: 2.2.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: spectus
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|