module AxleAttributes module HasAttributes class JsonReader # json = { # { # "location": { # "street": {"type": "string"}, # "city": {"type": "string", "readonly": true} # } # "group2": { # }, # ... # }, # "contacts": { # "type": "serialize_many", # "attributes": { # "first_name": {"type": "string"}, # "professional_title": {"type": "string"} # } # } # } # # AxleAttributes::HasAttributes::JsonReader.read_definitions(Widget, json) # def self.read_definitions(model, json, options = {}) new(model, options).read_definitions(json) end attr_reader :model attr_reader :reader_options def initialize(model, reader_options = {}) @model = model @reader_options = reader_options end def read_definitions(json) json = ActiveSupport::JSON.decode(json) unless json.is_a?(Hash) json.each do |namespace, options| if options['type'] read_serialization namespace, options else read_definition_group options end end end private def read_definition_group(definitions) definitions.each do |attribute_name, options| model.has_attribute attribute_name, normalize_options(options) end end SERIALIZATION_TYPES = %w(serialize_one serialize_many) def read_serialization(serialization_name, options) raise "unknown serialization #{options['type']}" unless SERIALIZATION_TYPES.include?(options['type']) serialization_type = options['type'] serialization_attributes = options['attributes'] child_model = (options['class_name'] || serialization_name.classify).constantize AxleAttributes::HasAttributes::JsonReader.read_definitions(child_model, {serialization_type => serialization_attributes}, reader_options) reflection = model.send(serialization_type, serialization_name.to_sym, options.slice('class_name').symbolize_keys!) end SYMBOL_OPTIONS = [:type, :format, :index, :mmdb_name] def normalize_options(options) options.symbolize_keys! SYMBOL_OPTIONS.each do |option_name| if (value = options[option_name]).is_a?(String) options[option_name] = value.to_sym end end options.reverse_merge! default_options options end def default_options @default_options ||= (reader_options[:defaults] || {}) end end end end