Class: HaveAPI::Params

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

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(direction, action) ⇒ Params

Returns a new instance of Params.



70
71
72
73
74
75
76
# File 'lib/haveapi/params.rb', line 70

def initialize(direction, action)
  @direction = direction
  @params = []
  @action = action
  @cache = {}
  @blocks = []
end

Instance Attribute Details

#actionObject

Returns the value of attribute action.



29
30
31
# File 'lib/haveapi/params.rb', line 29

def action
  @action
end

#paramsObject (readonly)

Returns the value of attribute params.



28
29
30
# File 'lib/haveapi/params.rb', line 28

def params
  @params
end

Class Method Details

.action_i18n_path(context, direction) ⇒ Object



32
33
34
35
36
37
# File 'lib/haveapi/params.rb', line 32

def action_i18n_path(context, direction)
  prefix = action_i18n_prefix(context)
  return unless prefix

  "#{prefix}.#{i18n_segment(direction)}"
end

.i18n_segment(value) ⇒ Object



51
52
53
# File 'lib/haveapi/params.rb', line 51

def i18n_segment(value)
  value.to_s.underscore.downcase.gsub(/[^a-z0-9_]+/, '_').gsub(/\A_+|_+\z/, '')
end

.metadata_i18n_path(context, type, direction) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
# File 'lib/haveapi/params.rb', line 39

def (context, type, direction)
  prefix = action_i18n_prefix(context)
  return unless prefix

  [
    prefix,
    'meta',
    i18n_segment(type),
    i18n_segment(direction)
  ].join('.')
end

Instance Method Details

#[](name) ⇒ Object



349
350
351
# File 'lib/haveapi/params.rb', line 349

def [](name)
  @params.detect { |p| p.name == name }
end

#add_block(b) ⇒ Object



78
79
80
# File 'lib/haveapi/params.rb', line 78

def add_block(b)
  @blocks << b
end

#bool(name, **kwargs) ⇒ Object



151
152
153
# File 'lib/haveapi/params.rb', line 151

def bool(name, **kwargs)
  add_param(name, apply(kwargs, type: Boolean))
end

#check_layout(params) ⇒ Object

First step of validation. Check if input is in correct namespace and has a correct layout.



270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/haveapi/params.rb', line 270

def check_layout(params)
  value = namespace ? params[namespace] : params

  if value.nil?
    raise ValidationError.new(HaveAPI.message('haveapi.validation.invalid_input_layout'), {}) if any_required_params?

  elsif !valid_layout?(value)
    raise ValidationError.new(HaveAPI.message('haveapi.validation.invalid_input_layout'), {})
  end

  return unless namespace

  case layout
  when :object, :hash
    params[namespace] ||= {}

  when :object_list, :hash_list
    params[namespace] ||= []
  end
end

#cloneObject



88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/haveapi/params.rb', line 88

def clone
  obj = super
  params = @params
  blocks = @blocks

  obj.instance_eval do
    @params = params.dup
    @cache = {}
    @blocks = blocks.dup
  end

  obj
end

#custom(name, symbolize_keys: false, **kwargs, &block) ⇒ Object

Action returns custom data.



220
221
222
# File 'lib/haveapi/params.rb', line 220

def custom(name, symbolize_keys: false, **kwargs, &block)
  add_param(name, apply(kwargs, type: Custom, clean: block, symbolize_keys:))
end

#datetime(name, **kwargs) ⇒ Object



166
167
168
# File 'lib/haveapi/params.rb', line 166

def datetime(name, **kwargs)
  add_param(name, apply(kwargs, type: Datetime))
end

#describe(context, metadata: false, i18n_path: nil) ⇒ Object



224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/haveapi/params.rb', line 224

def describe(context, metadata: false, i18n_path: nil)
  context.layout = layout

  ret = { parameters: {} }
  ret[:layout] = layout
  ret[:namespace] = namespace
  ret[:format] = @structure if @structure

  i18n_path ||= self.class.action_i18n_path(context, @direction)

  @params.each do |p|
    ret[:parameters][p.name] = p.describe(context, i18n_path:)
  end

  ret[:parameters] = filtered_description_parameters(context, ret, )

  ret
end

#execObject



82
83
84
85
86
# File 'lib/haveapi/params.rb', line 82

def exec
  @blocks.each do |b|
    instance_exec(&b)
  end
end

#float(name, **kwargs) ⇒ Object



162
163
164
# File 'lib/haveapi/params.rb', line 162

def float(name, **kwargs)
  add_param(name, apply(kwargs, type: Float))
end

#integer(name, **kwargs) ⇒ Object Also known as: id, foreign_key



155
156
157
# File 'lib/haveapi/params.rb', line 155

def integer(name, **kwargs)
  add_param(name, apply(kwargs, type: Integer))
end

#layoutObject



102
103
104
105
106
# File 'lib/haveapi/params.rb', line 102

def layout
  return @cache[:layout] if @cache[:layout]

  @cache[:layout] = @layout || :object
end

#layout=(l) ⇒ Object



108
109
110
# File 'lib/haveapi/params.rb', line 108

def layout=(l)
  @layout = l if l
end

#namespaceObject



112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/haveapi/params.rb', line 112

def namespace
  return @cache[:namespace] unless @cache[:namespace].nil?
  return @cache[:namespace] = @namespace unless @namespace.nil?

  n = @action.resource.resource_name.underscore
  n = if %i[object_list hash_list].include?(layout)
        n.pluralize
      else
        n.singularize
      end

  @cache[:namespace] = n.to_sym
end

#namespace=(n) ⇒ Object



126
127
128
129
# File 'lib/haveapi/params.rb', line 126

def namespace=(n)
  @namespace = false if n === false
  @namespace = n.to_sym if n
end

#optional(name, **kwargs) ⇒ Object



135
136
137
# File 'lib/haveapi/params.rb', line 135

def optional(name, **kwargs)
  add_param(name, apply(kwargs, required: false))
end

#param(name, **kwargs) ⇒ Object



170
171
172
# File 'lib/haveapi/params.rb', line 170

def param(name, **kwargs)
  add_param(name, kwargs)
end

#parameter_metadata_i18n_items(context, i18n_path: nil, meta_type: nil) ⇒ Object



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/haveapi/params.rb', line 243

def (context, i18n_path: nil, meta_type: nil)
  i18n_path ||= self.class.action_i18n_path(context, @direction)

  @params.flat_map do |param|
    next [] unless param.respond_to?(:metadata_i18n_catalog_items)

    param.(context, i18n_path).map do |item|
      item.merge(
        resource_path: Array(context.resource_path).map { |v| self.class.i18n_segment(v) },
        action: self.class.i18n_segment(context.action.action_name),
        direction: self.class.i18n_segment(@direction),
        meta_type: meta_type && self.class.i18n_segment(meta_type)
      )
    end
  end
end

#password(name, **kwargs) ⇒ Object



147
148
149
# File 'lib/haveapi/params.rb', line 147

def password(name, **kwargs)
  add_param(name, apply(kwargs, type: String, protected: true))
end

#patch(name, **changes) ⇒ Object



208
209
210
# File 'lib/haveapi/params.rb', line 208

def patch(name, **changes)
  @params.detect { |p| p.name == name }.patch(changes)
end

#remove(name) ⇒ Object



212
213
214
215
216
217
# File 'lib/haveapi/params.rb', line 212

def remove(name)
  i = @params.index { |p| p.name == name }
  raise "Parameter #{name.inspect} not found" if i.nil?

  @params.delete_at(i)
end

#requires(name, **kwargs) ⇒ Object



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

def requires(name, **kwargs)
  add_param(name, apply(kwargs, required: true))
end

#resource(name, **kwargs) ⇒ Object Also known as: references, belongs_to



201
202
203
# File 'lib/haveapi/params.rb', line 201

def resource(name, **kwargs)
  add_resource(name, kwargs)
end

#string(name, **kwargs) ⇒ Object



139
140
141
# File 'lib/haveapi/params.rb', line 139

def string(name, **kwargs)
  add_param(name, apply(kwargs, type: String))
end

#text(name, **kwargs) ⇒ Object



143
144
145
# File 'lib/haveapi/params.rb', line 143

def text(name, **kwargs)
  add_param(name, apply(kwargs, type: Text))
end

#use(name, include: nil, exclude: nil) ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/haveapi/params.rb', line 174

def use(name, include: nil, exclude: nil)
  @include_back ||= []
  @exclude_back ||= []

  block = @action.resource.params(name)

  return unless block

  @include_back << @include.clone if @include
  @exclude_back << @exclude.clone if @exclude

  if include
    @include ||= []
    @include.concat(normalize_names(include))
  end

  if exclude
    @exclude ||= []
    @exclude.concat(normalize_names(exclude))
  end

  instance_eval(&block)

  @include = @include_back.pop if @include
  @exclude = @exclude_back.pop if @exclude
end

#validate(params, context: nil, only: nil) ⇒ Object

Third step of validation. Check if all required params are present, convert params to correct data types, set default values if necessary.



293
294
295
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
340
341
342
343
344
345
346
347
# File 'lib/haveapi/params.rb', line 293

def validate(params, context: nil, only: nil)
  errors = {}
  permitted = only && only.map(&:to_sym)

  layout_aware(params) do |input|
    # First run - coerce values to correct types
    @params.each do |p|
      next if permitted && !permitted.include?(p.name)

      if p.required? && input[p.name].nil?
        errors[p.name] = [HaveAPI.message('haveapi.validation.required_parameter_missing')]
        next
      end

      unless input.has_key?(p.name)
        input[p.name] = p.default if p.respond_to?(:fill?) && p.fill?
        next
      end

      begin
        cleaned = if p.method(:clean).arity.abs > 1
                    p.clean(input[p.name], context)
                  else
                    p.clean(input[p.name])
                  end
      rescue ValidationError => e
        errors[p.name] ||= []
        errors[p.name] << e.message_value
        next
      end

      input[p.name] = cleaned if cleaned != :_nil
    end

    # Second run - validate parameters
    @params.each do |p|
      next if permitted && !permitted.include?(p.name)
      next if errors.has_key?(p.name)
      next if input[p.name].nil?

      res = p.validate(input[p.name], input)

      unless res === true
        errors[p.name] ||= []
        errors[p.name].concat(res)
      end
    end
  end

  unless errors.empty?
    raise ValidationError.new(HaveAPI.message('haveapi.validation.input_parameters_not_valid'), errors)
  end

  params
end

#validate_buildObject



260
261
262
263
264
265
266
# File 'lib/haveapi/params.rb', line 260

def validate_build
  m = :"validate_build_#{@direction}"

  @params.each do |p|
    p.send(m) if p.respond_to?(m)
  end
end