Module: IknowParams::Parser

Extended by:
ActiveSupport::Concern
Included in:
HashParser
Defined in:
lib/iknow_params/parser.rb

Overview

IknowParams::Parser provides a mix-in for ActiveRecord controllers to parse input parameters.

Defined Under Namespace

Classes: HashParser, ParseError

Constant Summary collapse

PARAM_REQUIRED =
Object.new
BLANK =
Object.new

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.parse_hash(hash, &block) ⇒ Object



27
28
29
# File 'lib/iknow_params/parser.rb', line 27

def parse_hash(hash, &block)
  HashParser.new(hash).parse(&block)
end

.parse_value(value, **args) ⇒ Object



31
32
33
# File 'lib/iknow_params/parser.rb', line 31

def parse_value(value, **args)
  HashParser.new({ sentinel: value }).parse_param(:sentinel, **args)
end

.parse_values(values, **args) ⇒ Object



35
36
37
# File 'lib/iknow_params/parser.rb', line 35

def parse_values(values, **args)
  HashParser.new({ sentinel: values }).parse_array_param(:sentinel, **args)
end

.register_serializer(name, serializer) ⇒ Object

Allow serializers to register themselves



146
147
148
149
150
151
152
153
# File 'lib/iknow_params/parser.rb', line 146

def self.register_serializer(name, serializer)
  define_method(:"parse_#{name.underscore}_param") do |param, default: PARAM_REQUIRED|
    parse_param(param, with: serializer, default: default)
  end
  define_method(:"parse_#{name.underscore}_array_param") do |param, default: PARAM_REQUIRED|
    parse_array_param(param, with: serializer, default: default)
  end
end

Instance Method Details

#parse_array_param(param, with: nil, default: PARAM_REQUIRED, dump: false) ⇒ Object

Parse an array-typed param using the provided serializer for each member element.



89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/iknow_params/parser.rb', line 89

def parse_array_param(param, with: nil, default: PARAM_REQUIRED, dump: false)
  serializer =
    case with
    when String, Symbol
      IknowParams::Serializer.for!(with)
    else
      with
    end

  vals = params[param]

  parses =
    if vals.nil?
      raise ParseError.new("Required parameter '#{param}' missing", param, nil) if default == PARAM_REQUIRED
      default
    elsif !vals.is_a?(Array)
      raise ParseError.new("Invalid type for parameter '#{param}': '#{vals.class.name}'", param, vals)
    elsif serializer.present?
      vals.map do |val|
        begin
          serializer.load(val)
        rescue IknowParams::Serializer::LoadError => ex
          raise ParseError.new("Invalid member in array parameter '#{param}': '#{val.inspect}' - #{ex.message}", param, val)
        end
      end
    else
      vals
    end

  if dump && parses != BLANK
    parses.map! { |v| serializer.dump(v) }
  end

  parses
end

#parse_param(param, with: nil, default: PARAM_REQUIRED, dump: false) ⇒ Object

Parse the specified parameter, optionally deserializing with the provided IKnowParams::Serializer. If the parameter is missing and no default is provided, raises a ParseError.

If BLANK is provided as a default, return a placeholder object that can be later stripped out with remove_blanks

If dump is true, use the serializer to re-serialize any successfully parsed argument back to a canonical string. This can be useful to validate and normalize the input to another service without parsing it. A serializer must be passed to use this option.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/iknow_params/parser.rb', line 51

def parse_param(param, with: nil, default: PARAM_REQUIRED, dump: false)
  serializer =
    case with
    when String, Symbol
      IknowParams::Serializer.for!(with)
    else
      with
    end

  parse =
    if !params.has_key?(param)
      raise ParseError.new("Required parameter '#{param}' missing", param, nil) if default == PARAM_REQUIRED
      default
    else
      val = params[param]
      if serializer.present?
        begin
          serializer.load(val)
        rescue IknowParams::Serializer::LoadError => ex
          raise ParseError.new("Invalid parameter '#{param}': '#{val.inspect}' - #{ex.message}", param, val)
        end
      else
        val
      end
    end

  if dump && parse != BLANK
    begin
      parse = serializer.dump(parse)
    rescue NoMethodError => ex
      raise ParseError.new("Serializer '#{serializer}' can't dump param '#{param}' #{val.inspect} - #{ex.message}", param, val)
    end
  end

  parse
end

#remove_blanks(arg) ⇒ Object

Convenience method to make it simpler to build a hash structure with optional members from parsed data. This method recursively traverses the provided structure and removes any instances of the sentinel value Parser::BLANK.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/iknow_params/parser.rb', line 129

def remove_blanks(arg)
  case arg
  when Hash
    arg.each do |k, v|
      if v == BLANK
        arg.delete(k)
      else
        remove_blanks(v)
      end
    end
  when Array
    arg.delete(BLANK)
    arg.each { |e| remove_blanks(e) }
  end
end