gourami 1.4.0 → 2.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/lib/gourami/extensions/resources.rb +102 -1
- data/lib/gourami/validations.rb +69 -10
- data/lib/gourami/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0cc34cc23b4323b885cb63b0c82cd98921e0467fac34a97fcc584550f85de29d
|
4
|
+
data.tar.gz: '0737019b3dcb2cc40567287a94f4a3bd9dc13ef3b32a28e0e140b0745cc5a29e'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb5e34109e4c24fd1394e8888acee9d2a0ff99542fb9aadd9072f6e81ca9c7cb65f05d65ba7dfb505ea3ba520f803a9eceeaebd2b0fc2260bae740ce7ea60246
|
7
|
+
data.tar.gz: 55a3dffab397480607dfa1bb0edbee3b5d17a52c859e855423aec56b349a1a15542e47238b45c3edb5740d3c3680f0e363767da40e0edf7f93835c9f884f1b72
|
@@ -2,6 +2,107 @@ module Gourami
|
|
2
2
|
module Extensions
|
3
3
|
module Resources
|
4
4
|
|
5
|
+
# yield to the given block for each resource in the given namespace.
|
6
|
+
#
|
7
|
+
# @param resource_namespace [Symbol] The namespace of the resource (e.g. :users, :payments)
|
8
|
+
#
|
9
|
+
# @option offset [Integer] The offset of the resource (e.g. 0, 1, 2) for example in an update form, there may be existing items that already exist, however only the new items are sent to the form.
|
10
|
+
#
|
11
|
+
# @yield The block to execute, each time with a resource active.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# def validate
|
15
|
+
# with_each_resource(:social_broadcasts) do
|
16
|
+
# validate_presence(:title) # validates `attributes[:social_broadcasts][<EACH>][:title]`
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @example
|
21
|
+
# def validate
|
22
|
+
# with_each_resource(:items, offset: existing_items.count) do |item, key, index|
|
23
|
+
# # Standard validation methods are available, and will validate the attributes on the resource:
|
24
|
+
# validate_decimal_places(:price, max: 2)
|
25
|
+
#
|
26
|
+
# # You may reference the resource object directly to perform custom validation logic inline:
|
27
|
+
# append_error(:password_confirmation, :doesnt_match) if item["password"] != item["password_confirmation"]
|
28
|
+
#
|
29
|
+
# # If `items` is a Hash, `key` is the hash key of the resource.
|
30
|
+
# # If `items` is an Array, `key` is the index of the resource (`+ offset`, if an offset is given).
|
31
|
+
# validate_length(:name, max: 255) if key % 2 == 0
|
32
|
+
#
|
33
|
+
# # If `items` is a Hash, `index` is the hash key of the resource.
|
34
|
+
# # If `items` is an Array, `index` is the index of the resource (offset is NOT applied to index).
|
35
|
+
# append_error(:id, :is_invalid) if index > 500
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
def with_each_resource(resource_namespace, offset: nil, &_block)
|
39
|
+
resources = send(resource_namespace)
|
40
|
+
if resources.is_a?(Hash)
|
41
|
+
return resources.each_with_index do |(key, resource), index|
|
42
|
+
with_resource(resource_namespace, key, offset: offset) do
|
43
|
+
yield(resource, key, index)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
send(resource_namespace).each_with_index do |resource, index|
|
49
|
+
with_resource(resource_namespace, index, offset: offset) do
|
50
|
+
yield(resource, offset ? index + offset : index, index)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# For the duration of the given block, all validations will be done on the given resource.
|
56
|
+
#
|
57
|
+
# @param resource_namespace [Symbol] The namespace of the resource (e.g. :users, :payments)
|
58
|
+
# @param resource_uid [String|Number] The uid of the resource (e.g. 0, 1, "123")
|
59
|
+
#
|
60
|
+
# @option offset [Integer] The offset of the resource (e.g. 0, 1, 2) for example in an update form, there may be existing items that already exist, however only the new items are sent to the form.
|
61
|
+
#
|
62
|
+
# @yield The block to execute with the resource active.
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# def validate
|
66
|
+
# validate_presence(:title) # validates `attributes[:title]` of the form
|
67
|
+
#
|
68
|
+
# with_resource(:social_broadcasts, "facebook_page-41") do
|
69
|
+
# # Within this block all validations will be done on the resource.
|
70
|
+
# validate_presence(:title) # validates `attributes[:social_broadcasts]["facebook_page-41"][:title]`
|
71
|
+
# validate_presence(:trim_start_time) # validates `attributes[:social_broadcasts]["facebook_page-41"][:trim_start_time]`
|
72
|
+
# validate_presence(:trim_end_time) # validates `attributes[:social_broadcasts]["facebook_page-41"][:trim_end_time]`
|
73
|
+
# end
|
74
|
+
# end
|
75
|
+
def with_resource(resource_namespace, resource_uid, offset: nil, &_block)
|
76
|
+
@resource_namespace = resource_namespace
|
77
|
+
@resource_uid = resource_uid
|
78
|
+
@offset = offset
|
79
|
+
yield
|
80
|
+
ensure
|
81
|
+
@resource_namespace = nil
|
82
|
+
@resource_uid = nil
|
83
|
+
@offset = nil
|
84
|
+
end
|
85
|
+
|
86
|
+
# If a resource namespace is active (within with_resource block), find the resource using the namespace and uid.
|
87
|
+
# Otherwise, return the form object.
|
88
|
+
def current_resource
|
89
|
+
if @resource_namespace
|
90
|
+
send(@resource_namespace)[@resource_uid]
|
91
|
+
else
|
92
|
+
super
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# If a resource namespace is active (within with_resource block), append the error to the resource.
|
97
|
+
# Otherwise, append the error to the form object.
|
98
|
+
def append_error(attribute_name, message)
|
99
|
+
if @resource_namespace
|
100
|
+
append_resource_error(@resource_namespace, @offset ? @resource_uid + @offset : @resource_uid, attribute_name, message)
|
101
|
+
else
|
102
|
+
super
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
5
106
|
# Return a deeply nested Hash which allows you to identify errors by resource.
|
6
107
|
#
|
7
108
|
# @return [Hash<Symbol>]
|
@@ -56,7 +157,7 @@ module Gourami
|
|
56
157
|
|
57
158
|
# TODO: YARD
|
58
159
|
def resource_has_errors?(resource_namespace, resource_uid)
|
59
|
-
resource_errors[resource_namespace
|
160
|
+
resource_errors[resource_namespace][resource_uid.to_s].values.map(&:flatten).any?
|
60
161
|
end
|
61
162
|
|
62
163
|
# TODO: YARD
|
data/lib/gourami/validations.rb
CHANGED
@@ -85,16 +85,45 @@ module Gourami
|
|
85
85
|
# @param attribute_name [Symbol, nil] nil for base
|
86
86
|
# @param error [Symbol, String]
|
87
87
|
# The error identifier.
|
88
|
-
def
|
88
|
+
def append_root_error(attribute_name, error)
|
89
89
|
errors[attribute_name] << error
|
90
90
|
end
|
91
91
|
|
92
|
+
# NOTE: The following resource methods are to support the validate_* methods
|
93
|
+
# to cooperate with resource when using Extensions::Resources.
|
94
|
+
|
95
|
+
# Overridden and super invoked from Extensions::Resources
|
96
|
+
def current_resource
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
# Overridden and super invoked from Extensions::Resources
|
101
|
+
def append_error(attribute_name, message)
|
102
|
+
append_root_error(attribute_name, message)
|
103
|
+
end
|
104
|
+
|
105
|
+
def get_current_resource_attribute_value(attribute_name)
|
106
|
+
resource = current_resource
|
107
|
+
# If resource responds to the attribute, return the value. Otherwise, check if it's a hash and return the value for the attribute.
|
108
|
+
if resource.respond_to?(attribute_name)
|
109
|
+
resource.send(attribute_name)
|
110
|
+
elsif resource.respond_to?(:[])
|
111
|
+
if resource.key?(attribute_name.to_sym)
|
112
|
+
resource[attribute_name.to_sym]
|
113
|
+
elsif resource.key?(attribute_name.to_s)
|
114
|
+
resource[attribute_name.to_s]
|
115
|
+
end
|
116
|
+
else
|
117
|
+
nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
92
121
|
# Validate the presence of the attribute value. If the value is nil or
|
93
122
|
# false append the :cant_be_empty error to the attribute.
|
94
123
|
#
|
95
124
|
# @param attribute_name [Symbol]
|
96
125
|
def validate_presence(attribute_name, message = nil)
|
97
|
-
value =
|
126
|
+
value = get_current_resource_attribute_value(attribute_name)
|
98
127
|
if !value || value.to_s.strip.empty?
|
99
128
|
append_error(attribute_name, message || :cant_be_empty)
|
100
129
|
end
|
@@ -109,7 +138,7 @@ module Gourami
|
|
109
138
|
# A block to determine if a given value is unique or not. It receives
|
110
139
|
# the value and returns true if the value is unique.
|
111
140
|
def validate_uniqueness(attribute_name, message = nil, &block)
|
112
|
-
value =
|
141
|
+
value = get_current_resource_attribute_value(attribute_name)
|
113
142
|
unless block.call(value)
|
114
143
|
append_error(attribute_name, message || :is_duplicated)
|
115
144
|
end
|
@@ -137,7 +166,7 @@ module Gourami
|
|
137
166
|
# @param attribute_name [Symbol]
|
138
167
|
# @param format [Regexp]
|
139
168
|
def validate_format(attribute_name, format, message = nil)
|
140
|
-
value =
|
169
|
+
value = get_current_resource_attribute_value(attribute_name)
|
141
170
|
if value && !(format =~ value)
|
142
171
|
append_error(attribute_name, message || :is_invalid)
|
143
172
|
end
|
@@ -157,7 +186,7 @@ module Gourami
|
|
157
186
|
|
158
187
|
min = options.fetch(:min, nil)
|
159
188
|
max = options.fetch(:max, nil)
|
160
|
-
value =
|
189
|
+
value = get_current_resource_attribute_value(attribute_name)
|
161
190
|
|
162
191
|
return if options[:allow_blank] && value.blank?
|
163
192
|
|
@@ -185,7 +214,7 @@ module Gourami
|
|
185
214
|
# @param attribute_name [Symbol]
|
186
215
|
# @param list [Array]
|
187
216
|
def validate_inclusion(attribute_name, list, message = nil)
|
188
|
-
value =
|
217
|
+
value = get_current_resource_attribute_value(attribute_name)
|
189
218
|
if value && !list.include?(value)
|
190
219
|
append_error(attribute_name, message || :isnt_listed)
|
191
220
|
end
|
@@ -194,7 +223,7 @@ module Gourami
|
|
194
223
|
# Validate the presence of each object in attribute name within list. If the object
|
195
224
|
# is not included in the list, append the :not_listed error to the attribute.
|
196
225
|
def validate_inclusion_of_each(attribute_name, list, message = nil)
|
197
|
-
value =
|
226
|
+
value = get_current_resource_attribute_value(attribute_name)
|
198
227
|
value && value.each do |obj|
|
199
228
|
unless list.include?(obj)
|
200
229
|
append_error(attribute_name, message || "#{obj} isn't listed")
|
@@ -208,7 +237,7 @@ module Gourami
|
|
208
237
|
#
|
209
238
|
# @param attribute_name [Symbol]
|
210
239
|
def validate_any(attribute_name, message = nil)
|
211
|
-
value =
|
240
|
+
value = get_current_resource_attribute_value(attribute_name)
|
212
241
|
if value && value.empty?
|
213
242
|
append_error(attribute_name, message || :cant_be_empty)
|
214
243
|
end
|
@@ -220,7 +249,7 @@ module Gourami
|
|
220
249
|
# @param attribute_name [Symbol]
|
221
250
|
# @param filetypes [Array<String>]
|
222
251
|
def validate_filetype(attribute_name, filetypes, message = nil)
|
223
|
-
value =
|
252
|
+
value = get_current_resource_attribute_value(attribute_name)
|
224
253
|
if value && !filetypes.include?(value[:type].to_s.split("/").first)
|
225
254
|
append_error(attribute_name, message || :is_invalid)
|
226
255
|
end
|
@@ -237,7 +266,7 @@ module Gourami
|
|
237
266
|
# @option options [Integer] :max (nil)
|
238
267
|
# The maximum value the attribute can take, if nil, no validation is made.
|
239
268
|
def validate_range(attribute_name, options = {})
|
240
|
-
value =
|
269
|
+
value = get_current_resource_attribute_value(attribute_name)
|
241
270
|
|
242
271
|
return unless value
|
243
272
|
|
@@ -247,5 +276,35 @@ module Gourami
|
|
247
276
|
append_error(attribute_name, options.fetch(:max_message, nil) || :greater_than_max) if max && value > max
|
248
277
|
end
|
249
278
|
|
279
|
+
# Ensure the provided numeric attribute has the correct number of decimal places within the given range.
|
280
|
+
#
|
281
|
+
# @param attribute_name [Symbol]
|
282
|
+
# @option options [Integer] :max (nil)
|
283
|
+
# The maximum number of decimal places the attribute can have.
|
284
|
+
# @option options [Integer] :min (0)
|
285
|
+
# The minimum number of decimal places the attribute can have.
|
286
|
+
# @option options [String] :max_message (nil)
|
287
|
+
# The error message to append if the attribute has too many decimal places.
|
288
|
+
# @option options [String] :min_message (nil)
|
289
|
+
# The error message to append if the attribute has too few decimal places.
|
290
|
+
#
|
291
|
+
# @example
|
292
|
+
# validate_decimal_places(:price, max: 2)
|
293
|
+
# validate_decimal_places(:price, min: 2, min_message: "Price must have at least 2 decimal places.")
|
294
|
+
def validate_decimal_places(attribute_name, max:, min: 0, max_message: nil, min_message: nil)
|
295
|
+
value = get_current_resource_attribute_value(attribute_name)&.to_s
|
296
|
+
return unless value
|
297
|
+
|
298
|
+
decimal_places = value.split(".", 2).last&.length || 0
|
299
|
+
|
300
|
+
if max && max > 0 && decimal_places > max
|
301
|
+
append_error(attribute_name, max_message || :too_many_decimal_places)
|
302
|
+
end
|
303
|
+
|
304
|
+
if min && min > 0 && decimal_places < min
|
305
|
+
append_error(attribute_name, min_message || :too_few_decimal_places)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
250
309
|
end
|
251
310
|
end
|
data/lib/gourami/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gourami
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TSMMark
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|