class RocketAMF::ClassMapping

Handles class name mapping between AS 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:

  RocketAMF::CLASS_MAPPER.define do |m|
    m.map as: 'AsClass', ruby: 'RubyClass'
    m.map as: 'vo.User', ruby: 'Model::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
<tt>attr_accessor</tt> for properties is currently built in, but custom classes
may require subclassing the class mapper to add support.

== Complete Replacement

In some cases, it may be beneficial to replace the default provider of class
mapping completely. In this case, simply assign your class mapper class to
<tt>RocketAMF::CLASS_MAPPER</tt> after loading RocketAMF. Through the magic of
<tt>const_missing</tt>, <tt>CLASS_MAPPER</tt> is only defined after the first
access by default, so you get no annoying warning messages. Custom class mappers
must implement the following methods on instances: <tt>use_array_collection</tt>,
<tt>get_as_class_name</tt>, <tt>get_ruby_obj</tt>, <tt>populate_ruby_obj</tt>,
and <tt>props_for_serialization</tt>. In addition, it should have a class level
<tt>mappings</tt> method that returns the mapping set it's using, although its
not required. If you'd like to see an example of what complete replacement
offers, check out RubyAMF (http://github.com/rubyamf/rubyamf).

Example:

  require 'rubygems'
  require 'rocketamf'

  RocketAMF.const_set(CLASS_MAPPER, MyCustomClassMapper)

== C ClassMapper

The C class mapper, <tt>RocketAMF::Ext::FastClassMapping</tt>, has the same
public API that <tt>RubyAMF::ClassMapping</tt> does, but has some additional
performance optimizations that may interfere with the proper serialization of
objects. To reduce the cost of processing public methods for every object,
its implementation of <tt>props_for_serialization</tt> caches valid properties
by class, using the class as the hash key for property lookup. This means that
adding and removing properties from instances while serializing using a given
class mapper instance will result in the changes not being detected.  As such,
it's not enabled by default. So long as you aren't planning on modifying
classes during serialization using <tt>encode_amf</tt>, the faster C class
mapper should be perfectly safe to use.

Activating the C Class Mapper:

  require 'rubygems'
  require 'rocketamf'

todo:review

RocketAMF::ClassMapper = RocketAMF::Ext::FastClassMapping

Attributes

use_array_collection[RW]

Global configuration variable for sending Arrays as ArrayCollections. Defaults to false.

use_array_collection[R]

Properties

Public Class Methods

define() { |mapping_set| ... } click to toggle source

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

Example:

RocketAMF::CLASS_MAPPER.define do |m|
  m.map as: 'AsClass', ruby: 'RubyClass'
end
   # File lib/rocketamf/mapping/class_mapping.rb
86 def define(&block) #:yields: mapping_set
87   yield mappings
88 end
mappings() click to toggle source

Returns the mapping set with all the class mappings that is currently being used.

   # File lib/rocketamf/mapping/class_mapping.rb
74 def mappings
75   @mappings ||= MappingSet.new
76 end
new() click to toggle source

Copies configuration from class level configs to populate object

    # File lib/rocketamf/mapping/class_mapping.rb
110 def initialize
111   @mappings             = self.class.mappings
112   @use_array_collection = self.class.use_array_collection === true
113 end
reset() click to toggle source

Reset all class mappings except the defaults and return use_array_collection to false

   # File lib/rocketamf/mapping/class_mapping.rb
92 def reset
93   @use_array_collection = false
94   @mappings             = nil
95 end

Public Instance Methods

get_as_class_name(obj) click to toggle source

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

    # File lib/rocketamf/mapping/class_mapping.rb
117 def get_as_class_name(obj)
118   # Get class name
119   if obj.is_a?(String)
120     ruby_class_name = obj
121   elsif obj.is_a?(Types::TypedHash)
122     ruby_class_name = obj.type
123   elsif obj.is_a?(Hash)
124     return nil
125   else
126     ruby_class_name = obj.class.name
127   end
128 
129   # Get mapped AS class name
130   @mappings.get_as_class_name(ruby_class_name)
131 end
get_ruby_obj(as_class_name) click to toggle source

Instantiates a ruby object using the mapping configuration based on the source ActionScript class name. If there is no mapping defined, it returns a RocketAMF::Types::TypedHash with the serialized class name.

    # File lib/rocketamf/mapping/class_mapping.rb
137 def get_ruby_obj(as_class_name)
138   result = nil
139 
140   ruby_class_name = @mappings.get_ruby_class_name(as_class_name)
141   if ruby_class_name.nil?
142     # Populate a simple hash, since no mapping
143     result = Types::TypedHash.new(as_class_name)
144   else
145     ruby_class = ruby_class_name.split('::').inject(Kernel) { |scope, const_name| scope.const_get(const_name) }
146     result     = ruby_class.new
147   end
148 
149   result
150 end
populate_ruby_obj(target, props) click to toggle source

Populates the ruby object using the given properties. props will be hashes with symbols for keys.

    # File lib/rocketamf/mapping/class_mapping.rb
154 def populate_ruby_obj(target, props)
155 
156   # Don't even bother checking if it responds to setter methods if it's a TypedHash
157   if target.is_a?(Types::TypedHash)
158     target.merge! props
159     return target
160   end
161 
162   # Some type of object
163   hash_like = target.respond_to?("[]=")
164   props.each do |key, value|
165     if target.respond_to?("#{key}=")
166       target.send("#{key}=", value)
167     elsif hash_like
168       target[key] = value
169     end
170   end
171 
172   target
173 end
props_for_serialization(ruby_obj) click to toggle source

Extracts all exportable properties from the given ruby object and returns them in a hash. If overriding, make sure to return a hash wth string keys unless you are only going to be using the native C extensions, as the pure ruby serializer performs a sort on the keys to acheive consistent, testable results.

    # File lib/rocketamf/mapping/class_mapping.rb
181 def props_for_serialization(ruby_obj)
182   result = {}
183 
184   # Handle hashes
185   if ruby_obj.is_a?(Hash)
186 
187     # Stringify keys to make it easier later on and allow sorting
188     ruby_obj.each { |k, v| result[k.to_s] = v }
189 
190   else
191 
192     # Generic object serializer
193     @ignored_props ||= Object.new.public_methods
194     (ruby_obj.public_methods - @ignored_props).each do |method_name|
195       # Add them to the prop hash if they take no arguments
196       method_def               = ruby_obj.method(method_name)
197       result[method_name.to_s] = ruby_obj.send(method_name) if method_def.arity == 0
198     end
199   end
200 
201   result
202 end