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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f9b6d58547e6b78494ab484447f08c43a2fd233db5ef946c977b0f21fc0311d
4
- data.tar.gz: 0fb204fd7cb1ccf56ddfacfe6737e137c387d5734855e629edae6a5289d2e291
3
+ metadata.gz: 361429a943a5149aeea4da4dd83150360db392275ec4d9d98e76969e60768dce
4
+ data.tar.gz: 6df8aaff424652d4e73cb163cc1dfd973c9a4a03ec2e2d6e351db5f87b0674a8
5
5
  SHA512:
6
- metadata.gz: 67bd36e9816e7f92c0a2534d3d7055a73c5c249182b6b0e7842441c856e0fb6d47e0fb59dbe89b9fbe3124212b98e765cf5f312a14e276017b1dcd29d120002f
7
- data.tar.gz: e58648ee25f43b7d964a2f0782a05724c935b2661dc4c2afa5c71bff51af0baac694ef86a12c911266bb1d4e4ebc50d3f499e05531722d0362be5fc1f1f6bd5e
6
+ metadata.gz: 24a1c58a8e0db0ef62d97881eabc8a4ff0596d82c96f1dee40fc68edffdc17f0206c6d45aa11040e3b11af35038df58ee7bca1f6190330f91b1b384304dcc304
7
+ data.tar.gz: 0a5ff783abf6bce80c8ff4a3e3f2e938c004bf5cd02e8300f56650e6312638e911638ed41c9293047aa757ae73048cd412bae5b6cc031e43bab82a2f4b92e41c
data/README.md CHANGED
@@ -7,6 +7,8 @@
7
7
  [![RuboCop](https://github.com/fixrb/fix/workflows/RuboCop/badge.svg?branch=main)](https://github.com/fixrb/fix/actions?query=workflow%3Arubocop+branch%3Amain)
8
8
  [![License](https://img.shields.io/github/license/fixrb/fix?label=License&logo=github)](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
  ![Fix specing framework for Ruby](https://github.com/fixrb/fix/raw/main/img/fix.jpg)
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.beta5"
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 { MUST eql "Swoosh..." }
66
+ it MUST eql "Swoosh..."
63
67
  end
64
68
 
65
69
  on :speaks do
66
- it { MUST raise_exception NoMethodError }
70
+ it MUST raise_exception NoMethodError
67
71
  end
68
72
 
69
73
  on :sings do
70
- it { MAY eql "♪... ♫..." }
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].call(Duck.new)
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
- Test #<Duck:0x00007fc5289bcf68> against Duck:
94
- - NoMethodError: undefined method `sings' for #<Duck:0x00007fc5289bcf68>.
95
- - Success: expected to eql "Swoosh...".
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 are [fixed here](https://github.com/fixrb/fix/blob/main/fix/) and can be tested against __Fix__'s codebase executing [test/](https://github.com/fixrb/fix/blob/main/test/)'s files.
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 "- #{report.colored_string}"
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 "- #{report.colored_string}"
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 "console"
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.describe "Name stories" do
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
- private_class_method define_singleton_method(name, &block)
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.on String do
58
- # on "+" do
59
- # it("concats") { expect("foo" + "bar").to eq "foobar" }
62
+ # Fix do
63
+ # on :+, 2 do
64
+ # it MUST be 42
60
65
  # end
61
66
  # end
62
67
  #
63
- # # Output to the console
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(:SPECS) << klass
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 test case.
95
+ # Defines a concrete spec definition.
84
96
  #
85
- # The test is performed by the block supplied to `&block`.
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 :Integer do
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(&block)
121
- define_method("test_#{block.object_id}", &block)
103
+ def self.it(requirement)
104
+ define_method("test_#{requirement.object_id}") { requirement }
122
105
  end
123
106
 
124
- def self.its(method_name, *args, **kwargs, &block)
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(:SPECS) << klass
127
- const_set("Child#{block.object_id}", klass)
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, *args, **kwargs)]
115
+ super() + [::Defi.send(method_name)]
131
116
  end
132
117
 
133
- klass.it(&block)
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
- def initialize(subject)
145
- @subject = subject
146
- end
142
+ attr_reader :subject
147
143
 
148
- ::Spectus.methods(false).each do |method_name|
149
- define_method(method_name.upcase) do |matcher|
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
- def method_missing(method_name, *args, &block)
159
- self.class.send(method_name)
160
- rescue ::NoMethodError
161
- super
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
- def respond_to_missing?(method_name, include_private = false)
165
- self.class.respond_to?(method_name) || super
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 :name
11
+ attr_reader :contexts
12
12
 
13
- def initialize(name)
14
- @name = name
13
+ def initialize(*contexts)
14
+ @contexts = contexts
15
15
  end
16
16
 
17
- def call(subject)
18
- Console.title(name, subject)
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(subject)
26
- specs.flat_map do |spec|
27
- example = spec.new(subject)
28
- example.public_methods(false).map do |public_method|
29
- example.method(public_method)
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.shuffle
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(:SPECS, [klass])
24
+ klass.const_set(:CONTEXTS, [klass])
25
25
  klass.instance_eval(&block)
26
- ::Fix::Doc.const_set(name, klass)
27
- ::Fix::Test.new(name)
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.beta5
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-14 00:00:00.000000000 Z
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.1.1
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.1.1
40
+ version: 2.2.0
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: spectus
43
43
  requirement: !ruby/object:Gem::Requirement