Class: RocketAMF::ClassMapping
- Inherits:
-
Object
- Object
- RocketAMF::ClassMapping
- Defined in:
- lib/rocketamf/mapping/class_mapping.rb
Overview
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 attr_accessor
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 RocketAMF::CLASS_MAPPER
after loading RocketAMF. Through the magic of const_missing
, CLASS_MAPPER
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: use_array_collection
, get_as_class_name
, get_ruby_obj
, populate_ruby_obj
, and props_for_serialization
. In addition, it should have a class level mappings
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 (github.com/rubyamf/rubyamf).
Example:
require 'rubygems'
require 'rocketamf'
RocketAMF.const_set(CLASS_MAPPER, MyCustomClassMapper)
C ClassMapper
The C class mapper, RocketAMF::Ext::FastClassMapping
, has the same public API that RubyAMF::ClassMapping
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 props_for_serialization
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 encode_amf
, 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
Class Attribute Summary collapse
-
.use_array_collection ⇒ Object
Global configuration variable for sending Arrays as ArrayCollections.
Instance Attribute Summary collapse
-
#use_array_collection ⇒ Object
readonly
Properties.
Class Method Summary collapse
-
.define {|mappings| ... } ⇒ Object
Define class mappings in the block.
-
.mappings ⇒ Object
Returns the mapping set with all the class mappings that is currently being used.
-
.reset ⇒ Object
Reset all class mappings except the defaults and return
use_array_collection
to false.
Instance Method Summary collapse
-
#get_as_class_name(obj) ⇒ Object
Returns the ActionScript class name for the given ruby object.
- #get_ruby_obj(as_class_name) ⇒ Object
-
#initialize ⇒ ClassMapping
constructor
A new instance of ClassMapping.
- #populate_ruby_obj(target, props) ⇒ Object
- #props_for_serialization(ruby_obj) ⇒ Object
Constructor Details
#initialize ⇒ ClassMapping
Returns a new instance of ClassMapping.
110 111 112 113 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 110 def initialize @mappings = self.class.mappings @use_array_collection = self.class.use_array_collection === true end |
Class Attribute Details
.use_array_collection ⇒ Object
Global configuration variable for sending Arrays as ArrayCollections. Defaults to false.
70 71 72 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 70 def use_array_collection @use_array_collection end |
Instance Attribute Details
#use_array_collection ⇒ Object (readonly)
Properties
102 103 104 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 102 def use_array_collection @use_array_collection end |
Class Method Details
.define {|mappings| ... } ⇒ Object
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
86 87 88 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 86 def define(&block) #:yields: mapping_set yield mappings end |
.mappings ⇒ Object
Returns the mapping set with all the class mappings that is currently being used.
74 75 76 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 74 def mappings @mappings ||= MappingSet.new end |
.reset ⇒ Object
Reset all class mappings except the defaults and return use_array_collection
to false
92 93 94 95 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 92 def reset @use_array_collection = false @mappings = nil end |
Instance Method Details
#get_as_class_name(obj) ⇒ Object
Returns the ActionScript class name for the given ruby object. Will also take a string containing the ruby class name.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 117 def get_as_class_name(obj) # Get class name if obj.is_a?(String) ruby_class_name = obj elsif obj.is_a?(Types::TypedHash) ruby_class_name = obj.type elsif obj.is_a?(Hash) return nil 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
137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 137 def get_ruby_obj(as_class_name) result = nil ruby_class_name = @mappings.get_ruby_class_name(as_class_name) if ruby_class_name.nil? # Populate a simple hash, since no mapping result = Types::TypedHash.new(as_class_name) else ruby_class = ruby_class_name.split('::').inject(Kernel) { |scope, const_name| scope.const_get(const_name) } result = ruby_class.new end result end |
#populate_ruby_obj(target, props) ⇒ Object
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 154 def populate_ruby_obj(target, props) # Don't even bother checking if it responds to setter methods if it's a TypedHash if target.is_a?(Types::TypedHash) target.merge! props return target end # Some type of object hash_like = target.respond_to?("[]=") props.each do |key, value| if target.respond_to?("#{key}=") target.send("#{key}=", value) elsif hash_like target[key] = value end end target end |
#props_for_serialization(ruby_obj) ⇒ Object
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/rocketamf/mapping/class_mapping.rb', line 181 def props_for_serialization(ruby_obj) result = {} # Handle hashes if ruby_obj.is_a?(Hash) # Stringify keys to make it easier later on and allow sorting ruby_obj.each { |k, v| result[k.to_s] = v } else # Generic object serializer @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) result[method_name.to_s] = ruby_obj.send(method_name) if method_def.arity == 0 end end result end |