Class: Params::Registry::Template

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

Overview

This class manages an individual parameter template.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(registry, id, slug: nil, type: Types::NormalizedString, composite: nil, format: nil, aliases: nil, depends: nil, conflicts: nil, consumes: nil, preproc: nil, min: 0, max: nil, shift: false, empty: false, default: nil, universe: nil, complement: nil, unwind: nil, reverse: false) ⇒ Template

Initialize the template object.

Parameters:

  • registry (Params::Registry)

    A backreference to the parameter registry

  • id (Object)

    The canonical, unique identifier for the parameter

  • slug (#to_sym) (defaults to: nil)

    A "friendly" symbol that will end up in the serialization

  • aliases (Array<#to_sym>) (defaults to: nil)

    Alternative nicknames for the parameter

  • type (Dry::Types::Type, Symbol, Proc) (defaults to: Types::NormalizedString)

    An "atomic" type for single values

  • composite (Dry::Types::Type, Symbol, Proc) (defaults to: nil)

    A composite type into which multiple values are loaded

  • format (String, Proc, nil) (defaults to: nil)

    A format string or function

  • depends (Array) (defaults to: nil)

    Parameters that this one depends on

  • conflicts (Array) (defaults to: nil)

    Parameters that conflict with this one

  • consumes (Array) (defaults to: nil)

    Parameters that can be given in lieu of this one, that will be composed into this one. Parameters this one consumes implies depends and conflicts.

  • preproc (Proc, nil) (defaults to: nil)

    A preprocessing function that is fed parameters from consumes and depends to generate this parameter

  • min (Integer, nil) (defaults to: 0)

    Minimum cardinality

  • max (Integer, nil) (defaults to: nil)

    Maximum cardinality

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

    When given more than max values, do we take the ones we want from the back or from the front

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

    whether to treat an empty value as nil, the empty string, or discard it

  • default (Object, nil) (defaults to: nil)

    A default value

  • universe (Proc) (defaults to: nil)

    For Set or Range composite types and derivatives, a function that returns the universal set or range

  • complement (Proc) (defaults to: nil)

    For Set or Range composite types, a function that will return the complement of the set or range

  • unwind (Proc) (defaults to: nil)

    A function that takes the composite type and turns it into an Array of atomic values

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

    For Range composite types, a flag that indicates whether the values should be interpreted and/or serialized in reverse order. Also governs the serialization of Set composites.



64
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
# File 'lib/params/registry/template.rb', line 64

def initialize registry, id, slug: nil, type: Types::NormalizedString,
    composite: nil, format: nil, aliases: nil, depends: nil, conflicts: nil,
    consumes: nil, preproc: nil, min: 0, max: nil, shift: false,
    empty: false, default: nil, universe: nil, complement: nil,
    unwind: nil, reverse: false

  @registry   = Types::Registry[registry]
  @id         = Types::NonNil[id]
  @slug       = Types::Symbol[slug] if slug
  @type       = Types[type]
  @composite  = Types[composite] if composite
  @format     = (Types::Proc | Types::String)[format] if format
  @aliases    = Types::Array[aliases]
  @depends    = Types::Array[depends]
  @conflicts  = Types::Array[conflicts]
  @consumes   = Types::Array[consumes]
  @preproc    = Types::Proc[preproc] if preproc
  @min        = Types::NonNegativeInteger[min || 0]
  @max        = Types::PositiveInteger.optional[max]
  @shift      = Types::Bool[shift]
  @empty      = Types::Bool[empty]
  @default    = Types::Nominal::Any[default]
  @unifunc    = Types::Proc[universe]   if universe
  @complement = Types::Proc[complement] if complement
  @unwind     = Types::Proc[unwind]     if unwind
  @reverse    = Types::Bool[reverse]

  # post-initialization hook
  post_init
end

Instance Attribute Details

#aliasesArray<Symbol> (readonly)

Returns any aliases for this parameter.

Returns:

  • (Array<Symbol>)

    any aliases for this parameter.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#blank?Boolean (readonly)

Returns true if the template has no configuration data to speak of.

Returns:

  • (Boolean)


227
228
229
230
231
232
233
234
# File 'lib/params/registry/template.rb', line 227

def blank?
  # XXX PHEWWW
  @slug.nil? && @type == Types::NormalizedString && @composite.nil? &&
    @format.nil? && @aliases.empty? && @depends.empty? &&
    @conflicts.empty? && @consumes.empty? && @preproc.nil? &&
    @min == 0 && @max.nil? && !@shift && !@empty && @default.nil? &&
    @unifunc.nil? && @complement.nil? && @unwind.nil? && !@reverse
end

#complement?Boolean (readonly)

Whether this (composite) parameter can be complemented or inverted.

Returns:

  • (Boolean)


222
# File 'lib/params/registry/template.rb', line 222

def complement? ; !!@complement; end

#compositeDry::Types::Type? (readonly)

Returns the type for composite values.

Returns:

  • (Dry::Types::Type, nil)

    the type for composite values.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#conflictsArray (readonly)

Any parameters this one conflicts with.

Returns:

  • (Array)

Raises:



155
156
157
158
159
160
161
162
163
164
# File 'lib/params/registry/template.rb', line 155

def conflicts
  out = (@conflicts | (@preproc ? @consumes : [])).map do |t|
    registry.templates.canonical t
  end

  raise Params::Registry::Error,
    "Malformed conflict declaration on #{t.id}" if out.any?(&:nil?)

  out
end

#consumesArray (readonly)

Any parameters this one consumes (implies depends + conflicts).

Returns:

  • (Array)

Raises:



178
179
180
181
182
183
184
185
# File 'lib/params/registry/template.rb', line 178

def consumes
  out = @consumes.map { |t| registry.templates.canonical t }

  raise Params::Registry::Error,
    "Malformed consumes declaration on #{t.id}" if out.any?(&:nil?)

  out
end

#defaultObject? (readonly)

Returns a default value for the parameter.

Returns:

  • (Object, nil)

    a default value for the parameter.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#dependsArray (readonly)

Any parameters this one depends on.

Returns:

  • (Array)

Raises:



139
140
141
142
143
144
145
146
147
148
# File 'lib/params/registry/template.rb', line 139

def depends
  out = (@depends | (@preproc ? @consumes : [])).map do |t|
    registry.templates.canonical t
  end

  raise Params::Registry::Error,
    "Malformed dependency declaration on #{t.id}" if out.any?(&:nil?)

  out
end

#empty?Boolean (readonly)

Whether to accept empty values.

Returns:

  • (Boolean)


208
# File 'lib/params/registry/template.rb', line 208

def empty? ; !!@empty; end

#idObject (readonly)

Returns the canonical identifier for the parameter.

Returns:

  • (Object)

    the canonical identifier for the parameter.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#maxInteger? (readonly)

Returns maximum cardinality for the parameter's values.

Returns:

  • (Integer, nil)

    maximum cardinality for the parameter's values.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#minInteger (readonly)

Returns minimum cardinality for the parameter's values.

Returns:

  • (Integer)

    minimum cardinality for the parameter's values.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#preproc(myself, others) ⇒ Array (readonly)

Preprocess a parameter value against itself and/or consumed values.

Parameters:

  • myself (Array)

    raw values for the parameter itself.

  • others (Array)

    processed values for the consumed parameters.

Returns:

  • (Array)

    pseudo-raw, preprocessed values for the parameter.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#preproc?Boolean (readonly)

Whether there is a preprocessor function.

Returns:

  • (Boolean)


171
# File 'lib/params/registry/template.rb', line 171

def preproc? ; !!@preproc ; end

#registryParams::Registry (readonly)

Returns a backreference to the registry.

Returns:



131
132
133
# File 'lib/params/registry/template.rb', line 131

def registry
  @registry
end

#reverse?Boolean (readonly)

Whether to interpret composite values as reversed.

Returns:

  • (Boolean)


215
# File 'lib/params/registry/template.rb', line 215

def reverse? ; !!@reverse; end

#shift?Boolean (readonly)

Whether to shift values more than max cardinality off the front.

Returns:

  • (Boolean)


201
# File 'lib/params/registry/template.rb', line 201

def shift? ; !!@shift; end

#slugSymbol? (readonly)

Returns the primary nickname for the parameter, if different from the id.

Returns:

  • (Symbol, nil)

    the primary nickname for the parameter, if different from the id.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#typeDry::Types::Type (readonly)

Returns the type for individual parameter values.

Returns:

  • (Dry::Types::Type)

    the type for individual parameter values.



131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

#universeObject? (readonly)

The universal composite object (e.g. set or range) from which valid values are drawn.

Returns:

  • (Object, nil)


191
192
193
194
# File 'lib/params/registry/template.rb', line 191

def universe
  refresh! unless @universe
  @universe
end

#unwindProc? (readonly)

A function that will take a composite object and turn it into an array of strings for serialization.

Returns:

  • (Proc, nil)


131
132
# File 'lib/params/registry/template.rb', line 131

attr_reader :registry, :id, :slug, :type, :composite, :aliases,
:preproc, :min, :max, :default, :unwind

Instance Method Details

#complement(value) ⇒ Object?

Return the complement of the composite value for the parameter.

Parameters:

  • value (Object)

    the composite object to complement.

Returns:

  • (Object, nil)

    the complementary object, if a complement is defined.



280
281
282
283
284
285
286
287
288
289
# File 'lib/params/registry/template.rb', line 280

def complement value
  return unless @complement
  begin
    instance_exec value, &@complement
  rescue e
    raise Params::Registry::Error::Empirical.new(
      "Complement function failed: #{e.message}",
      context: self, value: value)
  end if @complement
end

#format(scalar) ⇒ String

Format an individual atomic value.

Parameters:

  • scalar (Object)

    the scalar/atomic value.

Returns:

  • (String)

    serialized to a string.



264
265
266
267
268
269
270
271
272
# File 'lib/params/registry/template.rb', line 264

def format scalar
  return scalar.to_s unless @format

  if @format.is_a? Proc
    instance_exec scalar, &@format
  else
    @format.to_s % scalar
  end
end

#inspectString

Return a suitable representation for debugging.

Returns:

  • (String)

    the object.



413
414
415
416
417
418
419
# File 'lib/params/registry/template.rb', line 413

def inspect
  c = self.class
  i = id.inspect
  t = '%s%s' % [type, composite ? ", #{composite}]" : '']

  "#<#{c} #{i} (#{t})>"
end

#process(*values) ⇒ Object, Array

Validate a list of individual parameter values and (if one is present) construct a composite value.

Parameters:

  • values (Array)

    the values given for the parameter.

Returns:

  • (Object, Array)

    the processed value(s).

Raises:



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
# File 'lib/params/registry/template.rb', line 298

def process *values
  out = []

  values.each do |v|
    # skip over nil/empty values unless we can be empty
    if v.nil? or v.to_s.empty?
      next unless empty?
      v = nil
    end

    if v
      begin
        tmp = type[v] # this either crashes or it doesn't
        v = tmp # in which case v is only assigned if successful
      rescue Dry::Types::CoercionError => e
        raise Params::Registry::Error::Syntax.new e.message,
          context: self, value: v
      end
    end

    out << v
  end

  # now we deal with cardinality
  raise Params::Registry::Error::Cardinality.new(
    "Need #{min} values and there are only #{out.length} values") if
    out.length < min

  # warn "hurr #{out.inspect}, #{max}"

  if max
    # return if it's supposed to be a scalar value
    return out.first if max == 1
    # cut the values to length from either the front or back
    out.slice!((shift? ? -max : 0), max) if out.length > max
  end

  composite ? composite[out] : out
end

#refresh!void

This method returns an undefined value.

Refreshes stateful information like the universal set, if present.



396
397
398
399
400
401
402
403
404
405
406
407
# File 'lib/params/registry/template.rb', line 396

def refresh!
  if @unifunc
    # do we want to call or do we want to instance_exec?
    univ = @unifunc.call

    univ = @composite[univ] if @composite

    @universe = univ
  end

  nil
end

#unprocess(value, *rest, with_complement_flag: false) ⇒ Array<String>, ...

Applies unwind to value to get an array, then format over each of the elements to get strings. If scalar is true, it will also return the flag from unwind indicating whether or not the complement parameter should be set.

This method is called by Instance#to_s and others to produce content which is amenable to serialization. As what happens there, the content of rest should be the values of the parameters specified in depends.

Parameters:

  • value (Object, Array<Object>)

    The parameter value(s).

  • rest (Array<Object>)

    The rest of the parameter values.

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

    Whether to return the complement flag in addition to the unwound values.

Returns:

  • (Array<String>, Array<(Array<String>, false)>, Array<(Array<String>, true)>, nil)

    the unwound value(s), plus optionally the complement flag, or otherwise nil.



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
# File 'lib/params/registry/template.rb', line 357

def unprocess value, *rest, with_complement_flag: false
  # take care of empty properly
  if value.nil?
    if empty?
      return [''] if max == 1
      return [] if max.nil? or max > 1
    end

    # i guess this is nil?
    return
  end

  # complement flag
  comp = false
  begin
    tmp, comp = instance_exec value, *rest, &@unwind
    value = tmp
  rescue Exception, e
    raise Params::Registry::Error::Empirical.new(
      "Cannot unprocess value #{value} for parameter #{id}: #{e.message}",
      context: self, value: value)
  end if @unwind

  # ensure this thing is an array
  value = [value] unless value.is_a? Array

  # ensure the values are correctly formatted
  value.map! { |v| v.nil? ? '' : self.format(v) }

  # throw in the complement flag
  return value, comp if with_complement_flag

  value
end