lib/representable/definition.rb in representable-1.8.5 vs lib/representable/definition.rb in representable-2.0.0.rc1

- old
+ new

@@ -1,38 +1,45 @@ require 'uber/options' require "representable/parse_strategies" module Representable # Created at class compile time. Keeps configuration options for one property. - class Definition < Hash + class Definition + include Representable::Cloneable + attr_reader :name alias_method :getter, :name - def initialize(sym, options={}) - super() - options = options.clone + def initialize(sym, options={}, &block) + @options = {} + # @options = Inheritable::Hash.new # allows deep cloning. we then had to set Pipeline cloneable. + @name = sym.to_s + options = options.clone - handle_deprecations!(options) - - @name = sym.to_s # defaults: - options[:as] ||= @name + options[:parse_filter] = Pipeline[*options[:parse_filter]] + options[:render_filter] = Pipeline[*options[:render_filter]] + options[:as] ||= @name - setup!(options) + setup!(options, &block) end - # TODO: test merge!. - def merge!(options) - setup!(options) + def merge!(options, &block) + options = options.clone + + options[:parse_filter] = @options[:parse_filter].push(*options[:parse_filter]) + options[:render_filter] = @options[:render_filter].push(*options[:render_filter]) + + setup!(options, &block) # FIXME: this doesn't yield :as etc. self end - private :[]= # TODO: re-privatize #default when this is sorted with Rubinius. + extend Forwardable + def_delegators :@runtime_options, :[], :each - def options # TODO: remove in 2.0. - warn "Representable::Definition#option is deprecated, use #[] directly." - self + def clone + self.class.new(name, @options.clone) end def setter :"#{name}=" end @@ -53,64 +60,64 @@ def hash? self[:hash] end def default_for(value) - return self[:default] if skipable_nil_value?(value) + return self[:default] if skipable_empty_value?(value) value end def has_default? - has_key?(:default) + @options.has_key?(:default) end def representer_module - self[:extend] + @options[:extend] end def skipable_empty_value?(value) return true if array? and self[:render_empty] == false and value and value.size == 0 # TODO: change in 2.0, don't render emtpy. value.nil? and not self[:render_nil] end - alias_method :skipable_nil_value?, :skipable_empty_value? # TODO: remove in 1.9 . def create_binding(*args) self[:binding].call(self, *args) end private - def setup!(options) + def setup!(options, &block) handle_extend!(options) handle_as!(options) # DISCUSS: we could call more macros here (e.g. for :nested). Representable::ParseStrategy.apply!(options) + yield options if block_given? + @options.merge!(options) + + runtime_options!(@options) + end + + # wrapping dynamic options in Value does save runtime, as this is used very frequently (and totally unnecessary to wrap an option + # at runtime, its value never changes). + def runtime_options!(options) + @runtime_options = {} + for name, value in options value = Uber::Options::Value.new(value) if dynamic_options.include?(name) - self[name] = value + @runtime_options[name] = value end end def dynamic_options - [:as, :getter, :setter, :class, :instance, :reader, :writer, :extend, :prepare, :if, :deserialize, :serialize] + [:as, :getter, :setter, :class, :instance, :reader, :writer, :extend, :prepare, :if, :deserialize, :serialize, :render_filter, :parse_filter] end def handle_extend!(options) mod = options.delete(:extend) || options.delete(:decorator) and options[:extend] = mod end def handle_as!(options) options[:as] = options[:as].to_s if options[:as].is_a?(Symbol) # Allow symbols for as: - end - - # TODO: remove in 2.0. - def handle_deprecations!(options) - raise "The :from option got replaced by :as in Representable 1.8!" if options[:from] - - if options[:decorator_scope] - warn "[Representable] Deprecation: `decorator_scope: true` is deprecated, use `exec_context: :decorator` instead." - options.merge!(:exec_context => :decorator) - end end end end