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.
@@ -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