phillumeny 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 53f0a80e90261ef7bd81c063c905b8cd84e95cdb
4
- data.tar.gz: bb55c8e0eb57052af2bf0dec1cc6c6666c98fcf0
2
+ SHA256:
3
+ metadata.gz: 8403edeb95537840758d0411c34a4cb4eac959f3ae89498309a1c3faf62c7b59
4
+ data.tar.gz: cdddf19e194bdf21d13f8beaaf58f5e8185986cd443b5867381033c4c872edcb
5
5
  SHA512:
6
- metadata.gz: 8abac74f92990787081850397babe4fecfeeaaf1302186ce0ee64f1c006aca43dcf4e2ddb9f81c1e3504a4f541188becb47e724718139f6524bb5d2514d40f59
7
- data.tar.gz: cf740b8212962b00295acb35ae679b2a0a9654b5be2e5064c89021e5d256b064d4eb981502c32f60c990095853f543db425f5cef8dc235a9e6c7922aa7a395ee
6
+ metadata.gz: 31e35ad66e92c1618c210c2a3a26a5d5a6f14b136c31179314e0b990d132c40163943ba0a1f213fc9e5989d9d5eabf8f6a7a8d8d3b8f7834a168d418d73f803e
7
+ data.tar.gz: 37a789b49915fb23ce58f7cf4ee1863226eada76cbef064b173440bac967e9cca55864519aef919345144dd5b78ae6296a93e27de0b860c65c281795e750a78c
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Phillumeny
4
+
5
+ # Matchers testing ActiveModel functionality
6
+ module ActiveModel
7
+
8
+ def validate_presence_of_any(*args)
9
+ ValidatePresenceOfAny.new(args)
10
+ end
11
+
12
+ # Used for testing conditional validation of presence where you need one of the other
13
+ #
14
+ # @example
15
+ #
16
+ # class Webpage
17
+ #
18
+ # include ActiveModel::Validations
19
+ #
20
+ # attr_accessor :body
21
+ # attr_accessor :headline
22
+ # attr_accessor :title
23
+ #
24
+ # validates :body,
25
+ # presence: true
26
+ #
27
+ # validates :headline,
28
+ # presence: true,
29
+ # unless: -> { title.present? }
30
+ #
31
+ # validates :title,
32
+ # presence: true,
33
+ # inclusion: { allow_blank: true, in: ['this'] },
34
+ # unless: -> { headline.present? && headline != 'needs title' }
35
+ #
36
+ # end
37
+ #
38
+ # RSpec.describe Webpage, type: :model do
39
+ #
40
+ # it { should validate_presence_of_any(:headline, :title).valid_values(title: 'this') }
41
+ # it { should_not validate_presence_of_any(:headline, :title) }
42
+ # it { should_not validate_presence_of_any(:headline, :title).valid_value(:title, 'that') }
43
+ #
44
+ # end
45
+ class ValidatePresenceOfAny
46
+
47
+ attr_reader :attributes
48
+ attr_reader :subject
49
+
50
+ # Description used when matcher is used
51
+ #
52
+ # @api private
53
+ #
54
+ # @return [String]
55
+ def description
56
+ "validate the presence of any of these attributes: #{attributes.join(', ')}"
57
+ end
58
+
59
+ # Compiles the error message for display
60
+ #
61
+ # @api private
62
+ #
63
+ # @return [String]
64
+ def failure_message
65
+ messages = [subject.inspect]
66
+ attributes.each do |attribute|
67
+ messages << subject.errors.full_messages_for(attribute)
68
+ end
69
+ messages.compact.join("\n")
70
+ end
71
+
72
+ # Sets up arguments for the matcher
73
+ #
74
+ # @api private
75
+ #
76
+ # @return [void]
77
+ def initialize(args)
78
+ @attributes = args
79
+ end
80
+
81
+ # Runs the logic to determine if expectations are being met
82
+ #
83
+ # @api private
84
+ #
85
+ # @return [Boolean]
86
+ def matches?(subject)
87
+ @subject = subject
88
+ store_initial_values
89
+ invalid_when_none_present? && attributes.all? do |attribute|
90
+ clear_attributes_and_errors
91
+ initialize_value(attribute)
92
+ free_of_errors_on_attribute?(attribute) ? other_attributes_valid?(attribute) : false
93
+ end
94
+ end
95
+
96
+ # Explicitly set the value to test for an attribute if 'X' is not acceptable
97
+ #
98
+ # @api public
99
+ #
100
+ # @example
101
+ # it { should validate_presence_of_any(:headline, :title).valid_value(:title, 'A valid title') }
102
+ #
103
+ # @return [self]
104
+ def valid_value(attribute, value)
105
+ attribute_values[attribute] = value
106
+ self
107
+ end
108
+
109
+ # Explicitly set the value to test for an attribute if 'X' is not acceptable
110
+ #
111
+ # @api public
112
+ #
113
+ # @example
114
+ # it do
115
+ # should validate_presence_of_any(:headline, :title).valid_values(title: 'A valid title')
116
+ # end
117
+ #
118
+ # @return [self]
119
+ def valid_values(**values)
120
+ attribute_values.merge!(values)
121
+ self
122
+ end
123
+
124
+ private
125
+
126
+ # Storage for our initial and valid values for the attributes we are testing against
127
+ #
128
+ # @api private
129
+ #
130
+ # @return [Hash]
131
+ def attribute_values
132
+ @attribute_values ||= {}
133
+ end
134
+
135
+ # Clears all of the attributes that we are testing against
136
+ #
137
+ # @api private
138
+ #
139
+ # @return [void]
140
+ def clear_attributes_and_errors
141
+ attributes.each do |attribute|
142
+ subject.send("#{attribute}=", nil)
143
+ end
144
+ subject.errors.clear
145
+ end
146
+
147
+ # Checks that the current attribute we are checking against passes its other validations
148
+ #
149
+ # @api private
150
+ #
151
+ # @return [Boolean]
152
+ def free_of_errors_on_attribute?(attribute)
153
+ subject.class.validators_on(attribute).each do |validator|
154
+ # Can/do we use self[attribute] here or would that be better used in the
155
+ # conditional Proc on the validation itself?
156
+ validator.validate_each(subject, attribute, subject.send(attribute))
157
+ end
158
+ subject.errors[attribute].empty?
159
+ end
160
+
161
+ # Sets the value of the attribute that we currently testing against
162
+ #
163
+ # @api private
164
+ #
165
+ # @return [void]
166
+ def initialize_value(attribute)
167
+ subject.send("#{attribute}=", attribute_values[attribute] || 'X')
168
+ end
169
+
170
+ def invalid_when_none_present?
171
+ clear_attributes_and_errors
172
+ !subject.valid? && attributes.all? { |attribute| subject.errors[attribute].present? }
173
+ end
174
+
175
+ # Checks that the other attributes that we are checking against are valid as promised
176
+ #
177
+ # @api private
178
+ #
179
+ # @return [Boolean]
180
+ def other_attributes_valid?(exclude_attribute)
181
+ subject.valid?
182
+ (attributes - [exclude_attribute]).all? do |attribute|
183
+ subject.errors[attribute].empty?
184
+ end
185
+ end
186
+
187
+ # Store the initial values of our subject before we start messing around with it
188
+ #
189
+ # @api private
190
+ #
191
+ # @return [void]
192
+ def store_initial_values
193
+ attributes.each do |attribute|
194
+ next if attribute_values.key?(attribute)
195
+ attribute_values[attribute] = subject.send(attribute)
196
+ end
197
+ end
198
+
199
+ end
200
+
201
+ end
202
+
203
+ end
@@ -19,9 +19,7 @@ module Phillumeny
19
19
  class HaveAValidFactory
20
20
 
21
21
  def description
22
- msg = "have a valid factory '#{@name}'"
23
- msg << " with the trait '#{@trait}'" if @trait
24
- msg
22
+ "have a valid factory '#{@name}'#{"with the trait '#{@trait}'" if @trait}"
25
23
  end
26
24
 
27
25
  def failure_message
@@ -7,7 +7,7 @@ module Phillumeny
7
7
  module Version
8
8
 
9
9
  MAJOR = 0
10
- MINOR = 1
10
+ MINOR = 2
11
11
  PATCH = 0
12
12
  PRERELEASE = nil
13
13
  # PRERELEASE = 'alpha'.freeze
data/lib/phillumeny.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'phillumeny/version'
4
4
 
5
+ require 'phillumeny/active_model'
5
6
  require 'phillumeny/factory_bot'
6
7
 
7
8
  # Phillumeny is a collection of RSpec matchers for verbose testers that I use to fills some of the gaps
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: phillumeny
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Deering
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-30 00:00:00.000000000 Z
11
+ date: 2018-02-25 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: rspec
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -32,6 +46,7 @@ extensions: []
32
46
  extra_rdoc_files: []
33
47
  files:
34
48
  - lib/phillumeny.rb
49
+ - lib/phillumeny/active_model.rb
35
50
  - lib/phillumeny/factory_bot.rb
36
51
  - lib/phillumeny/version.rb
37
52
  homepage: https://github.com/mdeering/phillumeny
@@ -53,7 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
53
68
  version: '0'
54
69
  requirements: []
55
70
  rubyforge_project:
56
- rubygems_version: 2.6.14
71
+ rubygems_version: 2.7.5
57
72
  signing_key:
58
73
  specification_version: 4
59
74
  summary: Collection of RSpec matchers for verbose testers.