form_input 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/LICENSE +1 -1
- data/README.md +27 -12
- data/form_input.gemspec +1 -1
- data/lib/form_input/core.rb +30 -7
- data/lib/form_input/steps.rb +4 -4
- data/lib/form_input/version.rb +1 -1
- data/test/helper.rb +5 -6
- data/test/test_core.rb +62 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d7eb22ab0a9fbdbf797fd70548c4caed7201b4e7
|
4
|
+
data.tar.gz: d8fd5dbc4f0e7a10238aedddb889c37163e419f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d8ccd8693068596ca26d4d6b15ddfbd5434b558062de2371a154c1b5e562712792065ba4ec32bc937bcd4870cac1a4f4bab4e428409f02d75303d8707c9e9ad
|
7
|
+
data.tar.gz: 7df1a5feca9a80307e1f1fbeb6f5a1e840775743cf96136a45e723a7cd434117563b297d57264cb5169dab8534cc125ea5af3a0009a99cb6123d4e7ce4024946
|
data/CHANGELOG.md
ADDED
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -171,7 +171,7 @@ The following two declarations are therefore the same:
|
|
171
171
|
```
|
172
172
|
|
173
173
|
Parameters support many more parameter options,
|
174
|
-
and we will discuss each in turn as we go.
|
174
|
+
and we will discuss each one in turn as we go.
|
175
175
|
Comprehensive summary for an avid reader is however available in [Parameter Options](#parameter-options).
|
176
176
|
|
177
177
|
The value of each parameter is a string by default (or `nil` if the parameter is not set at all).
|
@@ -643,6 +643,10 @@ The advantage of the `:test` callback is that it works the same way regardless o
|
|
643
643
|
scalar or not,
|
644
644
|
so it is preferable to use it
|
645
645
|
if you plan to factor this into a `COUNTRY_ARGS` helper which works with both kinds of parameters.
|
646
|
+
If you do this,
|
647
|
+
you should also know that each parameter can support multiple `:check` and `:test` callbacks,
|
648
|
+
and when the parameter options are merged together, all of them are preserved by default
|
649
|
+
(unless you set it to `nil`, which resets all previously defined ones).
|
646
650
|
|
647
651
|
In either case, the `report` method is used to report any problems about the parameter,
|
648
652
|
which marks the parameter as invalid at the same time.
|
@@ -951,14 +955,22 @@ and let them report any belated additional errors which might get detected durin
|
|
951
955
|
for example:
|
952
956
|
|
953
957
|
``` ruby
|
954
|
-
form.report( :email, "Email is already taken" ) unless unique_email?( form.email )
|
958
|
+
form.report( :email, "Email address is already taken" ) unless unique_email?( form.email )
|
955
959
|
```
|
956
960
|
|
957
|
-
|
961
|
+
If you want the error message to have priority over anything else what might have been reported before,
|
962
|
+
you can use the `report!` method instead:
|
963
|
+
|
964
|
+
``` ruby
|
965
|
+
form.filled_params.each{ |p| p.report!( "Fill only one of these" ) } unless form.filled_params.one?
|
966
|
+
```
|
967
|
+
|
968
|
+
As we have already seen [before](#array-and-hash-parameters), it is common to use the `report`
|
958
969
|
method from within the `:check` or `:test` callback of the parameter itself as well:
|
959
970
|
|
960
971
|
``` ruby
|
961
|
-
check: ->{ report( "%p is
|
972
|
+
check: ->{ report( "%p is odd number" ) unless value.to_i.even? }
|
973
|
+
test: ->( value ){ report( "%p contain odd number" ) unless value.to_i.even? }
|
962
974
|
```
|
963
975
|
|
964
976
|
In this case the `%p` string is replaced by the `title` of the parameter.
|
@@ -1119,13 +1131,17 @@ so you can get back to it using the `form` method if you need to:
|
|
1119
1131
|
fail unless p.form.valid?
|
1120
1132
|
```
|
1121
1133
|
|
1122
|
-
As we have seen, you can report errors about the parameter using its `report`
|
1134
|
+
As we have seen, you can report errors about the parameter using its `report` or `report!` methods.
|
1123
1135
|
You can ask it about all its errors or just the first error using the `errors` or `error` methods, respectively:
|
1124
1136
|
|
1125
1137
|
``` ruby
|
1126
1138
|
p.report( "This is invalid" )
|
1127
1139
|
p.errors # [ "This is invalid" ]
|
1128
1140
|
p.error # "This is invalid"
|
1141
|
+
|
1142
|
+
p.report!( "Do not fill this!" )
|
1143
|
+
p.errors # [ "Do not fill this!", "This is invalid" ]
|
1144
|
+
p.error # "Do not fill this!"
|
1129
1145
|
```
|
1130
1146
|
|
1131
1147
|
You can also simply ask whether the parameter is valid or not by using the `valid?` and `invalid?` methods.
|
@@ -1398,7 +1414,7 @@ you will eventually want to extend it further to better fit your project.
|
|
1398
1414
|
To do this, it's common to define the `Form` class inherited from `FormInput`,
|
1399
1415
|
put various helpers there, and base your own forms on that.
|
1400
1416
|
This is also the place where you can include your own `FormInput` types extensions.
|
1401
|
-
This chapter shows some ideas you may want to
|
1417
|
+
This chapter shows some ideas you may want to build upon to get you started.
|
1402
1418
|
|
1403
1419
|
Adding custom boolean getters which you may need:
|
1404
1420
|
|
@@ -1488,9 +1504,9 @@ This is a brief but comprehensive summary of all parameter options:
|
|
1488
1504
|
See [Output Format](#output-format).
|
1489
1505
|
* `:class` - object type (or array thereof) which the input filter is expected to convert the input value into.
|
1490
1506
|
See [Input Filter](#input-filter).
|
1491
|
-
* `:check` - optional callback used to perform arbitrary checks when testing the parameter validity.
|
1507
|
+
* `:check` - optional callback (or array thereof) used to perform arbitrary checks when testing the parameter validity.
|
1492
1508
|
See [Errors and Validation](#errors-and-validation).
|
1493
|
-
* `:test` - optional callback used to perform arbitrary tests when testing validity of each parameter value.
|
1509
|
+
* `:test` - optional callback (or array thereof) used to perform arbitrary tests when testing validity of each parameter value.
|
1494
1510
|
See [Errors and Validation](#errors-and-validation).
|
1495
1511
|
* `:min_key` - minimum allowed value for keys of hash parameters. Defaults to 0.
|
1496
1512
|
* `:max_key` - maximum allowed value for keys of hash parameters. Defaults to 2<sup>64</sup>-1.
|
@@ -1554,8 +1570,7 @@ For example, this is a `snippet` helper based on [Sinatra]'s partials:
|
|
1554
1570
|
|
1555
1571
|
``` ruby
|
1556
1572
|
# Render partial, our style.
|
1557
|
-
def snippet( name, opts = {}, locals
|
1558
|
-
opts, locals = {}, opts unless locals
|
1573
|
+
def snippet( name, opts = {}, **locals )
|
1559
1574
|
partial( "snippets/#{name}", opts.merge( locals: locals ) )
|
1560
1575
|
end
|
1561
1576
|
```
|
@@ -2683,7 +2698,7 @@ you can override it by setting the `:plural` parameter option to `true` or `'p'`
|
|
2683
2698
|
and to `false` or `'s'` for singular, respectively:
|
2684
2699
|
|
2685
2700
|
``` ruby
|
2686
|
-
param :keywords, "Keywords, plural: true
|
2701
|
+
param :keywords, "Keywords", plural: true
|
2687
2702
|
array :countries, "List of countries", plural: false
|
2688
2703
|
```
|
2689
2704
|
|
@@ -2959,7 +2974,7 @@ might look like:
|
|
2959
2974
|
|
2960
2975
|
The `pt` method is usable only in the parameter context.
|
2961
2976
|
It works similar to the `ft` method,
|
2962
|
-
except that all translations are automatically looked up in the parameter's own
|
2977
|
+
except that all translations are automatically looked up in the parameter's own `forms.<form_translation_name>.<parameter_name>` namespace,
|
2963
2978
|
rather than the global namespace.
|
2964
2979
|
|
2965
2980
|
``` ruby
|
data/form_input.gemspec
CHANGED
@@ -21,7 +21,7 @@ EOT
|
|
21
21
|
s.homepage = 'https://github.com/raxoft/form_input'
|
22
22
|
s.license = 'MIT'
|
23
23
|
|
24
|
-
s.files = %w[ LICENSE README.md Rakefile .yardopts form_input.gemspec ] + Dir[ '{lib,test,example}/**/*.{rb,yml,txt,slim}' ]
|
24
|
+
s.files = %w[ LICENSE README.md CHANGELOG.md Rakefile .yardopts form_input.gemspec ] + Dir[ '{lib,test,example}/**/*.{rb,yml,txt,slim}' ]
|
25
25
|
|
26
26
|
s.required_ruby_version = '>= 2.0.0'
|
27
27
|
s.add_runtime_dependency 'rack', '>= 1.5', '< 3.0'
|
data/lib/form_input/core.rb
CHANGED
@@ -49,6 +49,9 @@ class FormInput
|
|
49
49
|
match_msg: "%p like this is not valid",
|
50
50
|
}
|
51
51
|
|
52
|
+
# Parameter options which can be merged together into an array when multiple option hashes are merged.
|
53
|
+
MERGEABLE_OPTIONS = [ :check, :test ]
|
54
|
+
|
52
55
|
# Form parameter.
|
53
56
|
class Parameter
|
54
57
|
|
@@ -336,12 +339,22 @@ class FormInput
|
|
336
339
|
|
337
340
|
# Report an error concerning this parameter.
|
338
341
|
# String %p in the message is automatically replaced with error title.
|
342
|
+
# In case of multiple errors, the message is added to the end of the list, making it less important than the other errors.
|
339
343
|
# Returns self for chaining.
|
340
344
|
def report( msg, *args )
|
341
345
|
form.report( name, format_error_message( msg, *args ) ) if form
|
342
346
|
self
|
343
347
|
end
|
344
348
|
|
349
|
+
# Report an error concerning this parameter.
|
350
|
+
# String %p in the message is automatically replaced with error title.
|
351
|
+
# In case of multiple errors, the message is added to the beginning of the list, making it more important than the other errors.
|
352
|
+
# Returns self for chaining.
|
353
|
+
def report!( msg, *args )
|
354
|
+
form.report!( name, format_error_message( msg, *args ) ) if form
|
355
|
+
self
|
356
|
+
end
|
357
|
+
|
345
358
|
end
|
346
359
|
|
347
360
|
include LocaleMethods
|
@@ -373,10 +386,10 @@ class FormInput
|
|
373
386
|
validate_value( value )
|
374
387
|
end
|
375
388
|
|
376
|
-
# Finally, invoke the custom check
|
389
|
+
# Finally, invoke the custom check callbacks if there are any.
|
377
390
|
|
378
|
-
if
|
379
|
-
instance_exec( &
|
391
|
+
if checks = opts[ :check ]
|
392
|
+
[ *checks ].each{ |x| instance_exec( &x ) }
|
380
393
|
end
|
381
394
|
end
|
382
395
|
|
@@ -512,10 +525,10 @@ class FormInput
|
|
512
525
|
return
|
513
526
|
end
|
514
527
|
|
515
|
-
# Finally, invoke the custom
|
528
|
+
# Finally, invoke the custom callbacks if there are any.
|
516
529
|
|
517
|
-
if
|
518
|
-
instance_exec( value, &
|
530
|
+
if tests = opts[ :test ]
|
531
|
+
[ *tests ].each{ |x| instance_exec( value, &x ) }
|
519
532
|
return unless valid?
|
520
533
|
end
|
521
534
|
|
@@ -662,7 +675,7 @@ class FormInput
|
|
662
675
|
size = args.shift if args.first.is_a? Numeric
|
663
676
|
|
664
677
|
opts = {}
|
665
|
-
opts.merge!( args.shift ) while args.first.is_a? Hash
|
678
|
+
opts.merge!( args.shift ){ |k, o, n| ( n && MERGEABLE_OPTIONS.include?( k ) ) ? [ *o, *n ] : n } while args.first.is_a? Hash
|
666
679
|
|
667
680
|
fail ArgumentError, "invalid arguments #{args}" unless args.empty?
|
668
681
|
|
@@ -1099,6 +1112,7 @@ class FormInput
|
|
1099
1112
|
end
|
1100
1113
|
|
1101
1114
|
# Remember error concerning given parameter.
|
1115
|
+
# In case of multiple errors, the message is added to the end of the list, making it less important than the other errors.
|
1102
1116
|
# Returns self for chaining.
|
1103
1117
|
def report( name, msg )
|
1104
1118
|
validate?
|
@@ -1106,6 +1120,15 @@ class FormInput
|
|
1106
1120
|
self
|
1107
1121
|
end
|
1108
1122
|
|
1123
|
+
# Remember error concerning given parameter.
|
1124
|
+
# In case of multiple errors, the message is added to the beginning of the list, making it more important than the other errors.
|
1125
|
+
# Returns self for chaining.
|
1126
|
+
def report!( name, msg )
|
1127
|
+
validate?
|
1128
|
+
( @errors[ name ] ||= [] ).unshift( msg.to_s.dup.freeze )
|
1129
|
+
self
|
1130
|
+
end
|
1131
|
+
|
1109
1132
|
# Get list of errors for given parameter. Returns empty list if there were no errors.
|
1110
1133
|
def errors_for( name )
|
1111
1134
|
errors[ name ] || []
|
data/lib/form_input/steps.rb
CHANGED
@@ -338,22 +338,22 @@ class FormInput
|
|
338
338
|
finished_step?( step ) and incorrect_step?( step )
|
339
339
|
end
|
340
340
|
|
341
|
-
# Get steps which
|
341
|
+
# Get steps which shall be displayed as correct.
|
342
342
|
def good_steps
|
343
343
|
steps.select{ |step| good_step?( step ) }
|
344
344
|
end
|
345
345
|
|
346
|
-
# Get steps which
|
346
|
+
# Get steps which shall be displayed as incorrect.
|
347
347
|
def bad_steps
|
348
348
|
steps.select{ |step| bad_step?( step ) }
|
349
349
|
end
|
350
350
|
|
351
|
-
# Test if given/current step
|
351
|
+
# Test if given/current step shall be displayed as correct.
|
352
352
|
def good_step?( step = self.step )
|
353
353
|
complete_step?( step ) and filled_step?( step ) and regular_step?( step )
|
354
354
|
end
|
355
355
|
|
356
|
-
# Test if given/current step
|
356
|
+
# Test if given/current step shall be displayed as incorrect.
|
357
357
|
def bad_step?( step = self.step )
|
358
358
|
incomplete_step?( step )
|
359
359
|
end
|
data/lib/form_input/version.rb
CHANGED
data/test/helper.rb
CHANGED
@@ -6,16 +6,15 @@ def jruby?
|
|
6
6
|
defined?( RUBY_ENGINE ) and RUBY_ENGINE == 'jruby'
|
7
7
|
end
|
8
8
|
|
9
|
-
if ENV[ 'COVERAGE' ]
|
10
|
-
require 'simplecov'
|
11
|
-
SimpleCov.start
|
12
|
-
end
|
13
|
-
|
14
9
|
begin
|
15
10
|
require 'codeclimate-test-reporter'
|
16
|
-
CodeClimate::TestReporter.start
|
17
11
|
ENV[ 'COVERAGE' ] = 'on'
|
18
12
|
rescue LoadError
|
19
13
|
end unless jruby?
|
20
14
|
|
15
|
+
if ENV[ 'COVERAGE' ]
|
16
|
+
require 'simplecov'
|
17
|
+
SimpleCov.start
|
18
|
+
end
|
19
|
+
|
21
20
|
# EOF #
|
data/test/test_core.rb
CHANGED
@@ -380,6 +380,55 @@ describe FormInput do
|
|
380
380
|
f.error_messages.should == [ "s may have at most 5 characters" ]
|
381
381
|
end
|
382
382
|
|
383
|
+
should 'support reasonable option merging' do
|
384
|
+
c = Class.new( FormInput )
|
385
|
+
c.param :p, { max_size: 2 }, { min_size: 2, max_size: 3 }, { max_size: 4 }
|
386
|
+
c[ :p ][ :min_size ].should == 2
|
387
|
+
c[ :p ][ :max_size ].should == 4
|
388
|
+
|
389
|
+
c = Class.new( FormInput )
|
390
|
+
c.param :p, { tag: :foo }, { tag: :bar }, { tags: [ :x, :y ] }
|
391
|
+
c.param :q, { tag: :foo }, { tag: :bar }, { tag: nil }, { tags: [ :x, :y ] }
|
392
|
+
c.param :r, { tag: :foo }, { tag: :bar }, { tags: [ :x, :y ] }, { tags: nil }
|
393
|
+
c[ :p ].tags.should == [ :bar, :x, :y ]
|
394
|
+
c[ :q ].tags.should == [ :x, :y ]
|
395
|
+
c[ :r ].tags.should == [ :bar ]
|
396
|
+
|
397
|
+
c = Class.new( FormInput )
|
398
|
+
c.param :p, { tags: :foo }, { tags: :bar }, { tags: [ :x, :y ] }
|
399
|
+
c.param :q, { tags: :foo }, { tags: :bar }, { tags: nil }, { tags: [ :x, :y ] }
|
400
|
+
c.param :r, { tags: :foo }, { tags: :bar }, { tags: [ :x, :y ] }, { tags: nil }
|
401
|
+
c[ :p ].tags.should == [ :x, :y ]
|
402
|
+
c[ :q ].tags.should == [ :x, :y ]
|
403
|
+
c[ :r ].tags.should == []
|
404
|
+
|
405
|
+
c = Class.new( FormInput )
|
406
|
+
c.param :p, { check: ->{ report( "A" ) } }, { check: ->{ report( "B" ) } }
|
407
|
+
c.param :q, { check: ->{ report( "A" ) } }, { check: nil }, { check: ->{ report( "B" ) } }
|
408
|
+
c.param :r, { check: ->{ report( "A" ) } }, { check: ->{ report( "B" ) } }, { check: nil }
|
409
|
+
c.new( p: "x" ).errors_for( :p ).should == [ "A", "B" ]
|
410
|
+
c.new( q: "x" ).errors_for( :q ).should == [ "B" ]
|
411
|
+
c.new( r: "x" ).errors_for( :q ).should == []
|
412
|
+
|
413
|
+
c = Class.new( FormInput )
|
414
|
+
c.param :p, { test: ->( value ){ report( "A" ) } }, { test: ->( value ){ report( "B" ) } }
|
415
|
+
c.param :q, { test: ->( value ){ report( "A" ) } }, { test: nil }, { test: ->( value ){ report( "B" ) } }
|
416
|
+
c.param :r, { test: ->( value ){ report( "A" ) } }, { test: ->( value ){ report( "B" ) } }, { test: nil }
|
417
|
+
c.new( p: "x" ).errors_for( :p ).should == [ "A", "B" ]
|
418
|
+
c.new( q: "x" ).errors_for( :q ).should == [ "B" ]
|
419
|
+
c.new( r: "x" ).errors_for( :q ).should == []
|
420
|
+
|
421
|
+
for name in [:reject, :match, :match_key]
|
422
|
+
c = Class.new( FormInput )
|
423
|
+
c.param :p, { name => /\d/ }, { name => /[A-Z]/ }
|
424
|
+
c.param :q, { name => /\d/ }, { name => nil }, { name => /[A-Z]/ }
|
425
|
+
c.param :r, { name => /\d/ }, { name => /[A-Z]/ }, { name => nil }
|
426
|
+
c[ :p ][ name ].should == /[A-Z]/
|
427
|
+
c[ :q ][ name ].should == /[A-Z]/
|
428
|
+
c[ :r ][ name ].should == nil
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
383
432
|
should 'convert to/from internal value format' do
|
384
433
|
c = Class.new( FormInput )
|
385
434
|
c.param :str
|
@@ -1224,6 +1273,19 @@ describe FormInput do
|
|
1224
1273
|
f[].errors_for( :password ).should == [ "bad" ]
|
1225
1274
|
f[].error_for( :password ).should == "bad"
|
1226
1275
|
|
1276
|
+
f = TestForm.new.report!( :query, "important" ).report( :query, "less important" )
|
1277
|
+
f.errors.should == { query: [ "important", "q is required", "less important" ] }
|
1278
|
+
f.error_messages.should == [ "important" ]
|
1279
|
+
f.errors_for( :query ).should == [ "important", "q is required", "less important" ]
|
1280
|
+
f.error_for( :query ).should == "important"
|
1281
|
+
|
1282
|
+
f = TestForm.new
|
1283
|
+
f.param( :query ).report( "less important" ).report!( "important" )
|
1284
|
+
f.errors.should == { query: [ "important", "q is required", "less important" ] }
|
1285
|
+
f.error_messages.should == [ "important" ]
|
1286
|
+
f.errors_for( :query ).should == [ "important", "q is required", "less important" ]
|
1287
|
+
f.error_for( :query ).should == "important"
|
1288
|
+
|
1227
1289
|
f = TestForm.new
|
1228
1290
|
f.should.be.invalid
|
1229
1291
|
f.set( query: "x" ).should.be.valid
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: form_input
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrik Rak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -86,6 +86,7 @@ extensions: []
|
|
86
86
|
extra_rdoc_files: []
|
87
87
|
files:
|
88
88
|
- ".yardopts"
|
89
|
+
- CHANGELOG.md
|
89
90
|
- LICENSE
|
90
91
|
- README.md
|
91
92
|
- Rakefile
|