class Typed::Struct

Public Class Methods

allow_extra_keys(new_flag) click to toggle source
# File lib/typed/struct.rb, line 53
def allow_extra_keys(new_flag)
    define_singleton_method(:allow_extra_keys?) { new_flag }
end
allow_extra_keys?() click to toggle source
# File lib/typed/struct.rb, line 57
def allow_extra_keys?
    true
end
attribute(name, type = Typed.any) click to toggle source
# File lib/typed/struct.rb, line 36
def attribute(name, type = Typed.any)
    expected_type(type)

    name = name.to_sym

    raise Typed::InvalidType, "Property already defined: #{name}" if typed_attributes.key?(name)

    typed_attributes[name] = type
    define_method(name) { @_data.fetch(name) { Typed::Undefined } }
end
new(input_data = {}) click to toggle source
# File lib/typed/struct.rb, line 142
def initialize(input_data = {})
    case input_data
    when Typed::Builder::Result then initialize_from_result(input_data)
    else initialize_from_result(self.class.parse_as_hash(input_data))
    end
end
parse_as_hash(input_data) click to toggle source
# File lib/typed/struct.rb, line 70
def parse_as_hash(input_data)
    return Typed::Builder::Result.success(input_data.to_h) if input_data.is_a?(self)

    # TODO: remove this hack
    unless input_data.is_a?(::Hash) || input_data.class.name == 'ActionController::Parameters'
        return Typed::Builder::Result.failure { "Expected Hash, got #{input_data.inspect}" }
    end

    # Start by creating a new "clean" hash from input
    # This way, we can easily handle some variants (ActionController::Parameters, ...)
    clean_data = Hash.new { ::Typed::Undefined }
    input_data.each { |key, value| clean_data[key.to_sym] = value }

    # Check presence of extra keys
    extra_property = (clean_data.keys - schema.keys).first
    if extra_property && !allow_extra_keys?
        return Typed::Builder::Result
            .failure("Unknown property '#{extra_property}' of #{inspect}")
    end

    # Construct the final hash which will be stored internally to represent
    # Struct's data.
    output = schema.each_with_object({}) { |(name, type), acc|
        result = type.process(clean_data[name])

        unless result.ok
            return Typed::Builder::Result.failure {
                "Invalid property '#{name}' of #{inspect}: #{result.message}"
            }
        end

        acc[name] = result.value unless Typed::Undefined.equal?(result.value)
    }.freeze

    Typed::Builder::Result.success(output)
end
process(data) click to toggle source
# File lib/typed/struct.rb, line 65
def process(data)
    result = parse_as_hash(data)
    result.ok ? Typed::Builder::Result.success(new(result)) : result
end
schema() click to toggle source
# File lib/typed/struct.rb, line 47
def schema
    @schema ||= ancestors.select { |a| Typed::Struct > a }.reverse.reduce({}) { |acc, clazz|
        acc.merge(clazz.typed_attributes)
    }.freeze
end
typed_attributes() click to toggle source
# File lib/typed/struct.rb, line 61
def typed_attributes
    @typed_attributes ||= {}
end

Public Instance Methods

==(other) click to toggle source
# File lib/typed/struct.rb, line 127
def ==(other)
    return true if other.equal?(self)
    return false unless other.instance_of?(self.class)

    @_data == other.instance_variable_get(:@_data)
end
[](key) click to toggle source
# File lib/typed/struct.rb, line 121
def [](key)
    raise Typed::InvalidType, "Unknown property: #{key.inspect}" unless self.class.schema.key?(key)

    @_data.fetch(key) { Typed::Undefined }
end
hash() click to toggle source
# File lib/typed/struct.rb, line 134
def hash
    @_data.hash
end
inspect() click to toggle source
# File lib/typed/struct.rb, line 112
def inspect
    attrs = self.class.schema.keys.map { |key| " #{key}=#{@_data[key].inspect}" }.join
    "#<#{self.class.name || self.class.inspect}#{attrs}>"
end
key?(key) click to toggle source
# File lib/typed/struct.rb, line 138
def key?(key)
    @_data.key?(key)
end
to_h() click to toggle source
# File lib/typed/struct.rb, line 117
def to_h
    @_data
end
updater(target) click to toggle source
# File lib/typed/struct.rb, line 108
def updater(target)
    Updater.new(target, self)
end

Private Instance Methods

initialize_from_result(result) click to toggle source
# File lib/typed/struct.rb, line 151
def initialize_from_result(result)
    raise Typed::InvalidValue, result.message unless result.ok

    @_data = result.value
end