class YASL::Loader
Attributes
class_objects[R]
structure[R]
whitelist_classes[R]
Public Class Methods
new(structure, whitelist_classes: [])
click to toggle source
# File lib/yasl/loader.rb, line 26 def initialize(structure, whitelist_classes: []) @structure = structure @whitelist_classes = whitelist_classes @class_objects = {} end
Public Instance Methods
load(include_classes: false)
click to toggle source
# File lib/yasl/loader.rb, line 32 def load(include_classes: false) load_structure(structure).tap do load_classes_structure if include_classes end end
load_classes_structure()
click to toggle source
# File lib/yasl/loader.rb, line 38 def load_classes_structure structure['_classes'].to_a.each do |class_structure| load_non_basic_data_type_object(class_structure, for_classes: true) end end
load_structure(structure, for_classes: false)
click to toggle source
# File lib/yasl/loader.rb, line 44 def load_structure(structure, for_classes: false) if top_level_class?(structure) class_for(structure['_class']) elsif YASL.json_basic_data_type?(structure) && !(structure.is_a?(String) && structure.start_with?('_')) structure elsif ruby_basic_data_type_structure?(structure) load_ruby_basic_data_type_object(structure['_class'], structure['_data']) elsif load_non_basic_data_type_structure?(structure) load_non_basic_data_type_object(structure) end end
Private Instance Methods
add_to_class_array(object, class_object_id)
click to toggle source
# File lib/yasl/loader.rb, line 143 def add_to_class_array(object, class_object_id) return if object.is_a?(Class) || object.is_a?(Module) || class_object_id.nil? object_class = object.class found_object = object_for_id(object_class, class_object_id) class_objects_for(object_class)[class_object_id.to_i] = object unless found_object end
class_for(class_name)
click to toggle source
# File lib/yasl/loader.rb, line 114 def class_for(class_name) class_name_components = class_name.to_s.split('::') current_class = Object object_class = class_name_components.reduce(Object) do |result_class, class_name| result_class.const_get(class_name) end if ![@whitelist_classes].compact.flatten.map(&:to_s).include?(object_class.to_s) raise "Class `#{class_name}` is not mentioned in `whitelist_classes` (e.g. `YASL.load(data, whitelist_classes: [#{class_name}])`)!" end object_class rescue NameError # TODO materialize a class matching the non-existing class raise "Class `#{class_name}` does not exist! YASL expects the same classes used for serialization to exist during deserialization." end
class_objects_for(object_class)
click to toggle source
# File lib/yasl/loader.rb, line 133 def class_objects_for(object_class) class_objects[object_class] ||= {} end
load_non_basic_data_type_object(structure, for_classes: false)
click to toggle source
# File lib/yasl/loader.rb, line 66 def load_non_basic_data_type_object(structure, for_classes: false) class_name = structure['_class'] object_class = class_for(class_name) object_class.alias_method(:initialize_without_yasl, :initialize) object = object_for_id(object_class, structure['_id']) if object.nil? object = for_classes ? object_class : object_class.new add_to_class_array(object, structure['_id']) end structure['_class_variables'].to_a.each { |class_var, value| object.class_variable_set("@@#{class_var}".to_sym, load_structure(value)) } structure['_instance_variables'].to_a.each { |instance_var, value| object.instance_variable_set("@#{instance_var}".to_sym, load_structure(value)) } structure['_struct_member_values'].to_a.each { |member, value| load_struct_member_value(object, member, value) } object ensure object_class&.define_method(:initialize, object_class.instance_method(:initialize_without_yasl)) end
load_non_basic_data_type_structure?(structure)
click to toggle source
# File lib/yasl/loader.rb, line 62 def load_non_basic_data_type_structure?(structure) structure['_class'] && (structure['_id'] || structure['_instance_variables'] || structure['_class_variables'] || structure['_struct_member_values']) end
load_ruby_basic_data_type_object(class_name, data)
click to toggle source
# File lib/yasl/loader.rb, line 83 def load_ruby_basic_data_type_object(class_name, data) case class_name when 'Time' DateTime.new.marshal_load(data.map(&:to_r)).to_time when 'BigDecimal' BigDecimal(data) when 'Date' Date.new.marshal_load(data.map(&:to_r)) when 'DateTime' DateTime.new.marshal_load(data.map(&:to_r)) when 'Complex' Complex(data) when 'Rational' Rational(data) when 'Regexp' Regexp.new(data) when 'Symbol' data.to_sym when 'Set' Set.new(data.map {|element| load_structure(element)}) when 'Range' Range.new(*data) when 'Array' data.map {|element| load_structure(element)} when 'Hash' data.reduce({}) { |new_hash, pair| new_hash.merge(load_structure(pair.first) => load_structure(pair.last)) } end end
load_struct_member_value(object, member, value)
click to toggle source
# File lib/yasl/loader.rb, line 150 def load_struct_member_value(object, member, value) value = load_structure(value) begin object[member.to_sym] = value rescue => e puts "#{e.message}. Setting `@#{member}` instance variable instead." object.instance_variable_set("@#{member}".to_sym, value) end end
object_for_id(object_class, class_object_id)
click to toggle source
# File lib/yasl/loader.rb, line 137 def object_for_id(object_class, class_object_id) return if class_object_id.nil? return unless (object_class.is_a?(Class) || object_class.is_a?(Module)) class_objects_for(object_class)[class_object_id.to_i] end
ruby_basic_data_type_structure?(structure)
click to toggle source
# File lib/yasl/loader.rb, line 58 def ruby_basic_data_type_structure?(structure) (structure['_class'] && (structure['_data'] || !structure.keys.detect {|key| key.start_with?('_') && key != '_class'} )) end
top_level_class?(structure)
click to toggle source
# File lib/yasl/loader.rb, line 129 def top_level_class?(structure) structure && structure.is_a?(Hash) && structure['_class'] && structure['_id'].nil? && structure['_instance_variables'].nil? && structure['_class_variables'].nil? && structure['_struct_member_values'].nil? && structure['_data'].nil? end