rspec-sleeping_king_studios 2.0.0.beta.0 → 2.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +84 -13
  3. data/DEVELOPMENT.md +16 -0
  4. data/README.md +203 -100
  5. data/lib/rspec/sleeping_king_studios/all.rb +4 -0
  6. data/lib/rspec/sleeping_king_studios/configuration.rb +42 -0
  7. data/lib/rspec/sleeping_king_studios/examples/all.rb +5 -0
  8. data/lib/rspec/sleeping_king_studios/examples/property_examples.rb +58 -0
  9. data/lib/rspec/sleeping_king_studios/examples/rspec_matcher_examples.rb +105 -0
  10. data/lib/rspec/sleeping_king_studios/examples/shared_example_group.rb +62 -0
  11. data/lib/rspec/sleeping_king_studios/examples.rb +8 -0
  12. data/lib/rspec/sleeping_king_studios/matchers/active_model/all.rb +5 -0
  13. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation.rb +0 -1
  14. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/message_expectation.rb +1 -2
  15. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb +75 -24
  16. data/lib/rspec/sleeping_king_studios/matchers/active_model.rb +6 -3
  17. data/lib/rspec/sleeping_king_studios/matchers/all.rb +5 -0
  18. data/lib/rspec/sleeping_king_studios/matchers/base_matcher.rb +20 -1
  19. data/lib/rspec/sleeping_king_studios/matchers/built_in/all.rb +5 -0
  20. data/lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb +16 -10
  21. data/lib/rspec/sleeping_king_studios/matchers/built_in/include.rb +14 -9
  22. data/lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb +45 -31
  23. data/lib/rspec/sleeping_king_studios/matchers/built_in.rb +5 -3
  24. data/lib/rspec/sleeping_king_studios/matchers/core/all.rb +5 -0
  25. data/lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb +11 -4
  26. data/lib/rspec/sleeping_king_studios/matchers/core/construct.rb +56 -32
  27. data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +59 -29
  28. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +31 -22
  29. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +21 -55
  30. data/lib/rspec/sleeping_king_studios/matchers/core.rb +5 -3
  31. data/lib/rspec/sleeping_king_studios/matchers/shared/match_parameters.rb +1 -3
  32. data/lib/rspec/sleeping_king_studios/matchers/shared/match_property.rb +52 -0
  33. data/lib/rspec/sleeping_king_studios/matchers.rb +10 -3
  34. data/lib/rspec/sleeping_king_studios/version.rb +22 -1
  35. data/lib/rspec/sleeping_king_studios.rb +7 -1
  36. metadata +38 -16
  37. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/require.rb +0 -7
  38. data/lib/rspec/sleeping_king_studios/matchers/active_model/require.rb +0 -8
  39. data/lib/rspec/sleeping_king_studios/matchers/built_in/require.rb +0 -7
  40. data/lib/rspec/sleeping_king_studios/matchers/core/require.rb +0 -7
  41. data/lib/rspec/sleeping_king_studios/matchers/meta/fail_with_actual.rb +0 -107
  42. data/lib/rspec/sleeping_king_studios/matchers/meta/pass_with_actual.rb +0 -95
  43. data/lib/rspec/sleeping_king_studios/matchers/meta/require.rb +0 -7
  44. data/lib/rspec/sleeping_king_studios/matchers/meta.rb +0 -5
  45. data/lib/rspec/sleeping_king_studios/matchers/require.rb +0 -12
  46. data/lib/rspec/sleeping_king_studios/matchers/shared/require.rb +0 -7
  47. data/lib/rspec/sleeping_king_studios/require.rb +0 -7
@@ -1,46 +1,65 @@
1
1
  # lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb
2
2
 
3
3
  require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
- require 'rspec/sleeping_king_studios/matchers/built_in/require'
4
+ require 'rspec/sleeping_king_studios/matchers/built_in'
5
5
  require 'rspec/sleeping_king_studios/matchers/shared/match_parameters'
6
+ require 'sleeping_king_studios/tools/enumerable_tools'
7
+ require 'sleeping_king_studios/tools/string_tools'
6
8
 
7
9
  module RSpec::SleepingKingStudios::Matchers::BuiltIn
8
10
  class RespondToMatcher < RSpec::Matchers::BuiltIn::RespondTo
9
11
  include RSpec::SleepingKingStudios::Matchers::Shared::MatchParameters
12
+ include SleepingKingStudios::Tools::EnumerableTools
13
+ include SleepingKingStudios::Tools::StringTools
14
+
15
+ def initialize *expected
16
+ @include_all = [true, false].include?(expected.last) ? expected.pop : false
17
+
18
+ super(*expected)
19
+ end # constructor
20
+
21
+ # Generates a description of the matcher expectation.
22
+ #
23
+ # @return [String] The matcher description.
24
+ def description
25
+ expected_message = format_expected_arguments
26
+ "respond to #{pp_names}#{expected_message.empty? ? '' : " with #{expected_message}"}"
27
+ end # method description
10
28
 
11
29
  # @overload with count
12
30
  # Adds a parameter count expectation.
13
- #
31
+ #
14
32
  # @param [Integer, Range, nil] count (optional) The number of expected
15
33
  # parameters.
16
- #
34
+ #
17
35
  # @return [RespondToMatcher] self
18
36
  # @overload with *keywords
19
37
  # Adds one or more keyword expectations (Ruby 2.0 only).
20
- #
38
+ #
21
39
  # @param [Array<String, Symbol>] keywords List of keyword arguments
22
40
  # accepted by the method.
23
- #
41
+ #
24
42
  # @return [RespondToMatcher] self
25
43
  # @overload with count, *keywords
26
44
  # Adds a parameter count expectation and one or more keyword
27
45
  # expectations (Ruby 2.0 only).
28
- #
46
+ #
29
47
  # @param [Integer, Range, nil] count (optional) The number of expected
30
48
  # parameters.
31
49
  # @param [Array<String, Symbol>] keywords List of keyword arguments
32
50
  # accepted by the method.
33
- #
51
+ #
34
52
  # @return [RespondToMatcher] self
35
53
  def with *keywords
36
54
  @expected_arity = keywords.shift if Integer === keywords.first || Range === keywords.first
37
55
  @expected_keywords = keywords
56
+
38
57
  self
39
58
  end # method with
40
59
 
41
60
  # Adds a block expectation. The actual object will only match a block
42
61
  # expectation if it expects a parameter of the form &block.
43
- #
62
+ #
44
63
  # @return [RespondToMatcher] self
45
64
  def with_a_block
46
65
  @expected_block = true
@@ -50,30 +69,32 @@ module RSpec::SleepingKingStudios::Matchers::BuiltIn
50
69
  # @see BaseMatcher#failure_message
51
70
  def failure_message
52
71
  @failing_method_names ||= []
53
- methods, messages = @names - @failing_method_names, []
72
+ methods, messages = @failing_method_names, []
54
73
 
55
74
  methods.map do |method|
56
75
  message = "expected #{@actual.inspect} to respond to #{method.inspect}"
57
- if @actual.respond_to?(method)
76
+ if @actual.respond_to?(method, @include_all)
58
77
  message << " with arguments:\n#{format_errors_for_method method}"
59
78
  end # if-else
60
79
  messages << message
61
80
  end # method
81
+
62
82
  messages.join "\n"
63
83
  end # method failure_message
64
84
 
65
85
  # @see BaseMatcher#failure_message_when_negated
66
86
  def failure_message_when_negated
67
87
  @failing_method_names ||= []
68
- methods, messages = @names - @failing_method_names, []
88
+ methods, messages = @failing_method_names, []
69
89
 
70
90
  methods.map do |method|
71
- message = "expected #{@actual.inspect} not to respond to #{method.inspect}"
91
+ message = "expected #{@actual.inspect} not to respond to #{method.inspect}"
72
92
  unless (formatted = format_expected_arguments).empty?
73
93
  message << " with #{formatted}"
74
94
  end # unless
75
95
  messages << message
76
96
  end # method
97
+
77
98
  messages.join "\n"
78
99
  end # method failure_message_when_negated
79
100
 
@@ -83,7 +104,7 @@ module RSpec::SleepingKingStudios::Matchers::BuiltIn
83
104
  @actual = actual
84
105
  @failing_method_reasons = {}
85
106
  @failing_method_names = @names.__send__(filter_method) do |name|
86
- @actual.respond_to?(name) &&
107
+ @actual.respond_to?(name, @include_all) &&
87
108
  matches_arity?(actual, name) &&
88
109
  matches_keywords?(actual, name) &&
89
110
  matches_block?(actual, name)
@@ -121,7 +142,7 @@ module RSpec::SleepingKingStudios::Matchers::BuiltIn
121
142
  raise error
122
143
  end # if-else
123
144
  end # method matches_keywords?
124
-
145
+
125
146
  def matches_block? actual, name
126
147
  return true unless @expected_block
127
148
 
@@ -135,32 +156,25 @@ module RSpec::SleepingKingStudios::Matchers::BuiltIn
135
156
 
136
157
  def format_expected_arguments
137
158
  messages = []
138
-
159
+
139
160
  if !@expected_arity.nil?
140
- messages << "#{@expected_arity.inspect} argument#{1 == @expected_arity ? "" : "s"}"
161
+ messages << "#{@expected_arity.inspect} #{pluralize @expected_arity, 'argument', 'arguments'}"
141
162
  end # if
142
163
 
143
164
  if !(@expected_keywords.nil? || @expected_keywords.empty?)
144
- messages << "keywords #{@expected_keywords.map(&:inspect).join(", ")}"
165
+ messages << "#{pluralize @expected_keywords.count, 'keyword', 'keywords'} #{humanize_list @expected_keywords.map(&:inspect)}"
145
166
  end # if
146
167
 
147
168
  if @expected_block
148
169
  messages << "a block"
149
170
  end # if
150
171
 
151
- case messages.count
152
- when 0..1
153
- messages.join(", ")
154
- when 2
155
- "#{messages[0]} and #{messages[1]}"
156
- else
157
- "#{messages[1..-1].join(", ")}, and #{messages[0]}"
158
- end # case
172
+ humanize_list messages
159
173
  end # method format_expected_arguments
160
174
 
161
175
  def format_errors_for_method method
162
176
  reasons, messages = @failing_method_reasons[method], []
163
-
177
+
164
178
  if hsh = reasons.fetch(:not_enough_args, false)
165
179
  messages << " expected at least #{hsh[:count]} arguments, but received #{hsh[:arity]}"
166
180
  elsif hsh = reasons.fetch(:too_many_args, false)
@@ -168,11 +182,11 @@ module RSpec::SleepingKingStudios::Matchers::BuiltIn
168
182
  end # if-elsif
169
183
 
170
184
  if ary = reasons.fetch(:missing_keywords, false)
171
- messages << " missing keywords #{ary.map(&:inspect).join(", ")}"
185
+ messages << " missing #{pluralize ary.count, 'keyword', 'keywords'} #{humanize_list ary.map(&:inspect)}"
172
186
  end # if
173
187
 
174
188
  if ary = reasons.fetch(:unexpected_keywords, false)
175
- messages << " unexpected keywords #{ary.map(&:inspect).join(", ")}"
189
+ messages << " unexpected #{pluralize ary.count, 'keyword', 'keywords'} #{humanize_list ary.map(&:inspect)}"
176
190
  end # if
177
191
 
178
192
  if reasons.fetch(:expected_block, false)
@@ -180,13 +194,13 @@ module RSpec::SleepingKingStudios::Matchers::BuiltIn
180
194
  end # if
181
195
 
182
196
  messages.join "\n"
183
- end # method format_errors_for_method
197
+ end # method format_errors_for_method
184
198
  end # class
185
199
  end # module
186
200
 
187
201
  module RSpec::SleepingKingStudios::Matchers
188
202
  # @see RSpec::SleepingKingStudios::Matchers::BuiltIn::RespondToMatcher#matches?
189
- def respond_to expected
190
- RSpec::SleepingKingStudios::Matchers::BuiltIn::RespondToMatcher.new expected
203
+ def respond_to *expected
204
+ RSpec::SleepingKingStudios::Matchers::BuiltIn::RespondToMatcher.new *expected
191
205
  end # method respond_to
192
206
  end # module
@@ -1,5 +1,7 @@
1
1
  # lib/rspec/sleeping_king_studios/matchers/built_in.rb
2
2
 
3
- Dir[File.join File.dirname(__FILE__), 'built_in', '*.rb'].each do |file|
4
- require file
5
- end # end each
3
+ require 'rspec/sleeping_king_studios/matchers'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers
6
+ module BuiltIn; end
7
+ end # module
@@ -0,0 +1,5 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/core/all.rb
2
+
3
+ Dir[File.join File.dirname(__FILE__), '*.rb'].each do |file|
4
+ require file
5
+ end # end each
@@ -1,17 +1,24 @@
1
1
  # lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb
2
2
 
3
3
  require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
- require 'rspec/sleeping_king_studios/matchers/core/require'
4
+ require 'rspec/sleeping_king_studios/matchers/core'
5
5
 
6
6
  module RSpec::SleepingKingStudios::Matchers::Core
7
7
  # Matcher for testing whether an object is true or false.
8
- #
8
+ #
9
9
  # @since 1.0.0
10
10
  class BeBooleanMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
11
+ # Generates a description of the matcher expectation.
12
+ #
13
+ # @return [String] The matcher description.
14
+ def description
15
+ 'be true or false'
16
+ end # method description
17
+
11
18
  # Checks if the object is true or false.
12
- #
19
+ #
13
20
  # @param [Object] actual the object to check
14
- #
21
+ #
15
22
  # @return [Boolean] true if the object is true or false, otherwise false
16
23
  def matches? actual
17
24
  super
@@ -1,24 +1,35 @@
1
1
  # spec/rspec/sleeping_king_studios/matchers/core/construct.rb
2
2
 
3
3
  require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
- require 'rspec/sleeping_king_studios/matchers/core/require'
5
-
4
+ require 'rspec/sleeping_king_studios/matchers/core'
6
5
  require 'rspec/sleeping_king_studios/matchers/shared/match_parameters'
6
+ require 'sleeping_king_studios/tools/enumerable_tools'
7
+ require 'sleeping_king_studios/tools/string_tools'
7
8
 
8
9
  module RSpec::SleepingKingStudios::Matchers::Core
9
10
  # Matcher for checking whether an object can be constructed via #new and
10
11
  # #initialize, and the parameters accepted by #initialize.
11
- #
12
+ #
12
13
  # @since 1.0.0
13
14
  class ConstructMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
14
15
  include RSpec::SleepingKingStudios::Matchers::Shared::MatchParameters
16
+ include SleepingKingStudios::Tools::EnumerableTools
17
+ include SleepingKingStudios::Tools::StringTools
18
+
19
+ # Generates a description of the matcher expectation.
20
+ #
21
+ # @return [String] The matcher description.
22
+ def description
23
+ expected_message = format_expected_arguments
24
+ "construct#{expected_message.empty? ? '' : " with #{expected_message}"}"
25
+ end # method description
15
26
 
16
27
  # Checks if the object responds to :new. If so, allocates an instance and
17
28
  # checks the parameters expected by #initialize against the expected
18
29
  # parameters, if any.
19
- #
30
+ #
20
31
  # @param [Object] actual the object to check
21
- #
32
+ #
22
33
  # @return [Boolean] true if the object responds to :new and accepts the
23
34
  # specified parameters for #initialize; otherwise false
24
35
  def matches? actual
@@ -28,16 +39,33 @@ module RSpec::SleepingKingStudios::Matchers::Core
28
39
  matches_arity?(actual) &&
29
40
  matches_keywords?(actual)
30
41
  end # method matches?
31
-
32
- # Adds a parameter count expectation and/or one or more keyword
33
- # expectations (Ruby 2.0 only).
34
- #
35
- # @param [Integer, Range, nil] count the number of expected parameters; can
36
- # be an integer, a range, or nil (parameter count is ignored)
37
- # @param [Array<String, Symbol>] keywords list of keyword arguments
38
- # accepted by the method
39
- #
40
- # @return [ConstructMatcher] self
42
+
43
+ # @overload with(count)
44
+ # Adds a parameter count expectation and removes any keyword expectations
45
+ # (Ruby 2.0+ only).
46
+ #
47
+ # @param [Integer, Range] count the number of expected parameters
48
+ #
49
+ # @return [ConstructMatcher] self
50
+ #
51
+ # @overload with(count, *keywords)
52
+ # Adds a parameter count expectation and one or more keyword expectations
53
+ # (Ruby 2.0 only).
54
+ #
55
+ # @param [Integer, Range] count the number of expected parameters
56
+ # @param [Array<String, Symbol>] keywords list of keyword arguments
57
+ # accepted by the method
58
+ #
59
+ # @return [ConstructMatcher] self
60
+ #
61
+ # @overload with(*keywords)
62
+ # Removes a parameter count expectation (if any) and adds one or more
63
+ # keyword expectations (Ruby 2.0 only).
64
+ #
65
+ # @param [Array<String, Symbol>] keywords list of keyword arguments
66
+ # accepted by the method
67
+ #
68
+ # @return [ConstructMatcher] self
41
69
  def with *keywords
42
70
  @expected_arity = keywords.shift if Integer === keywords.first || Range === keywords.first
43
71
  @expected_keywords = keywords
@@ -45,11 +73,14 @@ module RSpec::SleepingKingStudios::Matchers::Core
45
73
  end # method with
46
74
 
47
75
  # Convenience method for more fluent specs. Does nothing and returns self.
48
- #
76
+ #
49
77
  # @return [ConstructMatcher] self
50
- def arguments
78
+ #
79
+ # @since 2.0.0
80
+ def argument
51
81
  self
52
- end # method arguments
82
+ end # method argument
83
+ alias_method :arguments, :argument
53
84
 
54
85
  # @see BaseMatcher#failure_message
55
86
  def failure_message
@@ -62,7 +93,7 @@ module RSpec::SleepingKingStudios::Matchers::Core
62
93
  def failure_message_when_negated
63
94
  message = "expected #{@actual.inspect} not to construct"
64
95
  unless (formatted = format_expected_arguments).empty?
65
- message << " with #{formatted}"
96
+ message << " with #{formatted}"
66
97
  end # unless
67
98
  message
68
99
  end # method failure_message_when_negated
@@ -71,7 +102,7 @@ module RSpec::SleepingKingStudios::Matchers::Core
71
102
 
72
103
  def matches_arity? actual
73
104
  return true unless @expected_arity
74
-
105
+
75
106
  if result = check_method_arity(actual.allocate.method(:initialize), @expected_arity)
76
107
  @failing_method_reasons.update result
77
108
  return false
@@ -100,22 +131,15 @@ module RSpec::SleepingKingStudios::Matchers::Core
100
131
  end # if
101
132
 
102
133
  if !(@expected_keywords.nil? || @expected_keywords.empty?)
103
- messages << "keywords #{@expected_keywords.map(&:inspect).join(", ")}"
134
+ messages << "#{pluralize @expected_keywords.count, 'keyword', 'keywords'} #{humanize_list @expected_keywords.map(&:inspect)}"
104
135
  end # if
105
136
 
106
- case messages.count
107
- when 0..1
108
- messages.join(", ")
109
- when 2
110
- "#{messages[0]} and #{messages[1]}"
111
- else
112
- "#{messages[1..-1].join(", ")}, and #{messages[0]}"
113
- end # case
137
+ humanize_list messages
114
138
  end # method format_expected_arguments
115
139
 
116
140
  def format_errors
117
141
  reasons, messages = @failing_method_reasons, []
118
-
142
+
119
143
  if hsh = reasons.fetch(:not_enough_args, false)
120
144
  messages << " expected at least #{hsh[:count]} arguments, but received #{hsh[:arity]}"
121
145
  elsif hsh = reasons.fetch(:too_many_args, false)
@@ -123,11 +147,11 @@ module RSpec::SleepingKingStudios::Matchers::Core
123
147
  end # if-elsif
124
148
 
125
149
  if ary = reasons.fetch(:missing_keywords, false)
126
- messages << " missing keywords #{ary.map(&:inspect).join(", ")}"
150
+ messages << " missing #{pluralize ary.count, 'keyword', 'keywords'} #{humanize_list ary.map(&:inspect)}"
127
151
  end # if
128
152
 
129
153
  if ary = reasons.fetch(:unexpected_keywords, false)
130
- messages << " unexpected keywords #{ary.map(&:inspect).join(", ")}"
154
+ messages << " unexpected #{pluralize ary.count, 'keyword', 'keywords'} #{humanize_list ary.map(&:inspect)}"
131
155
  end # if
132
156
 
133
157
  messages.join "\n"
@@ -1,77 +1,107 @@
1
1
  # lib/rspec/sleeping_king_studios/matchers/core/have_property.rb
2
2
 
3
3
  require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
- require 'rspec/sleeping_king_studios/matchers/core/require'
4
+ require 'rspec/sleeping_king_studios/matchers/core'
5
+ require 'rspec/sleeping_king_studios/matchers/shared/match_property'
5
6
 
6
7
  module RSpec::SleepingKingStudios::Matchers::Core
7
8
  # Matcher for testing whether an object has a specific property, e.g.
8
9
  # responds to :property and :property= and :property= updates the value of
9
10
  # :property.
10
- #
11
+ #
11
12
  # @since 1.0.0
12
13
  class HavePropertyMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
14
+ include RSpec::SleepingKingStudios::Matchers::Shared::MatchProperty
15
+
16
+ # Generates a description of the matcher expectation.
17
+ #
18
+ # @return [String] The matcher description.
19
+ def description
20
+ value_message = value_to_string
21
+ "have property :#{@expected}#{@value_set ? " with value #{value_message}" : ''}"
22
+ end # method description
23
+
13
24
  # @param [String, Symbol] expected the property to check for on the actual
14
25
  # object
15
26
  def initialize expected
16
27
  @expected = expected.intern
17
28
  end # method initialize
18
29
 
30
+ def does_not_match? actual
31
+ super
32
+
33
+ matches_property?(:none?)
34
+ end # method does_not_match?
35
+
19
36
  # Checks if the object responds to :expected and :expected=. Additionally,
20
- # if a value expectation is set, assigns the value via :expected= and
21
- # compares the subsequent value of :expected to the specified value.
22
- #
37
+ # if a value expectation is set, compares the result of calling :expected
38
+ # to the value.
39
+ #
23
40
  # @param [Object] actual the object to check
24
- #
41
+ #
25
42
  # @return [Boolean] true if the object responds to :expected and
26
43
  # :expected= and matches the value expectation (if any); otherwise false
27
44
  def matches? actual
28
45
  super
29
46
 
30
- @match_reader = @actual.respond_to? @expected
31
- @match_writer = @actual.respond_to? :"#{@expected}="
32
-
33
- return false unless @match_reader && @match_writer
34
-
35
- if @value_set
36
- @actual.send :"#{@expected}=", @value
37
- return false unless @actual.send(@expected) == @value
38
- end # if
39
-
40
- true
47
+ matches_property?(:all?)
41
48
  end # method matches?
42
49
 
43
- # Sets a value expectation. The matcher will set the object's value to the
44
- # specified value using :property=, then compare the value from :property
45
- # with the specified value.
46
- #
50
+ # Sets a value expectation. The matcher will compare the value to the
51
+ # result of calling :property.
52
+ #
47
53
  # @param [Object] value the value to set and then compare
48
- #
54
+ #
49
55
  # @return [HavePropertyMatcher] self
50
56
  def with value
51
57
  @value = value
52
58
  @value_set = true
53
59
  self
54
60
  end # method with
61
+ alias_method :with_value, :with
55
62
 
56
63
  # @see BaseMatcher#failure_message
57
64
  def failure_message
58
65
  methods = []
59
- methods << ":#{@expected}" unless @match_reader
60
- methods << ":#{@expected}=" unless @match_writer
66
+ methods << ":#{@expected}" unless @matches_reader
67
+ methods << ":#{@expected}=" unless @matches_writer
68
+
69
+ message = "expected #{@actual.inspect} to respond to :#{@expected} and :#{@expected}="
70
+ message << " and return #{value_to_string}" if @value_set
61
71
 
62
- return "expected #{@actual.inspect} to respond to #{methods.join " and "}" unless methods.empty?
72
+ errors = []
73
+ errors << "did not respond to #{methods.join " or "}" unless methods.empty?
74
+ errors << "returned #{@actual.send(@expected).inspect}" unless @matches_reader_value || !@value_set
63
75
 
64
- "unexpected value for #{@actual.inspect}\##{@expected}" +
65
- "\n expected: #{@value.inspect}" +
66
- "\n got: #{@actual.send(@expected).inspect}"
76
+ message << ", but #{errors.join(" and ")}"
77
+ message
67
78
  end # failure_message
68
79
 
69
80
  # @see BaseMatcher#failure_message_when_negated
70
81
  def failure_message_when_negated
82
+ methods = []
83
+ methods << ":#{@expected}" if @matches_reader
84
+ methods << ":#{@expected}=" if @matches_writer
85
+
71
86
  message = "expected #{@actual.inspect} not to respond to :#{@expected} or :#{@expected}="
72
- message << " with value #{@value.inspect}" if @value_set
87
+ message << " and return #{value_to_string}" if @value_set
88
+
89
+ errors = []
90
+ errors << "responded to #{methods.join " and "}" unless methods.empty?
91
+ errors << "returned #{@actual.send(@expected).inspect}" if @matches_reader_value
92
+
93
+ message << ", but #{errors.join(" and ")}"
73
94
  message
74
95
  end # failure_message_when_negated
96
+
97
+ private
98
+
99
+ def matches_property? filter
100
+ [ responds_to_reader?,
101
+ responds_to_writer?,
102
+ matches_reader_value?
103
+ ].send(filter) { |bool| bool }
104
+ end # method matches_property?
75
105
  end # class
76
106
  end # module
77
107
 
@@ -1,14 +1,25 @@
1
1
  # lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb
2
2
 
3
3
  require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
- require 'rspec/sleeping_king_studios/matchers/core/require'
4
+ require 'rspec/sleeping_king_studios/matchers/core'
5
+ require 'rspec/sleeping_king_studios/matchers/shared/match_property'
5
6
 
6
7
  module RSpec::SleepingKingStudios::Matchers::Core
7
8
  # Matcher for testing whether an object has a specific property reader, e.g.
8
9
  # responds to :property.
9
- #
10
+ #
10
11
  # @since 1.0.0
11
12
  class HaveReaderMatcher < RSpec::SleepingKingStudios::Matchers::BaseMatcher
13
+ include RSpec::SleepingKingStudios::Matchers::Shared::MatchProperty
14
+
15
+ # Generates a description of the matcher expectation.
16
+ #
17
+ # @return [String] The matcher description.
18
+ def description
19
+ value_message = value_to_string
20
+ "have reader :#{@expected}#{@value_set ? " with value #{value_message}" : ''}"
21
+ end # method description
22
+
12
23
  # @param [String, Symbol] expected the property to check for on the actual
13
24
  # object
14
25
  def initialize expected
@@ -18,50 +29,48 @@ module RSpec::SleepingKingStudios::Matchers::Core
18
29
  # Checks if the object responds to :expected. Additionally, if a value
19
30
  # expectation is set, compares the value of :expected to the specified
20
31
  # value.
21
- #
32
+ #
22
33
  # @param [Object] actual the object to check
23
- #
34
+ #
24
35
  # @return [Boolean] true if the object responds to :expected and matches
25
36
  # the value expectation (if any); otherwise false
26
37
  def matches? actual
27
38
  super
28
39
 
29
- return false unless @match_reader = @actual.respond_to?(@expected)
30
-
31
- if @value_set
32
- return false unless @match_value = @actual.send(@expected) == @value
33
- end # if
34
-
35
- true
40
+ responds_to_reader? && matches_reader_value?
36
41
  end # method matches?
37
42
 
38
43
  # Sets a value expectation. The matcher will compare the value from
39
44
  # :property with the specified value.
40
- #
45
+ #
41
46
  # @param [Object] value the value to compare
42
- #
47
+ #
43
48
  # @return [HaveReaderMatcher] self
44
49
  def with value
45
50
  @value = value
46
51
  @value_set = true
47
52
  self
48
53
  end # method with
54
+ alias_method :with_value, :with
49
55
 
50
56
  # @see BaseMatcher#failure_message
51
57
  def failure_message
52
- unless @match_reader
53
- return "expected #{@actual} to respond to #{@expected.inspect}"
54
- end # unless
55
-
56
- "unexpected value for #{@actual}\##{@expected}\n" +
57
- " expected: #{@value.inspect}\n" +
58
- " got: #{@actual.send(@expected).inspect}"
58
+ message = "expected #{@actual} to respond to :#{@expected}"
59
+ message << " and return #{value_to_string}" if @value_set
60
+
61
+ if !@matches_reader
62
+ message << ", but did not respond to :#{@expected}"
63
+ elsif !@matches_reader_value
64
+ message << ", but returned #{@actual.send(@expected).inspect}"
65
+ end # if
66
+
67
+ message
59
68
  end # method failure_message
60
69
 
61
70
  # @see BaseMatcher#failure_message_when_negated
62
71
  def failure_message_when_negated
63
- message = "expected #{@actual} not to respond to #{@expected.inspect}"
64
- message << " with value #{@value.inspect}" if @value_set
72
+ message = "expected #{@actual} not to respond to :#{@expected}"
73
+ message << " and return #{value_to_string}" if @value_set
65
74
  message
66
75
  end # method failure_message
67
76
  end # class