lib/representable.rb in representable-2.3.0 vs lib/representable.rb in representable-2.4.0.rc1

- old
+ new

@@ -1,143 +1,130 @@ -require 'forwardable' +require "uber/delegates" -require 'representable/inheritable' -require 'representable/config' -require 'representable/definition' -require 'representable/mapper' -require 'representable/for_collection' -require 'representable/represent' -require 'representable/declarative' -require 'representable/apply' -require "representable/populator" +require "declarative/schema" + +require "representable/config" +require "representable/definition" +require "representable/declarative" require "representable/deserializer" require "representable/serializer" +require "representable/binding" +require "representable/pipeline" +require "representable/insert" # Pipeline::Insert require "representable/cached" +require "representable/for_collection" +require "representable/represent" - -require "uber/callable" -require "representable/pipeline" - module Representable attr_writer :representable_attrs def self.included(base) base.class_eval do extend Declarative - extend ClassInclusions, ModuleExtensions + # make Representable horizontally and vertically inheritable. + extend ModuleExtensions, ::Declarative::Heritage::Inherited, ::Declarative::Heritage::Included extend ClassMethods - extend Feature extend ForCollection extend Represent - extend Apply - # register_feature Representable # Representable gets included automatically when creating inline representer. end end private # Reads values from +doc+ and sets properties accordingly. def update_properties_from(doc, options, format) - propagated_options, private_options = normalize_options!(options) + propagated_options = normalize_options(options) - representable_mapper(format, propagated_options).deserialize(represented, doc, propagated_options, private_options) + representable_map!(doc, propagated_options, format, :uncompile_fragment) + represented end # Compiles the document going through all properties. def create_representation_with(doc, options, format) - propagated_options, private_options = normalize_options!(options) + propagated_options = normalize_options(options) # {_private: {include: }, is_admin: true} - representable_mapper(format, propagated_options).serialize(represented, doc, propagated_options, private_options) + representable_map!(doc, propagated_options, format, :compile_fragment) + doc end - def representable_bindings_for(format, options) - representable_attrs.collect {|definition| representable_binding_for(definition, format, options) } + class Binding::Map < Array + def call(method, options) + each do |bin| + options[:binding] = bin # this is so much faster than options.merge(). + bin.send(method, options) + end + end + + # TODO: Merge with Definitions. + def <<(binding) # can be slow. this is compile time code. + (existing = find { |bin| bin.name == binding.name }) ? self[index(existing)] = binding : super(binding) + end end - def representable_binding_for(definition, format, options) - format.build(definition, self) + def representable_map(options, format) + Binding::Map.new(representable_bindings_for(format, options)) end + def representable_map!(doc, propagated_options, format, method) + options = {doc: doc, _private: propagated_options[:_private], user_options: propagated_options, represented: represented, decorator: self} + + representable_map(options, format).(method, options) # .(:uncompile_fragment, options) + end + + def representable_bindings_for(format, options) + representable_attrs.collect {|definition| format.build(definition) } + end + # Make sure we do not change original options. However, private options like :include or :wrap are # not passed on to child representers. - def normalize_options!(options) + def normalize_options(options) # here, we could also filter out local options e.g. like options[:band]. - private_options = {} - return [options, private_options] if options.size == 0 + return options unless options.any? propagated_options = options.dup + propagated_options.delete(:wrap) # FIXME. + propagated_options.delete(:_private) + private_options = {} private_options[:include] = propagated_options.delete(:include) if options[:include] private_options[:exclude] = propagated_options.delete(:exclude) if options[:exclude] - propagated_options.delete(:wrap) # FIXME. - [propagated_options, private_options] + propagated_options[:_private] = private_options if private_options.any? + + propagated_options end def representable_attrs - @representable_attrs ||= self.class.representable_attrs # DISCUSS: copy, or better not? what about "freezing"? + @representable_attrs ||= self.class.definitions end - def representable_mapper(format, options) - bindings = representable_bindings_for(format, options) - Mapper.new(bindings) - end - def representation_wrap(*args) - representable_attrs.wrap_for(nil, represented, *args) { self.class.name } + representable_attrs.wrap_for(represented, *args) end def represented self end - module ClassInclusions - def included(base) - super - base.inherit_module!(self) - end - - def inherited(subclass) # DISCUSS: this could be in Decorator? but then we couldn't do B < A(include X) for non-decorators, right? - super - # FIXME: subclass.representable_attrs is ALWAYS empty at this point. - subclass.representable_attrs.inherit!(representable_attrs) # this should be inherit_class! - # DISCUSS: this could also just be: subclass.inheritable_attr :representable_attrs --> superclass.representable_attrs.clone - end - end - module ModuleExtensions # Copies the representable_attrs reference to the extended object. # Note that changing attrs in the instance will affect the class configuration. def extended(object) super object.representable_attrs=(representable_attrs) # yes, we want a hard overwrite here and no inheritance. end end - module ClassMethods - # Gets overridden by Decorator as inheriting representers via include in Decorator means a bit more work (manifesting). - def inherit_module!(parent) - representable_attrs.inherit!(parent.representable_attrs) # Module just inherits. - end - def prepare(represented) represented.extend(self) end end - - module Feature - def feature(*mods) - mods.each do |mod| - include mod - register_feature(mod) - end - end - - private - def register_feature(mod) - representable_attrs[:features][mod] = true - end + require "representable/deprecations" + def self.deprecations=(value) + evaluator = value==false ? Binding::EvaluateOption : Binding::Deprecation::EvaluateOption + ::Representable::Binding.send :include, evaluator end + self.deprecations = true # TODO: change to false in 2.5 or remove entirely. end -require 'representable/autoload' \ No newline at end of file +require 'representable/autoload'