form_input 1.2.0 → 1.3.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/CHANGELOG.md +10 -3
- data/README.md +34 -12
- data/example/example.rb +97 -0
- data/lib/form_input/core.rb +38 -14
- data/lib/form_input/version.rb +1 -1
- data/test/test_core.rb +56 -4
- data/test/test_types.rb +33 -7
- 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: c46667c81eb96ef6deeaf13501e06f6bc328b862
|
|
4
|
+
data.tar.gz: e6dc22529b1fdfead38c01c5bd2d6f5b2e1fc52a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 178de263faf14e4621298bfdee13025cd0852020178448f9370d4c27904c9a9a5bbad2c8fb250a55ee10051c370716f23b42eadeec89a4c157055aa12b444bf7
|
|
7
|
+
data.tar.gz: e62589e13773fd867abbd1bec66a66dad851bda8214968820348ac3566e612ffe48e702a93d1928b5f505c8b53b7d06591923a67969b19e1989979ec3bf2f275
|
data/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
|
+
= 1.3.0
|
|
2
|
+
|
|
3
|
+
* Further improvements for JSON payloads:
|
|
4
|
+
* Added set of methods for distinguishing between set and unset parameters.
|
|
5
|
+
* The `import` now properly handles parameters with `nil` and `false` values.
|
|
6
|
+
* The `to_data` method now returns all set parameters, regardless of their value.
|
|
7
|
+
|
|
1
8
|
= 1.2.0
|
|
2
9
|
|
|
3
10
|
* Few changes for easier import and export of JSON payloads:
|
|
4
|
-
* The import and the new from_data methods now support numeric, boolean, and nil values natively.
|
|
5
|
-
* Added to_data method which creates a hash of all non
|
|
11
|
+
* The `import` and the new `from_data` methods now support numeric, boolean, and `nil` values natively.
|
|
12
|
+
* Added `to_data` method which creates a hash of all non-`nil` parameters.
|
|
6
13
|
|
|
7
14
|
= 1.1.0
|
|
8
15
|
|
|
9
|
-
* Added report
|
|
16
|
+
* Added `report!` methods for late reporting of the most fundamental errors.
|
|
10
17
|
|
|
11
18
|
* Added support for multiple `check` and `test` validation callbacks.
|
|
12
19
|
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Form input
|
|
2
2
|
|
|
3
|
-
[](http://rubygems.org/gems/form_input) [](http://travis-ci.org/raxoft/form_input) [](http://rubygems.org/gems/form_input) [](http://travis-ci.org/raxoft/form_input) [](https://codeclimate.com/github/raxoft/form_input/maintainability) [](https://codeclimate.com/github/raxoft/form_input/test_coverage)
|
|
4
4
|
|
|
5
5
|
Form input is a gem which helps dealing with web request input and with the creation of HTML forms.
|
|
6
6
|
|
|
@@ -794,16 +794,19 @@ to include parts of the URL as the form input:
|
|
|
794
794
|
|
|
795
795
|
``` ruby
|
|
796
796
|
get '/contact/:email' do
|
|
797
|
-
form = ContactForm.new( params )
|
|
798
|
-
form = ContactForm.new.import( params )
|
|
797
|
+
form = ContactForm.new( params ) # NEVER EVER DO THIS!
|
|
798
|
+
form = ContactForm.new.import( params ) # Do this instead (or use from_params).
|
|
799
|
+
...
|
|
799
800
|
end
|
|
800
801
|
```
|
|
801
802
|
|
|
802
803
|
Similarly, you want to use `import` when feeding form input with JSON data (see [JSON Helpers](#json-helpers) for details):
|
|
803
804
|
|
|
804
805
|
``` ruby
|
|
805
|
-
post '/api/v1/
|
|
806
|
-
form = ContactForm.new
|
|
806
|
+
post '/api/v1/contacts' do
|
|
807
|
+
form = ContactForm.new( json_data ) # NEVER EVER DO THIS!
|
|
808
|
+
form = ContactForm.new.import( json_data ) # Do this instead (or use from_data).
|
|
809
|
+
...
|
|
807
810
|
end
|
|
808
811
|
```
|
|
809
812
|
|
|
@@ -829,6 +832,14 @@ You can either clear the entire form, named parameters, or parameter subsets (wh
|
|
|
829
832
|
form.clear( form.disabled_params )
|
|
830
833
|
```
|
|
831
834
|
|
|
835
|
+
The `unset` method works the same way, except that it always requires an argument:
|
|
836
|
+
|
|
837
|
+
``` ruby
|
|
838
|
+
form.unset( :message )
|
|
839
|
+
form.unset( :name, :company )
|
|
840
|
+
form.unset( form.invalid_params )
|
|
841
|
+
```
|
|
842
|
+
|
|
832
843
|
Alternatively, you can create form copies with just a subset of parameters set:
|
|
833
844
|
|
|
834
845
|
``` ruby
|
|
@@ -1165,6 +1176,9 @@ In fact, the parameter has a dozen of simple boolean getters like this which you
|
|
|
1165
1176
|
p.empty? # Is the value nil or empty?
|
|
1166
1177
|
p.filled? # Is the value neither nil nor empty?
|
|
1167
1178
|
|
|
1179
|
+
p.set? # Was the parameter value set to something?
|
|
1180
|
+
p.unset? # Was the parameter value not set to anything?
|
|
1181
|
+
|
|
1168
1182
|
p.required? # Is the parameter required?
|
|
1169
1183
|
p.optional? # Is the parameter not required?
|
|
1170
1184
|
|
|
@@ -1193,6 +1207,8 @@ The following methods are available:
|
|
|
1193
1207
|
form.blank_params # Parameters with nil, empty, or blank value.
|
|
1194
1208
|
form.empty_params # Parameters with nil or empty value.
|
|
1195
1209
|
form.filled_params # Parameters with some non-empty value.
|
|
1210
|
+
form.set_params # Parameters whose value was set to something.
|
|
1211
|
+
form.unset_params # Parameters whose value was not set to anything.
|
|
1196
1212
|
form.required_params # Parameters which are required and have to be filled.
|
|
1197
1213
|
form.optional_params # Parameters which are not required and can be nil or empty.
|
|
1198
1214
|
form.disabled_params # Parameters which are disabled and shall be rendered as such.
|
|
@@ -1349,8 +1365,9 @@ The only difference is that the [input filter](#input-filter) is not run in such
|
|
|
1349
1365
|
The [input transform](#input-transform) is run as usual,
|
|
1350
1366
|
and so are all the [validation methods](#errors-and-validation).
|
|
1351
1367
|
|
|
1352
|
-
Among other things this means that you can declare a parameter as integer using the `INTEGER_ARGS` macro
|
|
1368
|
+
Among other things this means that you can declare a parameter as integer using the `INTEGER_ARGS` macro
|
|
1353
1369
|
and pass in the value as either string or integer, and you end up with integer in both cases, which is pretty convenient.
|
|
1370
|
+
Of course, this works similarly for `FLOAT_ARGS` and `BOOL_ARGS`, too:
|
|
1354
1371
|
|
|
1355
1372
|
``` ruby
|
|
1356
1373
|
class NumericInput < FormInput
|
|
@@ -1363,10 +1380,11 @@ and pass in the value as either string or integer, and you end up with integer i
|
|
|
1363
1380
|
```
|
|
1364
1381
|
|
|
1365
1382
|
Another difference when dealing with JSON data is that
|
|
1366
|
-
the empty strings have completely different significance than in case of web forms.
|
|
1367
|
-
For this reason, the result of the `to_data` method includes
|
|
1383
|
+
the empty strings have completely different significance than in the case of the web forms.
|
|
1384
|
+
For this reason, the result of the `to_data` method includes any set parameters,
|
|
1385
|
+
even if the values are empty strings, arrays, or hashes
|
|
1368
1386
|
(unlike the `to_hash` and `to_params` methods).
|
|
1369
|
-
|
|
1387
|
+
Even the `nil` values are included for parameters which were explicitly set to `nil`:
|
|
1370
1388
|
|
|
1371
1389
|
``` ruby
|
|
1372
1390
|
class OptionalInput < FormInput
|
|
@@ -1376,6 +1394,7 @@ The `nil` values are still filtered out, though.
|
|
|
1376
1394
|
end
|
|
1377
1395
|
|
|
1378
1396
|
OptionalInput.from_data( string: '' ).to_data # { string: '' }
|
|
1397
|
+
OptionalInput.from_data( string: nil ).to_data # { string: nil }
|
|
1379
1398
|
OptionalInput.from_data( array: [] ).to_data # { array: [] }
|
|
1380
1399
|
OptionalInput.from_data( hash: {} ).to_data # { hash: {} }
|
|
1381
1400
|
```
|
|
@@ -1384,19 +1403,22 @@ The whole JSON processing may in the end look something like this:
|
|
|
1384
1403
|
|
|
1385
1404
|
``` ruby
|
|
1386
1405
|
require 'oj'
|
|
1406
|
+
|
|
1387
1407
|
def json_data
|
|
1388
|
-
data = Oj.load( request.body, symbolize_keys: true )
|
|
1408
|
+
data = Oj.load( request.body, mode: :strict, symbolize_keys: true )
|
|
1389
1409
|
halt( 422, 'Invalid data' ) unless Hash === data
|
|
1390
1410
|
data
|
|
1391
1411
|
rescue Oj::Error
|
|
1392
1412
|
halt( 422, 'Invalid JSON' )
|
|
1393
1413
|
end
|
|
1394
1414
|
|
|
1395
|
-
post '/api/v1/
|
|
1415
|
+
post '/api/v1/contacts' do
|
|
1396
1416
|
input = ContactForm.from_data( json_data )
|
|
1397
1417
|
halt( 422, "Invalid data: #{input.error_messages.first}" ) unless input.valid?
|
|
1398
1418
|
# Somehow use the input.
|
|
1399
|
-
Contact.create( input.to_data )
|
|
1419
|
+
entry = Contact.create( input.to_data )
|
|
1420
|
+
content_type :json
|
|
1421
|
+
[ 201, Oj.dump( entry.to_hash ) ]
|
|
1400
1422
|
end
|
|
1401
1423
|
```
|
|
1402
1424
|
|
data/example/example.rb
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#! /usr/bin/env ruby
|
|
2
|
+
#
|
|
3
|
+
# Simple but functional example FormInput application for Sinatra.
|
|
4
|
+
#
|
|
5
|
+
# You will need the following gems:
|
|
6
|
+
# gem install sinatra sinatra-partial slim form_input
|
|
7
|
+
#
|
|
8
|
+
# Then just run it like this:
|
|
9
|
+
# ruby example.rb
|
|
10
|
+
|
|
11
|
+
require 'sinatra'
|
|
12
|
+
require 'sinatra/partial'
|
|
13
|
+
require 'slim/smart'
|
|
14
|
+
require 'form_input'
|
|
15
|
+
|
|
16
|
+
# The example form. Feel free to experiment with changing this section to whatever you want to test.
|
|
17
|
+
|
|
18
|
+
class ExampleForm < FormInput
|
|
19
|
+
param! :email, 'Email address', EMAIL_ARGS
|
|
20
|
+
param! :name, 'Name'
|
|
21
|
+
param :company, 'Company'
|
|
22
|
+
param! :message, 'Message', 1000, type: :textarea, size: 6, filter: ->{ rstrip }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Support for snippets.
|
|
26
|
+
|
|
27
|
+
set :partial_template_engine, :slim
|
|
28
|
+
helpers do
|
|
29
|
+
def snippet( name, opts = {}, **locals )
|
|
30
|
+
partial( "snippets/#{name}", opts.merge( locals: locals ) )
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# The whole application itself.
|
|
35
|
+
|
|
36
|
+
get '/' do
|
|
37
|
+
@form = ExampleForm.new( request )
|
|
38
|
+
slim :form
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
post '/' do
|
|
42
|
+
@form = ExampleForm.new( request )
|
|
43
|
+
return slim :form unless @form.valid? and params[:action] == 'post'
|
|
44
|
+
logger.info "These data were successfully posted: #{@form.to_hash.inspect}"
|
|
45
|
+
slim :post
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Inline templates follow.
|
|
49
|
+
|
|
50
|
+
__END__
|
|
51
|
+
|
|
52
|
+
@@ layout
|
|
53
|
+
doctype html
|
|
54
|
+
html
|
|
55
|
+
head
|
|
56
|
+
title = @title
|
|
57
|
+
meta charset='utf-8'
|
|
58
|
+
meta name='viewport' content='width=device-width, initial-scale=1, shrink-to-fit=no'
|
|
59
|
+
link rel='stylesheet' href='https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css' integrity='sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu' crossorigin='anonymous'
|
|
60
|
+
css:
|
|
61
|
+
label { width: 100%; }
|
|
62
|
+
body.container == yield
|
|
63
|
+
|
|
64
|
+
@@ form
|
|
65
|
+
.panel.panel-default
|
|
66
|
+
.panel-heading
|
|
67
|
+
= @title = "Example Form"
|
|
68
|
+
.panel-body
|
|
69
|
+
form method='post' action=request.path
|
|
70
|
+
fieldset
|
|
71
|
+
== snippet :form_panel, params: @form.params
|
|
72
|
+
button.btn.btn-default type='submit' name='action' value='post' Submit
|
|
73
|
+
- unless @form.empty?
|
|
74
|
+
.panel-footer
|
|
75
|
+
== partial :dump
|
|
76
|
+
|
|
77
|
+
@@ post
|
|
78
|
+
.panel.panel-default
|
|
79
|
+
.panel-heading
|
|
80
|
+
= @title = "Congratulations!"
|
|
81
|
+
All inputs are valid.
|
|
82
|
+
.panel-body
|
|
83
|
+
== partial :dump
|
|
84
|
+
form method='post' action=request.path
|
|
85
|
+
== snippet :form_hidden, params: @form.params
|
|
86
|
+
button.btn.btn-default type='submit' Go back
|
|
87
|
+
a.btn.btn-default< href=request.path Start over
|
|
88
|
+
|
|
89
|
+
@@ dump
|
|
90
|
+
p These are the filled form values:
|
|
91
|
+
dl.dl-horizontal
|
|
92
|
+
- for p in @form.filled_params
|
|
93
|
+
dt = p.form_title
|
|
94
|
+
dd
|
|
95
|
+
code = p.value.inspect
|
|
96
|
+
|
|
97
|
+
// EOF //
|
data/lib/form_input/core.rb
CHANGED
|
@@ -162,6 +162,16 @@ class FormInput
|
|
|
162
162
|
not empty?
|
|
163
163
|
end
|
|
164
164
|
|
|
165
|
+
# Test if value of given parameter was set.
|
|
166
|
+
def set?
|
|
167
|
+
form ? form.instance_variable_defined?( "@#{name}" ) : false
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Test if value of given parameter is not set.
|
|
171
|
+
def unset?
|
|
172
|
+
not set?
|
|
173
|
+
end
|
|
174
|
+
|
|
165
175
|
# Get the proper name for use in form names, adding [] to array and [key] to hash parameters.
|
|
166
176
|
def form_name( key = nil )
|
|
167
177
|
if array?
|
|
@@ -835,8 +845,10 @@ class FormInput
|
|
|
835
845
|
# Import parameter values from given request or hash. Applies parameter input filters and transforms as well.
|
|
836
846
|
# Returns self for chaining.
|
|
837
847
|
def import( request )
|
|
848
|
+
hash = request.respond_to?( :params ) ? request.params : request.to_hash
|
|
838
849
|
for name, param in @params
|
|
839
|
-
|
|
850
|
+
value = hash.fetch( param.code ) { hash.fetch( param.code.to_s, self ) }
|
|
851
|
+
unless value == self
|
|
840
852
|
value = sanitize_value( value, param.filter )
|
|
841
853
|
if transform = param.transform
|
|
842
854
|
value = value.instance_exec( &transform )
|
|
@@ -856,12 +868,20 @@ class FormInput
|
|
|
856
868
|
self
|
|
857
869
|
end
|
|
858
870
|
|
|
871
|
+
# Unset values of given parameters. Both names and parameters are accepted.
|
|
872
|
+
# Returns self for chaining.
|
|
873
|
+
def unset( name, *names )
|
|
874
|
+
clear( name, *names )
|
|
875
|
+
end
|
|
876
|
+
|
|
859
877
|
# Clear all/given parameter values. Both names and parameters are accepted.
|
|
860
878
|
# Returns self for chaining.
|
|
861
879
|
def clear( *names )
|
|
862
880
|
names = names.empty? ? params_names : validate_names( names )
|
|
863
881
|
for name in names
|
|
882
|
+
# Set the value to nil first so it triggers anything necessary.
|
|
864
883
|
self[ name ] = nil
|
|
884
|
+
remove_instance_variable( "@#{name}" )
|
|
865
885
|
end
|
|
866
886
|
self
|
|
867
887
|
end
|
|
@@ -883,7 +903,7 @@ class FormInput
|
|
|
883
903
|
end
|
|
884
904
|
|
|
885
905
|
# Return all non-empty parameters as a hash.
|
|
886
|
-
# See also #to_data, which creates a hash of
|
|
906
|
+
# See also #to_data, which creates a hash of set parameters,
|
|
887
907
|
# and #url_params, which creates a hash suitable for url output.
|
|
888
908
|
def to_hash
|
|
889
909
|
result = {}
|
|
@@ -892,13 +912,13 @@ class FormInput
|
|
|
892
912
|
end
|
|
893
913
|
alias to_h to_hash
|
|
894
914
|
|
|
895
|
-
# Return all
|
|
915
|
+
# Return all set parameters as a hash.
|
|
896
916
|
# Note that the keys are external names of the parameters (should they differ),
|
|
897
917
|
# so the keys created by `from_data(data).to_data` remain consistent.
|
|
898
918
|
# See also #to_hash, which creates a hash of non-empty parameters.
|
|
899
919
|
def to_data
|
|
900
920
|
result = {}
|
|
901
|
-
|
|
921
|
+
set_params.each{ |x| result[ x.code ] = x.value }
|
|
902
922
|
result
|
|
903
923
|
end
|
|
904
924
|
|
|
@@ -914,11 +934,7 @@ class FormInput
|
|
|
914
934
|
|
|
915
935
|
# Create copy of itself, with given parameters unset. Both names and parameters are accepted.
|
|
916
936
|
def except( *names )
|
|
917
|
-
|
|
918
|
-
for name in validate_names( names )
|
|
919
|
-
result[ name ] = nil
|
|
920
|
-
end
|
|
921
|
-
result
|
|
937
|
+
dup.clear( names )
|
|
922
938
|
end
|
|
923
939
|
|
|
924
940
|
# Create copy of itself, with only given parameters set. Both names and parameters are accepted.
|
|
@@ -926,11 +942,7 @@ class FormInput
|
|
|
926
942
|
# It would be easier to create new instance here and only copy selected values,
|
|
927
943
|
# but we want to use dup instead of new here, as the derived form can use
|
|
928
944
|
# different parameters in its construction.
|
|
929
|
-
|
|
930
|
-
for name in params_names - validate_names( names )
|
|
931
|
-
result[ name ] = nil
|
|
932
|
-
end
|
|
933
|
-
result
|
|
945
|
+
dup.clear( params_names - validate_names( names ) )
|
|
934
946
|
end
|
|
935
947
|
|
|
936
948
|
# Parameter lists.
|
|
@@ -990,6 +1002,18 @@ class FormInput
|
|
|
990
1002
|
end
|
|
991
1003
|
alias filled_parameters filled_params
|
|
992
1004
|
|
|
1005
|
+
# Get list of parameters whose values were set.
|
|
1006
|
+
def set_params
|
|
1007
|
+
params.select{ |x| x.set? }
|
|
1008
|
+
end
|
|
1009
|
+
alias set_parameters set_params
|
|
1010
|
+
|
|
1011
|
+
# Get list of parameters whose values were not set.
|
|
1012
|
+
def unset_params
|
|
1013
|
+
params.select{ |x| x.unset? }
|
|
1014
|
+
end
|
|
1015
|
+
alias unset_parameters unset_params
|
|
1016
|
+
|
|
993
1017
|
# Get list of required parameters.
|
|
994
1018
|
def required_params
|
|
995
1019
|
params.select{ |x| x.required? }
|
data/lib/form_input/version.rb
CHANGED
data/test/test_core.rb
CHANGED
|
@@ -782,6 +782,9 @@ describe FormInput do
|
|
|
782
782
|
names( f.empty_params ).should == [ :age, :rate, :password, :opts, :on ]
|
|
783
783
|
names( f.blank_params ).should == [ :email, :age, :rate, :password, :opts, :on ]
|
|
784
784
|
|
|
785
|
+
names( f.set_params ).should == [ :query, :email, :text, :password ]
|
|
786
|
+
names( f.unset_params ).should == [ :age, :rate, :opts, :on ]
|
|
787
|
+
|
|
785
788
|
names( f.tagged_params ).should == [ :age, :rate ]
|
|
786
789
|
names( f.untagged_params ).should == [ :query, :email, :text, :password, :opts, :on ]
|
|
787
790
|
|
|
@@ -857,6 +860,8 @@ describe FormInput do
|
|
|
857
860
|
p.should.not.be.blank
|
|
858
861
|
p.should.not.be.empty
|
|
859
862
|
p.should.be.filled
|
|
863
|
+
p.should.be.set
|
|
864
|
+
p.should.not.be.unset
|
|
860
865
|
p.should.be.valid
|
|
861
866
|
p.should.not.be.invalid
|
|
862
867
|
p.should.be.required
|
|
@@ -890,6 +895,8 @@ describe FormInput do
|
|
|
890
895
|
p.should.be.blank
|
|
891
896
|
p.should.not.be.empty
|
|
892
897
|
p.should.be.filled
|
|
898
|
+
p.should.be.set
|
|
899
|
+
p.should.not.be.unset
|
|
893
900
|
p.should.not.be.valid
|
|
894
901
|
p.should.be.invalid
|
|
895
902
|
p.should.not.be.required
|
|
@@ -914,6 +921,8 @@ describe FormInput do
|
|
|
914
921
|
p.should.be.blank
|
|
915
922
|
p.should.be.empty
|
|
916
923
|
p.should.not.be.filled
|
|
924
|
+
p.should.not.be.set
|
|
925
|
+
p.should.be.unset
|
|
917
926
|
p.should.be.disabled
|
|
918
927
|
p.should.not.be.enabled
|
|
919
928
|
p[ :tag ].should == :mix
|
|
@@ -942,6 +951,8 @@ describe FormInput do
|
|
|
942
951
|
p.should.be.blank
|
|
943
952
|
p.should.be.empty
|
|
944
953
|
p.should.not.be.filled
|
|
954
|
+
p.should.not.be.set
|
|
955
|
+
p.should.be.unset
|
|
945
956
|
p.should.be.array
|
|
946
957
|
p.should.not.be.hash
|
|
947
958
|
p.should.not.be.scalar
|
|
@@ -953,6 +964,8 @@ describe FormInput do
|
|
|
953
964
|
p.should.be.blank
|
|
954
965
|
p.should.be.empty
|
|
955
966
|
p.should.not.be.filled
|
|
967
|
+
p.should.not.be.set
|
|
968
|
+
p.should.be.unset
|
|
956
969
|
p.should.not.be.array
|
|
957
970
|
p.should.be.hash
|
|
958
971
|
p.should.not.be.scalar
|
|
@@ -990,6 +1003,8 @@ describe FormInput do
|
|
|
990
1003
|
f.except( [ :email, :query ] ).url_query.should == "text=foo"
|
|
991
1004
|
f.except( [] ).url_query.should == "q=x&email=a%40b&text=foo"
|
|
992
1005
|
|
|
1006
|
+
f.except( :email ).to_data.should == { q: 'x', text: 'foo' }
|
|
1007
|
+
|
|
993
1008
|
f.only( :email ).url_query.should == "email=a%40b"
|
|
994
1009
|
f.only( :email, :query ).url_query.should == "q=x&email=a%40b"
|
|
995
1010
|
f.only().url_query.should == ""
|
|
@@ -997,15 +1012,34 @@ describe FormInput do
|
|
|
997
1012
|
f.only( [ :email, :query ] ).url_query.should == "q=x&email=a%40b"
|
|
998
1013
|
f.only( [] ).url_query.should == ""
|
|
999
1014
|
|
|
1015
|
+
f.only( :email ).to_data.should == { email: 'a@b' }
|
|
1016
|
+
|
|
1017
|
+
d = f.dup
|
|
1018
|
+
d.unset( :text )
|
|
1019
|
+
d.should.not.be.empty
|
|
1020
|
+
d.url_query.should == "q=x&email=a%40b"
|
|
1021
|
+
d.to_data.should == { q: 'x', email: 'a@b' }
|
|
1022
|
+
d.unset( d.required_params )
|
|
1023
|
+
d.should.not.be.empty
|
|
1024
|
+
d.url_query.should == "email=a%40b"
|
|
1025
|
+
d.to_data.should == { email: 'a@b' }
|
|
1026
|
+
d.unset( [] )
|
|
1027
|
+
d.should.not.be.empty
|
|
1028
|
+
d.url_query.should == "email=a%40b"
|
|
1029
|
+
d.to_data.should == { email: 'a@b' }
|
|
1030
|
+
|
|
1000
1031
|
f.clear( :text )
|
|
1001
1032
|
f.should.not.be.empty
|
|
1002
1033
|
f.url_query.should == "q=x&email=a%40b"
|
|
1034
|
+
f.to_data.should == { q: 'x', email: 'a@b' }
|
|
1003
1035
|
f.clear( f.required_params )
|
|
1004
1036
|
f.should.not.be.empty
|
|
1005
1037
|
f.url_query.should == "email=a%40b"
|
|
1038
|
+
f.to_data.should == { email: 'a@b' }
|
|
1006
1039
|
f.clear
|
|
1007
1040
|
f.should.be.empty
|
|
1008
1041
|
f.url_query.should == ""
|
|
1042
|
+
f.to_data.should == {}
|
|
1009
1043
|
|
|
1010
1044
|
f = TestForm.new( { age: 2, query: "x" }, { rate: 1, query: "y" } )
|
|
1011
1045
|
f.url_query.should == "q=y&age=2&rate=1"
|
|
@@ -1052,6 +1086,8 @@ describe FormInput do
|
|
|
1052
1086
|
f.named_params( :typo, :missing ).should == [ nil, nil ]
|
|
1053
1087
|
|
|
1054
1088
|
->{ f.set( typo: 10 ) }.should.raise( NoMethodError )
|
|
1089
|
+
->{ f.unset() }.should.raise( ArgumentError )
|
|
1090
|
+
->{ f.unset( :typo ) }.should.raise( ArgumentError )
|
|
1055
1091
|
->{ f.clear( :typo ) }.should.raise( ArgumentError )
|
|
1056
1092
|
->{ f.except( :typo ) }.should.raise( ArgumentError )
|
|
1057
1093
|
->{ f.except( [ :typo ] ) }.should.raise( ArgumentError )
|
|
@@ -1109,6 +1145,7 @@ describe FormInput do
|
|
|
1109
1145
|
f = TestForm.new( query: true, age: 3, rate: 0.35, text: false, opts: [], on: {} )
|
|
1110
1146
|
->{ f.validate }.should.not.raise
|
|
1111
1147
|
f.to_hash.should == { query: true, age: 3, rate: 0.35, text: false }
|
|
1148
|
+
f.to_data.should == { q: true, age: 3, rate: 0.35, text: false, opts: [], on: {} }
|
|
1112
1149
|
f.url_params.should == { q: "true", age: "3", rate: "0.35", text: "false" }
|
|
1113
1150
|
f.url_query.should == "q=true&age=3&rate=0.35&text=false"
|
|
1114
1151
|
names( f.incorrect_params ).should == [ :query, :rate, :text ]
|
|
@@ -1116,6 +1153,7 @@ describe FormInput do
|
|
|
1116
1153
|
f = TestForm.new( opts: 1 )
|
|
1117
1154
|
->{ f.validate }.should.not.raise
|
|
1118
1155
|
f.to_hash.should == { opts: 1 }
|
|
1156
|
+
f.to_data.should == { opts: 1 }
|
|
1119
1157
|
f.url_params.should == { opts: [ "1" ] }
|
|
1120
1158
|
f.url_query.should == "opts[]=1"
|
|
1121
1159
|
names( f.incorrect_params ).should == [ :opts ]
|
|
@@ -1123,6 +1161,7 @@ describe FormInput do
|
|
|
1123
1161
|
f = TestForm.new( opts: [ 2.5, true ] )
|
|
1124
1162
|
->{ f.validate }.should.not.raise
|
|
1125
1163
|
f.to_hash.should == { opts: [ 2.5, true ] }
|
|
1164
|
+
f.to_data.should == { opts: [ 2.5, true ] }
|
|
1126
1165
|
f.url_params.should == { opts: [ "2.5", "true" ] }
|
|
1127
1166
|
f.url_query.should == "opts[]=2.5&opts[]=true"
|
|
1128
1167
|
names( f.incorrect_params ).should == []
|
|
@@ -1130,6 +1169,7 @@ describe FormInput do
|
|
|
1130
1169
|
f = TestForm.new( opts: { "foo" => 10, true => false } )
|
|
1131
1170
|
->{ f.validate }.should.not.raise
|
|
1132
1171
|
f.to_hash.should == { opts: { "foo" => 10, true => false } }
|
|
1172
|
+
f.to_data.should == { opts: { "foo" => 10, true => false } }
|
|
1133
1173
|
f.url_params.should == { opts: [ '["foo", 10]', '[true, false]' ] }
|
|
1134
1174
|
f.url_query.should == "opts[]=%5B%22foo%22%2C+10%5D&opts[]=%5Btrue%2C+false%5D"
|
|
1135
1175
|
names( f.incorrect_params ).should == [ :opts ]
|
|
@@ -1137,6 +1177,7 @@ describe FormInput do
|
|
|
1137
1177
|
f = TestForm.new( on: 1 )
|
|
1138
1178
|
->{ f.validate }.should.not.raise
|
|
1139
1179
|
f.to_hash.should == { on: 1 }
|
|
1180
|
+
f.to_data.should == { on: 1 }
|
|
1140
1181
|
f.url_params.should == { on: { "1" => "" } }
|
|
1141
1182
|
f.url_query.should == "on[1]="
|
|
1142
1183
|
names( f.incorrect_params ).should == [ :on ]
|
|
@@ -1144,6 +1185,7 @@ describe FormInput do
|
|
|
1144
1185
|
f = TestForm.new( on: { 0 => 1, 2 => 3.4 } )
|
|
1145
1186
|
->{ f.validate }.should.not.raise
|
|
1146
1187
|
f.to_hash.should == { on: { 0 => 1, 2 => 3.4 } }
|
|
1188
|
+
f.to_data.should == { on: { 0 => 1, 2 => 3.4 } }
|
|
1147
1189
|
f.url_params.should == { on: { "0" => "1", "2" => "3.4" } }
|
|
1148
1190
|
f.url_query.should == "on[0]=1&on[2]=3.4"
|
|
1149
1191
|
names( f.incorrect_params ).should == []
|
|
@@ -1151,6 +1193,7 @@ describe FormInput do
|
|
|
1151
1193
|
f = TestForm.new( on: [ [ 10, 20 ], [ true, false ] ] )
|
|
1152
1194
|
->{ f.validate }.should.not.raise
|
|
1153
1195
|
f.to_hash.should == { on: [ [ 10, 20 ], [ true, false ] ] }
|
|
1196
|
+
f.to_data.should == { on: [ [ 10, 20 ], [ true, false ] ] }
|
|
1154
1197
|
f.url_params.should == { on: { "10" => "20", "true" => "false" } }
|
|
1155
1198
|
f.url_query.should == "on[10]=20&on[true]=false"
|
|
1156
1199
|
names( f.incorrect_params ).should == [ :on ]
|
|
@@ -1158,6 +1201,7 @@ describe FormInput do
|
|
|
1158
1201
|
f = TestForm.new( on: [ 1, true, false ] )
|
|
1159
1202
|
->{ f.validate }.should.not.raise
|
|
1160
1203
|
f.to_hash.should == { on: [ 1, true, false ] }
|
|
1204
|
+
f.to_data.should == { on: [ 1, true, false ] }
|
|
1161
1205
|
f.url_params.should == { on: { "1" => "", "true" => "", "false" => "" } }
|
|
1162
1206
|
f.url_query.should == "on[1]=&on[true]=&on[false]="
|
|
1163
1207
|
names( f.incorrect_params ).should == [ :on ]
|
|
@@ -1172,6 +1216,7 @@ describe FormInput do
|
|
|
1172
1216
|
f.error_messages.should == [ "q must use valid encoding" ]
|
|
1173
1217
|
f.param( :query ).should.not.be.blank
|
|
1174
1218
|
f.to_hash.should == { query: s }
|
|
1219
|
+
f.to_data.should == { q: s }
|
|
1175
1220
|
f.url_params.should == { q: s }
|
|
1176
1221
|
f.url_query.should == "q=%FF"
|
|
1177
1222
|
|
|
@@ -1181,6 +1226,7 @@ describe FormInput do
|
|
|
1181
1226
|
f.error_messages.should == [ "q must use valid encoding" ]
|
|
1182
1227
|
f.param( :query ).should.not.be.blank
|
|
1183
1228
|
f.to_hash.should == { query: s.dup.force_encoding( 'BINARY' ) }
|
|
1229
|
+
f.to_data.should == { q: s.dup.force_encoding( 'BINARY' ) }
|
|
1184
1230
|
f.url_params.should == { q: s.dup.force_encoding( 'BINARY' ) }
|
|
1185
1231
|
f.url_query.should == "q=%FF"
|
|
1186
1232
|
end
|
|
@@ -1208,10 +1254,11 @@ describe FormInput do
|
|
|
1208
1254
|
opts: [],
|
|
1209
1255
|
on: {},
|
|
1210
1256
|
}
|
|
1211
|
-
f = TestForm.from_data(data)
|
|
1257
|
+
f = TestForm.from_data( data )
|
|
1212
1258
|
f.to_data.should == data
|
|
1213
1259
|
|
|
1214
|
-
|
|
1260
|
+
data[ :password ] = nil
|
|
1261
|
+
f = TestForm.from_data( data )
|
|
1215
1262
|
f.to_data.should == data
|
|
1216
1263
|
|
|
1217
1264
|
f.to_hash.should == {
|
|
@@ -1220,8 +1267,6 @@ describe FormInput do
|
|
|
1220
1267
|
age: 10,
|
|
1221
1268
|
rate: 0.5,
|
|
1222
1269
|
}
|
|
1223
|
-
f.valid?(:age).should.be.true # has filter and correct class
|
|
1224
|
-
f.valid?(:rate).should.be.false # has no filter and class
|
|
1225
1270
|
end
|
|
1226
1271
|
|
|
1227
1272
|
should 'make it easy to create URLs' do
|
|
@@ -1370,6 +1415,13 @@ describe FormInput do
|
|
|
1370
1415
|
f.dup.validate?.should.be.valid
|
|
1371
1416
|
f.validate.should.be.valid
|
|
1372
1417
|
f.validate!.should.be.valid
|
|
1418
|
+
|
|
1419
|
+
f.unset( :query ).should.equal f
|
|
1420
|
+
f.should.be.invalid
|
|
1421
|
+
f.validate?.should.be.invalid
|
|
1422
|
+
f.dup.validate?.should.be.invalid
|
|
1423
|
+
f.validate.should.be.invalid
|
|
1424
|
+
f.validate!.should.be.invalid
|
|
1373
1425
|
end
|
|
1374
1426
|
|
|
1375
1427
|
should 'support some custom error messages' do
|
data/test/test_types.rb
CHANGED
|
@@ -7,41 +7,40 @@ require 'form_input/types'
|
|
|
7
7
|
require 'rack/test'
|
|
8
8
|
|
|
9
9
|
class TestBasicTypesForm < FormInput
|
|
10
|
-
|
|
11
10
|
param :int, INTEGER_ARGS
|
|
12
11
|
param :float, FLOAT_ARGS
|
|
13
12
|
param :bool, BOOL_ARGS
|
|
14
13
|
param :checkbox, CHECKBOX_ARGS
|
|
14
|
+
end
|
|
15
15
|
|
|
16
|
+
class TestJSONTypesForm < FormInput
|
|
17
|
+
param :str
|
|
18
|
+
param :int, INTEGER_ARGS
|
|
19
|
+
param :float, FLOAT_ARGS
|
|
20
|
+
param :bool, BOOL_ARGS
|
|
16
21
|
end
|
|
17
22
|
|
|
18
23
|
class TestAddressTypesForm < FormInput
|
|
19
|
-
|
|
20
24
|
param :email, EMAIL_ARGS
|
|
21
25
|
param :zip, ZIP_ARGS
|
|
22
26
|
param :phone, PHONE_ARGS
|
|
23
|
-
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
class TestTimeTypesForm < FormInput
|
|
27
|
-
|
|
28
30
|
param :time, TIME_ARGS
|
|
29
31
|
param :us_date, US_DATE_ARGS
|
|
30
32
|
param :uk_date, UK_DATE_ARGS
|
|
31
33
|
param :eu_date, EU_DATE_ARGS
|
|
32
34
|
param :hours, HOURS_ARGS
|
|
33
|
-
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
class TestPrunedTypesForm < FormInput
|
|
37
|
-
|
|
38
38
|
param :str, PRUNED_ARGS
|
|
39
39
|
param :int, INTEGER_ARGS, PRUNED_ARGS
|
|
40
40
|
array :arr, PRUNED_ARGS
|
|
41
41
|
array :int_arr, INTEGER_ARGS, PRUNED_ARGS
|
|
42
42
|
hash :hsh, PRUNED_ARGS
|
|
43
43
|
hash :int_hsh, INTEGER_ARGS, PRUNED_ARGS
|
|
44
|
-
|
|
45
44
|
end
|
|
46
45
|
|
|
47
46
|
class Bacon::Context
|
|
@@ -131,6 +130,33 @@ describe FormInput do
|
|
|
131
130
|
f.url_query.should == "int=a&float=b&bool=false&checkbox=true"
|
|
132
131
|
end
|
|
133
132
|
|
|
133
|
+
should 'provide presets for standard JSON types' do
|
|
134
|
+
f = TestJSONTypesForm.from_data( {} )
|
|
135
|
+
f.should.be.valid
|
|
136
|
+
f.to_data.should == {}
|
|
137
|
+
|
|
138
|
+
f = TestJSONTypesForm.from_data( str: "foo", int: "0123", float: "0123.456", bool: "true" )
|
|
139
|
+
f.should.be.valid
|
|
140
|
+
f.to_data.should == { str: 'foo', int: 123, float: 123.456, bool: true }
|
|
141
|
+
|
|
142
|
+
f = TestJSONTypesForm.from_data( str: nil, int: 123, float: 123.456, bool: true )
|
|
143
|
+
f.should.be.valid
|
|
144
|
+
f.to_data.should == { str: nil, int: 123, float: 123.456, bool: true }
|
|
145
|
+
|
|
146
|
+
f = TestJSONTypesForm.from_data( bool: "false" )
|
|
147
|
+
f.should.be.valid
|
|
148
|
+
f.to_data.should == { bool: false }
|
|
149
|
+
|
|
150
|
+
f = TestJSONTypesForm.from_data( bool: false )
|
|
151
|
+
f.should.be.valid
|
|
152
|
+
f.to_data.should == { bool: false }
|
|
153
|
+
|
|
154
|
+
f = TestJSONTypesForm.from_data( int: "a", float: "b", bool: "c" )
|
|
155
|
+
f.should.be.invalid
|
|
156
|
+
names( f.invalid_params ).should == [ :int, :float ]
|
|
157
|
+
f.to_data.should == { int: "a", float: "b", bool: false }
|
|
158
|
+
end
|
|
159
|
+
|
|
134
160
|
should 'provide presets for address parameter types' do
|
|
135
161
|
f = TestAddressTypesForm.new( request( "?email=me@1.com&zip=12345&phone=123%20456%20789" ) )
|
|
136
162
|
f.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.3.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: 2019-
|
|
11
|
+
date: 2019-07-31 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rack
|
|
@@ -94,6 +94,7 @@ files:
|
|
|
94
94
|
- example/controllers/ramaze/profile.rb
|
|
95
95
|
- example/controllers/sinatra/press_release.rb
|
|
96
96
|
- example/controllers/sinatra/profile.rb
|
|
97
|
+
- example/example.rb
|
|
97
98
|
- example/forms/change_password_form.rb
|
|
98
99
|
- example/forms/login_form.rb
|
|
99
100
|
- example/forms/lost_password_form.rb
|