Class: RocketAMF::ClassMapping
- Inherits:
-
Object
- Object
- RocketAMF::ClassMapping
- Defined in:
- lib/rocketamf/class_mapping.rb
Overview
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:
RocketAMF::ClassMapper.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::ClassMapper
after loading RocketAMF. Through the magic of const_missing
, ClassMapper
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::ClassMapper = MyCustomClassMapper
# No warning about already initialized constant ClassMapper
RocketAMF::ClassMapper # 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'
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
Returns the value of attribute use_array_collection.
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
Instantiates a ruby object using the mapping configuration based on the source ActionScript class name.
-
#initialize ⇒ ClassMapping
constructor
Copies configuration from class level configs to populate object.
-
#populate_ruby_obj(obj, props, dynamic_props = nil) ⇒ Object
Populates the ruby object using the given properties.
-
#props_for_serialization(ruby_obj) ⇒ Object
Extracts all exportable properties from the given ruby object and returns them in a hash.
Constructor Details
#initialize ⇒ ClassMapping
Copies configuration from class level configs to populate object
152 153 154 155 |
# File 'lib/rocketamf/class_mapping.rb', line 152 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.
121 122 123 |
# File 'lib/rocketamf/class_mapping.rb', line 121 def use_array_collection @use_array_collection end |
Instance Attribute Details
#use_array_collection ⇒ Object (readonly)
Returns the value of attribute use_array_collection.
149 150 151 |
# File 'lib/rocketamf/class_mapping.rb', line 149 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::ClassMapper.define do |m|
m.map :as => 'AsClass', :ruby => 'RubyClass'
end
137 138 139 |
# File 'lib/rocketamf/class_mapping.rb', line 137 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.
125 126 127 |
# File 'lib/rocketamf/class_mapping.rb', line 125 def mappings @mappings ||= MappingSet.new end |
.reset ⇒ Object
Reset all class mappings except the defaults and return use_array_collection
to false
143 144 145 146 |
# File 'lib/rocketamf/class_mapping.rb', line 143 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.
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/rocketamf/class_mapping.rb', line 159 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 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
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::Values::TypedHash
with the serialized class name.
178 179 180 181 182 183 184 185 186 187 |
# File 'lib/rocketamf/class_mapping.rb', line 178 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. props and dynamic_props will be hashes with symbols for keys.
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/rocketamf/class_mapping.rb', line 191 def populate_ruby_obj obj, props, dynamic_props=nil props.merge! dynamic_props if dynamic_props # Don't even bother checking if it responds to setter methods if it's a TypedHash if obj.is_a?(Values::TypedHash) obj.merge! props return obj end # Some type of object hash_like = obj.respond_to?("[]=") props.each do |key, value| if obj.respond_to?("#{key}=") obj.send("#{key}=", value) elsif hash_like obj[key] = 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. 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.
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 |
# File 'lib/rocketamf/class_mapping.rb', line 217 def props_for_serialization ruby_obj # 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 # Generic object 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.to_s] = ruby_obj.send(method_name) if method_def.arity == 0 end props end |