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, params: nil, defaults: false, force: false) ⇒ Instance

Initialize a parameter instance. Any params will be passed to #process.

Parameters:

  • registry (Params::Registry, Params::Registry::Group)

    the registry

  • params (String, Hash{Symbol => Array}) (defaults to: nil)

    something that resembles either the input or the output of URI.decode_www_form.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/params/registry/instance.rb', line 97

def initialize registry, params: nil, defaults: false, force: false
  # deal with registry/group stuff
  if registry.is_a? Params::Registry::Group
    @group    = registry.id
    @registry = registry = registry.registry
  else
    @group    = nil
    @registry = registry
  end

  # set up members
  @content  = {}
  @extra    = {}

  process params, defaults: defaults, force: force if params
end

Instance Attribute Details

#extraObject (readonly)

Returns the value of attribute extra.



89
90
91
# File 'lib/params/registry/instance.rb', line 89

def extra
  @extra
end

#registryObject (readonly)

Returns the value of attribute registry.



89
90
91
# File 'lib/params/registry/instance.rb', line 89

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.



198
199
200
201
# File 'lib/params/registry/instance.rb', line 198

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.



216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/params/registry/instance.rb', line 216

def []= param, value
  unless template = registry.templates[param]
    # XXX THIS IS POTENTIALLY DUMB
    value = value.respond_to?(:to_a) ? value : [value]
    return @extras[param] = value
  end

  # XXX THIS MIGHT FUCK SHIT UP
  if value.nil?
    @content.delete template.id
  else
    @content[template.id] = template.process value
  end
end

#content=(struct) ⇒ Object

Bulk-assign instance content.

Parameters:

  • struct (Hash)


235
236
237
238
# File 'lib/params/registry/instance.rb', line 235

def content= struct
  # just use the member assign we already have
  struct.each { |k, v| self[k] = v }
end

#dupParams::Registry::Instance

Create a shallow copy of the parameter instance.

Returns:



281
282
283
284
285
# File 'lib/params/registry/instance.rb', line 281

def dup
  out = self.class.new @registry[@group]
  out.content = @content.dup
  out
end

#inspectString

Return a string representation of the object suitable for debugging.

Returns:

  • (String)

    said string representation



345
346
347
# File 'lib/params/registry/instance.rb', line 345

def inspect
  "<#{self.class} content: #{@content.inspect}, extra: #{@extra.inspect}>"
end

#make_uri(uri, defaults: false, extra: false) ⇒ URI, #query=

Return a URI with the query set to the string value of this instance.

Parameters:

  • uri (URI, #query=)

    the URI you want to assign

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

    whether to include defaults

Returns:

  • (URI, #query=)

    the URI with the new query string



247
248
249
250
251
# File 'lib/params/registry/instance.rb', line 247

def make_uri uri, defaults: false, extra: false
  uri = uri.dup
  uri.query = to_s defaults: defaults, extra: extra
  uri
end

#process(params, defaults: true, force: false) ⇒ self

Process a set of parameters of varying degrees of parsed-ness, up to and including a raw query string.

Parameters:

  • params (String, Hash{Symbol => Array})

    something that resembles either the input or the output of URI.decode_www_form.

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

    whether to include defaults in the result

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

    force strict cardinality checking

Returns:

  • (self)

    for daisy-chaining

Raises:

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


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/params/registry/instance.rb', line 124

def process params, defaults: true, force: false

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

  # warn [:before, params].inspect

  # make sure we get a struct-like object with canonical keys but
  # don't touch the values yet
  params = Types::Input[params].reduce({}) do |hash, pair|
    key, value = pair
    # warn "kv: #{key.inspect} => #{value.inspect}"
    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 these keys for deletion

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

  # warn registry.templates.ranked.inspect

  # warn [:process, params].inspect

  # 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 = params.fetch t.id, []

      c = complements.include? t.id

      begin
        del += process_one t, raw,
          defaults: defaults, 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 }

  # this is a daisy chainer
  self
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.



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/params/registry/instance.rb', line 260

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_s(defaults: false, extra: false) ⇒ String

Serialize the instance back to a URI query string.

Returns:

  • (String)

    the instance serialized as a URI query string.



296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/params/registry/instance.rb', line 296

def to_s defaults: false, extra: false
  ts = registry.templates

  # warn ts.inspect

  # this should give us a list of keys that have defaults that we
  # want to show up
  defaults = case defaults
             when nil, false then []
             when true then ts.select { |k| ts[k].default? }.values.map(&:id)
             when -> d { d.respond_to? :to_a } then defaults.to_a
             else [defaults]
             end.map { |d| ts[d]&.id }.compact

  # the template keys should have the original order so we want to intersee
  sequence = ts.keys & @content.keys
  complements = Set[]
  out = sequence.map do |k|
    template = ts[k]

    # we want to skip the parameter if it's the same as
    next if template.default? and @content[k] == template.default and
      not defaults.include? k

    # get the dependencies, convert to an array of strings, harvest
    # complement flag (if present)
    deps = @content.slice(*(template.depends - template.consumes))
    v, c = template.unprocess @content[k], deps, try_complement: true
    complements << k if c

    # warn @content[k], v.inspect

    next if v.empty?

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

  # XXX TODO complement and extras i just don't feel like looking up how
  # that's supposed to work rn but they would go here

  out.join ?&
end