matchi 4.2.0 → 5.0.0
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/LICENSE.md +1 -1
- data/README.md +91 -227
- data/lib/matchi/be.rb +10 -65
- data/lib/matchi/be_a_kind_of.rb +21 -116
- data/lib/matchi/be_an_instance_of.rb +24 -113
- data/lib/matchi/be_within/of.rb +57 -0
- data/lib/matchi/be_within.rb +17 -134
- data/lib/matchi/change/delta.rb +56 -0
- data/lib/matchi/change/from.rb +21 -61
- data/lib/matchi/change/from_to.rb +46 -0
- data/lib/matchi/change/to.rb +17 -81
- data/lib/matchi/change.rb +73 -148
- data/lib/matchi/constant.rb +55 -0
- data/lib/matchi/eq.rb +24 -65
- data/lib/matchi/match.rb +28 -64
- data/lib/matchi/number.rb +37 -0
- data/lib/matchi/predicate.rb +40 -139
- data/lib/matchi/raise_exception.rb +72 -104
- data/lib/matchi/satisfy.rb +21 -96
- data/lib/matchi.rb +22 -60
- metadata +17 -17
- data/lib/matchi/change/by.rb +0 -137
- data/lib/matchi/change/by_at_least.rb +0 -158
- data/lib/matchi/change/by_at_most.rb +0 -171
- data/lib/matchi/change/from/to.rb +0 -132
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Matchi
|
|
4
|
-
class Change
|
|
5
|
-
class From
|
|
6
|
-
# Value transition matcher that verifies both initial and final states of an operation.
|
|
7
|
-
#
|
|
8
|
-
# This matcher ensures that a value not only changes to an expected final state but also
|
|
9
|
-
# starts from a specific initial state. This is particularly useful when testing state
|
|
10
|
-
# transitions where both the starting and ending conditions are important, such as in
|
|
11
|
-
# workflow systems, state machines, or data transformations.
|
|
12
|
-
#
|
|
13
|
-
# @example Basic string transformation
|
|
14
|
-
# text = "hello"
|
|
15
|
-
# matcher = Matchi::Change::From::To.new("hello", "HELLO") { text.to_s }
|
|
16
|
-
# matcher.match? { text.upcase! } # => true
|
|
17
|
-
# matcher.match? { text.reverse! } # => false # Wrong final state
|
|
18
|
-
#
|
|
19
|
-
# text = "other"
|
|
20
|
-
# matcher.match? { text.upcase! } # => false # Wrong initial state
|
|
21
|
-
#
|
|
22
|
-
# @example State machine transitions
|
|
23
|
-
# class Order
|
|
24
|
-
# attr_accessor :status
|
|
25
|
-
# def initialize(status)
|
|
26
|
-
# @status = status
|
|
27
|
-
# end
|
|
28
|
-
# end
|
|
29
|
-
#
|
|
30
|
-
# order = Order.new(:pending)
|
|
31
|
-
# matcher = Matchi::Change::From::To.new(:pending, :shipped) { order.status }
|
|
32
|
-
# matcher.match? { order.status = :shipped } # => true
|
|
33
|
-
#
|
|
34
|
-
# @example Complex object transformations
|
|
35
|
-
# class User
|
|
36
|
-
# attr_accessor :permissions
|
|
37
|
-
# def initialize
|
|
38
|
-
# @permissions = [:read]
|
|
39
|
-
# end
|
|
40
|
-
#
|
|
41
|
-
# def promote!
|
|
42
|
-
# @permissions += [:write, :delete]
|
|
43
|
-
# end
|
|
44
|
-
# end
|
|
45
|
-
#
|
|
46
|
-
# user = User.new
|
|
47
|
-
# matcher = Matchi::Change::From::To.new(
|
|
48
|
-
# [:read],
|
|
49
|
-
# [:read, :write, :delete]
|
|
50
|
-
# ) { user.permissions }
|
|
51
|
-
# matcher.match? { user.promote! } # => true
|
|
52
|
-
#
|
|
53
|
-
# @see Matchi::Change::To For checking only the final state
|
|
54
|
-
# @see Matchi::Change::By For checking numeric changes
|
|
55
|
-
class To
|
|
56
|
-
# Initialize the matcher with expected initial and final values.
|
|
57
|
-
#
|
|
58
|
-
# @api public
|
|
59
|
-
#
|
|
60
|
-
# @param expected_init [#==] The expected initial value
|
|
61
|
-
# @param expected_new_value [#==] The expected final value
|
|
62
|
-
# @param state [Proc] Block that retrieves the current value
|
|
63
|
-
#
|
|
64
|
-
# @raise [ArgumentError] if no state block is provided
|
|
65
|
-
#
|
|
66
|
-
# @return [To] a new instance of the matcher
|
|
67
|
-
#
|
|
68
|
-
# @example With simple value
|
|
69
|
-
# To.new("draft", "published") { document.status }
|
|
70
|
-
#
|
|
71
|
-
# @example With complex state
|
|
72
|
-
# To.new([:user], [:user, :admin]) { account.roles }
|
|
73
|
-
def initialize(expected_init, expected_new_value, &state)
|
|
74
|
-
raise ::ArgumentError, "a block must be provided" unless block_given?
|
|
75
|
-
|
|
76
|
-
@expected_init = expected_init
|
|
77
|
-
@expected = expected_new_value
|
|
78
|
-
@state = state
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
# Verifies both initial and final states during a transition.
|
|
82
|
-
#
|
|
83
|
-
# This method first checks if the initial state matches the expected value,
|
|
84
|
-
# then executes the provided block and verifies the final state. The match
|
|
85
|
-
# fails if either the initial or final state doesn't match expectations.
|
|
86
|
-
#
|
|
87
|
-
# @api public
|
|
88
|
-
#
|
|
89
|
-
# @yield [] Block that should cause the state transition
|
|
90
|
-
# @yieldreturn [Object] The result of the block (not used)
|
|
91
|
-
#
|
|
92
|
-
# @return [Boolean] true if both initial and final states match expectations
|
|
93
|
-
#
|
|
94
|
-
# @raise [ArgumentError] if no block is provided
|
|
95
|
-
#
|
|
96
|
-
# @example Basic usage
|
|
97
|
-
# text = "hello"
|
|
98
|
-
# matcher = To.new("hello", "HELLO") { text }
|
|
99
|
-
# matcher.match? { text.upcase! } # => true
|
|
100
|
-
#
|
|
101
|
-
# @example Failed initial state
|
|
102
|
-
# text = "wrong"
|
|
103
|
-
# matcher = To.new("hello", "HELLO") { text }
|
|
104
|
-
# matcher.match? { text.upcase! } # => false
|
|
105
|
-
def match?
|
|
106
|
-
raise ::ArgumentError, "a block must be provided" unless block_given?
|
|
107
|
-
|
|
108
|
-
value_before = @state.call
|
|
109
|
-
return false unless @expected_init == value_before
|
|
110
|
-
|
|
111
|
-
yield
|
|
112
|
-
value_after = @state.call
|
|
113
|
-
|
|
114
|
-
@expected == value_after
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# Returns a human-readable description of the matcher.
|
|
118
|
-
#
|
|
119
|
-
# @api public
|
|
120
|
-
#
|
|
121
|
-
# @return [String] A string describing what this matcher verifies
|
|
122
|
-
#
|
|
123
|
-
# @example
|
|
124
|
-
# To.new("draft", "published").to_s
|
|
125
|
-
# # => 'change from "draft" to "published"'
|
|
126
|
-
def to_s
|
|
127
|
-
"change from #{@expected_init.inspect} to #{@expected.inspect}"
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
end
|
|
132
|
-
end
|