minicrest 1.0.18 → 1.0.20

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: f46a2de6fb6f9554b4c1ac3173509b635631656494e1bb21107432fa649bb8e2
4
- data.tar.gz: 57f30ab1602404ce651ba18883f83030d97d717eeaca2e94f86d83d4e407163f
3
+ metadata.gz: 58f5e87992e24bee1a51f8f51ce095394c64f6900b4dbbbb4bdbde2010432343
4
+ data.tar.gz: b5b8bc6eed685cbcd6e8b07292c141dcafcb10475e6162df7c54b4c736ccb434
5
5
  SHA512:
6
- metadata.gz: 613f579f8e76833d76abd447db70fc124c40a92e57c0d1d83db1747bce622b606b4fd638048e1f2b0997d463239653e3df33c0e11b26df9449b97768a85d959a
7
- data.tar.gz: 3ab240913fd4cbda0a2a502a9311014d43f0e5081392a812d9bb658e89418e6b741021e4d4153033d973e462597d61fdac3f8f17ae349aff12519c6180f24f00
6
+ metadata.gz: 277c1b9a9bd11b6443cd55ce20b3444a951cea80b0f1bda89c052dbf5bb2d0cfa36e01cc03c9532bacc7ca903b81912bba60442a1c017232237a2b1a9f67835a
7
+ data.tar.gz: 25adcc959dde84205306c2bd6d56d83164534b8607cfcd0f64716afec17da97b206d15e4202d861531b3092476e6a6febf2fc3c1b74c14bfd77d18e860d17a0e
data/.yardopts CHANGED
@@ -4,5 +4,6 @@
4
4
  lib/**/*.rb
5
5
  -
6
6
  README.md
7
+ USAGE.md
7
8
  CHANGELOG.md
8
9
  LICENSE
data/CHANGELOG.md CHANGED
@@ -7,7 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [1.0.0 - 1.0.18] - 2026-01-18
10
+ ## [1.0.20] - 2026-01-18
11
+
12
+ ### Changed
13
+ - Reorganized documentation: extracted detailed usage into `USAGE.md` and added Table of Contents.
14
+ - Internal refactoring: moved `DescendsFrom` to `value_matchers.rb` and consolidated type matchers.
15
+
16
+ ### Fixed
17
+ - Added missing tests for `NilValue`, `Truthy`, `Falsy`, and `InstanceOf` matchers.
18
+
19
+ ## [1.0.0 - 1.0.19] - 2026-01-18
11
20
 
12
21
  - Housekeeping: automate CI and release workflows
13
22
 
data/README.md CHANGED
@@ -46,6 +46,8 @@ class MyTest < Minitest::Test
46
46
  end
47
47
  ```
48
48
 
49
+ See [USAGE.md](USAGE.md) for more details and a full list of available matchers.
50
+
49
51
  ## Running Tests
50
52
 
51
53
  To run the library's own tests:
@@ -54,633 +56,6 @@ To run the library's own tests:
54
56
  rake test
55
57
  ```
56
58
 
57
- ## Core Matchers
58
-
59
- ### Value Equality
60
-
61
- ```ruby
62
- # Simple values
63
- assert_that("hello").equals("hello")
64
-
65
- # Arrays with deep comparison
66
- assert_that([1, [2, 3]]).equals([1, [2, 3]])
67
-
68
- # Hashes with deep comparison
69
- assert_that({ user: { name: "Alice" } }).equals({ user: { name: "Alice" } })
70
- ```
71
-
72
- ### Reference Equality
73
-
74
- Test that two variables point to the same object:
75
-
76
- ```ruby
77
- obj = Object.new
78
- assert_that(obj).is(obj)
79
- ```
80
-
81
- ### Negation
82
-
83
- ```ruby
84
- assert_that(42).never(equals(0))
85
- assert_that(nil).never(equals(false))
86
-
87
- # Aliases for more natural flow
88
- assert_that(42).is_not(0)
89
- assert_that("hello").does_not(start_with("bye"))
90
- ```
91
-
92
- ### Placeholder Matching
93
-
94
- Use `anything` when you don't care about a particular value:
95
-
96
- ```ruby
97
- assert_that(some_value).is(anything)
98
- ```
99
-
100
- Use `truthy` or `falsy` to match any truthy or falsy value in Ruby:
101
-
102
- ```ruby
103
- assert_that(some_value).is(truthy)
104
- assert_that(some_value).is(anything)
105
- ```
106
-
107
- ## Type and Method Matchers
108
-
109
- ### `is_a(type)` / `descends_from(type)`
110
-
111
- Matches if the value is an instance of the expected type (including inheritance):
112
-
113
- ```ruby
114
- assert_that("hello").matches(is_a(String))
115
- assert_that(42).matches(descends_from(Integer))
116
- assert_that([]).matches(is_a(Enumerable)) # works with modules
117
- ```
118
-
119
- ### `instance_of(type)`
120
-
121
- Matches if the value is an exact instance of the expected class (no inheritance):
122
-
123
- ```ruby
124
- assert_that("hello").matches(instance_of(String))
125
- assert_that(42).never(instance_of(Numeric)) # Integer is a Numeric, but not exactly InstanceOf Numeric
126
- ```
127
-
128
- ### `responds_to(*methods)`
129
-
130
- Matches if the value responds to all specified methods:
131
-
132
- ```ruby
133
- assert_that("hello").matches(responds_to(:upcase))
134
- assert_that([]).matches(responds_to(:push, :pop))
135
- ```
136
-
137
- ## Value Matchers
138
-
139
- ### `nil_value`
140
-
141
- Matches if the value is `nil`:
142
-
143
- ```ruby
144
- assert_that(nil).matches(nil_value)
145
- assert_that(42).never(nil_value)
146
- ```
147
-
148
- ### `truthy`
149
-
150
- Matches if the value is considered true (anything except `nil` or `false`):
151
-
152
- ```ruby
153
- assert_that(true).matches(truthy)
154
- assert_that(42).matches(truthy)
155
- assert_that("hello").matches(truthy)
156
- ```
157
-
158
- ### `falsy`
159
-
160
- Matches if the value is considered false (`nil` or `false`):
161
-
162
- ```ruby
163
- assert_that(false).matches(falsy)
164
- assert_that(nil).matches(falsy)
165
- ```
166
-
167
- ## String Matchers
168
-
169
- ### `starts_with(prefix)`
170
-
171
- ```ruby
172
- assert_that("hello world").matches(starts_with("hello"))
173
- ```
174
-
175
- ### `ends_with(suffix)`
176
-
177
- ```ruby
178
- assert_that("hello world").matches(ends_with("world"))
179
- ```
180
-
181
- ### `matches_pattern(regex)`
182
-
183
- ```ruby
184
- assert_that("hello123").matches(matches_pattern(/\d+/))
185
- assert_that("test@example.com").matches(matches_pattern(/\A[\w.]+@[\w.]+\z/))
186
- ```
187
-
188
- ### `blank`
189
-
190
- Matches empty or whitespace-only strings:
191
-
192
- ```ruby
193
- assert_that("").matches(blank)
194
- assert_that(" ").matches(blank)
195
- assert_that("\t\n").matches(blank)
196
- ```
197
-
198
- ## Size and Emptiness Matchers
199
-
200
- ### `empty`
201
-
202
- Matches empty strings, arrays, or hashes:
203
-
204
- ```ruby
205
- assert_that("").matches(empty)
206
- assert_that([]).matches(empty)
207
- assert_that({}).matches(empty)
208
- ```
209
-
210
- ### `has_size(expected)`
211
-
212
- Matches values with a specific size:
213
-
214
- ```ruby
215
- assert_that("hello").matches(has_size(5))
216
- assert_that([1, 2, 3]).matches(has_size(3))
217
- assert_that({ a: 1, b: 2 }).matches(has_size(2))
218
-
219
- # Can use matchers for flexible size checks
220
- assert_that([1, 2, 3]).matches(has_size(is_greater_than(2)))
221
- ```
222
-
223
- ## Numeric Comparison Matchers
224
-
225
- ### `is_greater_than(expected)`
226
-
227
- ```ruby
228
- assert_that(5).matches(is_greater_than(3))
229
- ```
230
-
231
- ### `is_greater_than_or_equal_to(expected)`
232
-
233
- ```ruby
234
- assert_that(5).matches(is_greater_than_or_equal_to(5))
235
- assert_that(6).matches(is_greater_than_or_equal_to(5))
236
- ```
237
-
238
- ### `is_less_than(expected)`
239
-
240
- ```ruby
241
- assert_that(3).matches(is_less_than(5))
242
- ```
243
-
244
- ### `is_less_than_or_equal_to(expected)`
245
-
246
- ```ruby
247
- assert_that(5).matches(is_less_than_or_equal_to(5))
248
- assert_that(4).matches(is_less_than_or_equal_to(5))
249
- ```
250
-
251
- ### `between(min, max, exclusive: false)`
252
-
253
- Matches if the value is within the range:
254
-
255
- ```ruby
256
- assert_that(5).matches(between(1, 10))
257
- assert_that(10).never(between(1, 10, exclusive: true))
258
- ```
259
-
260
- ### `is_close_to(expected, delta)`
261
-
262
- Floating-point equality with tolerance:
263
-
264
- ```ruby
265
- assert_that(3.14159).matches(is_close_to(3.14, 0.01))
266
- assert_that(10.0).matches(is_close_to(10.5, 0.5))
267
- ```
268
-
269
- ## Collection Content Matchers
270
-
271
- ### `includes(*items)`
272
-
273
- Matches if the value contains all specified items:
274
-
275
- ```ruby
276
- # Strings: contains substrings
277
- assert_that("hello world").matches(includes("hello", "world"))
278
-
279
- # Arrays: contains elements
280
- assert_that([1, 2, 3, 4]).matches(includes(2, 4))
281
-
282
- # Hashes: contains key-value pairs
283
- assert_that({ a: 1, b: 2, c: 3 }).matches(includes(a: 1, c: 3))
284
- ```
285
-
286
- ### `has_key(*keys)`
287
-
288
- Matches if the hash contains all specified keys:
289
-
290
- ```ruby
291
- assert_that({ a: 1, b: 2 }).matches(has_key(:a))
292
- assert_that({ a: 1, b: 2 }).matches(has_key(:a, :b))
293
- ```
294
-
295
- ### `has_value(*values)`
296
-
297
- Matches if the hash contains all specified values:
298
-
299
- ```ruby
300
- assert_that({ a: 1, b: 2 }).matches(has_value(1))
301
- assert_that({ a: 1, b: 2 }).matches(has_value(1, 2))
302
- ```
303
-
304
- ### `contains(*items)`
305
-
306
- Matches if the collection contains exactly the specified items in any order:
307
-
308
- ```ruby
309
- assert_that([3, 1, 2]).matches(contains(1, 2, 3))
310
- assert_that({ b: 2, a: 1 }).matches(contains(a: 1, b: 2))
311
- ```
312
-
313
- ### `contains_exactly(*items)`
314
-
315
- Matches if the array contains exactly the specified items in order:
316
-
317
- ```ruby
318
- assert_that([1, 2, 3]).matches(contains_exactly(1, 2, 3))
319
- ```
320
-
321
- ## Collection Item Matchers
322
-
323
- ### `all_items(matcher)`
324
-
325
- Matches if all items in the collection match:
326
-
327
- ```ruby
328
- assert_that([2, 4, 6]).matches(all_items(descends_from(Integer)))
329
- assert_that([2, 4, 6]).matches(all_items(is_greater_than(0)))
330
- ```
331
-
332
- ### `some_items(matcher)`
333
-
334
- Matches if at least one item matches:
335
-
336
- ```ruby
337
- assert_that([1, "two", 3]).matches(some_items(descends_from(String)))
338
- ```
339
-
340
- ### `no_items(matcher)`
341
-
342
- Matches if no items match:
343
-
344
- ```ruby
345
- assert_that([1, 2, 3]).matches(no_items(descends_from(String)))
346
- ```
347
-
348
- ### `all_entries(matcher)` / `some_entry(matcher)` / `no_entry(matcher)`
349
-
350
- Similar to item matchers, but specifically for hash entries (key-value pairs):
351
-
352
- ```ruby
353
- # all_entries expects a matcher that works with [key, value] arrays
354
- assert_that({ a: 1, b: 2 }).matches(all_entries(includes(:a, :b) | includes(1, 2)))
355
-
356
- # You can also use a Proc for more complex entry matching
357
- assert_that({ a: 1, b: 2 }).matches(some_entry(->(entry) { entry[1] > 1 }))
358
- ```
359
-
360
- ## Membership Matcher
361
-
362
- ### `is_in(collection)`
363
-
364
- Matches if the value is present in the collection:
365
-
366
- ```ruby
367
- assert_that(2).matches(is_in([1, 2, 3]))
368
- assert_that(:a).matches(is_in({ a: 1, b: 2 })) # checks keys
369
- assert_that("el").matches(is_in("hello")) # substring
370
- assert_that(5).matches(is_in(1..10)) # ranges
371
- ```
372
-
373
- ## Object Attribute Matcher
374
-
375
- ### `has_attribute(name, matcher = nil)`
376
-
377
- Matches if the object has the attribute, optionally checking its value:
378
-
379
- ```ruby
380
- User = Struct.new(:name, :age)
381
-
382
- user = User.new("Alice", 30)
383
-
384
- assert_that(user).matches(has_attribute(:name))
385
- assert_that(user).matches(has_attribute(:name, equals("Alice")))
386
- assert_that(user).matches(has_attribute(:age, is_greater_than(18)))
387
-
388
- # Also works with hashes
389
- assert_that({ name: "Bob" }).matches(has_attribute(:name, equals("Bob")))
390
- ```
391
-
392
- ## Error Assertions
393
-
394
- ### `raises_error`
395
-
396
- Assert that a block raises an error:
397
-
398
- ```ruby
399
- # Any error
400
- assert_that { raise "boom" }.raises_error
401
-
402
- # Specific error class
403
- assert_that { raise ArgumentError, "bad" }.raises_error(ArgumentError)
404
-
405
- # Error class with message matcher
406
- assert_that { raise ArgumentError, "bad input" }.raises_error(ArgumentError, includes("bad"))
407
- assert_that { raise ArgumentError, "code: 123" }.raises_error(ArgumentError, matches_pattern(/\d+/))
408
- ```
409
-
410
- ### `raises_nothing`
411
-
412
- Assert that a block does not raise:
413
-
414
- ```ruby
415
- assert_that { safe_operation }.raises_nothing
416
- ```
417
-
418
- ## Combining Matchers
419
-
420
- Use `|` for OR and `&` for AND:
421
-
422
- ```ruby
423
- # Either/or
424
- assert_that(status).matches(equals(:success) | equals(:pending))
425
-
426
- # Both conditions
427
- assert_that(value).matches(is_greater_than(0) & is_less_than(100))
428
-
429
- # Complex combinations
430
- assert_that(result).matches(
431
- (equals(1) | equals(2)) & never(equals(nil))
432
- )
433
- ```
434
-
435
- ### Collection Combinators
436
-
437
- ```ruby
438
- # All matchers must pass
439
- assert_that(5).matches(all_of(is_greater_than(0), is_less_than(10)))
440
-
441
- # No matchers should pass
442
- assert_that(10).matches(none_of(equals(5), equals(6)))
443
-
444
- # At least one matcher must pass
445
- assert_that(5).matches(some_of(equals(5), equals(999)))
446
- ```
447
-
448
- ## Custom Matchers
449
-
450
- Create your own matchers by subclassing `Minicrest::Matcher`:
451
-
452
- ```ruby
453
- class BePositive < Minicrest::Matcher
454
- def matches?(actual)
455
- actual.is_a?(Numeric) && actual > 0
456
- end
457
-
458
- def description
459
- "be positive"
460
- end
461
-
462
- def failure_message(actual)
463
- "expected #{actual.inspect} to be a positive number"
464
- end
465
- end
466
-
467
- # Register the matcher
468
- Minicrest.register_matcher(:be_positive) { BePositive.new }
469
-
470
- # Use in tests
471
- assert_that(5).matches(be_positive)
472
- ```
473
-
474
- ### Parameterized Matchers
475
-
476
- Matchers can accept arguments:
477
-
478
- ```ruby
479
- class BeDivisibleBy < Minicrest::Matcher
480
- def initialize(divisor)
481
- super()
482
- @divisor = divisor
483
- end
484
-
485
- def matches?(actual)
486
- actual % @divisor == 0
487
- end
488
-
489
- def description
490
- "be divisible by #{@divisor}"
491
- end
492
- end
493
-
494
- Minicrest.register_matcher(:be_divisible_by) { |n| BeDivisibleBy.new(n) }
495
-
496
- # Use in tests
497
- assert_that(10).matches(be_divisible_by(5))
498
- ```
499
-
500
- ### Custom Matchers with Combinators
501
-
502
- Registered matchers automatically work with all combinators:
503
-
504
- ```ruby
505
- # With AND/OR operators
506
- assert_that(10).matches(be_divisible_by(5) & be_divisible_by(2))
507
- assert_that(10).matches(be_divisible_by(3) | be_divisible_by(5))
508
-
509
- # With never()
510
- assert_that(7).never(be_divisible_by(2))
511
-
512
- # With all_of, some_of, none_of
513
- assert_that(10).matches(all_of(be_positive, be_divisible_by(5)))
514
- ```
515
-
516
- ## Failure Messages
517
-
518
- Minicrest provides detailed failure messages with diffs:
519
-
520
- ```ruby
521
- assert_that({ name: "Bob" }).equals({ name: "Alice" })
522
- ```
523
-
524
- Output:
525
-
526
- ```
527
- expected {:name=>"Bob"}
528
- to equal {:name=>"Alice"}
529
-
530
- Diff:
531
- key :name:
532
- expected: "Alice"
533
- actual: "Bob"
534
- ```
535
-
536
- Array diffs show the index:
537
-
538
- ```ruby
539
- assert_that([1, 2, 4]).equals([1, 2, 3])
540
- ```
541
-
542
- Output:
543
-
544
- ```
545
- expected [1, 2, 4]
546
- to equal [1, 2, 3]
547
-
548
- Diff:
549
- [2]:
550
- expected: 3
551
- actual: 4
552
- ```
553
-
554
- String diffs show the first difference:
555
-
556
- ```ruby
557
- assert_that("hello").equals("hallo")
558
- ```
559
-
560
- Output:
561
-
562
- ```
563
- expected "hello"
564
- to equal "hallo"
565
-
566
- Diff:
567
- at index 1:
568
- expected: "a"
569
- actual: "e"
570
- ```
571
-
572
- ## API Reference
573
-
574
- ### Assertions Module - Core
575
-
576
- | Method | Description |
577
- |--------|-------------|
578
- | `assert_that(actual, message = nil)` | Entry point for value assertions |
579
- | `assert_that { block }` | Entry point for block assertions |
580
- | `equals(expected)` | Value equality matcher |
581
- | `is(expected)` | Reference equality matcher (supports matchers) |
582
- | `anything` | Matches any value |
583
- | `never(matcher)` | Negates a matcher (aliases: `is_not`, `does_not`) |
584
-
585
- ### Assertions Module - Type & Method
586
-
587
- | Method | Description |
588
- |--------|-------------|
589
- | `is_a(type)` | Type/class matcher (alias of `descends_from`) |
590
- | `descends_from(type)` | Type/class matcher |
591
- | `instance_of(type)` | Exact class matcher |
592
- | `responds_to(*methods)` | Method presence matcher |
593
-
594
- ### Assertions Module - Values
595
-
596
- | Method | Description |
597
- |--------|-------------|
598
- | `nil_value` | Matches `nil` |
599
- | `truthy` | Matches non-nil, non-false values |
600
- | `falsy` | Matches `nil` or `false` |
601
-
602
- ### Assertions Module - Strings
603
-
604
- | Method | Description |
605
- |--------|-------------|
606
- | `starts_with(prefix)` | String prefix matcher |
607
- | `ends_with(suffix)` | String suffix matcher |
608
- | `matches_pattern(regex)` | Regex pattern matcher |
609
- | `blank` | Blank string matcher |
610
-
611
- ### Assertions Module - Size & Emptiness
612
-
613
- | Method | Description |
614
- |--------|-------------|
615
- | `empty` | Empty collection matcher |
616
- | `has_size(expected)` | Size/length matcher |
617
-
618
- ### Assertions Module - Numeric
619
-
620
- | Method | Description |
621
- |--------|-------------|
622
- | `is_greater_than(n)` | Greater than comparison |
623
- | `is_greater_than_or_equal_to(n)` | Greater than or equal comparison |
624
- | `is_less_than(n)` | Less than comparison |
625
- | `is_less_than_or_equal_to(n)` | Less than or equal comparison |
626
- | `between(min, max, exclusive: false)` | Range comparison |
627
- | `is_close_to(n, delta)` | Floating-point tolerance |
628
-
629
- ### Assertions Module - Collections
630
-
631
- | Method | Description |
632
- |--------|-------------|
633
- | `includes(*items)` | Partial containment |
634
- | `has_key(*keys)` | Hash key presence |
635
- | `has_value(*values)` | Hash value presence |
636
- | `contains(*items)` | Exact items, any order |
637
- | `contains_exactly(*items)` | Exact items, exact order |
638
- | `all_items(matcher)` | All items match |
639
- | `some_items(matcher)` | At least one matches |
640
- | `no_items(matcher)` | No items match |
641
- | `all_entries(matcher)` | All hash entries match |
642
- | `some_entry(matcher)` | At least one entry matches |
643
- | `no_entry(matcher)` | No entries match |
644
- | `is_in(collection)` | Membership check |
645
-
646
- ### Assertions Module - Objects
647
-
648
- | Method | Description |
649
- |--------|-------------|
650
- | `has_attribute(name, matcher = nil)` | Object attribute matcher |
651
-
652
- ### Assertions Module - Combinators
653
-
654
- | Method | Description |
655
- |--------|-------------|
656
- | `all_of(*matchers)` | All matchers must match |
657
- | `none_of(*matchers)` | No matcher should match |
658
- | `some_of(*matchers)` | At least one must match |
659
-
660
- ### Asserter Methods
661
-
662
- | Method | Description |
663
- |--------|-------------|
664
- | `.equals(expected)` | Assert value equality |
665
- | `.is(expected)` | Assert reference equality (supports matchers) |
666
- | `.never(matcher)` | Assert negation (aliases: `is_not`, `does_not`) |
667
- | `.matches(matcher)` | Use any matcher |
668
- | `.raises_error(class = nil, message_matcher = nil)` | Assert block raises |
669
- | `.raises_nothing` | Assert block doesn't raise |
670
-
671
- ### Matcher Operators
672
-
673
- | Operator | Description |
674
- |----------|-------------|
675
- | `&` | AND - both matchers must succeed |
676
- | `\|` | OR - at least one matcher must succeed |
677
-
678
- ### Module Methods
679
-
680
- | Method | Description |
681
- |--------|-------------|
682
- | `Minicrest.register_matcher(name, &block)` | Register custom matcher |
683
-
684
59
  ## License
685
60
 
686
61
  AGPL-3.0-only