module ActiveModelSerializerPlus

@author Todd Knarr <tknarr@silverglass.org>

Top-level namespace for the ActiveModelSerializerPlus extensions.

The methods and module variables here aren’t commonly used directly by applications, they’re mainly for internal use by the Assignment, JSON and Xml namespaces. You’ll want to become familiar with the contents if you want to extend the set of types/classes handled automatically during serialization and deserialization.

Currently the formatting-related functionality is unused. It’s included for use in a planned XML serialization/deserialization extension.

Constants

VERSION

Version number.

Public Class Methods

add_arraylike_container(typename) click to toggle source

Add a new kind of Array-like container @param [String] typename type name of the container type to add @return [void]

# File lib/active_model_serializer_plus/assignment.rb, line 109
def self.add_arraylike_container(typename)
    return if typename.blank?
    @@container_iterators[typename] = @@build_from_arraylike_proc
    @@container_adders[typename] = @@add_to_arraylike_proc
    ActiveModelSerializerPlus.add_xlate(typename, 'Container')
    return
end
add_container(typename, iterator_proc, adder_proc) click to toggle source

Add iterator and adder procs for a new kind of container. @param [String] typename type name of the container type to add @param [Proc] iterator_proc Proc to build from that type of container @param [Proc] adder_proc Proc to add an item to that type of container @return [void]

# File lib/active_model_serializer_plus/assignment.rb, line 98
def self.add_container(typename, iterator_proc, adder_proc)
    return if typename.blank? || iterator_proc.nil? || adder_proc.nil?
    @@container_iterators[typename] = iterator_proc
    @@container_adders[typename] = adder_proc
    ActiveModelSerializerPlus.add_xlate(typename, 'Container')
    return
end
add_hashlike_container(typename) click to toggle source

Add a new kind of Hash-like container @param [String] typename type name of the container type to add @return [void]

# File lib/active_model_serializer_plus/assignment.rb, line 120
def self.add_hashlike_container(typename)
    return if typename.blank?
    @@container_iterators[typename] = @@build_from_hashlike_proc
    @@container_adders[typename] = @@add_to_hashlike_proc
    ActiveModelSerializerPlus.add_xlate(typename, 'Container')
    return
end
add_type(type_name, formatting_proc = nil, parsing_proc = nil, building_proc = nil) click to toggle source

Add information about a new type to the formatting/parsing/building hashes. type_name is required, all others are optional and should be specified as nil if not being defined. @param [String] type_name name of the type to add @param [Proc] formatting_proc Proc to add to format an object’s value into a string @param [Proc] parsing_proc Proc to add to parse a string value and create an object from it @param [Proc] building_proc Proc to add to create an object from a hash of attribute names and values @return [void] no return value

# File lib/active_model_serializer_plus/translations.rb, line 162
def self.add_type(type_name, formatting_proc = nil, parsing_proc = nil, building_proc = nil)
    return if type_name.blank?
    @@formatting[type_name] = formatting_proc unless formatting_proc.nil?
    @@parsing[type_name] = parsing_proc unless parsing_proc.nil?
    @@building[type_name] = building_proc unless building_proc.nil?
    return
end
add_xlate( type_name, parent_type_name ) click to toggle source

Add a new type translation. Translations are used to create pseudo-parent classes in cases where several classes can use common Procs for formatting, parsing and/or building but don’t share a common parent class, eg. TrueClass and FalseClass which can both use the Boolean formatting and parsing Procs. @param [String] type_name name of the specific type @param [String] parent_type_name name of the pseudo-parent type @return [void] no return value

# File lib/active_model_serializer_plus/translations.rb, line 148
def self.add_xlate( type_name, parent_type_name )
    return if type_name.blank?
    @@type_name_xlate[type_name] = parent_type_name unless parent_type_name.blank?
    return
end
build(class_name, hash) click to toggle source

Build an object of the named type from a hash if a building Proc is defined. @param [String] class_name name of the class of object being built from the hash @param [Hash] hash hash containing the attribute names and values from which the object is to be built @return [Object] the new object, or nil if no building Proc for class_name is defined

# File lib/active_model_serializer_plus/translations.rb, line 134
def self.build(class_name, hash)
    p = nil
    xlt = @@type_name_xlate[class_name] || class_name
    p = @@building[xlt] unless xlt.nil?
    p ? p.call(hash) : nil
end
build_object(obj_klass, value) click to toggle source

Break out the logic for creating a new object of a class from a hash or string value. It’s needed for both individual attributes and for each element of a container. @param [Class] obj_klass class of the object to create @param [String, Hash] value value to use to initialize the object @return [Object] newly-created object or nil @raise [ArgumentError] if the object cannot be created

# File lib/active_model_serializer_plus/assignment.rb, line 73
def self.build_object(obj_klass, value)
    obj = nil
    if value.is_a?(Hash)
        # If we're looking at a contained object (our value is a hash), see if we have a Proc
        # to build the object from a hash. If we don't, fall back to creating an object and
        # using the hash #attributes= method if possible. If all else fails just leave the value
        obj = ActiveModelSerializerPlus.build(obj_klass.name, value)
        if obj.nil? && obj_klass.method_defined?('attributes=')
            obj = obj_klass.new
            if obj.nil?
                raise ArgumentError, "Cannot create object of type #{obj_klass.name}."
            end
            obj.attributes = value
        end
    elsif value.is_a?(String)
        obj = ActiveModelSerializerPlus.parse(obj_klass.name, value)
    end
    obj
end
format(value) click to toggle source

Format a value into a string using the defined formatting Proc for value‘s class. @note If no formatting Proc is defined, #to_s is used instead. @note Checks all parent classes of value for Procs. @param [Object] value the value to format @return [String] the value formatted into a string

# File lib/active_model_serializer_plus/translations.rb, line 82
def self.format(value)
    # Check the translation table first for a pseudo-parent, and if we found one check
    # for it's proc. Then start with the value's class name and work up through it's
    # parent classes until we find a proc for one. If we can't find a proc, just use
    # the #to_s method.
    p = nil
    n = @@type_name_xlate[value.class.name]
    p = @@formatting[n] unless n.nil?
    if p.nil?
        b = value.class
        until b.nil? do
            p = @@formatting[b.name]
            break unless p.nil?
            b = b.superclass
        end
    end
    p ? p.call(value) : value.to_s
end
get_container_adder(typename) click to toggle source

Look up adder proc.

# File lib/active_model_serializer_plus/assignment.rb, line 62
def self.get_container_adder(typename)
    @@container_adders[typename]
end
get_container_iterator(typename) click to toggle source

Look up iterator proc.

# File lib/active_model_serializer_plus/assignment.rb, line 57
def self.get_container_iterator(typename)
    @@container_iterators[typename]
end
parse(class_name, value) click to toggle source

Parse a string value into an object of the named type if a parsing Proc is defined. @note Checks all parent classes of class_name for Procs. @param [String] class_name name of the class of object being created from the value @param [String] value the string containing the formatted value to be parsed @return [Object] the new object, or nil if no parsing Proc for class_name is defined

# File lib/active_model_serializer_plus/translations.rb, line 106
def self.parse(class_name, value)
    # Check for a proc for the type name given, and if we find one use it. Otherwise
    # try to convert that name to a class. If we can, start with it and work up through
    # it's parent classes checking for a proc for each. If we can't find a proc, return
    # nil.
    p = nil
    xlt = @@type_name_xlate[class_name] || class_name
    p = @@parsing[xlt] unless xlt.nil?
    if p.nil?
        klass = nil
        begin
            klass = class_name.constantize
        rescue NameError
            klass = nil
        end
        until klass.nil?
            p = @@parsing[klass.name]
            break unless p.nil?
            klass = klass.superclass
        end
    end
    p ? p.call(value.to_s) : nil
end
to_class(class_name) click to toggle source

Helper method to convert a type/class name into an actual class. @param [Class, Symbol, String] class_name name to convert into a Class object @return [Class] Class object for the named class @raise [ArgumentError] if class_name is not of an acceptable type @raise [NameError] if class_name is a Class that doesn’t exist

# File lib/active_model_serializer_plus/translations.rb, line 175
def self.to_class(class_name)
    klass = nil
    if class_name.is_a?(Class)
        klass = class_name
    elsif class_name.is_a?(String)
        begin
            klass = class_name.constantize unless class_name.blank?
        rescue NameError
            raise ArgumentError, "Type #{class_name} is invalid"
        end
    elsif class_name.is_a?(Symbol)
        begin
            klass = class_name.to_s.constantize
        rescue NameError
            raise ArgumentError, "Type #{class_name.to_s} is invalid"
        end
    else
        raise ArgumentError, "Type #{class_name.to_s} is invalid"
    end
    klass
end
to_classname(class_name) click to toggle source

Helper method to convert a representation of a class or class name into a string containing the class name. @param [Class, Symbol, String] class_name the Class whose name you need or a symbol or string representing a class name @return [String] the class name represented by class_name converted to a string @raise [ArgumentError] if class_name is not of an acceptable type @raise [NameError] if class_name is a Class that doesn’t exist

# File lib/active_model_serializer_plus/translations.rb, line 202
def self.to_classname(class_name)
    klassname = nil
    if class_name.is_a?(Class)
        klassname = class_name.name
    elsif class_name.is_a?(String)
        klassname = class_name
    elsif class_name.is_a?(Symbol)
        klassname = class_name.to_s
    else
        raise ArgumentError, "Argument type #{class_name.class.name} is not Class, String or Symbol"
    end
    klassname
end
type_name_xlate(class_name) click to toggle source

Translate a type/class name to it’s psuedo-parent class name if it has one. @param [String] class_name the name of the class to translate @return [String] the translated name

# File lib/active_model_serializer_plus/translations.rb, line 73
def self.type_name_xlate(class_name)
    @@type_name_xlate[class_name]
end