Class: Params::Registry::Instance

Inherits:
Object
  • Object
show all
Defined in:
lib/params/registry/instance.rb

Overview

This class represents a parsed instance of a set of parameters. It is intended to be used like a Hash, and, among other things, manages the serialization of the parameters back into a normalized query string.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registry, struct, defaults: false, force: false) ⇒ Instance

Make a new instance.

Parameters:

  • registry (Params::Registry)

    the registry

  • struct (Hash{Symbol => Array<String>})

    something that resembles the output of URI.decode_www_form.

Raises:

  • (Params::Registry::Error::Processing)


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
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
124
125
126
127
128
129
130
131
132
# File 'lib/params/registry/instance.rb', line 65

def initialize registry, struct, defaults: false, force: false
  if registry.is_a? Params::Registry::Group
    @group    = registry.id
    @registry = registry = registry.registry
  else
    @group    = nil
    @registry = registry
  end

  @content  = {}
  @extra    = {}

  # warn "wtf lol #{@registry[@group].inspect}"

  # canonicalize the keys of the struct
  struct = Types::Input[struct].reduce({}) do |hash, pair|
    key, value = pair
    if t = @registry[@group][key]
      # warn "yep #{key.inspect}"
      hash[t.id] = value
    else
      # warn "nope #{key.inspect}"
      @extra[key] = value
    end

    hash
  end

  errors = {} # collect errors so we only raise once at the end
  del = Set[] # mark for deletion

  # grab the complements now
  complements = @content[@registry.complement.id] =
    @registry.complement.process(*struct.fetch(@registry.complement.id, []))

  # warn registry.templates.ranked.inspect

  # warn complements.class

  # now we get the ranked templates and pass them through
  @registry[@group].ranked.each do |templates|
    # give me the intersection of templates
    templates.values.each do |t|

      # warn t.id

      # obtain the raw values or an empty array instead
      raw = struct.fetch t.id, []

      c = complements.include? t.id

      begin
        del += process_one t, raw, force: force, complement: c
      rescue Params::Registry::Error => e
        errors[t.id] = e
      end

    end
  end

  # raise any errors if we need to
  raise Params::Registry::Error::Processing.new(
    'One or more parameters failed to process', errors: errors) unless
    errors.empty?

  # delete the unwanted parameters
  del.each { |d| @content.delete d }
end

Instance Attribute Details

#registryObject (readonly)

Returns the value of attribute registry.



57
58
59
# File 'lib/params/registry/instance.rb', line 57

def registry
  @registry
end

Instance Method Details

#[](param) ⇒ Object, ...

Retrieve the processed value for a parameter.

Parameters:

  • param (Object, #to_sym)

    the parameter identifier, or slug, or alias.

Returns:

  • (Object, Array, nil)

    the value, if present.



141
142
143
144
# File 'lib/params/registry/instance.rb', line 141

def [] param
  param = @registry.templates.canonical(param) or return @extra[param]
  @content[param]
end

#[]=(param, value) ⇒ Object, Array

Assign a new value to a key. The new value will be tested against the composite type if one is present, then an Array of the ordinary atomic type if the cardinality is greater than 1, then finally the atomic type.

Parameters:

  • param (Object, #to_sym)

    the parameter identifier, or slug, or alias.

  • value (Object, Array)

    the value, which is subject to type assertion/coercion.

Returns:

  • (Object, Array)

    the value(s) associated with the parameter.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/params/registry/instance.rb', line 159

def []= param, value
  unless template = registry.templates[param]
    value = value.respond_to?(:to_a) ? value.to_a : value
    return @extras[param] = value
  end

  # XXX do something less dumb about this
  c = (@content[registry.complement.id] || Set[]).include? template.id

  # this modifies @content and may raise
  del = process_one template, value, force: true, complement: c

  del.each { |d| @content.delete d }

  # return
  @content[template.id]
end

#to_h(slugs: true, extra: false) ⇒ Hash

Taxidermy this object as an ordinary hash.

Parameters:

  • slugs (true, false) (defaults to: true)

    whether to use slugs versus canonical keys.

  • extra (false, true) (defaults to: false)

    whether to include the "extra" parameters.

Returns:

  • (Hash)

    basically the same thing, minus its metadata.



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/params/registry/instance.rb', line 184

def to_h slugs: true, extra: false
  g = registry[@group]

  out = {}

  g.templates.each do |t|
    next unless @content.key? t.id
    key = slugs ? t.slug || t.id.to_s.to_sym : t.id
    out[key] = @content[t.id]
  end

  # XXX maybe enforce the ordering better??
  out.merge! @extra if extra

  out
end

#to_sString

Serialize the instance back to a URI query string.

Returns:

  • (String)

    the instance serialized as a URI query string.



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/params/registry/instance.rb', line 218

def to_s
  ts = registry.templates
  sequence = ts.keys & @content.keys
  complements = Set[]
  sequence.map do |k|
    template = ts[k]
    deps = @content.values_at(*(template.depends - template.consumes))
    v, c = template.unprocess @content[k], *deps, with_complement_flag: true
    complements << k if c

    # warn @content[k], v.inspect

    next if v.empty?

    v.map { |v| "#{template.slug || k}=#{v}" }.join ?&
  end.compact.join ?&
end