matchi 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,20 +2,102 @@
2
2
 
3
3
  module Matchi
4
4
  class Change
5
- # *Change by at least* matcher.
5
+ # Minimum delta matcher that verifies numeric changes meet or exceed a threshold.
6
+ #
7
+ # This matcher ensures that a numeric value changes by at least the specified amount
8
+ # after executing a block of code. It's particularly useful when testing operations
9
+ # where you want to ensure a minimum change occurs but larger changes are acceptable,
10
+ # such as performance improvements, resource allocation, or progressive counters.
11
+ #
12
+ # @example Testing collection growth
13
+ # items = []
14
+ # matcher = Matchi::Change::ByAtLeast.new(2) { items.size }
15
+ # matcher.match? { items.push(1, 2) } # => true # Changed by exactly 2
16
+ # matcher.match? { items.push(1, 2, 3) } # => true # Changed by more than 2
17
+ # matcher.match? { items.push(1) } # => false # Changed by less than 2
18
+ #
19
+ # @example Verifying performance improvements
20
+ # class Benchmark
21
+ # def initialize
22
+ # @score = 100
23
+ # end
24
+ #
25
+ # def optimize!
26
+ # @score += rand(20..30) # Improvement varies
27
+ # end
28
+ #
29
+ # def score
30
+ # @score
31
+ # end
32
+ # end
33
+ #
34
+ # benchmark = Benchmark.new
35
+ # matcher = Matchi::Change::ByAtLeast.new(20) { benchmark.score }
36
+ # matcher.match? { benchmark.optimize! } # => true # Any improvement >= 20 passes
37
+ #
38
+ # @example Resource allocation
39
+ # class Pool
40
+ # def initialize
41
+ # @capacity = 1000
42
+ # end
43
+ #
44
+ # def allocate(minimum, maximum)
45
+ # actual = rand(minimum..maximum)
46
+ # @capacity -= actual
47
+ # actual
48
+ # end
49
+ #
50
+ # def available
51
+ # @capacity
52
+ # end
53
+ # end
54
+ #
55
+ # pool = Pool.new
56
+ # matcher = Matchi::Change::ByAtLeast.new(50) { -pool.available }
57
+ # matcher.match? { pool.allocate(50, 100) } # => true # Allocates at least 50
58
+ #
59
+ # @example Price threshold monitoring
60
+ # class Stock
61
+ # attr_reader :price
62
+ #
63
+ # def initialize(price)
64
+ # @price = price
65
+ # end
66
+ #
67
+ # def fluctuate!
68
+ # @price += rand(-10.0..20.0)
69
+ # end
70
+ # end
71
+ #
72
+ # stock = Stock.new(100.0)
73
+ # matcher = Matchi::Change::ByAtLeast.new(10.0) { stock.price }
74
+ # matcher.match? { stock.fluctuate! } # => true if price rises by 10.0 or more
75
+ #
76
+ # @note This matcher verifies minimum changes only. For exact changes, use By,
77
+ # and for maximum changes, use ByAtMost.
78
+ #
79
+ # @see Matchi::Change::By For exact change validation
80
+ # @see Matchi::Change::ByAtMost For maximum change validation
81
+ # @see Matchi::Change::To For final value validation
6
82
  class ByAtLeast
7
- # Initialize the matcher with an object and a block.
83
+ # Initialize the matcher with a minimum expected change and a state block.
8
84
  #
9
- # @example
10
- # require "matchi/change/by_at_least"
85
+ # @api public
86
+ #
87
+ # @param expected [Numeric] The minimum amount by which the value should change
88
+ # @param state [Proc] Block that retrieves the current value
89
+ #
90
+ # @raise [ArgumentError] if expected is not a Numeric
91
+ # @raise [ArgumentError] if expected is negative
92
+ # @raise [ArgumentError] if no state block is provided
11
93
  #
12
- # object = []
94
+ # @return [ByAtLeast] a new instance of the matcher
13
95
  #
14
- # Matchi::Change::ByAtLeast.new(1) { object.length }
96
+ # @example With integer minimum
97
+ # ByAtLeast.new(5) { counter.value }
15
98
  #
16
- # @param expected [#object_id] An expected delta.
17
- # @param state [Proc] A block of code to execute to get the
18
- # state of the object.
99
+ # @example With floating point minimum
100
+ # ByAtLeast.new(0.5) { temperature.celsius }
19
101
  def initialize(expected, &state)
20
102
  raise ::ArgumentError, "expected must be a Numeric" unless expected.is_a?(::Numeric)
21
103
  raise ::ArgumentError, "a block must be provided" unless block_given?
@@ -25,21 +107,30 @@ module Matchi
25
107
  @state = state
26
108
  end
27
109
 
28
- # Boolean comparison on the expected change by comparing the value
29
- # before and after the code execution.
110
+ # Checks if the value changes by at least the expected amount.
30
111
  #
31
- # @example
32
- # require "matchi/change/by_at_least"
112
+ # This method compares the value before and after executing the provided block,
113
+ # ensuring that the difference is greater than or equal to the expected minimum.
114
+ # This is useful when you want to verify that a change meets a minimum threshold.
115
+ #
116
+ # @api public
33
117
  #
34
- # object = []
118
+ # @yield [] Block that should cause the state change
119
+ # @yieldreturn [Object] The result of the block (not used)
35
120
  #
36
- # matcher = Matchi::Change::ByAtLeast.new(1) { object.length }
37
- # matcher.match? { object << "foo" } # => true
121
+ # @return [Boolean] true if the value changed by at least the expected amount
38
122
  #
39
- # @yieldreturn [#object_id] The block of code to execute.
123
+ # @raise [ArgumentError] if no block is provided
40
124
  #
41
- # @return [Boolean] Comparison between the value before and after the
42
- # code execution.
125
+ # @example Basic usage
126
+ # counter = 0
127
+ # matcher = ByAtLeast.new(5) { counter }
128
+ # matcher.match? { counter += 7 } # => true # Changed by more than minimum
129
+ #
130
+ # @example Edge case - exact minimum
131
+ # items = []
132
+ # matcher = ByAtLeast.new(2) { items.size }
133
+ # matcher.match? { items.push(1, 2) } # => true # Changed by exactly minimum
43
134
  def match?
44
135
  raise ::ArgumentError, "a block must be provided" unless block_given?
45
136
 
@@ -50,9 +141,15 @@ module Matchi
50
141
  @expected <= (value_after - value_before)
51
142
  end
52
143
 
53
- # Returns a string representing the matcher.
144
+ # Returns a human-readable description of the matcher.
145
+ #
146
+ # @api public
54
147
  #
55
- # @return [String] a human-readable description of the matcher
148
+ # @return [String] A string describing what this matcher verifies
149
+ #
150
+ # @example
151
+ # ByAtLeast.new(5).to_s # => "change by at least 5"
152
+ # ByAtLeast.new(2.5).to_s # => "change by at least 2.5"
56
153
  def to_s
57
154
  "change by at least #{@expected.inspect}"
58
155
  end
@@ -2,44 +2,148 @@
2
2
 
3
3
  module Matchi
4
4
  class Change
5
- # *Change by at most* matcher.
5
+ # Maximum delta matcher that verifies numeric changes don't exceed a limit.
6
+ #
7
+ # This matcher ensures that a numeric value changes by no more than the specified amount
8
+ # after executing a block of code. It's particularly useful when testing operations
9
+ # where you want to enforce an upper bound on changes, such as rate limiting,
10
+ # resource consumption, or controlled increments.
11
+ #
12
+ # @example Testing controlled collection growth
13
+ # items = []
14
+ # matcher = Matchi::Change::ByAtMost.new(2) { items.size }
15
+ # matcher.match? { items.push(1) } # => true # Changed by less than limit
16
+ # matcher.match? { items.push(1, 2) } # => true # Changed by exactly limit
17
+ # matcher.match? { items.push(1, 2, 3) } # => false # Changed by more than limit
18
+ #
19
+ # @example Rate limiting
20
+ # class RateLimiter
21
+ # def initialize
22
+ # @requests = 0
23
+ # end
24
+ #
25
+ # def process_batch(items)
26
+ # items.each do |item|
27
+ # break if @requests >= 3 # Rate limit
28
+ # process_item(item)
29
+ # end
30
+ # end
31
+ #
32
+ # private
33
+ #
34
+ # def process_item(item)
35
+ # @requests += 1
36
+ # # Processing logic...
37
+ # end
38
+ #
39
+ # def requests
40
+ # @requests
41
+ # end
42
+ # end
43
+ #
44
+ # limiter = RateLimiter.new
45
+ # matcher = Matchi::Change::ByAtMost.new(3) { limiter.requests }
46
+ # matcher.match? { limiter.process_batch([1, 2, 3, 4, 5]) } # => true
47
+ #
48
+ # @example Resource consumption
49
+ # class ResourcePool
50
+ # attr_reader :used
51
+ #
52
+ # def initialize
53
+ # @used = 0
54
+ # end
55
+ #
56
+ # def allocate(requested)
57
+ # available = 5 - @used # Maximum pool size is 5
58
+ # granted = [requested, available].min
59
+ # @used += granted
60
+ # granted
61
+ # end
62
+ # end
63
+ #
64
+ # pool = ResourcePool.new
65
+ # matcher = Matchi::Change::ByAtMost.new(2) { pool.used }
66
+ # matcher.match? { pool.allocate(2) } # => true
67
+ # matcher.match? { pool.allocate(3) } # => false
68
+ #
69
+ # @example Score adjustments
70
+ # class GameScore
71
+ # attr_reader :value
72
+ #
73
+ # def initialize
74
+ # @value = 100
75
+ # end
76
+ #
77
+ # def apply_penalty(amount)
78
+ # max_penalty = 10
79
+ # actual_penalty = [amount, max_penalty].min
80
+ # @value -= actual_penalty
81
+ # end
82
+ # end
83
+ #
84
+ # score = GameScore.new
85
+ # matcher = Matchi::Change::ByAtMost.new(10) { -score.value }
86
+ # matcher.match? { score.apply_penalty(5) } # => true # Small penalty
87
+ # matcher.match? { score.apply_penalty(15) } # => true # Limited to max
88
+ #
89
+ # @note This matcher verifies maximum changes only. For exact changes, use By,
90
+ # and for minimum changes, use ByAtLeast.
91
+ #
92
+ # @see Matchi::Change::By For exact change validation
93
+ # @see Matchi::Change::ByAtLeast For minimum change validation
94
+ # @see Matchi::Change::To For final value validation
6
95
  class ByAtMost
7
- # Initialize the matcher with an object and a block.
96
+ # Initialize the matcher with a maximum allowed change and a state block.
8
97
  #
9
- # @example
10
- # require "matchi/change/by_at_most"
98
+ # @api public
99
+ #
100
+ # @param expected [Numeric] The maximum amount by which the value should change
101
+ # @param state [Proc] Block that retrieves the current value
102
+ #
103
+ # @raise [ArgumentError] if expected is not a Numeric
104
+ # @raise [ArgumentError] if expected is negative
105
+ # @raise [ArgumentError] if no state block is provided
11
106
  #
12
- # object = []
107
+ # @return [ByAtMost] a new instance of the matcher
13
108
  #
14
- # Matchi::Change::ByAtMost.new(1) { object.length }
109
+ # @example With integer maximum
110
+ # ByAtMost.new(5) { counter.value }
15
111
  #
16
- # @param expected [#object_id] An expected delta.
17
- # @param state [Proc] A block of code to execute to get the
18
- # state of the object.
112
+ # @example With floating point maximum
113
+ # ByAtMost.new(0.5) { temperature.celsius }
19
114
  def initialize(expected, &state)
20
115
  raise ::ArgumentError, "expected must be a Numeric" unless expected.is_a?(::Numeric)
21
116
  raise ::ArgumentError, "a block must be provided" unless block_given?
22
117
  raise ::ArgumentError, "expected must be non-negative" if expected.negative?
23
118
 
24
119
  @expected = expected
25
- @state = state
120
+ @state = state
26
121
  end
27
122
 
28
- # Boolean comparison on the expected change by comparing the value
29
- # before and after the code execution.
123
+ # Checks if the value changes by no more than the expected amount.
30
124
  #
31
- # @example
32
- # require "matchi/change/by_at_most"
125
+ # This method compares the value before and after executing the provided block,
126
+ # ensuring that the absolute difference is less than or equal to the expected maximum.
127
+ # This is useful for enforcing upper bounds on state changes.
128
+ #
129
+ # @api public
33
130
  #
34
- # object = []
131
+ # @yield [] Block that should cause the state change
132
+ # @yieldreturn [Object] The result of the block (not used)
35
133
  #
36
- # matcher = Matchi::Change::ByAtMost.new(1) { object.length }
37
- # matcher.match? { object << "foo" } # => true
134
+ # @return [Boolean] true if the value changed by at most the expected amount
38
135
  #
39
- # @yieldreturn [#object_id] The block of code to execute.
136
+ # @raise [ArgumentError] if no block is provided
40
137
  #
41
- # @return [Boolean] Comparison between the value before and after the
42
- # code execution.
138
+ # @example Basic usage with growth
139
+ # users = []
140
+ # matcher = ByAtMost.new(2) { users.size }
141
+ # matcher.match? { users.push('alice') } # => true
142
+ #
143
+ # @example With negative changes
144
+ # stock = 10
145
+ # matcher = ByAtMost.new(3) { stock }
146
+ # matcher.match? { stock -= 2 } # => true
43
147
  def match?
44
148
  raise ::ArgumentError, "a block must be provided" unless block_given?
45
149
 
@@ -50,9 +154,15 @@ module Matchi
50
154
  @expected >= (value_after - value_before)
51
155
  end
52
156
 
53
- # Returns a string representing the matcher.
157
+ # Returns a human-readable description of the matcher.
158
+ #
159
+ # @api public
54
160
  #
55
- # @return [String] a human-readable description of the matcher
161
+ # @return [String] A string describing what this matcher verifies
162
+ #
163
+ # @example
164
+ # ByAtMost.new(5).to_s # => "change by at most 5"
165
+ # ByAtMost.new(2.5).to_s # => "change by at most 2.5"
56
166
  def to_s
57
167
  "change by at most #{@expected.inspect}"
58
168
  end
@@ -3,44 +3,105 @@
3
3
  module Matchi
4
4
  class Change
5
5
  class From
6
- # *Change from to* matcher.
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
7
55
  class To
8
- # Initialize the matcher with two objects and a block.
56
+ # Initialize the matcher with expected initial and final values.
9
57
  #
10
- # @example
11
- # require "matchi/change/from/to"
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
12
65
  #
13
- # object = "foo"
66
+ # @return [To] a new instance of the matcher
14
67
  #
15
- # Matchi::Change::From::To.new("foo", "FOO") { object.to_s }
68
+ # @example With simple value
69
+ # To.new("draft", "published") { document.status }
16
70
  #
17
- # @param expected_init [#object_id] An expected initial value.
18
- # @param expected_new_value [#object_id] An expected new value.
19
- # @param state [Proc] A block of code to execute to
20
- # get the state of the object.
71
+ # @example With complex state
72
+ # To.new([:user], [:user, :admin]) { account.roles }
21
73
  def initialize(expected_init, expected_new_value, &state)
22
74
  raise ::ArgumentError, "a block must be provided" unless block_given?
23
75
 
24
- @expected_init = expected_init
25
- @expected = expected_new_value
26
- @state = state
76
+ @expected_init = expected_init
77
+ @expected = expected_new_value
78
+ @state = state
27
79
  end
28
80
 
29
- # Boolean comparison on the expected change by comparing the value
30
- # before and after the code execution.
81
+ # Verifies both initial and final states during a transition.
31
82
  #
32
- # @example
33
- # require "matchi/change/from/to"
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
34
88
  #
35
- # object = "foo"
89
+ # @yield [] Block that should cause the state transition
90
+ # @yieldreturn [Object] The result of the block (not used)
36
91
  #
37
- # matcher = Matchi::Change::From::To.new("foo", "FOO") { object.to_s }
38
- # matcher.match? { object.upcase! } # => true
92
+ # @return [Boolean] true if both initial and final states match expectations
39
93
  #
40
- # @yieldreturn [#object_id] The block of code to execute.
94
+ # @raise [ArgumentError] if no block is provided
41
95
  #
42
- # @return [Boolean] Comparison between the value before and after the
43
- # code execution.
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
44
105
  def match?
45
106
  raise ::ArgumentError, "a block must be provided" unless block_given?
46
107
 
@@ -53,9 +114,15 @@ module Matchi
53
114
  @expected == value_after
54
115
  end
55
116
 
56
- # Returns a string representing the matcher.
117
+ # Returns a human-readable description of the matcher.
118
+ #
119
+ # @api public
57
120
  #
58
- # @return [String] a human-readable description of the matcher
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"'
59
126
  def to_s
60
127
  "change from #{@expected_init.inspect} to #{@expected.inspect}"
61
128
  end
@@ -4,7 +4,32 @@ require_relative File.join("from", "to")
4
4
 
5
5
  module Matchi
6
6
  class Change
7
- # *Change from to* wrapper.
7
+ # Initial state wrapper for building a value transition matcher.
8
+ #
9
+ # This class acts as a wrapper that captures the expected initial state and
10
+ # provides methods to build a complete transition matcher. When combined with
11
+ # the 'to' method, it creates a matcher that verifies both the starting and
12
+ # ending values of a change operation. This is useful when you need to ensure
13
+ # not only the final state but also the initial state of a value.
14
+ #
15
+ # @example Basic string transformation
16
+ # text = "hello"
17
+ # Change.new(text, :to_s).from("hello").to("HELLO").match? { text.upcase! } # => true
18
+ #
19
+ # @example Object state transition
20
+ # class User
21
+ # attr_accessor :status
22
+ # def initialize
23
+ # @status = "pending"
24
+ # end
25
+ # end
26
+ #
27
+ # user = User.new
28
+ # Change.new(user, :status).from("pending").to("active").match? {
29
+ # user.status = "active"
30
+ # } # => true
31
+ #
32
+ # @see Matchi::Change::From::To For the complete transition matcher
8
33
  class From
9
34
  # Initialize the wrapper with an object and a block.
10
35
  #
@@ -27,6 +52,11 @@ module Matchi
27
52
 
28
53
  # Specifies the new value to expect.
29
54
  #
55
+ # Creates a complete transition matcher that verifies both the initial
56
+ # and final states of a value. The matcher will succeed only if the
57
+ # value starts at the expected initial state and changes to the specified
58
+ # new value after executing the test block.
59
+ #
30
60
  # @example
31
61
  # require "matchi/change/from"
32
62
  #
@@ -2,54 +2,103 @@
2
2
 
3
3
  module Matchi
4
4
  class Change
5
- # *Change to* matcher.
5
+ # Final state matcher that verifies if a method returns an expected value after a change.
6
+ #
7
+ # This matcher focuses on the final state of an object, verifying that a method call
8
+ # returns an expected value after executing a block of code. Unlike the full from/to
9
+ # matcher, it only cares about the end result, not the initial state.
10
+ #
11
+ # @example Basic string transformation
12
+ # text = "hello"
13
+ # matcher = Matchi::Change::To.new("HELLO") { text.to_s }
14
+ # matcher.match? { text.upcase! } # => true
15
+ # matcher.match? { text.reverse! } # => false
16
+ #
17
+ # @example Number calculations
18
+ # counter = 0
19
+ # matcher = Matchi::Change::To.new(5) { counter }
20
+ # matcher.match? { counter = 5 } # => true
21
+ # matcher.match? { counter += 1 } # => false
22
+ #
23
+ # @example With object attributes
24
+ # class User
25
+ # attr_accessor :status
26
+ # def initialize(status)
27
+ # @status = status
28
+ # end
29
+ # end
30
+ #
31
+ # user = User.new(:pending)
32
+ # matcher = Matchi::Change::To.new(:active) { user.status }
33
+ # matcher.match? { user.status = :active } # => true
34
+ #
35
+ # @see Matchi::Change::From::To For checking both initial and final states
36
+ # @see Matchi::Change::By For checking numeric changes
6
37
  class To
7
- # Initialize the matcher with an object and a block.
38
+ # Initialize the matcher with an expected new value and a state block.
8
39
  #
9
- # @example
10
- # require "matchi/change/to"
40
+ # @api public
41
+ #
42
+ # @param expected [#eql?] The expected final value
43
+ # @param state [Proc] Block that retrieves the value to check
44
+ #
45
+ # @raise [ArgumentError] if no state block is provided
11
46
  #
12
- # object = "foo"
47
+ # @return [To] a new instance of the matcher
13
48
  #
14
- # Matchi::Change::To.new("FOO") { object.to_s }
49
+ # @example With simple value
50
+ # To.new("test") { object.value }
15
51
  #
16
- # @param expected [#object_id] An expected new value.
17
- # @param state [Proc] A block of code to execute to get the
18
- # state of the object.
52
+ # @example With complex calculation
53
+ # To.new(100) { object.items.count }
19
54
  def initialize(expected, &state)
20
55
  raise ::ArgumentError, "a block must be provided" unless block_given?
21
56
 
22
57
  @expected = expected
23
- @state = state
58
+ @state = state
24
59
  end
25
60
 
26
- # Boolean comparison on the expected change by comparing the value
27
- # before and after the code execution.
61
+ # Checks if the state block returns the expected value after executing the provided block.
28
62
  #
29
- # @example
30
- # require "matchi/change/to"
63
+ # This method executes the provided block and then checks if the state block
64
+ # returns the expected value. It only cares about the final state, not any
65
+ # intermediate values or the initial state.
66
+ #
67
+ # @api public
31
68
  #
32
- # object = "foo"
69
+ # @yield [] Block that should cause the state change
70
+ # @yieldreturn [Object] The result of the block (not used)
33
71
  #
34
- # matcher = Matchi::Change::To.new("FOO") { object.to_s }
35
- # matcher.match? { object.upcase! } # => true
72
+ # @return [Boolean] true if the final state matches the expected value
36
73
  #
37
- # @yieldreturn [#object_id] The block of code to execute.
74
+ # @raise [ArgumentError] if no block is provided
38
75
  #
39
- # @return [Boolean] Comparison between the value before and after the
40
- # code execution.
76
+ # @example Basic usage
77
+ # text = "hello"
78
+ # matcher = To.new("HELLO") { text.to_s }
79
+ # matcher.match? { text.upcase! } # => true
80
+ #
81
+ # @example With method chaining
82
+ # array = [1, 2, 3]
83
+ # matcher = To.new(6) { array.sum }
84
+ # matcher.match? { array.map! { |x| x * 2 } } # => false
41
85
  def match?
42
86
  raise ::ArgumentError, "a block must be provided" unless block_given?
43
87
 
44
88
  yield
45
89
  value_after = @state.call
46
90
 
47
- @expected == value_after
91
+ @expected.eql?(value_after)
48
92
  end
49
93
 
50
- # Returns a string representing the matcher.
94
+ # Returns a human-readable description of the matcher.
95
+ #
96
+ # @api public
51
97
  #
52
- # @return [String] a human-readable description of the matcher
98
+ # @return [String] A string describing what this matcher verifies
99
+ #
100
+ # @example
101
+ # To.new("test").to_s # => 'change to "test"'
53
102
  def to_s
54
103
  "change to #{@expected.inspect}"
55
104
  end