fix 1.0.0.beta10 → 1.0.0.beta12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +233 -45
- data/lib/fix/dsl.rb +10 -3
- data/lib/fix/matcher.rb +38 -230
- data/lib/fix/requirement.rb +5 -5
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4d32cb2da3e2823f71175074536af7f55c981cba88f1fc39952f5c91ecc27756
|
4
|
+
data.tar.gz: bfbf3da66b20085030ecffadbfe908dfe90ea3fe5620fdfaceeedbb5eaec0e9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e66633ce3e37380f20f83f3747ef158e9baadc0853898850972c7e119fe7615eadd53c3197c9bfbd8e48f341d38991060f8dfba16070f34953a08208eefa5bf
|
7
|
+
data.tar.gz: 798abf5941f2fbac379d6b19622d1dfe8fd278c81a715a8e1f55a0f8c91aa6b0b1febfd2a60241ddb9a12f5320ed112a77a0a39f860d3e26e43985277f4d0e99
|
data/README.md
CHANGED
@@ -1,27 +1,20 @@
|
|
1
|
-
# Fix
|
1
|
+
# Fix Framework
|
2
2
|
|
3
3
|
[![Home](https://img.shields.io/badge/Home-fixrb.dev-00af8b)](https://fixrb.dev/)
|
4
4
|
[![Version](https://img.shields.io/github/v/tag/fixrb/fix?label=Version&logo=github)](https://github.com/fixrb/fix/tags)
|
5
5
|
[![Yard documentation](https://img.shields.io/badge/Yard-documentation-blue.svg?logo=github)](https://rubydoc.info/github/fixrb/fix/main)
|
6
|
-
[![Ruby](https://github.com/fixrb/fix/workflows/Ruby/badge.svg?branch=main)](https://github.com/fixrb/fix/actions?query=workflow%3Aruby+branch%3Amain)
|
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
6
|
[![License](https://img.shields.io/github/license/fixrb/fix?label=License&logo=github)](https://github.com/fixrb/fix/raw/main/LICENSE.md)
|
9
7
|
|
10
|
-
|
8
|
+
## Introduction
|
11
9
|
|
12
|
-
|
13
|
-
|
14
|
-
- **Distinguish Specifications from Examples**: Clear separation between what is expected (specifications) and how it's demonstrated (examples).
|
15
|
-
- **Logic-Free Specification Documents**: Create specifications that are straightforward and free of complex logic, focusing purely on defining expected behaviors.
|
16
|
-
- **Nuanced Semantic Language in Specifications**: Utilize a rich, nuanced semantic language, similar to that in RFC 2119, employing keywords like MUST, SHOULD, and MAY to define different levels of requirement in specifications.
|
17
|
-
- **Fast and Individual Test Execution**: Enable quick execution of tests on an individual basis, providing immediate feedback on compliance with specifications.
|
10
|
+
Fix is a modern Ruby testing framework that emphasizes clear separation between specifications and examples. Unlike traditional testing frameworks, Fix focuses on creating pure specification documents that define expected behaviors without mixing in implementation details.
|
18
11
|
|
19
12
|
## Installation
|
20
13
|
|
21
14
|
Add to your Gemfile:
|
22
15
|
|
23
16
|
```ruby
|
24
|
-
gem "fix", ">= 1.0.0.
|
17
|
+
gem "fix", ">= 1.0.0.beta12"
|
25
18
|
```
|
26
19
|
|
27
20
|
Then execute:
|
@@ -36,15 +29,161 @@ Or install it yourself:
|
|
36
29
|
gem install fix --pre
|
37
30
|
```
|
38
31
|
|
39
|
-
##
|
32
|
+
## Core Principles
|
33
|
+
|
34
|
+
- **Specifications vs Examples**: Fix makes a clear distinction between specifications (what is expected) and examples (how it's demonstrated). This separation leads to cleaner, more maintainable test suites.
|
35
|
+
|
36
|
+
- **Logic-Free Specifications**: Your specification documents remain pure and focused on defining behaviors, without getting cluttered by implementation logic.
|
37
|
+
|
38
|
+
- **Rich Semantic Language**: Following RFC 2119 conventions, Fix uses precise language with keywords like MUST, SHOULD, and MAY to clearly define different requirement levels in specifications.
|
39
|
+
|
40
|
+
- **Fast Individual Testing**: Tests execute quickly and independently, providing rapid feedback on specification compliance.
|
41
|
+
|
42
|
+
## Framework Features
|
43
|
+
|
44
|
+
### Property Definition with `let`
|
45
|
+
|
46
|
+
Define reusable properties across your specifications:
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
Fix do
|
50
|
+
let(:name) { "Bob" }
|
51
|
+
let(:age) { 42 }
|
52
|
+
|
53
|
+
it MUST eq name
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
### Context Creation with `with`
|
58
|
+
|
59
|
+
Test behavior under different conditions:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
Fix do
|
63
|
+
with name: "Alice", role: "admin" do
|
64
|
+
it MUST be_allowed
|
65
|
+
end
|
66
|
+
|
67
|
+
with name: "Bob", role: "guest" do
|
68
|
+
it MUST_NOT be_allowed
|
69
|
+
end
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
73
|
+
### Method Testing with `on`
|
74
|
+
|
75
|
+
Test how objects respond to specific messages:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
Fix do
|
79
|
+
on :upcase do
|
80
|
+
it MUST eq "HELLO"
|
81
|
+
end
|
82
|
+
|
83
|
+
on :+, 2 do
|
84
|
+
it MUST eq 42
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
### Requirement Levels
|
90
|
+
|
91
|
+
Fix provides three levels of requirements, each with clear semantic meaning:
|
40
92
|
|
41
|
-
|
93
|
+
- **MUST/MUST_NOT**: Absolute requirements or prohibitions
|
94
|
+
- **SHOULD/SHOULD_NOT**: Recommended practices with valid exceptions
|
95
|
+
- **MAY**: Optional features
|
42
96
|
|
43
97
|
```ruby
|
44
|
-
|
98
|
+
Fix do
|
99
|
+
it MUST be_valid # Required
|
100
|
+
it SHOULD be_optimized # Recommended
|
101
|
+
it MAY include_metadata # Optional
|
102
|
+
end
|
103
|
+
```
|
104
|
+
|
105
|
+
## Quick Start
|
45
106
|
|
107
|
+
Create your first test file:
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
# first_test.rb
|
46
111
|
require "fix"
|
47
112
|
|
113
|
+
Fix :HelloWorld do
|
114
|
+
it MUST eq "Hello, World!"
|
115
|
+
end
|
116
|
+
|
117
|
+
Fix[:HelloWorld].test { "Hello, World!" }
|
118
|
+
```
|
119
|
+
|
120
|
+
Run it:
|
121
|
+
|
122
|
+
```sh
|
123
|
+
ruby first_test.rb
|
124
|
+
```
|
125
|
+
|
126
|
+
## Real-World Examples
|
127
|
+
|
128
|
+
Fix is designed to work with real-world applications of any complexity. Here are some examples demonstrating how Fix can be used in different scenarios:
|
129
|
+
|
130
|
+
### Example 1: User Account Management
|
131
|
+
|
132
|
+
Here's a comprehensive example showing how to specify a user account system:
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
Fix :UserAccount do
|
136
|
+
# Define reusable properties
|
137
|
+
let(:admin) { User.new(role: "admin") }
|
138
|
+
let(:guest) { User.new(role: "guest") }
|
139
|
+
|
140
|
+
# Test basic instance properties
|
141
|
+
it MUST be_an_instance_of User
|
142
|
+
|
143
|
+
# Test with different contexts
|
144
|
+
with role: "admin" do
|
145
|
+
it MUST be_admin
|
146
|
+
|
147
|
+
on :can_access?, "settings" do
|
148
|
+
it MUST be_true
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
with role: "guest" do
|
153
|
+
it MUST_NOT be_admin
|
154
|
+
|
155
|
+
on :can_access?, "settings" do
|
156
|
+
it MUST be_false
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Test specific methods
|
161
|
+
on :full_name do
|
162
|
+
with first_name: "John", last_name: "Doe" do
|
163
|
+
it MUST eq "John Doe"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
on :update_password, "new_password" do
|
168
|
+
it MUST change(admin, :password_hash)
|
169
|
+
it MUST be_true # Return value check
|
170
|
+
end
|
171
|
+
end
|
172
|
+
```
|
173
|
+
|
174
|
+
This example demonstrates:
|
175
|
+
- Using `let` to define test fixtures
|
176
|
+
- Context-specific testing with `with`
|
177
|
+
- Method behavior testing with `on`
|
178
|
+
- Different requirement levels with `MUST`/`MUST_NOT`
|
179
|
+
- Testing state changes with the `change` matcher
|
180
|
+
- Nested contexts for complex scenarios
|
181
|
+
|
182
|
+
### Example 2: Duck Specification
|
183
|
+
|
184
|
+
Here's how Fix can be used to specify a Duck class:
|
185
|
+
|
186
|
+
```ruby
|
48
187
|
Fix :Duck do
|
49
188
|
it SHOULD be_an_instance_of :Duck
|
50
189
|
|
@@ -63,11 +202,9 @@ Fix :Duck do
|
|
63
202
|
end
|
64
203
|
```
|
65
204
|
|
66
|
-
|
205
|
+
The implementation:
|
67
206
|
|
68
207
|
```ruby
|
69
|
-
# examples/duck/app.rb
|
70
|
-
|
71
208
|
class Duck
|
72
209
|
def walks
|
73
210
|
"Klop klop!"
|
@@ -86,36 +223,92 @@ end
|
|
86
223
|
Running the test:
|
87
224
|
|
88
225
|
```ruby
|
89
|
-
# examples/duck/test.rb
|
90
|
-
|
91
|
-
require_relative "app"
|
92
|
-
require_relative "fix"
|
93
|
-
|
94
226
|
Fix[:Duck].test { Duck.new }
|
95
227
|
```
|
96
228
|
|
97
|
-
|
229
|
+
## Available Matchers
|
98
230
|
|
99
|
-
|
100
|
-
|
101
|
-
|
231
|
+
Fix includes a comprehensive set of matchers through its integration with the [Matchi library](https://github.com/fixrb/matchi):
|
232
|
+
|
233
|
+
### Basic Comparison Matchers
|
234
|
+
- `eq(expected)` - Tests equality using `eql?`
|
235
|
+
- `be(expected)` - Tests object identity using `equal?`
|
236
|
+
|
237
|
+
### Type Checking Matchers
|
238
|
+
- `be_an_instance_of(class)` - Verifies exact class match
|
239
|
+
- `be_a_kind_of(class)` - Checks class inheritance and module inclusion
|
240
|
+
|
241
|
+
### Change Testing Matchers
|
242
|
+
- `change(object, method)` - Base matcher for state changes
|
243
|
+
- `.by(n)` - Expects exact change by n
|
244
|
+
- `.by_at_least(n)` - Expects minimum change by n
|
245
|
+
- `.by_at_most(n)` - Expects maximum change by n
|
246
|
+
- `.from(old).to(new)` - Expects change from old to new value
|
247
|
+
- `.to(new)` - Expects change to new value
|
248
|
+
|
249
|
+
### Numeric Matchers
|
250
|
+
- `be_within(delta).of(value)` - Tests if a value is within ±delta of expected value
|
102
251
|
|
103
|
-
|
252
|
+
### Pattern Matchers
|
253
|
+
- `match(regex)` - Tests string against regular expression pattern
|
254
|
+
- `satisfy { |value| ... }` - Custom matching with block
|
255
|
+
|
256
|
+
### State Matchers
|
257
|
+
- `be_true` - Tests for true
|
258
|
+
- `be_false` - Tests for false
|
259
|
+
- `be_nil` - Tests for nil
|
260
|
+
|
261
|
+
### Exception Matchers
|
262
|
+
- `raise_exception(class)` - Tests if code raises specified exception
|
263
|
+
|
264
|
+
### Dynamic Predicate Matchers
|
265
|
+
- `be_*` - Dynamically matches `object.*?` methods (e.g., `be_empty` calls `empty?`)
|
266
|
+
- `have_*` - Dynamically matches `object.has_*?` methods (e.g., `have_key` calls `has_key?`)
|
267
|
+
|
268
|
+
Example usage:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
Fix :Calculator do
|
272
|
+
it MUST be_an_instance_of Calculator
|
104
273
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
274
|
+
on :add, 2, 3 do
|
275
|
+
it MUST eq 5
|
276
|
+
it MUST be_within(0.001).of(5.0)
|
277
|
+
end
|
278
|
+
|
279
|
+
on :divide, 1, 0 do
|
280
|
+
it MUST raise_exception ZeroDivisionError
|
281
|
+
end
|
282
|
+
|
283
|
+
with numbers: [1, 2, 3] do
|
284
|
+
it MUST_NOT be_empty
|
285
|
+
it MUST satisfy { |result| result.all? { |n| n.positive? } }
|
286
|
+
end
|
287
|
+
end
|
111
288
|
```
|
112
289
|
|
113
|
-
##
|
290
|
+
## Why Choose Fix?
|
291
|
+
|
292
|
+
Fix brings several unique advantages to Ruby testing that set it apart from traditional testing frameworks:
|
293
|
+
|
294
|
+
- **Clear Separation of Concerns**: Keep your specifications clean and your examples separate
|
295
|
+
- **Semantic Precision**: Express requirements with different levels of necessity
|
296
|
+
- **Fast Execution**: Get quick feedback on specification compliance
|
297
|
+
- **Pure Specifications**: Write specification documents that focus on behavior, not implementation
|
298
|
+
- **Rich Matcher Library**: Comprehensive set of matchers for different testing needs
|
299
|
+
- **Modern Ruby**: Takes advantage of modern Ruby features and practices
|
300
|
+
|
301
|
+
## Get Started
|
302
|
+
|
303
|
+
Ready to write better specifications? Visit our [GitHub repository](https://github.com/fixrb/fix) to start using Fix in your Ruby projects.
|
304
|
+
|
305
|
+
## Community & Resources
|
114
306
|
|
115
|
-
- [
|
116
|
-
- [
|
117
|
-
- [
|
118
|
-
- [
|
307
|
+
- [Blog](https://fixrb.dev/) - Related articles
|
308
|
+
- [Bluesky](https://bsky.app/profile/fixrb.dev) - Latest updates and discussions
|
309
|
+
- [Documentation](https://www.rubydoc.info/gems/fix) - Comprehensive guides and API reference
|
310
|
+
- [Source Code](https://github.com/fixrb/fix) - Contribute and report issues
|
311
|
+
- [asciinema](https://asciinema.org/~fix) - Watch practical examples in action
|
119
312
|
|
120
313
|
## Versioning
|
121
314
|
|
@@ -125,11 +318,6 @@ __Fix__ follows [Semantic Versioning 2.0](https://semver.org/).
|
|
125
318
|
|
126
319
|
The [gem](https://rubygems.org/gems/fix) is available as open source under the terms of the [MIT License](https://github.com/fixrb/fix/raw/main/LICENSE.md).
|
127
320
|
|
128
|
-
|
321
|
+
## Sponsors
|
129
322
|
|
130
|
-
|
131
|
-
This project is sponsored by:<br />
|
132
|
-
<a href="https://sashite.com/"><img
|
133
|
-
src="https://github.com/fixrb/fix/raw/main/img/sashite.png"
|
134
|
-
alt="Sashité" /></a>
|
135
|
-
</p>
|
323
|
+
This project is sponsored by [Sashité](https://sashite.com/)
|
data/lib/fix/dsl.rb
CHANGED
@@ -95,13 +95,20 @@ module Fix
|
|
95
95
|
#
|
96
96
|
# Fix { it MUST be 42 }
|
97
97
|
#
|
98
|
+
# Fix do
|
99
|
+
# it { MUST be 42 }
|
100
|
+
# end
|
101
|
+
#
|
98
102
|
# @api public
|
99
|
-
def self.it(requirement)
|
103
|
+
def self.it(requirement = nil, &block)
|
104
|
+
raise ::ArgumentError, "Must provide either requirement or block, not both" if requirement && block
|
105
|
+
raise ::ArgumentError, "Must provide either requirement or block" unless requirement || block
|
106
|
+
|
100
107
|
location = caller_locations(1, 1).fetch(0)
|
101
108
|
location = [location.path, location.lineno].join(":")
|
102
109
|
|
103
|
-
define_method(:"test_#{requirement.object_id}") do
|
104
|
-
[location, requirement, self.class.challenges]
|
110
|
+
define_method(:"test_#{(requirement || block).object_id}") do
|
111
|
+
[location, requirement || singleton_class.class_eval(&block), self.class.challenges]
|
105
112
|
end
|
106
113
|
end
|
107
114
|
|
data/lib/fix/matcher.rb
CHANGED
@@ -5,237 +5,45 @@ require "matchi"
|
|
5
5
|
module Fix
|
6
6
|
# Collection of expectation matchers.
|
7
7
|
#
|
8
|
+
# The following matchers are available:
|
9
|
+
#
|
10
|
+
# Basic Comparison:
|
11
|
+
# - eq(expected) # Checks equality using eql?
|
12
|
+
# - eql(expected) # Alias for eq
|
13
|
+
# - be(expected) # Checks exact object identity using equal?
|
14
|
+
# - equal(expected) # Alias for be
|
15
|
+
#
|
16
|
+
# Type Checking:
|
17
|
+
# - be_an_instance_of(class) # Checks exact class match
|
18
|
+
# - be_a_kind_of(class) # Checks class inheritance and module inclusion
|
19
|
+
#
|
20
|
+
# State & Changes:
|
21
|
+
# - change(object, method) # Base for checking state changes
|
22
|
+
# .by(n) # Exact change by n
|
23
|
+
# .by_at_least(n) # Minimum change by n
|
24
|
+
# .by_at_most(n) # Maximum change by n
|
25
|
+
# .from(old).to(new) # Change from old to new value
|
26
|
+
# .to(new) # Change to new value
|
27
|
+
#
|
28
|
+
# Value Testing:
|
29
|
+
# - be_within(delta).of(value) # Checks numeric value within delta
|
30
|
+
# - match(regex) # Tests against regular expression
|
31
|
+
# - satisfy { |value| ... } # Custom matcher with block
|
32
|
+
#
|
33
|
+
# Exceptions:
|
34
|
+
# - raise_exception(class) # Checks if code raises exception
|
35
|
+
#
|
36
|
+
# State Testing:
|
37
|
+
# - be_true # Tests for true
|
38
|
+
# - be_false # Tests for false
|
39
|
+
# - be_nil # Tests for nil
|
40
|
+
#
|
41
|
+
# Predicate Matchers:
|
42
|
+
# - be_* # Matches object.*? method
|
43
|
+
# - have_* # Matches object.has_*? method
|
44
|
+
#
|
8
45
|
# @api private
|
9
46
|
module Matcher
|
10
|
-
|
11
|
-
#
|
12
|
-
# @example
|
13
|
-
# matcher = eq("foo")
|
14
|
-
# matcher.matches? { "foo" } # => true
|
15
|
-
# matcher.matches? { "bar" } # => false
|
16
|
-
#
|
17
|
-
# @param expected [#eql?] An expected equivalent object.
|
18
|
-
#
|
19
|
-
# @return [#matches?] An equivalence matcher.
|
20
|
-
#
|
21
|
-
# @api public
|
22
|
-
def eq(expected)
|
23
|
-
::Matchi::Eq.new(expected)
|
24
|
-
end
|
25
|
-
|
26
|
-
alias eql eq
|
27
|
-
|
28
|
-
# Identity matcher
|
29
|
-
#
|
30
|
-
# @example
|
31
|
-
# object = "foo"
|
32
|
-
# matcher = be(object)
|
33
|
-
# matcher.matches? { object } # => true
|
34
|
-
# matcher.matches? { "foo" } # => false
|
35
|
-
#
|
36
|
-
# @param expected [#equal?] The expected identical object.
|
37
|
-
#
|
38
|
-
# @return [#matches?] An identity matcher.
|
39
|
-
#
|
40
|
-
# @api public
|
41
|
-
def be(expected)
|
42
|
-
::Matchi::Be.new(expected)
|
43
|
-
end
|
44
|
-
|
45
|
-
alias equal be
|
46
|
-
|
47
|
-
# Comparisons matcher
|
48
|
-
#
|
49
|
-
# @example
|
50
|
-
# matcher = be_within(1).of(41)
|
51
|
-
# matcher.matches? { 42 } # => true
|
52
|
-
# matcher.matches? { 43 } # => false
|
53
|
-
#
|
54
|
-
# @param delta [Numeric] A numeric value.
|
55
|
-
#
|
56
|
-
# @return [#matches?] A comparison matcher.
|
57
|
-
#
|
58
|
-
# @api public
|
59
|
-
def be_within(delta)
|
60
|
-
::Matchi::BeWithin.new(delta)
|
61
|
-
end
|
62
|
-
|
63
|
-
# Regular expressions matcher
|
64
|
-
#
|
65
|
-
# @example
|
66
|
-
# matcher = match(/^foo$/)
|
67
|
-
# matcher.matches? { "foo" } # => true
|
68
|
-
# matcher.matches? { "bar" } # => false
|
69
|
-
#
|
70
|
-
# @param expected [#match] A regular expression.
|
71
|
-
#
|
72
|
-
# @return [#matches?] A regular expression matcher.
|
73
|
-
#
|
74
|
-
# @api public
|
75
|
-
def match(expected)
|
76
|
-
::Matchi::Match.new(expected)
|
77
|
-
end
|
78
|
-
|
79
|
-
# Expecting errors matcher
|
80
|
-
#
|
81
|
-
# @example
|
82
|
-
# matcher = raise_exception(NameError)
|
83
|
-
# matcher.matches? { Boom } # => true
|
84
|
-
# matcher.matches? { true } # => false
|
85
|
-
#
|
86
|
-
# @param expected [Exception, #to_s] The expected exception name.
|
87
|
-
#
|
88
|
-
# @return [#matches?] An error matcher.
|
89
|
-
#
|
90
|
-
# @api public
|
91
|
-
def raise_exception(expected)
|
92
|
-
::Matchi::RaiseException.new(expected)
|
93
|
-
end
|
94
|
-
|
95
|
-
# True matcher
|
96
|
-
#
|
97
|
-
# @example
|
98
|
-
# matcher = be_true
|
99
|
-
# matcher.matches? { true } # => true
|
100
|
-
# matcher.matches? { false } # => false
|
101
|
-
# matcher.matches? { nil } # => false
|
102
|
-
# matcher.matches? { 4 } # => false
|
103
|
-
#
|
104
|
-
# @return [#matches?] A `true` matcher.
|
105
|
-
#
|
106
|
-
# @api public
|
107
|
-
def be_true
|
108
|
-
be(true)
|
109
|
-
end
|
110
|
-
|
111
|
-
# False matcher
|
112
|
-
#
|
113
|
-
# @example
|
114
|
-
# matcher = be_false
|
115
|
-
# matcher.matches? { false } # => true
|
116
|
-
# matcher.matches? { true } # => false
|
117
|
-
# matcher.matches? { nil } # => false
|
118
|
-
# matcher.matches? { 4 } # => false
|
119
|
-
#
|
120
|
-
# @return [#matches?] A `false` matcher.
|
121
|
-
#
|
122
|
-
# @api public
|
123
|
-
def be_false
|
124
|
-
be(false)
|
125
|
-
end
|
126
|
-
|
127
|
-
# Nil matcher
|
128
|
-
#
|
129
|
-
# @example
|
130
|
-
# matcher = be_nil
|
131
|
-
# matcher.matches? { nil } # => true
|
132
|
-
# matcher.matches? { false } # => false
|
133
|
-
# matcher.matches? { true } # => false
|
134
|
-
# matcher.matches? { 4 } # => false
|
135
|
-
#
|
136
|
-
# @return [#matches?] A `nil` matcher.
|
137
|
-
#
|
138
|
-
# @api public
|
139
|
-
def be_nil
|
140
|
-
be(nil)
|
141
|
-
end
|
142
|
-
|
143
|
-
# Type/class matcher
|
144
|
-
#
|
145
|
-
# @example
|
146
|
-
# matcher = be_an_instance_of(String)
|
147
|
-
# matcher.matches? { "foo" } # => true
|
148
|
-
# matcher.matches? { 4 } # => false
|
149
|
-
#
|
150
|
-
# @param expected [Class, #to_s] The expected class name.
|
151
|
-
#
|
152
|
-
# @return [#matches?] A type/class matcher.
|
153
|
-
#
|
154
|
-
# @api public
|
155
|
-
def be_an_instance_of(expected)
|
156
|
-
::Matchi::BeAnInstanceOf.new(expected)
|
157
|
-
end
|
158
|
-
|
159
|
-
# Change matcher
|
160
|
-
#
|
161
|
-
# @example
|
162
|
-
# object = []
|
163
|
-
# matcher = change(object, :length).by(1)
|
164
|
-
# matcher.matches? { object << 1 } # => true
|
165
|
-
#
|
166
|
-
# object = []
|
167
|
-
# matcher = change(object, :length).by_at_least(1)
|
168
|
-
# matcher.matches? { object << 1 } # => true
|
169
|
-
#
|
170
|
-
# object = []
|
171
|
-
# matcher = change(object, :length).by_at_most(1)
|
172
|
-
# matcher.matches? { object << 1 } # => true
|
173
|
-
#
|
174
|
-
# object = "foo"
|
175
|
-
# matcher = change(object, :to_s).from("foo").to("FOO")
|
176
|
-
# matcher.matches? { object.upcase! } # => true
|
177
|
-
#
|
178
|
-
# object = "foo"
|
179
|
-
# matcher = change(object, :to_s).to("FOO")
|
180
|
-
# matcher.matches? { object.upcase! } # => true
|
181
|
-
#
|
182
|
-
# @param object [#object_id] An object.
|
183
|
-
# @param method [Symbol] The name of a method.
|
184
|
-
#
|
185
|
-
# @return [#matches?] A change matcher.
|
186
|
-
#
|
187
|
-
# @api public
|
188
|
-
def change(object, method, ...)
|
189
|
-
::Matchi::Change.new(object, method, ...)
|
190
|
-
end
|
191
|
-
|
192
|
-
# Satisfy matcher
|
193
|
-
#
|
194
|
-
# @example
|
195
|
-
# matcher = satisfy { |value| value == 42 }
|
196
|
-
# matcher.matches? { 42 } # => true
|
197
|
-
#
|
198
|
-
# @yield [value] A block that defines the satisfaction criteria
|
199
|
-
# @yieldparam value The value to test
|
200
|
-
# @yieldreturn [Boolean] true if the value satisfies the criteria
|
201
|
-
#
|
202
|
-
# @return [#matches?] A satisfy matcher.
|
203
|
-
#
|
204
|
-
# @api public
|
205
|
-
def satisfy(&)
|
206
|
-
::Matchi::Satisfy.new(&)
|
207
|
-
end
|
208
|
-
|
209
|
-
private
|
210
|
-
|
211
|
-
# Predicate matcher, or default method missing behavior.
|
212
|
-
#
|
213
|
-
# @example Empty predicate matcher
|
214
|
-
# matcher = be_empty
|
215
|
-
# matcher.matches? { [] } # => true
|
216
|
-
# matcher.matches? { [4] } # => false
|
217
|
-
def method_missing(name, ...)
|
218
|
-
return super unless predicate_matcher_name?(name)
|
219
|
-
|
220
|
-
::Matchi::Predicate.new(name, ...)
|
221
|
-
end
|
222
|
-
|
223
|
-
# :nocov:
|
224
|
-
|
225
|
-
# Hook method to return whether the obj can respond to id method or not.
|
226
|
-
def respond_to_missing?(name, include_private = false)
|
227
|
-
predicate_matcher_name?(name) || super
|
228
|
-
end
|
229
|
-
|
230
|
-
# :nocov:
|
231
|
-
|
232
|
-
# Predicate matcher name detector.
|
233
|
-
#
|
234
|
-
# @param name [Array, Symbol] The name of a potential predicate matcher.
|
235
|
-
#
|
236
|
-
# @return [Boolean] Indicates if it is a predicate matcher name or not.
|
237
|
-
def predicate_matcher_name?(name)
|
238
|
-
name.start_with?("be_", "have_") && !name.end_with?("!", "?")
|
239
|
-
end
|
47
|
+
include Matchi
|
240
48
|
end
|
241
49
|
end
|
data/lib/fix/requirement.rb
CHANGED
@@ -14,7 +14,7 @@ module Fix
|
|
14
14
|
# This method mean that the definition is an absolute requirement of the
|
15
15
|
# specification.
|
16
16
|
#
|
17
|
-
# @param matcher [#
|
17
|
+
# @param matcher [#match?] The matcher.
|
18
18
|
#
|
19
19
|
# @return [Requirement::Required] An absolute requirement level instance.
|
20
20
|
#
|
@@ -25,7 +25,7 @@ module Fix
|
|
25
25
|
|
26
26
|
# This method mean that the definition is an absolute prohibition of the specification.
|
27
27
|
#
|
28
|
-
# @param matcher [#
|
28
|
+
# @param matcher [#match?] The matcher.
|
29
29
|
#
|
30
30
|
# @return [Requirement::Required] An absolute prohibition level instance.
|
31
31
|
#
|
@@ -38,7 +38,7 @@ module Fix
|
|
38
38
|
# circumstances to ignore a particular item, but the full implications must be
|
39
39
|
# understood and carefully weighed before choosing a different course.
|
40
40
|
#
|
41
|
-
# @param matcher [#
|
41
|
+
# @param matcher [#match?] The matcher.
|
42
42
|
#
|
43
43
|
# @return [Requirement::Recommended] A recommended requirement level instance.
|
44
44
|
#
|
@@ -52,7 +52,7 @@ module Fix
|
|
52
52
|
# the full implications should be understood and the case carefully weighed
|
53
53
|
# before implementing any behavior described with this label.
|
54
54
|
#
|
55
|
-
# @param matcher [#
|
55
|
+
# @param matcher [#match?] The matcher.
|
56
56
|
#
|
57
57
|
# @return [Requirement::Recommended] A not recommended requirement level
|
58
58
|
# instance.
|
@@ -73,7 +73,7 @@ module Fix
|
|
73
73
|
# implementation which does not include the option (except, of course, for the
|
74
74
|
# feature the option provides).
|
75
75
|
#
|
76
|
-
# @param matcher [#
|
76
|
+
# @param matcher [#match?] The matcher.
|
77
77
|
#
|
78
78
|
# @return [Requirement::Optional] An optional requirement level instance.
|
79
79
|
#
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
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.beta12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cyril Kato
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2024-12-
|
10
|
+
date: 2024-12-31 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: defi
|
@@ -29,28 +29,28 @@ dependencies:
|
|
29
29
|
requirements:
|
30
30
|
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: 4.1.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version:
|
39
|
+
version: 4.1.0
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: spectus
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 5.0.
|
46
|
+
version: 5.0.1
|
47
47
|
type: :runtime
|
48
48
|
prerelease: false
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - "~>"
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: 5.0.
|
53
|
+
version: 5.0.1
|
54
54
|
description: Specing framework.
|
55
55
|
email: contact@cyril.email
|
56
56
|
executables: []
|