Class: Roda::RodaPlugins::TypecastParams::Params
- Inherits:
-
Object
- Object
- Roda::RodaPlugins::TypecastParams::Params
- Defined in:
- lib/roda/plugins/typecast_params.rb
Overview
Class handling conversion of submitted parameters to desired types.
Class Method Summary collapse
-
.handle_type(type, opts = OPTS, &block) ⇒ Object
Handle conversions for the given type using the given block.
-
.max_input_bytesize(type, bytesize) ⇒ Object
Override the maximum input bytesize for the given type.
-
.nest(obj, nesting) ⇒ Object
Create a new instance with the given object and nesting level.
Instance Method Summary collapse
-
#[](key) ⇒ Object
Return a new Params instance for the given
key
. -
#array(type, key, default = nil) ⇒ Object
Convert the value of
key
to an array of values of the giventype
. -
#array!(type, key, default = nil) ⇒ Object
Call
array
with thetype
,key
, anddefault
, but if the return value is nil or any value in the returned array isnil
, raise an Error. -
#convert!(keys = nil, opts = OPTS) ⇒ Object
Captures conversions inside the given block, and returns a hash of all conversions, including conversions of subkeys.
-
#convert_each!(opts = OPTS, &block) ⇒ Object
Runs conversions similar to convert! for each key specified by the :keys option.
-
#dig(type, *nest, key) ⇒ Object
Convert values nested under the current obj.
-
#dig!(type, *nest, key) ⇒ Object
Similar to
dig
, but raises an Error instead of returningnil
if no value is found. -
#fetch(key) ⇒ Object
Return the nested value for key.
-
#initialize(obj) ⇒ Params
constructor
Set the object used for converting.
-
#present?(key) ⇒ Boolean
If key is a String Return whether the key is present in the object,.
Constructor Details
#initialize(obj) ⇒ Params
Set the object used for converting. Conversion methods will convert members of the passed object.
585 586 587 588 589 590 591 592 593 594 595 596 |
# File 'lib/roda/plugins/typecast_params.rb', line 585 def initialize(obj) case @obj = obj when Hash, Array # nothing else if @nesting handle_error(nil, (@obj.nil? ? :missing : :invalid_type), "value of #{param_name(nil)} parameter not an array or hash: #{obj.inspect}", true) else handle_error(nil, :invalid_type, "parameters given not an array or hash: #{obj.inspect}", true) end end end |
Class Method Details
.handle_type(type, opts = OPTS, &block) ⇒ Object
Handle conversions for the given type using the given block. For a type named foo
, this will create the following methods:
-
foo(key, default=nil)
-
foo!(key)
-
convert_foo(value) # private
-
_convert_array_foo(value) # private
This method is used to define all type conversions, even the built in ones. It can be called in subclasses to setup subclass-specific types.
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
# File 'lib/roda/plugins/typecast_params.rb', line 448 def self.handle_type(type, opts=OPTS, &block) convert_meth = :"convert_#{type}" define_method(convert_meth, &block) max_input_bytesize = opts[:max_input_bytesize] max_input_bytesize_meth = :"_max_input_bytesize_for_#{type}" define_method(max_input_bytesize_meth){max_input_bytesize} convert_array_meth = :"_convert_array_#{type}" define_method(convert_array_meth) do |v| raise Error, "expected array but received #{v.inspect}" unless v.is_a?(Array) v.map! do |val| check_allowed_bytesize(val, send(max_input_bytesize_meth)) check_null_byte(val) send(convert_meth, val) end end private convert_meth, convert_array_meth, max_input_bytesize_meth alias_method max_input_bytesize_meth, max_input_bytesize_meth define_method(type) do |key, default=nil| process_arg(convert_meth, key, default, send(max_input_bytesize_meth)) if require_hash! end define_method(:"#{type}!") do |key| send(type, key, CHECK_NIL) end end |
.max_input_bytesize(type, bytesize) ⇒ Object
Override the maximum input bytesize for the given type. This is mostly useful for overriding the sizes for the default input types.
480 481 482 483 484 485 |
# File 'lib/roda/plugins/typecast_params.rb', line 480 def self.max_input_bytesize(type, bytesize) max_input_bytesize_meth = :"_max_input_bytesize_for_#{type}" define_method(max_input_bytesize_meth){bytesize} private max_input_bytesize_meth alias_method max_input_bytesize_meth, max_input_bytesize_meth end |
.nest(obj, nesting) ⇒ Object
Create a new instance with the given object and nesting level. obj
should be an array or hash, and nesting
should be an array. Designed for internal use, should not be called by external code.
491 492 493 494 495 496 |
# File 'lib/roda/plugins/typecast_params.rb', line 491 def self.nest(obj, nesting) v = allocate v.instance_variable_set(:@nesting, nesting) v.send(:initialize, obj) v end |
Instance Method Details
#[](key) ⇒ Object
Return a new Params instance for the given key
. The value of key
should be an array if key
is an integer, or hash otherwise.
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
# File 'lib/roda/plugins/typecast_params.rb', line 615 def [](key) @subs ||= {} if sub = @subs[key] return sub end if @obj.is_a?(Array) unless key.is_a?(Integer) handle_error(key, :invalid_type, "invalid use of non-integer key for accessing array: #{key.inspect}", true) end else if key.is_a?(Integer) handle_error(key, :invalid_type, "invalid use of integer key for accessing hash: #{key}", true) end end v = @obj[key] v = yield if v.nil? && defined?(yield) begin sub = self.class.nest(v, Array(@nesting) + [key]) rescue => e handle_error(key, :invalid_type, e, true) end @subs[key] = sub sub.sub_capture(@capture, @symbolize, @skip_missing) sub end |
#array(type, key, default = nil) ⇒ Object
Convert the value of key
to an array of values of the given type
. If default
is given, any nil
values in the array are replaced with default
. If key
is an array then this returns an array of arrays, one for each respective value of key
. If there is no value for key
, nil is returned instead of an array.
752 753 754 755 756 |
# File 'lib/roda/plugins/typecast_params.rb', line 752 def array(type, key, default=nil) meth = :"_convert_array_#{type}" raise ProgrammerError, "no typecast_params type registered for #{type.inspect}" unless respond_to?(meth, true) process_arg(meth, key, default, send(:"_max_input_bytesize_for_#{type}")) if require_hash! end |
#array!(type, key, default = nil) ⇒ Object
Call array
with the type
, key
, and default
, but if the return value is nil or any value in the returned array is nil
, raise an Error.
760 761 762 763 764 765 766 767 768 769 770 771 772 |
# File 'lib/roda/plugins/typecast_params.rb', line 760 def array!(type, key, default=nil) v = array(type, key, default) if key.is_a?(Array) key.zip(v).each do |k, arr| check_array!(k, arr) end else check_array!(key, v) end v end |
#convert!(keys = nil, opts = OPTS) ⇒ Object
Captures conversions inside the given block, and returns a hash of all conversions, including conversions of subkeys. keys
should be an array of subkeys to access, or nil to convert the current object. If keys
is given as a hash, it is used as the options hash. Options:
- :raise
-
If set to false, do not raise errors for missing keys
- :skip_missing
-
If set to true, does not store values if the key is not present in the params.
- :symbolize
-
Convert any string keys in the resulting hash and for any conversions below
661 662 663 664 665 666 667 668 669 670 671 672 |
# File 'lib/roda/plugins/typecast_params.rb', line 661 def convert!(keys=nil, opts=OPTS) if keys.is_a?(Hash) opts = keys keys = nil end _capture!(:nested_params, opts) do if sub = subkey(Array(keys).dup, opts.fetch(:raise, true)) yield sub end end end |
#convert_each!(opts = OPTS, &block) ⇒ Object
Runs conversions similar to convert! for each key specified by the :keys option. If :keys option is not given and the object is an array, runs conversions for all entries in the array. If the :keys option is not given and the object is a Hash with string keys ‘0’, ‘1’, …, ‘N’ (with no skipped keys), runs conversions for all entries in the hash. If :keys option is a Proc or a Method, calls the proc/method with the current object, which should return an array of keys to use. Supports options given to #convert!, and this additional option:
- :keys
-
The keys to extract from the object. If a proc or method, calls the value with the current object, which should return the array of keys to use.
685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 |
# File 'lib/roda/plugins/typecast_params.rb', line 685 def convert_each!(opts=OPTS, &block) np = !@capture _capture!(nil, opts) do case keys = opts[:keys] when nil keys = (0...@obj.length) valid = if @obj.is_a?(Array) true else keys = keys.map(&:to_s) keys.all?{|k| @obj.has_key?(k)} end unless valid handle_error(nil, :invalid_type, "convert_each! called on object not an array or hash with keys '0'..'N'") next end when Array # nothing to do when Proc, Method keys = keys.call(@obj) else raise ProgrammerError, "unsupported convert_each! :keys option: #{keys.inspect}" end keys.map do |i| begin if v = subkey([i], opts.fetch(:raise, true)) yield v v.nested_params if np end rescue => e handle_error(i, :invalid_type, e) end end end end |
#dig(type, *nest, key) ⇒ Object
Convert values nested under the current obj. Traverses the current object using nest
, then converts key
on that object using type
:
tp.dig(:pos_int, 'foo') # tp.pos_int('foo')
tp.dig(:pos_int, 'foo', 'bar') # tp['foo'].pos_int('bar')
tp.dig(:pos_int, 'foo', 'bar', 'baz') # tp['foo']['bar'].pos_int('baz')
Returns nil if any of the values are not present or not the expected type. If the nest path results in an object that is not an array or hash, then raises an Error.
You can use dig
to get access to nested arrays by using :array
or :array!
as the first argument and providing the type in the second argument:
tp.dig(:array, :pos_int, 'foo', 'bar', 'baz') # tp['foo']['bar'].array(:pos_int, 'baz')
739 740 741 |
# File 'lib/roda/plugins/typecast_params.rb', line 739 def dig(type, *nest, key) _dig(false, type, nest, key) end |
#dig!(type, *nest, key) ⇒ Object
Similar to dig
, but raises an Error instead of returning nil
if no value is found.
744 745 746 |
# File 'lib/roda/plugins/typecast_params.rb', line 744 def dig!(type, *nest, key) _dig(true, type, nest, key) end |
#fetch(key) ⇒ Object
Return the nested value for key. If there is no nested_value for key
, calls the block to return the value, or returns nil if there is no block given.
647 648 649 |
# File 'lib/roda/plugins/typecast_params.rb', line 647 def fetch(key) send(:[], key){return(yield if defined?(yield))} end |
#present?(key) ⇒ Boolean
If key is a String Return whether the key is present in the object,
599 600 601 602 603 604 605 606 607 608 609 610 611 |
# File 'lib/roda/plugins/typecast_params.rb', line 599 def present?(key) case key when String !any(key).nil? when Array key.all? do |k| raise ProgrammerError, "non-String element in array argument passed to present?: #{k.inspect}" unless k.is_a?(String) !any(k).nil? end else raise ProgrammerError, "unexpected argument passed to present?: #{key.inspect}" end end |