Class: TypedParams::Schema

Inherits:
Object
  • Object
show all
Defined in:
lib/typed_params/schema.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(controller: nil, source: nil, strict: true, parent: nil, type: :hash, key: nil, optional: false, coerce: false, polymorphic: false, allow_blank: false, allow_nil: false, allow_non_scalars: false, nilify_blanks: false, noop: false, inclusion: nil, exclusion: nil, format: nil, length: nil, transform: nil, validate: nil, if: nil, unless: nil, as: nil, alias: nil, casing: TypedParams.config.key_transform, &block) ⇒ Schema

Returns a new instance of Schema.

Raises:

  • (ArgumentError)


18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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
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
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
# File 'lib/typed_params/schema.rb', line 18

def initialize(
  controller: nil,
  source: nil,
  strict: true,
  parent: nil,
  type: :hash,
  key: nil,
  optional: false,
  coerce: false,
  polymorphic: false,
  allow_blank: false,
  allow_nil: false,
  allow_non_scalars: false,
  nilify_blanks: false,
  noop: false,
  inclusion: nil,
  exclusion: nil,
  format: nil,
  length: nil,
  transform: nil,
  validate: nil,
  if: nil,
  unless: nil,
  as: nil,
  alias: nil,
  casing: TypedParams.config.key_transform,
  &block
)
  key ||= ROOT

  raise ArgumentError, 'key is required for child schema' if
    key == ROOT && parent.present?

  raise ArgumentError, 'root cannot be null' if
    key == ROOT && allow_nil

  raise ArgumentError, 'source must be one of: :params or :query' unless
    source.nil? || source == :params || source == :query

  raise ArgumentError, 'inclusion must be a hash with :in key' unless
    inclusion.nil? || inclusion.is_a?(Hash) && inclusion.key?(:in)

  raise ArgumentError, 'exclusion must be a hash with :in key' unless
    exclusion.nil? || exclusion.is_a?(Hash) && exclusion.key?(:in)

  raise ArgumentError, 'format must be a hash with :with or :without keys (but not both)' unless
    format.nil? || format.is_a?(Hash) && (
      format.key?(:with) ^
      format.key?(:without)
    )

  raise ArgumentError, 'length must be a hash with :minimum, :maximum, :within, :in, or :is keys (but not multiple except for :minimum and :maximum)' unless
    length.nil? || length.is_a?(Hash) && (
      length.key?(:minimum) && length.key?(:maximum) && length.size == 2 ||
        length.key?(:minimum) ^
        length.key?(:maximum) ^
        length.key?(:within) ^
        length.key?(:in) ^
        length.key?(:is)
    )

  @controller        = controller
  @source            = source
  @type              = Types[type]
  @strict            = strict
  @parent            = parent
  @key               = key
  @as                = as
  @alias             = binding.local_variable_get(:alias)
  @optional          = optional
  @coerce            = coerce && @type.coercable?
  @polymorphic       = polymorphic
  @allow_blank       = key == ROOT || allow_blank
  @allow_nil         = allow_nil
  @allow_non_scalars = allow_non_scalars
  @nilify_blanks     = nilify_blanks
  @noop              = noop
  @inclusion         = inclusion
  @exclusion         = exclusion
  @format            = format
  @length            = length
  @casing            = casing
  @transform         = transform
  @children          = nil
  @if                = binding.local_variable_get(:if)
  @unless            = binding.local_variable_get(:unless)
  @formatter         = nil
  @options           = {}

  # Validations
  @validations = []

  @validations << Validations::Inclusion.new(inclusion) if
    inclusion.present?

  @validations << Validations::Exclusion.new(exclusion) if
    exclusion.present?

  @validations << Validations::Format.new(format) if
    format.present?

  @validations << Validations::Length.new(length) if
    length.present?

  @validations << Validations::Validation.wrap(validate) if
    validate.present?

  # Transforms
  @transforms = []

  @transforms << Transforms::KeyAlias.new(as) if
    as.present?

  @transforms << Transforms::NilifyBlanks.new if
    nilify_blanks

  @transforms << Transforms::Transform.wrap(transform) if
    transform.present?

  @transforms << Transforms::KeyCasing.new(casing) if
    casing.present?

  @transforms << Transforms::Noop.new if
    noop

  raise ArgumentError, "type #{type} is a not registered type" if
    @type.nil?

  if block_given?
    raise ArgumentError, "type #{@type} does not accept a block" if
      @type.present? && !@type.accepts_block?

    @children = case
                when Types.array?(@type)
                  []
                when Types.hash?(@type)
                  {}
                end

    self.instance_exec &block
  end
end

Instance Attribute Details

#aliasObject (readonly)

Returns the value of attribute alias.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def alias
  @alias
end

#asObject (readonly)

Returns the value of attribute as.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def as
  @as
end

#childrenObject (readonly)

Returns the value of attribute children.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def children
  @children
end

#formatterObject (readonly)

Returns the value of attribute formatter.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def formatter
  @formatter
end

#ifObject (readonly)

Returns the value of attribute if.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def if
  @if
end

#keyObject (readonly)

Returns the value of attribute key.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def key
  @key
end

#parentObject (readonly)

Returns the value of attribute parent.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def parent
  @parent
end

#sourceObject (readonly)

Returns the value of attribute source.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def source
  @source
end

#transformsObject (readonly)

Returns the value of attribute transforms.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def transforms
  @transforms
end

#typeObject (readonly)

Returns the value of attribute type.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def type
  @type
end

#unlessObject (readonly)

Returns the value of attribute unless.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def unless
  @unless
end

#validationsObject (readonly)

Returns the value of attribute validations.



5
6
7
# File 'lib/typed_params/schema.rb', line 5

def validations
  @validations
end

Instance Method Details

#aliased?Boolean



273
# File 'lib/typed_params/schema.rb', line 273

def aliased?           = !!@alias

#allow_blank?Boolean



274
# File 'lib/typed_params/schema.rb', line 274

def allow_blank?       = !!@allow_blank

#allow_nil?Boolean



275
# File 'lib/typed_params/schema.rb', line 275

def allow_nil?         = !!@allow_nil

#allow_non_scalars?Boolean



276
# File 'lib/typed_params/schema.rb', line 276

def allow_non_scalars? = !!@allow_non_scalars

#array?Boolean



282
# File 'lib/typed_params/schema.rb', line 282

def array?             = Types.array?(type)

#child?Boolean



265
# File 'lib/typed_params/schema.rb', line 265

def child?             = !root?

#children?Boolean



266
# File 'lib/typed_params/schema.rb', line 266

def children?          = !children.blank?

#coerce?Boolean



271
# File 'lib/typed_params/schema.rb', line 271

def coerce?            = !!@coerce

#endless?Boolean



278
# File 'lib/typed_params/schema.rb', line 278

def endless?           = !!@endless

#format(format) ⇒ Object

format defines the final output format for the schema, transforming the params from an input format to an output format, e.g. a JSONAPI document to Rails’ standard params format. This also applies the formatter’s decorators onto the controller.

Raises:

  • (NotImplementedError)


166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/typed_params/schema.rb', line 166

def format(format)
  raise NotImplementedError, 'cannot define format for child schema' if
    child?

  formatter = Formatters[format]

  raise ArgumentError, "invalid format: #{format.inspect}" if
    formatter.nil?

  # Apply the formatter's decorators onto the controller.
  controller.instance_exec(&formatter.decorator) if
    controller.present? && formatter.decorator?

  @formatter = formatter
end

#formatter?Boolean



285
# File 'lib/typed_params/schema.rb', line 285

def formatter?         = !!@formatter

#hash?Boolean



283
# File 'lib/typed_params/schema.rb', line 283

def hash?              = Types.hash?(type)

#if?Boolean



280
# File 'lib/typed_params/schema.rb', line 280

def if?                = !@if.nil?

#indexed?Boolean



279
# File 'lib/typed_params/schema.rb', line 279

def indexed?           = !endless?

#inspectObject



287
288
289
# File 'lib/typed_params/schema.rb', line 287

def inspect
  "#<#{self.class.name} key=#{key.inspect} type=#{type.inspect} children=#{children.inspect}>"
end

#item(key = children&.size || 0, type:, **kwargs, &block) ⇒ Object

item defines an indexed parameter for an array schema.

Raises:

  • (NotImplementedError)


226
227
228
229
230
231
232
233
234
# File 'lib/typed_params/schema.rb', line 226

def item(key = children&.size || 0, type:, **kwargs, &block)
  raise NotImplementedError, "cannot define item for non-array type (got #{self.type})" unless
    Types.array?(children)

  raise ArgumentError, "index #{key} has already been defined" if
    children[key].present? || endless?

  children << Schema.new(**options, **kwargs, key:, type:, strict:, source:, casing:, parent: self, &block)
end

#items(**kwargs) ⇒ Object

items defines a set of like-parameters for an array schema.



238
239
240
241
242
# File 'lib/typed_params/schema.rb', line 238

def items(**kwargs, &)
  item(0, **kwargs, &)

  endless!
end

#keysObject



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/typed_params/schema.rb', line 250

def keys
  return [] if
    children.blank?

  case children
  when Array
    (0...children.size).to_a
  when Hash
    children.keys
  else
    []
  end
end

#lenient?Boolean



268
# File 'lib/typed_params/schema.rb', line 268

def lenient?           = !strict?

#nilify_blanks?Boolean



277
# File 'lib/typed_params/schema.rb', line 277

def nilify_blanks?     = !!@nilify_blanks

#optional?Boolean



269
# File 'lib/typed_params/schema.rb', line 269

def optional?          = !!@optional

#param(key, type:, **kwargs, &block) ⇒ Object

param defines a keyed parameter for a hash schema.

Raises:

  • (NotImplementedError)


210
211
212
213
214
215
216
217
218
# File 'lib/typed_params/schema.rb', line 210

def param(key, type:, **kwargs, &block)
  raise NotImplementedError, "cannot define param for non-hash type (got #{self.type})" unless
    Types.hash?(children)

  raise ArgumentError, "key #{key} has already been defined" if
    children.key?(key)

  children[key] = Schema.new(**options, **kwargs, key:, type:, strict:, source:, casing:, parent: self, &block)
end

#params(*keys, **kwargs, &block) ⇒ Object

params defines multiple like-parameters for a hash schema.



222
# File 'lib/typed_params/schema.rb', line 222

def params(*keys, **kwargs, &block) = keys.each { param(_1, **kwargs, &block) }

#pathObject



244
245
246
247
248
# File 'lib/typed_params/schema.rb', line 244

def path
  key = @key == ROOT ? nil : @key

  @path ||= Path.new(*parent&.path&.keys, *key)
end

#polymorphic?Boolean



272
# File 'lib/typed_params/schema.rb', line 272

def polymorphic?       = !!@polymorphic

#required?Boolean



270
# File 'lib/typed_params/schema.rb', line 270

def required?          = !optional?

#root?Boolean



264
# File 'lib/typed_params/schema.rb', line 264

def root?              = key == ROOT

#scalar?Boolean



284
# File 'lib/typed_params/schema.rb', line 284

def scalar?            = Types.scalar?(type)

#strict?Boolean



267
# File 'lib/typed_params/schema.rb', line 267

def strict?            = !!strict

#unless?Boolean



281
# File 'lib/typed_params/schema.rb', line 281

def unless?            = !@unless.nil?

#with(**kwargs) ⇒ Object

with defines a set of options to use for all direct children of the schema defined within the block.

For example, it can be used to define a common guard:

with if: -> { ... } do
  param :foo, type: :string
  param :bar, type: :string
  param :baz, type: :hash do
    param :qux, type: :string
  end
end

In this example, :foo, :bar, and :baz will inherit the if: guard, but :qux will not, since it is not a direct child.



199
200
201
202
203
204
205
206
# File 'lib/typed_params/schema.rb', line 199

def with(**kwargs, &)
  orig     = @options
  @options = kwargs

  yield

  @options = orig
end