Class: FormInput

Inherits:
Object
  • Object
show all
Includes:
R18n::Helpers
Defined in:
lib/form_input/core.rb,
lib/form_input/r18n.rb,
lib/form_input/steps.rb,
lib/form_input/types.rb,
lib/form_input/version.rb,
lib/form_input/localize.rb

Overview

Version number.

Defined Under Namespace

Modules: StepMethods, Version Classes: Parameter

Constant Summary collapse

DEFAULT_SIZE_LIMIT =

Default size limit applied to all input.

255
DEFAULT_FILTER =

Default input filter applied to all input (unless replaced by user's filter).

->{ gsub( /\s+/, ' ' ).strip }
DEFAULT_MATCH =

Default match applied to all input (in addition to user's match(es)). Note that the Graph property, despite being defined as "Non-blank characters", currently includes Cf (Other: Format) and Co (Other: Private Use) categories, which include stuff like BOM or BIDI formatting and other invisible characters, which you may or may not want. To protect the innocent and prevent nasty surprises, DEFAULT_REJECT was introduced to avoid these by default, but make it possible to override.

/\A(\p{Graph}|[ \t\r\n])*\z/u
DEFAULT_REJECT =

Default reject applied to all input (in addition to user's reject(s)).

/\p{Cf}|\p{Co}/u
DEFAULT_MIN_KEY =

Minimum hash key value we allow by default.

0
DEFAULT_MAX_KEY =

Maximum hash key value we allow by default.

( 1 << 64 ) - 1
DEFAULT_ENCODING =

Encoding we convert all input request parameters into.

Encoding::UTF_8
DEFAULT_ERROR_MESSAGES =

Hash mapping error codes to default error messages.

{
  required_scalar: "%p is required",
  required_array: "%p are required",
  not_array: "%p are not an array",
  not_hash: "%p are not a hash",
  not_string: "%p is not a string",
  match_key: "%p contain invalid key",
  invalid_key: "%p contain invalid key",
  min_key: "%p contain too small key",
  max_key: "%p contain too large key",
  min_count: "%p must have at least",
  max_count: "%p may have at most",
  value_type: "%p like this is not valid",
  element_type: "%p contain invalid value",
  min_limit: "%p must be at least",
  max_limit: "%p may be at most",
  inf_limit: "%p must be greater than",
  sup_limit: "%p must be less than",
  invalid_encoding: "%p must use valid encoding",
  invalid_characters: "%p may not contain invalid characters",
  min_size: "%p must have at least",
  max_size: "%p may have at most",
  min_bytesize: "%p must have at least",
  max_bytesize: "%p may have at most",
  reject_msg: "%p like this is not allowed",
  match_msg: "%p like this is not valid",
}
DEFAULT_REPLACEMENT_CHARACTER =

Character used as default replacement for invalid characters when formatting values.

'?'
MERGEABLE_OPTIONS =

Parameter options which can be merged together into an array when multiple option hashes are merged.

[ :check, :test ]
LATIN_NAMES_RE =

Matches names using latin alphabet.

/\A[\p{Latin}\-\. ]+\z/u
SIMPLE_EMAIL_RE =

Matches common email addresses. Note that it doesn't match all addresses allowed by RFC, though.

/\A[-_.=+%a-z0-9]+@(?:[-_a-z0-9]+\.)+[a-z]{2,4}\z/i
ZIP_CODE_RE =

Matches generic ZIP code. Note that the real format changes for each country.

/\A[A-Z\d]++(?:[- ]?[A-Z\d]+)*+\z/i
PHONE_NUMBER_FILTER =

Filter for phone numbers.

->{ gsub( /\s*[-\/\.]\s*/, '-' ).gsub( /\s+/, ' ' ).strip }
PHONE_NUMBER_RE =

Matches generic phone number.

/\A\+?\d++(?:[- ]?(?:\d+|\(\d+\)))*+(?:[- ]?[A-Z\d]+)*+\z/i
INTEGER_ARGS =

Integer number.

{
  filter: ->{ ( Integer( self, 10 ) rescue self ) unless empty? },
  class: Integer,
}
FLOAT_ARGS =

Float number.

{
  filter: ->{ ( Float( self ) rescue self ) unless empty? },
  class: Float,
}
BOOL_ARGS =

Boolean value, displayed as a select menu.

{
  type: :select,
  data: [ [ true, 'Yes' ], [ false, 'No' ] ],
  filter: ->{ self == 'true' unless empty? },
  class: [ TrueClass, FalseClass ],
}
CHECKBOX_ARGS =

Boolean value, displayed as a checkbox.

{
  type: :checkbox,
  filter: ->{ not empty? },
  format: ->{ self if self },
  class: [ TrueClass, FalseClass ],
}
EMAIL_ARGS =

Email.

{
  match: SIMPLE_EMAIL_RE,
}
ZIP_ARGS =

Zip code.

{
  match: ZIP_CODE_RE,
}
PHONE_ARGS =

Phone number.

{
  filter: PHONE_NUMBER_FILTER,
  match: PHONE_NUMBER_RE,
}
TIME_FORMAT =

Full time format.

"%Y-%m-%d %H:%M:%S".freeze
TIME_FORMAT_EXAMPLE =

Full time format example.

"YYYY-MM-DD HH:MM:SS".freeze
TIME_ARGS =

Full time.

{
  placeholder: TIME_FORMAT_EXAMPLE,
  filter: ->{ ( FormInput.parse_time!( self, TIME_FORMAT ) rescue self ) unless empty? },
  format: ->{ utc.strftime( TIME_FORMAT ) rescue self },
  class: Time,
}
US_DATE_FORMAT =

US date format.

"%m/%d/%Y".freeze
US_DATE_FORMAT_EXAMPLE =

US date format example.

"MM/DD/YYYY".freeze
US_DATE_ARGS =

Time in US date format.

{
  placeholder: US_DATE_FORMAT_EXAMPLE,
  filter: ->{ ( FormInput.parse_time!( self, US_DATE_FORMAT ) rescue self ) unless empty? },
  format: ->{ utc.strftime( US_DATE_FORMAT ) rescue self },
  class: Time,
}
UK_DATE_FORMAT =

UK date format.

"%d/%m/%Y".freeze
UK_DATE_FORMAT_EXAMPLE =

UK date format example.

"DD/MM/YYYY".freeze
UK_DATE_ARGS =

Time in UK date format.

{
  placeholder: UK_DATE_FORMAT_EXAMPLE,
  filter: ->{ ( FormInput.parse_time!( self, UK_DATE_FORMAT ) rescue self ) unless empty? },
  format: ->{ utc.strftime( UK_DATE_FORMAT ) rescue self },
  class: Time,
}
EU_DATE_FORMAT =

EU date format.

"%-d.%-m.%Y".freeze
EU_DATE_FORMAT_EXAMPLE =

EU date format example.

"D.M.YYYY".freeze
EU_DATE_ARGS =

Time in EU date format.

{
  placeholder: EU_DATE_FORMAT_EXAMPLE,
  filter: ->{ ( FormInput.parse_time!( self, EU_DATE_FORMAT ) rescue self ) unless empty? },
  format: ->{ utc.strftime( EU_DATE_FORMAT ) rescue self },
  class: Time,
}
HOURS_FORMAT =

Hours format.

"%H:%M".freeze
HOURS_FORMAT_EXAMPLE =

Hours format example.

"HH:MM".freeze
HOURS_ARGS =

Seconds since midnight in hours:minutes format.

{
  placeholder: HOURS_FORMAT_EXAMPLE,
  filter: ->{ ( FormInput.parse_time( self, HOURS_FORMAT ).to_i % 86400 rescue self ) unless empty? },
  format: ->{ Time.at( self ).utc.strftime( HOURS_FORMAT ) rescue self },
  class: Integer,
}
PRUNED_ARGS =

Transformation which drops empty values from hashes and arrays and turns empty string into nil.

{
  transform: ->{
    case self
    when Array
      reject{ |v| v.nil? or ( v.respond_to?( :empty? ) && v.empty? ) }
    when Hash
      reject{ |k,v| v.nil? or ( v.respond_to?( :empty? ) && v.empty? ) }
    when String
      self unless empty?
    else
      self
    end
  }
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ FormInput

Create new form info, initializing it from given hash or request, if anything.



808
809
810
811
812
813
814
815
816
817
818
# File 'lib/form_input/core.rb', line 808

def initialize( *args )
  @params = bound_params
  @errors = nil
  for arg in args
    if arg.is_a? Hash
      set( arg )
    else
      import( arg )
    end
  end
end

Class Method Details

.[](*names) ⇒ Object

Get given parameter(s), hash style.



662
663
664
665
666
667
668
# File 'lib/form_input/core.rb', line 662

def []( *names )
  if names.count == 1
    form_params[ names.first ]
  else
    form_params.values_at( *names )
  end
end

.add(param) ⇒ Object

Add given parameter to the form, after performing basic validity checks.



671
672
673
674
675
676
677
678
679
680
# File 'lib/form_input/core.rb', line 671

def add( param )
  name = param.name

  fail ArgumentError, "duplicate parameter #{name}" if form_params[ name ]
  fail ArgumentError, "invalid parameter name #{name}" if method_defined?( name )

  self.send( :attr_accessor, name )

  form_params[ name ] = param
end

.array(name, *args, &block) ⇒ Object

Like param, except that it defines array parameter.



760
761
762
# File 'lib/form_input/core.rb', line 760

def array( name, *args, &block )
  param( name, *args, array: true, &block )
end

.array!(name, *args, &block) ⇒ Object

Like param!, except that it defines required array parameter.



765
766
767
# File 'lib/form_input/core.rb', line 765

def array!( name, *args, &block )
  param!( name, *args, array: true, &block )
end

.copy(source, opts = {}) ⇒ Object

Copy given/all form parameters. Returns self for chaining.



685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
# File 'lib/form_input/core.rb', line 685

def copy( source, opts = {} )
  case source
  when Parameter
    add( Parameter.new(
      opts[ :name ] || source.name,
      opts[ :code ] || opts[ :name ] || source.code,
      source.opts.merge( opts )
    ) )
  when Array
    source.each{ |x| copy( x, opts ) }
  when Class
    fail ArgumentError, "invalid source form #{source.inspect}" unless source < FormInput
    copy( source.form_params.values, opts )
  else
    fail ArgumentError, "invalid source parameter #{source.inspect}"
  end
  self
end

.default_translation(forms = self.forms) ⇒ Object

Get string containing YAML representation of the default R18n translation for all/given FormInput classes.



43
44
45
46
# File 'lib/form_input/localize.rb', line 43

def self.default_translation( forms = self.forms )
  hash = Hash[ forms.map{ |x| [ x.translation_name, x.translation_hash ] }.reject{ |k, v| v.empty? } ]
  YAML::dump( { forms: hash }.stringify_keys )
end

.define_steps(steps) ⇒ Object

Turn this form into multi-step form using given steps. Returns self for chaining.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
# File 'lib/form_input/steps.rb', line 7

def self.define_steps( steps )
  @steps = steps = steps.to_hash.dup.freeze

  self.send( :include, StepMethods )

  opts = { filter: ->{ steps.keys.find{ |x| x.to_s == self } }, class: Symbol }

  param :step, opts, type: :hidden
  param :next, opts, type: :ignore
  param :last, opts, type: :hidden
  param :seen, opts, type: :hidden

  self
end

.find_inflection(string) ⇒ Object

Iterate over each possible inflection for given inflection string and return first non-nil result. You may override this if you need more complex inflection fallbacks for some locale.



129
130
131
132
133
134
135
# File 'lib/form_input/r18n.rb', line 129

def self.find_inflection( string )
  until string.empty?
    break if result = yield( string )
    string = string[0..-2]
  end
  result
end

.form_paramsObject

Get hash mapping parameter names to parameters themselves.



657
658
659
# File 'lib/form_input/core.rb', line 657

def form_params
  @params ||= {}
end

.form_stepsObject

Get hash mapping defined steps to their names, or nil if there are none.



23
24
25
# File 'lib/form_input/steps.rb', line 23

def self.form_steps
  @steps
end

.formsObject

Get list of all classes inherited from FormInput.



38
39
40
# File 'lib/form_input/localize.rb', line 38

def self.forms
  ObjectSpace.each_object( Class ).select{ |x| x < FormInput and x.name }.sort_by{ |x| x.name }
end

.from_hash(hash) ⇒ Object

Create new form from hash with internal values.



791
792
793
# File 'lib/form_input/core.rb', line 791

def from_hash( hash )
  new.set( hash )
end

.from_params(params) ⇒ Object Also known as: from_data

Create new form from hash with external values.



785
786
787
# File 'lib/form_input/core.rb', line 785

def from_params( params )
  new.import( params )
end

.from_request(request) ⇒ Object

Create new form from request with external values.



780
781
782
# File 'lib/form_input/core.rb', line 780

def from_request( request )
  new.import( request )
end

.hash(name, *args, &block) ⇒ Object

Like param, except that it defines hash parameter.



770
771
772
# File 'lib/form_input/core.rb', line 770

def hash( name, *args, &block )
  param( name, *args, hash: true, &block )
end

.hash!(name, *args, &block) ⇒ Object

Like param!, except that it defines required hash parameter.



775
776
777
# File 'lib/form_input/core.rb', line 775

def hash!( name, *args, &block )
  param!( name, *args, hash: true, &block )
end

.inherited(into) ⇒ Object

Create standalone copy of form parameters in case someone inherits an existing form.



652
653
654
# File 'lib/form_input/core.rb', line 652

def inherited( into )
  into.instance_variable_set( '@params', form_params.dup )
end

.param(name, *args, &block) ⇒ Object

Define form parameter with given name, code, title, maximum size, options, and filter block. All fields except name are optional. In case the code is missing, name is used instead. If no size limits are specified, 255 characters and bytes limits are applied by default. If no filter is explicitly defined, default filter squeezing and stripping whitespace is applied. Returns self for chaining.



709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
# File 'lib/form_input/core.rb', line 709

def param( name, *args, &block )

  # Fetch arguments.

  code = name
  code = args.shift if args.first.is_a? Symbol

  title = args.shift if args.first.is_a? String

  size = args.shift if args.first.is_a? Numeric

  opts = {}
  opts.merge!( args.shift ){ |k, o, n| ( n && MERGEABLE_OPTIONS.include?( k ) ) ? [ *o, *n ] : n } while args.first.is_a? Hash

  fail ArgumentError, "invalid arguments #{args}" unless args.empty?

  # Set the title.

  opts[ :title ] = title.freeze if title

  # Set input filter.

  opts[ :filter ] = block if block
  opts[ :filter ] = DEFAULT_FILTER unless opts.key?( :filter )

  # Enforce default size limits for any input processed.

  limit = DEFAULT_SIZE_LIMIT

  size = ( opts[ :max_size ] ||= size || limit )
  opts[ :max_bytesize ] ||= limit if size.is_a?( Proc ) or size <= limit

  # Set default key limits for hash parameters.

  if opts[ :hash ]
    opts[ :min_key ] ||= DEFAULT_MIN_KEY
    opts[ :max_key ] ||= DEFAULT_MAX_KEY
  end

  # Define parameter.

  add( Parameter.new( name, code, opts ) )
  self
end

.param!(name, *args, &block) ⇒ Object

Like param, except this defines required parameter.



755
756
757
# File 'lib/form_input/core.rb', line 755

def param!( name, *args, &block )
  param( name, *args, required: true, &block )
end

.parse_time(string, format) ⇒ Object

Parse time like Time#strptime but raise on trailing garbage. Also ignores -, _ and ^ % modifiers, so the same format can be used for both parsing and formatting.



143
144
145
146
147
148
149
# File 'lib/form_input/types.rb', line 143

def self.parse_time( string, format )
  format = format.gsub( /%[-_^]?(.)/, '%\1' )
  # Rather than using _strptime and checking the leftover field,
  # add required trailing character to both the string and format parameters.
  suffix = ( string[ -1 ] == "\1" ? "\2" : "\1" )
  Time.strptime( "+0000 #{string}#{suffix}", "%z #{format}#{suffix}" ).utc
end

.parse_time!(string, format) ⇒ Object

Like parse_time, but falls back to DateTime.parse heuristics when the date/time can't be parsed.



152
153
154
155
156
# File 'lib/form_input/types.rb', line 152

def self.parse_time!( string, format )
  parse_time( string, format )
rescue
  DateTime.parse( string ).to_time.utc
end

.translation_hashObject

Get hash of all form values which may need to be localized.



31
32
33
34
35
# File 'lib/form_input/localize.rb', line 31

def self.translation_hash
  hash = Hash[ form_params.map{ |k, v| [ k, v.translation_hash ] }.reject{ |k, v| v.empty? } ]
  hash[ :steps ] = form_steps.reject{ |k, v| v.nil? } if form_steps
  hash
end

.translation_nameObject

Get name of the form used as translation scope for text translations.



112
113
114
115
116
117
# File 'lib/form_input/r18n.rb', line 112

def self.translation_name
  @translation_name ||= name.split( '::' ).last
    .gsub( /([A-Z]+)([A-Z][a-z])/, '\1_\2' )
    .gsub( /([a-z\d])([A-Z])/, '\1_\2' )
    .downcase
end

.translations_pathObject

Get path to R18n translations provided by this gem.



107
108
109
# File 'lib/form_input/r18n.rb', line 107

def self.translations_path
  File.expand_path( "#{__FILE__}/../r18n" )
end

Instance Method Details

#[](*names) ⇒ Object

Get given parameter(s) value(s), hash style.



923
924
925
926
927
928
929
# File 'lib/form_input/core.rb', line 923

def []( *names )
  if names.count == 1
    send( names.first )
  else
    names.map{ |x| send( x ) }
  end
end

#[]=(name, value) ⇒ Object

Set given parameter value, hash style. Unlike setting the attribute directly, this triggers a revalidation in the future.



933
934
935
936
# File 'lib/form_input/core.rb', line 933

def []=( name, value )
  @errors = nil
  send( "#{name}=", value )
end

#array_paramsObject Also known as: array_parameters

Get list of array parameters.



1093
1094
1095
# File 'lib/form_input/core.rb', line 1093

def array_params
  params.select{ |x| x.array? }
end

#blank_paramsObject Also known as: blank_parameters

Get list of parameters with blank values.



1021
1022
1023
# File 'lib/form_input/core.rb', line 1021

def blank_params
  params.select{ |x| x.blank? }
end

#build_url(url, args = {}) ⇒ Object

Build URL from given URL and combination of current paramaters and provided parameters.



1188
1189
1190
# File 'lib/form_input/core.rb', line 1188

def build_url( url, args = {} )
  dup.set( args ).extend_url( url )
end

#build_url_query(value, prefix = nil) ⇒ Object

Build URL query from given URL parameters.



1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
# File 'lib/form_input/core.rb', line 1161

def build_url_query( value, prefix = nil )
  case value
  when Hash
    value.map{ |k, v| k = url_escape( k ) ; build_url_query( v, prefix ? "#{prefix}[#{k}]" : k ) }.join( '&' )
  when Array
    value.map{ |v| build_url_query( v, "#{prefix}[]" ) }.join( '&' )
  else
    "#{prefix}=#{url_escape( value )}"
  end
end

#chunked_params(params = self.params) ⇒ Object

Get all/given parameters chunked into individual rows for nicer form display.



1135
1136
1137
# File 'lib/form_input/core.rb', line 1135

def chunked_params( params = self.params )
  params.chunk{ |p| p[ :row ] || :_alone }.map{ |x,a| a.count > 1 ? a : a.first }
end

#clear(*names) ⇒ Object

Clear all/given parameter values. Both names and parameters are accepted. Returns self for chaining.



912
913
914
915
916
917
918
919
920
# File 'lib/form_input/core.rb', line 912

def clear( *names )
  names = names.empty? ? params_names : validate_names( names )
  for name in names
    # Set the value to nil first so it triggers anything necessary.
    self[ name ] = nil
    remove_instance_variable( "@#{name}" )
  end
  self
end

#correct_paramsObject Also known as: correct_parameters

Get list of parameters with correct value types.



1009
1010
1011
# File 'lib/form_input/core.rb', line 1009

def correct_params
  params.select{ |x| x.correct? }
end

#disabled_paramsObject Also known as: disabled_parameters

Get list of disabled parameters.



1063
1064
1065
# File 'lib/form_input/core.rb', line 1063

def disabled_params
  params.select{ |x| x.disabled? }
end

#empty?Boolean

Return true if all parameters are empty.

Returns:

  • (Boolean)


1142
1143
1144
# File 'lib/form_input/core.rb', line 1142

def empty?
  filled_params.empty?
end

#empty_paramsObject Also known as: empty_parameters

Get list of parameters with empty values.



1027
1028
1029
# File 'lib/form_input/core.rb', line 1027

def empty_params
  params.select{ |x| x.empty? }
end

#enabled_paramsObject Also known as: enabled_parameters

Get list of enabled parameters.



1069
1070
1071
# File 'lib/form_input/core.rb', line 1069

def enabled_params
  params.select{ |x| x.enabled? }
end

#error_for(name) ⇒ Object

Get first error for given parameter. Returns nil if there were no errors.



1229
1230
1231
# File 'lib/form_input/core.rb', line 1229

def error_for( name )
  errors_for( name ).first
end

#error_messagesObject

Get list of error messages, but including only the first one reported for each parameter.



1201
1202
1203
# File 'lib/form_input/core.rb', line 1201

def error_messages
  errors.values.map{ |x| x.first }
end

#errorsObject

Get hash of all errors detected for each parameter.



1195
1196
1197
1198
# File 'lib/form_input/core.rb', line 1195

def errors
  validate?
  @errors.dup
end

#errors_for(name) ⇒ Object

Get list of errors for given parameter. Returns empty list if there were no errors.



1224
1225
1226
# File 'lib/form_input/core.rb', line 1224

def errors_for( name )
  errors[ name ] || []
end

#except(*names) ⇒ Object

Create copy of itself, with given parameters unset. Both names and parameters are accepted.



969
970
971
# File 'lib/form_input/core.rb', line 969

def except( *names )
  dup.clear( names )
end

#extend_url(url) ⇒ Object

Extend given URL with query created from all current non-empty parameters.



1178
1179
1180
1181
1182
1183
1184
1185
# File 'lib/form_input/core.rb', line 1178

def extend_url( url )
  url = url.to_s.dup
  query = url_query
  unless query.empty?
    url << ( url['?'] ? '&' : '?' ) << query
  end
  url
end

#filled_paramsObject Also known as: filled_parameters

Get list of parameters with non-empty values.



1033
1034
1035
# File 'lib/form_input/core.rb', line 1033

def filled_params
  params.select{ |x| x.filled? }
end

#freezeObject

Freeze the form.



835
836
837
838
839
840
841
# File 'lib/form_input/core.rb', line 835

def freeze
  unless frozen?
    validate?
    @errors.freeze.each{ |k,v| v.freeze }
  end
  super
end

#ft(*args) ⇒ Object

Like t helper, except that the translation is looked up in the forms. scope. Supports both ft.name( args ) and ft( :name, args ) forms.



121
122
123
124
125
# File 'lib/form_input/r18n.rb', line 121

def ft( *args )
  fail "You need to set the locale with R18n.set('en') or similar. No locale, no helper. Sorry." unless r18n
  translation = t.forms[ self.class.translation_name ]
  args.empty? ? translation : translation[ *args ]
end

#hash_paramsObject Also known as: hash_parameters

Get list of hash parameters.



1099
1100
1101
# File 'lib/form_input/core.rb', line 1099

def hash_params
  params.select{ |x| x.hash? }
end

#hidden_paramsObject Also known as: hidden_parameters

Get list of hidden parameters.



1075
1076
1077
# File 'lib/form_input/core.rb', line 1075

def hidden_params
  params.select{ |x| x.hidden? }
end

#ignored_paramsObject Also known as: ignored_parameters

Get list of ignored parameters.



1081
1082
1083
# File 'lib/form_input/core.rb', line 1081

def ignored_params
  params.select{ |x| x.ignored? }
end

#import(request) ⇒ Object

Import parameter values from given request or hash. Applies parameter input filters and transforms as well. Returns self for chaining.



880
881
882
883
884
885
886
887
888
889
890
891
892
893
# File 'lib/form_input/core.rb', line 880

def import( request )
  hash = request.respond_to?( :params ) ? request.params : request.to_hash
  for name, param in @params
    value = hash.fetch( param.code ) { hash.fetch( param.code.to_s, self ) }
    unless value == self
      value = sanitize_value( value, param.filter )
      if transform = param.transform
        value = value.instance_exec( &transform )
      end
      self[ name ] = value
    end
  end
  self
end

#incorrect_paramsObject Also known as: incorrect_parameters

Get list of parameters with incorrect value types.



1015
1016
1017
# File 'lib/form_input/core.rb', line 1015

def incorrect_params
  params.select{ |x| x.incorrect? }
end

#initialize_clone(other) ⇒ Object

Initialize form clone.



821
822
823
824
825
# File 'lib/form_input/core.rb', line 821

def initialize_clone( other )
  super
  @params = bound_params
  @errors &&= Hash[ @errors.map{ |k,v| [ k, v.clone ] } ]
end

#initialize_dup(other) ⇒ Object

Initialize form copy.



828
829
830
831
832
# File 'lib/form_input/core.rb', line 828

def initialize_dup( other )
  super
  @params = bound_params
  @errors = nil
end

#invalid?(*names) ⇒ Boolean

Test if there were some errors (overall or for given parameters) reported.

Returns:

  • (Boolean)


1243
1244
1245
# File 'lib/form_input/core.rb', line 1243

def invalid?( *names )
  not valid?( *names )
end

#invalid_paramsObject Also known as: invalid_parameters

Get list of parameters with some errors reported.



1129
1130
1131
# File 'lib/form_input/core.rb', line 1129

def invalid_params
  params.select{ |x| x.invalid? }
end

#named_params(*names) ⇒ Object Also known as: named_parameters

Get list of given named parameters. Note that nil is returned for unknown names, and duplicate parameters for duplicate names.



1003
1004
1005
# File 'lib/form_input/core.rb', line 1003

def named_params( *names )
  @params.values_at( *names )
end

#only(*names) ⇒ Object

Create copy of itself, with only given parameters set. Both names and parameters are accepted.



974
975
976
977
978
979
# File 'lib/form_input/core.rb', line 974

def only( *names )
  # It would be easier to create new instance here and only copy selected values,
  # but we want to use dup instead of new here, as the derived form can use
  # different parameters in its construction.
  dup.clear( params_names - validate_names( names ) )
end

#optional_paramsObject Also known as: optional_parameters

Get list of optional parameters.



1057
1058
1059
# File 'lib/form_input/core.rb', line 1057

def optional_params
  params.select{ |x| x.optional? }
end

#param(name) ⇒ Object Also known as: parameter

Get given named parameter.



984
985
986
# File 'lib/form_input/core.rb', line 984

def param( name )
  @params[ name ]
end

#paramsObject Also known as: parameters

Get list of all parameters.



990
991
992
# File 'lib/form_input/core.rb', line 990

def params
  @params.values
end

#params_namesObject Also known as: parameters_names

Get list of all parameter names.



996
997
998
# File 'lib/form_input/core.rb', line 996

def params_names
  @params.keys
end

#report(name, msg) ⇒ Object

Remember error concerning given parameter. In case of multiple errors, the message is added to the end of the list, making it less important than the other errors. Returns self for chaining.



1208
1209
1210
1211
1212
# File 'lib/form_input/core.rb', line 1208

def report( name, msg )
  validate?
  ( @errors[ name ] ||= [] ) << msg.to_s.dup.freeze
  self
end

#report!(name, msg) ⇒ Object

Remember error concerning given parameter. In case of multiple errors, the message is added to the beginning of the list, making it more important than the other errors. Returns self for chaining.



1217
1218
1219
1220
1221
# File 'lib/form_input/core.rb', line 1217

def report!( name, msg )
  validate?
  ( @errors[ name ] ||= [] ).unshift( msg.to_s.dup.freeze )
  self
end

#required_paramsObject Also known as: required_parameters

Get list of required parameters.



1051
1052
1053
# File 'lib/form_input/core.rb', line 1051

def required_params
  params.select{ |x| x.required? }
end

#scalar_paramsObject Also known as: scalar_parameters

Get list of scalar parameters.



1105
1106
1107
# File 'lib/form_input/core.rb', line 1105

def scalar_params
  params.select{ |x| x.scalar? }
end

#set(hash) ⇒ Object

Set parameter values from given hash. Returns self for chaining.



897
898
899
900
901
902
# File 'lib/form_input/core.rb', line 897

def set( hash )
  for name, value in hash
    self[ name ] = value
  end
  self
end

#set_paramsObject Also known as: set_parameters

Get list of parameters whose values were set.



1039
1040
1041
# File 'lib/form_input/core.rb', line 1039

def set_params
  params.select{ |x| x.set? }
end

#tagged_params(*tags) ⇒ Object Also known as: tagged_parameters

Get list of parameters tagged with given/any tags.



1111
1112
1113
# File 'lib/form_input/core.rb', line 1111

def tagged_params( *tags )
  params.select{ |x| x.tagged?( *tags ) }
end

#to_dataObject

Return all set parameters as a hash. Note that the keys are external names of the parameters (should they differ), so the keys created by from_data(data).to_data remain consistent. See also #to_hash, which creates a hash of non-empty parameters.



952
953
954
955
956
# File 'lib/form_input/core.rb', line 952

def to_data
  result = {}
  set_params.each{ |x| result[ x.code ] = x.value }
  result
end

#to_hashObject Also known as: to_h

Return all non-empty parameters as a hash. See also #to_data, which creates a hash of set parameters, and #url_params, which creates a hash suitable for url output.



941
942
943
944
945
# File 'lib/form_input/core.rb', line 941

def to_hash
  result = {}
  filled_params.each{ |x| result[ x.name ] = x.value }
  result
end

#unset(name, *names) ⇒ Object

Unset values of given parameters. Both names and parameters are accepted. Returns self for chaining.



906
907
908
# File 'lib/form_input/core.rb', line 906

def unset( name, *names )
  clear( name, *names )
end

#unset_paramsObject Also known as: unset_parameters

Get list of parameters whose values were not set.



1045
1046
1047
# File 'lib/form_input/core.rb', line 1045

def unset_params
  params.select{ |x| x.unset? }
end

#untagged_params(*tags) ⇒ Object Also known as: untagged_parameters

Get list of parameters not tagged with given/any tags.



1117
1118
1119
# File 'lib/form_input/core.rb', line 1117

def untagged_params( *tags )
  params.select{ |x| x.untagged?( *tags ) }
end

#url_escape(string) ⇒ Object

Escape given string for use in URL query.



1156
1157
1158
# File 'lib/form_input/core.rb', line 1156

def url_escape( string )
  URI.encode_www_form_component( string )
end

#url_paramsObject Also known as: url_parameters, to_params

Get hash of all non-empty parameters for use in URL.



1147
1148
1149
1150
1151
# File 'lib/form_input/core.rb', line 1147

def url_params
  result = {}
  filled_params.each{ |x| result[ x.code ] = x.url_value }
  result
end

#url_queryObject

Create string containing URL query from all current non-empty parameters.



1173
1174
1175
# File 'lib/form_input/core.rb', line 1173

def url_query
  build_url_query( url_params )
end

#valid(name, *names) ⇒ Object

Return parameter(s) value(s) as long as they are all valid, nil otherwise.



1248
1249
1250
# File 'lib/form_input/core.rb', line 1248

def valid( name, *names )
  self[ name, *names ] if valid?( name, *names )
end

#valid?(*names) ⇒ Boolean

Test if there were no errors (overall or for given parameters) reported.

Returns:

  • (Boolean)


1234
1235
1236
1237
1238
1239
1240
# File 'lib/form_input/core.rb', line 1234

def valid?( *names )
  if names.empty?
    errors.empty?
  else
    validate_names( names ).all?{ |x| errors_for( x ).empty? }
  end
end

#valid_paramsObject Also known as: valid_parameters

Get list of parameters with no errors reported.



1123
1124
1125
# File 'lib/form_input/core.rb', line 1123

def valid_params
  params.select{ |x| x.valid? }
end

#validateObject

Validate parameter values and remember any errors detected. You can override this in your class if you need more specific validation and :check callback is not good enough. Just make sure to call super first. Returns self for chaining.



1256
1257
1258
1259
1260
# File 'lib/form_input/core.rb', line 1256

def validate
  @errors ||= {}
  params.each{ |x| x.validate }
  self
end

#validate!Object

Like validate, except that it forces revalidation of all parameters. Returns self for chaining.



1264
1265
1266
1267
1268
# File 'lib/form_input/core.rb', line 1264

def validate!
  @errors = {}
  validate
  self
end

#validate?Boolean

Like validate, except that it does nothing if validation was already done. Returns self for chaining.

Returns:

  • (Boolean)


1272
1273
1274
1275
# File 'lib/form_input/core.rb', line 1272

def validate?
  validate unless @errors
  self
end

#visible_paramsObject Also known as: visible_parameters

Get list of visible parameters.



1087
1088
1089
# File 'lib/form_input/core.rb', line 1087

def visible_params
  params.select{ |x| x.visible? }
end