class SmartParams::Field

Attributes

keychain[R]
subfields[R]
type[R]

Public Class Methods

new(keychain:, type:, nullable: false, &nesting) click to toggle source
# File lib/smart_params/field.rb, line 7
def initialize(keychain:, type:, nullable: false, &nesting)
  @keychain = Array(keychain)
  @subfields = Set.new
  @type = type
  @nullable = nullable
  @specified = false
  @dirty = false

  if block_given?
    instance_eval(&nesting)
  end
end

Public Instance Methods

allow_empty?() click to toggle source

Check if we should consider this value even when empty.

# File lib/smart_params/field.rb, line 61
def allow_empty?
  return true if specified? && nullable?
  return subfields.select(&:allow_empty?).any?
  false
end
claim(raw) click to toggle source
# File lib/smart_params/field.rb, line 67
def claim(raw)
  return type[dug(raw)] if deep?

  @value = type[dug(raw)]
rescue Dry::Types::ConstraintError => bad_type_exception
  raise SmartParams::Error::InvalidPropertyType, keychain: keychain, wanted: type, raw: if keychain.empty? then raw else raw.dig(*keychain) end
end
clean?() click to toggle source
# File lib/smart_params/field.rb, line 54
def clean?
  return false if dirty?
  return true if empty? || subfields.select { |sub| !sub.empty? }.any?
  false
end
deep?() click to toggle source
# File lib/smart_params/field.rb, line 20
def deep?
  # We check @specified directly because we want to know if ANY
  # subfields have been passed, not just ones that match the schema.
  return false if nullable? && !!@specified
  subfields.present?
end
dirty?() click to toggle source

For nullable hashes: Any keys not in the schema make the hash dirty. If a key is found that matches the schema, we can consider the hash clean.

# File lib/smart_params/field.rb, line 50
def dirty?
  !!@dirty
end
empty?() click to toggle source
# File lib/smart_params/field.rb, line 81
def empty?
  value.nil?
end
nullable?() click to toggle source
# File lib/smart_params/field.rb, line 35
def nullable?
  !!@nullable
end
removable?() click to toggle source

Should this field be removed from resulting hash?

# File lib/smart_params/field.rb, line 86
def removable?
  empty? && !allow_empty?
end
root?() click to toggle source
# File lib/smart_params/field.rb, line 27
def root?
  keychain.size == 0
end
specified?() click to toggle source
# File lib/smart_params/field.rb, line 39
def specified?
  if nullable?
    !!@specified && clean?
  else
    !!@specified
  end
end
to_hash() click to toggle source
# File lib/smart_params/field.rb, line 75
def to_hash
  keychain.reverse.reduce(value) do |accumulation, key|
    { key => accumulation }
  end
end
value() click to toggle source
# File lib/smart_params/field.rb, line 31
def value
  @value || ({} if root?)
end
weight() click to toggle source
# File lib/smart_params/field.rb, line 90
def weight
  keychain.map(&:to_s)
end

Private Instance Methods

dug(raw) click to toggle source

Very busy method with recent changes. TODO: clean-up

# File lib/smart_params/field.rb, line 102
        def dug(raw)
  return raw if keychain.empty?

  # If value provided is a hash, check if it's dirty. See #dirty? for
  # more info.
  if nullable?
    hash = raw.dig(*keychain)
    if hash.respond_to?(:keys)
      others =  hash.keys - [keychain.last]
      @dirty = others.any?
    end
  end

  # Trace the keychain to find out if the field is explicitly set in the
  # input hash.
  at = raw
  exact = true
  keychain.each { |key|
    if at.respond_to?(:key?) && at.key?(key)
      at = at[key]
    else
      exact = false
      break
    end
  }
  @specified = exact

  raw.dig(*keychain)
end
field(key, type:, nullable: false, &subfield) click to toggle source
# File lib/smart_params/field.rb, line 94
        def field(key, type:, nullable: false, &subfield)
  if nullable
    type |= SmartParams::Strict::Nil
  end
  @subfields << self.class.new(keychain: [*keychain, key], type: type, nullable: nullable, &subfield)
end