Class: AMF::ClassMapping

Inherits:
Object
  • Object
show all
Defined in:
lib/amf/class_mapping.rb

Overview

Class Mapping

Handles class name mapping between actionscript and ruby and assists in serializing and deserializing data between them. Simply map an AS class to a ruby class and when the object is (de)serialized it will end up as the appropriate class.

Example:

AMF::ClassMapper.define do |m|
  m.map :as => 'AsClass', :ruby => 'RubyClass'
  m.map :as => 'vo.User', :ruby => 'User'
end

Object Population/Serialization

In addition to handling class name mapping, it also provides helper methods for populating ruby objects from AMF and extracting properties from ruby objects for serialization. Support for hash-like objects and objects using attr_accessor for properties is currently built in, but custom classes may need custom support. As such, it is possible to create a custom populator or serializer.

Populators are processed in insert order and must respond to the can_handle? and populate methods.

Example:

class CustomPopulator
  def can_handle? obj
    true
  end

  def populate obj, props, dynamic_props
    obj.merge! props
    obj.merge!(dynamic_props) if dynamic_props
  end
end
AMF::ClassMapper.object_populators << CustomPopulator.new

Serializers are also processed in insert order and must respond to the can_handle? and serialize methods.

Example:

class CustomSerializer
  def can_handle? obj
    true
  end

  def serialize obj
    {}
  end
end
AMF::ClassMapper.object_serializers << CustomSerializer.new

Defined Under Namespace

Classes: MappingSet

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeClassMapping

:nodoc:



110
111
112
113
# File 'lib/amf/class_mapping.rb', line 110

def initialize #:nodoc:
  @object_populators = []
  @object_serializers = []
end

Instance Attribute Details

#object_populatorsObject (readonly)

Array of custom object populators.



105
106
107
# File 'lib/amf/class_mapping.rb', line 105

def object_populators
  @object_populators
end

#object_serializersObject (readonly)

Array of custom object serializers.



108
109
110
# File 'lib/amf/class_mapping.rb', line 108

def object_serializers
  @object_serializers
end

Instance Method Details

#define {|mappings| ... } ⇒ Object

Define class mappings in the block. Block is passed a MappingSet object as the first parameter.

Example:

AMF::ClassMapper.define do |m|
  m.map :as => 'AsClass', :ruby => 'RubyClass'
end

Yields:

  • (mappings)


123
124
125
# File 'lib/amf/class_mapping.rb', line 123

def define #:yields: mapping_set
  yield mappings
end

#get_as_class_name(obj) ⇒ Object

Returns the AS class name for the given ruby object. Will also take a string containing the ruby class name



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/amf/class_mapping.rb', line 129

def get_as_class_name obj
  # Get class name
  if obj.is_a?(String)
    ruby_class_name = obj
  elsif obj.is_a?(Values::TypedHash)
    ruby_class_name = obj.type
  else
    ruby_class_name = obj.class.name
  end

  # Get mapped AS class name
  mappings.get_as_class_name ruby_class_name
end

#get_ruby_obj(as_class_name) ⇒ Object

Instantiates a ruby object using the mapping configuration based on the source AS class name. If there is no mapping defined, it returns a hash.



145
146
147
148
149
150
151
152
153
154
# File 'lib/amf/class_mapping.rb', line 145

def get_ruby_obj as_class_name
  ruby_class_name = mappings.get_ruby_class_name as_class_name
  if ruby_class_name.nil?
    # Populate a simple hash, since no mapping
    return Values::TypedHash.new(as_class_name)
  else
    ruby_class = ruby_class_name.split('::').inject(Kernel) {|scope, const_name| scope.const_get(const_name)}
    return ruby_class.new
  end
end

#populate_ruby_obj(obj, props, dynamic_props = nil) ⇒ Object

Populates the ruby object using the given properties



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/amf/class_mapping.rb', line 157

def populate_ruby_obj obj, props, dynamic_props=nil
  # Process custom populators
  @object_populators.each do |p|
    next unless p.can_handle?(obj)
    p.populate obj, props, dynamic_props
    return obj
  end

  # Fallback populator
  props.merge! dynamic_props if dynamic_props
  hash_like = obj.respond_to?("[]=")
  props.each do |key, value|
    if obj.respond_to?("#{key}=")
      obj.send("#{key}=", value)
    elsif hash_like
      obj[key.to_sym] = value
    end
  end
  obj
end

#props_for_serialization(ruby_obj) ⇒ Object

Extracts all exportable properties from the given ruby object and returns them in a hash



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/amf/class_mapping.rb', line 180

def props_for_serialization ruby_obj
  # Proccess custom serializers
  @object_serializers.each do |s|
    next unless s.can_handle?(ruby_obj)
    return s.serialize(ruby_obj)
  end

  # Handle hashes
  if ruby_obj.is_a?(Hash)
    # Stringify keys to make it easier later on and allow sorting
    h = {}
    ruby_obj.each {|k,v| h[k.to_s] = v}
    return h
  end

  # Fallback serializer
  props = {}
  @ignored_props ||= Object.new.public_methods
  (ruby_obj.public_methods - @ignored_props).each do |method_name|
    # Add them to the prop hash if they take no arguments
    method_def = ruby_obj.method(method_name)
    props[method_name] = ruby_obj.send(method_name) if method_def.arity == 0
  end
  props
end