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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4014e07ca32e3c7a76ee15db0dfe478a4103d123
4
- data.tar.gz: 83224f22dc199d2a3f1bf4d46011f616195d33ca
3
+ metadata.gz: c46667c81eb96ef6deeaf13501e06f6bc328b862
4
+ data.tar.gz: e6dc22529b1fdfead38c01c5bd2d6f5b2e1fc52a
5
5
  SHA512:
6
- metadata.gz: 82f8812fbd77215e7a058f1585bc7b2ee2a5082215d4247ae865b8ced6e2c739c39e836741482ebf4cb089fe57b6c330f8b19726d8998ed8cfca48910faf92ba
7
- data.tar.gz: e2e6853f4eb58193d11aa22696164844130c5c653df6b872372a40bfa1d790a8b61cf45bd287046cf7c375c14326709c49d907ba51e5779f0d3a72ad9ff12152
6
+ metadata.gz: 178de263faf14e4621298bfdee13025cd0852020178448f9370d4c27904c9a9a5bbad2c8fb250a55ee10051c370716f23b42eadeec89a4c157055aa12b444bf7
7
+ data.tar.gz: e62589e13773fd867abbd1bec66a66dad851bda8214968820348ac3566e612ffe48e702a93d1928b5f505c8b53b7d06591923a67969b19e1989979ec3bf2f275
@@ -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-nil parameters.
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! methods for late reporting of the most fundamental errors.
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
- [![Gem Version](https://img.shields.io/gem/v/form_input.svg)](http://rubygems.org/gems/form_input) [![Build Status](https://travis-ci.org/raxoft/form_input.svg?branch=master)](http://travis-ci.org/raxoft/form_input) [![Dependency Status](https://img.shields.io/gemnasium/raxoft/form_input.svg)](https://gemnasium.com/raxoft/form_input) [![Code Climate](https://img.shields.io/codeclimate/github/raxoft/form_input.svg)](https://codeclimate.com/github/raxoft/form_input) [![Coverage](https://img.shields.io/codeclimate/coverage/github/raxoft/form_input.svg)](https://codeclimate.com/github/raxoft/form_input)
3
+ [![Gem Version](https://img.shields.io/gem/v/form_input.svg)](http://rubygems.org/gems/form_input) [![Build Status](https://travis-ci.org/raxoft/form_input.svg?branch=master)](http://travis-ci.org/raxoft/form_input) [![Maintainability](https://api.codeclimate.com/v1/badges/ea19d227eb1285d59860/maintainability)](https://codeclimate.com/github/raxoft/form_input/maintainability) [![Coverage](https://api.codeclimate.com/v1/badges/ea19d227eb1285d59860/test_coverage)](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 ) # NEVER EVER DO THIS!
798
- form = ContactForm.new.import( params ) # Do this instead if you need to.
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/contact' do
806
- form = ContactForm.new.import( json_data )
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 even empty strings, arrays, and hashes
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
- The `nil` values are still filtered out, though.
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/contact' do
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
 
@@ -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 //
@@ -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
- if value = request[ param.code ]
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 non-nil parameters,
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 non-nil parameters as a hash.
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
- params.each{ |x| result[ x.code ] = x.value unless x.value.nil? }
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
- result = dup
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
- result = dup
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? }
@@ -3,7 +3,7 @@
3
3
  class FormInput
4
4
  module Version
5
5
  MAJOR = 1
6
- MINOR = 2
6
+ MINOR = 3
7
7
  PATCH = 0
8
8
  STRING = [ MAJOR, MINOR, PATCH ].join( '.' ).freeze
9
9
  end
@@ -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
- f = TestForm.from_data(data.merge(password: nil))
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
@@ -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.2.0
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-06-21 00:00:00.000000000 Z
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