formeze 1.3.0 → 1.4.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.
- data/README.md +16 -0
- data/formeze.gemspec +1 -1
- data/lib/formeze.rb +38 -26
- data/spec/formeze_spec.rb +19 -0
- metadata +1 -1
data/README.md
CHANGED
@@ -150,6 +150,22 @@ end
|
|
150
150
|
In this example, the `billing_address_line_one` field will only be defined
|
151
151
|
and validated if the `same_address` checkbox is checked.
|
152
152
|
|
153
|
+
Validation errors can be a frustrating experience for end users, so ideally
|
154
|
+
we want to [be liberal in what we accept](http://en.wikipedia.org/wiki/Jon_Postel#Postel.27s_Law),
|
155
|
+
but at the same time ensuring that data is consistently formatted to make it
|
156
|
+
easy for us to process. Meet the `scrub` option, which can be used to specify
|
157
|
+
methods for "cleaning" input data before validation. For example:
|
158
|
+
|
159
|
+
```ruby
|
160
|
+
field :postcode, scrub: [:strip, :squeeze, :upcase]
|
161
|
+
```
|
162
|
+
|
163
|
+
The input for this field will have leading/trailing whitespace stripped,
|
164
|
+
double (or more) spaces squeezed, and the result upcased automatically.
|
165
|
+
|
166
|
+
In order to define a custom scrub method just add a symbol/proc entry to
|
167
|
+
the `Formeze.scrub_methods` hash.
|
168
|
+
|
153
169
|
|
154
170
|
Rails usage
|
155
171
|
-----------
|
data/formeze.gemspec
CHANGED
data/lib/formeze.rb
CHANGED
@@ -18,19 +18,23 @@ module Formeze
|
|
18
18
|
@name, @options = name, options
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
def scrub(value)
|
22
|
+
Array(@options[:scrub]).inject(value) do |tmp, scrub_method|
|
23
|
+
Formeze.scrub_methods.fetch(scrub_method).call(tmp)
|
24
|
+
end
|
25
|
+
end
|
26
26
|
|
27
|
-
|
27
|
+
def validate(value)
|
28
|
+
if blank?(value)
|
29
|
+
yield error(:required, 'is required') if required?
|
30
|
+
else
|
31
|
+
yield error(:not_multiline, 'cannot contain newlines') if !multiline? && value.lines.count > 1
|
28
32
|
|
29
|
-
|
33
|
+
yield error(:too_long, 'is too long') if too_long?(value)
|
30
34
|
|
31
|
-
|
35
|
+
yield error(:no_match, 'is invalid') if no_match?(value)
|
32
36
|
|
33
|
-
|
37
|
+
yield error(:bad_value, 'is invalid') if values? && !values.include?(value)
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
@@ -47,11 +51,7 @@ module Formeze
|
|
47
51
|
end
|
48
52
|
|
49
53
|
def label
|
50
|
-
|
51
|
-
@options[:label]
|
52
|
-
else
|
53
|
-
translate(name, scope: [:formeze, :labels], default: Label.new(name))
|
54
|
-
end
|
54
|
+
@options.fetch(:label) { translate(name, scope: [:formeze, :labels], default: Label.new(name)) }
|
55
55
|
end
|
56
56
|
|
57
57
|
def required?
|
@@ -66,24 +66,24 @@ module Formeze
|
|
66
66
|
@options.fetch(:multiple) { false }
|
67
67
|
end
|
68
68
|
|
69
|
-
def
|
70
|
-
|
69
|
+
def too_long?(value)
|
70
|
+
too_many_characters?(value) || too_many_words?(value)
|
71
71
|
end
|
72
72
|
|
73
|
-
def
|
74
|
-
@options.
|
73
|
+
def too_many_characters?(value)
|
74
|
+
value.chars.count > @options.fetch(:char_limit) { 64 }
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
78
|
-
@options.
|
77
|
+
def too_many_words?(value)
|
78
|
+
@options.has_key?(:word_limit) && value.scan(/\w+/).length > @options[:word_limit]
|
79
79
|
end
|
80
80
|
|
81
|
-
def
|
82
|
-
@options.has_key?(:pattern)
|
81
|
+
def no_match?(value)
|
82
|
+
@options.has_key?(:pattern) && value !~ @options[:pattern]
|
83
83
|
end
|
84
84
|
|
85
|
-
def
|
86
|
-
|
85
|
+
def blank?(value)
|
86
|
+
value !~ /\S/
|
87
87
|
end
|
88
88
|
|
89
89
|
def values?
|
@@ -218,11 +218,13 @@ module Formeze
|
|
218
218
|
end
|
219
219
|
|
220
220
|
values.each do |value|
|
221
|
-
field.
|
221
|
+
scrubbed_value = field.scrub(value)
|
222
|
+
|
223
|
+
field.validate(scrubbed_value) do |error|
|
222
224
|
errors << UserError.new("#{field.label} #{error}")
|
223
225
|
end
|
224
226
|
|
225
|
-
send(:"#{field.name}=",
|
227
|
+
send(:"#{field.name}=", scrubbed_value)
|
226
228
|
end
|
227
229
|
end
|
228
230
|
|
@@ -252,6 +254,16 @@ module Formeze
|
|
252
254
|
end
|
253
255
|
end
|
254
256
|
|
257
|
+
def self.scrub_methods
|
258
|
+
@scrub_methods ||= {
|
259
|
+
:strip => :strip.to_proc,
|
260
|
+
:upcase => :upcase.to_proc,
|
261
|
+
:downcase => :downcase.to_proc,
|
262
|
+
:squeeze => proc { |string| string.squeeze(' ') },
|
263
|
+
:squeeze_lines => proc { |string| string.gsub(/(\r?\n)(\r?\n)(\r?\n)+/, '\\1\\2') }
|
264
|
+
}
|
265
|
+
end
|
266
|
+
|
255
267
|
def self.setup(form)
|
256
268
|
form.send :include, InstanceMethods
|
257
269
|
|
data/spec/formeze_spec.rb
CHANGED
@@ -507,3 +507,22 @@ describe 'I18n integration' do
|
|
507
507
|
form.errors.first.to_s.must_equal('TITLE is required')
|
508
508
|
end
|
509
509
|
end
|
510
|
+
|
511
|
+
class FormWithScrubbedFields
|
512
|
+
Formeze.setup(self)
|
513
|
+
|
514
|
+
field :postcode, scrub: [:strip, :squeeze, :upcase], pattern: /\A[A-Z0-9]{2,4} [A-Z0-9]{3}\z/
|
515
|
+
field :bio, scrub: [:strip, :squeeze_lines], multiline: true
|
516
|
+
end
|
517
|
+
|
518
|
+
describe 'FormWithScrubbedFields' do
|
519
|
+
describe 'parse method' do
|
520
|
+
it 'should apply the scrub methods to the input before validation' do
|
521
|
+
form = FormWithScrubbedFields.new
|
522
|
+
form.parse('postcode=++sw1a+++1aa&bio=My+name+is+Cookie+Monster.%0A%0A%0A%0AI+LOVE+COOKIES!!!!%0A%0A%0A%0A')
|
523
|
+
form.postcode.must_equal('SW1A 1AA')
|
524
|
+
form.bio.count(?\n).must_equal(2)
|
525
|
+
form.valid?.must_equal(true)
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|