class AttrPouch::Field

Attributes

name[R]
opts[R]
pouch[R]
raw_type[R]
type[R]

Public Class Methods

decode(type, &block) click to toggle source
# File lib/attr_pouch.rb, line 65
def self.decode(type, &block)
  @@decoders ||= {}
  @@decoders[type] = block
end
decoders() click to toggle source
# File lib/attr_pouch.rb, line 71
def self.decoders; @@decoders; end
encode(type, &block) click to toggle source
# File lib/attr_pouch.rb, line 60
def self.encode(type, &block)
  @@encoders ||= {}
  @@encoders[type] = block
end
encoders() click to toggle source
# File lib/attr_pouch.rb, line 70
def self.encoders; @@encoders; end
infer_type(field=nil, &block) click to toggle source
# File lib/attr_pouch.rb, line 73
def self.infer_type(field=nil, &block)
  if block_given?
    @@type_inferrer = block
  else
    if @@type_inferrer.nil?
      raise InvalidFieldError, "No type inference configured"
    else
      type = @@type_inferrer.call(field)
      if type.nil?
        raise InvalidFieldError, "Could not infer type of field #{field}"
      end
      type
    end
  end
end
new(pouch, name, opts) click to toggle source
# File lib/attr_pouch.rb, line 89
def initialize(pouch, name, opts)
  @name = name.to_s
  if opts.has_key?(:type)
    @type = to_class(opts.fetch(:type))
  else
    @type = self.class.infer_type(self)
  end
  @pouch = pouch
  @opts = opts
end

Public Instance Methods

alias_as(new_name) click to toggle source
# File lib/attr_pouch.rb, line 104
def alias_as(new_name)
  if new_name == name
    self
  else
    self.class.new(pouch, new_name, opts)
  end
end
all_names() click to toggle source
# File lib/attr_pouch.rb, line 142
def all_names
  [ name ] + previous_aliases
end
decode(value) click to toggle source
# File lib/attr_pouch.rb, line 179
def decode(value)
  decoder.call(self, value) unless value.nil?
end
decoder() click to toggle source
# File lib/attr_pouch.rb, line 187
def decoder
  @decoder ||= self.class.decoders
             .find(method(:ensure_decoder)) do |decoder_type, _|
    compatible_codec?(decoder_type)
  end.last
end
default() click to toggle source
# File lib/attr_pouch.rb, line 120
def default
  opts.fetch(:default, nil)
end
deletable?() click to toggle source
# File lib/attr_pouch.rb, line 128
def deletable?
  opts.fetch(:deletable, false)
end
encode(value) click to toggle source
# File lib/attr_pouch.rb, line 183
def encode(value)
  encoder.call(self, value) unless value.nil?
end
encoder() click to toggle source
# File lib/attr_pouch.rb, line 194
def encoder
  @encoder ||= self.class.encoders
             .find(method(:ensure_encoder)) do |encoder_type, _|
    compatible_codec?(encoder_type)
  end.last
end
has_default?() click to toggle source
# File lib/attr_pouch.rb, line 116
def has_default?
  opts.has_key?(:default)
end
mutable?() click to toggle source
# File lib/attr_pouch.rb, line 124
def mutable?
  opts.fetch(:mutable, true)
end
previous_aliases() click to toggle source
# File lib/attr_pouch.rb, line 132
def previous_aliases
  was = opts.fetch(:was, [])
  aliases = if was.respond_to?(:to_a)
              was.to_a
            else
              [ was ]
            end
  aliases.map(&:to_s)
end
read(store, decode: true) click to toggle source
# File lib/attr_pouch.rb, line 162
def read(store, decode: true)
  present_as = all_names.find { |n| !store.nil? && store.has_key?(n) }
  if store.nil? || present_as.nil?
    if required?
      raise MissingRequiredFieldError,
            "Expected field #{inspect} to exist"
    else
      default if decode
    end
  elsif present_as == name
    raw = store.fetch(name)
    decode ? decode(raw) : raw
  else
    alias_as(present_as).read(store)
  end
end
required?() click to toggle source
# File lib/attr_pouch.rb, line 112
def required?
  !(has_default? || deletable?)
end
write(store, value, encode: true) click to toggle source
# File lib/attr_pouch.rb, line 146
def write(store, value, encode: true)
  if store.has_key?(name)
    raise ImmutableFieldUpdateError unless mutable?
  end
  if encode
    value = self.encode(value)
  end
  if !store.has_key?(name) || value != store[name]
    store[name] = value
    previous_aliases.each { |a| store.delete(a) }
    true
  else
    false
  end
end

Private Instance Methods

compatible_codec?(codec_type) click to toggle source
# File lib/attr_pouch.rb, line 203
def compatible_codec?(codec_type)
  if self.type.is_a?(Class) && codec_type.is_a?(Class)
    self.type <= codec_type
  else
    self.type == codec_type
  end
rescue
  false
end
ensure_decoder() click to toggle source
# File lib/attr_pouch.rb, line 218
def ensure_decoder
  raise MissingCodecError,
        "No decoder found for #{inspect}"
end
ensure_encoder() click to toggle source
# File lib/attr_pouch.rb, line 213
def ensure_encoder
  raise MissingCodecError,
        "No encoder found for #{inspect}"
end
to_class(type) click to toggle source
# File lib/attr_pouch.rb, line 223
def to_class(type)
  return type if type.is_a?(Class) || type.is_a?(Symbol)
  type.to_s.split('::').inject(Object) do |moodule, klass|
    moodule.const_get(klass)
  end
end