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 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 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 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 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 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 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
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 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
Look up adder proc.
# File lib/active_model_serializer_plus/assignment.rb, line 62 def self.get_container_adder(typename) @@container_adders[typename] end
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 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
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
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
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