Class: RubySol::ClassMapping
- Inherits:
-
Object
- Object
- RubySol::ClassMapping
- Defined in:
- lib/ruby_sol/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:
RubySol::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 RubySol::ClassMapper after loading RubySol. 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 'ruby_sol'
RubySol::ClassMapper = MyCustomClassMapper
# No warning about already initialized constant ClassMapper
RubySol::ClassMapper # MyCustomClassMapper
C ClassMapper
The C class mapper, RubySol::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 'ruby_sol'
RubySol::ClassMapper = RubySol::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_collectionto 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
165 166 167 168 |
# File 'lib/ruby_sol/class_mapping.rb', line 165 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.
134 135 136 |
# File 'lib/ruby_sol/class_mapping.rb', line 134 def use_array_collection @use_array_collection end |
Instance Attribute Details
#use_array_collection ⇒ Object (readonly)
Returns the value of attribute use_array_collection.
162 163 164 |
# File 'lib/ruby_sol/class_mapping.rb', line 162 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:
RubySol::ClassMapper.define do |m|
m.map :as => 'AsClass', :ruby => 'RubyClass'
end
150 151 152 |
# File 'lib/ruby_sol/class_mapping.rb', line 150 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.
138 139 140 |
# File 'lib/ruby_sol/class_mapping.rb', line 138 def mappings @mappings ||= MappingSet.new end |
.reset ⇒ Object
Reset all class mappings except the defaults and return use_array_collection to false
156 157 158 159 |
# File 'lib/ruby_sol/class_mapping.rb', line 156 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.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/ruby_sol/class_mapping.rb', line 172 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 RubySol::Values::TypedHash with the serialized class name.
191 192 193 194 195 196 197 198 199 200 |
# File 'lib/ruby_sol/class_mapping.rb', line 191 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.
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/ruby_sol/class_mapping.rb', line 204 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.
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/ruby_sol/class_mapping.rb', line 230 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 |