lib/praxis-blueprints/field_expander.rb in praxis-blueprints-3.0 vs lib/praxis-blueprints/field_expander.rb in praxis-blueprints-3.1

- old
+ new

@@ -1,15 +1,7 @@ module Praxis class FieldExpander - class CircularExpansionError < StandardError - attr_reader :stack - def initialize(message, stack=[]) - super(message) - @stack = stack - end - end - def self.expand(object, fields=true) self.new.expand(object,fields) end attr_reader :stack @@ -24,25 +16,30 @@ end end def expand(object, fields=true) if stack[object].include? fields - raise CircularExpansionError, "Circular expansion detected for object #{object.inspect} with fields #{fields.inspect}" + if history[object].include? fields + return history[object][fields] + end + # We should probably never get here, since we should have a record + # of the history of an expansion if we're trying to redo it, + # but we should also be conservative and raise here just in case. + raise "Circular expansion detected for object #{object.inspect} with fields #{fields.inspect}" else stack[object] << fields end - if object.kind_of?(Praxis::View) + result = if object.kind_of?(Praxis::View) self.expand_view(object, fields) elsif object.kind_of? Attributor::Attribute self.expand_type(object.type, fields) else self.expand_type(object,fields) end - rescue CircularExpansionError => e - e.stack.unshift [object,fields] - raise + + result ensure stack[object].delete fields end def expand_fields(attributes, fields) @@ -65,24 +62,43 @@ end end def expand_view(object,fields=true) + history[object][fields] = if object.kind_of?(Praxis::CollectionView) + [] + else + {} + end + result = expand_fields(object.contents, fields) do |dumpable, sub_fields| self.expand(dumpable, sub_fields) end - return [result] if object.kind_of?(Praxis::CollectionView) - result + if object.kind_of?(Praxis::CollectionView) + history[object][fields] << result + else + history[object][fields].merge!(result) + end + history[object][fields] end def expand_type(object,fields=true) unless object.respond_to?(:attributes) if object.respond_to?(:member_attribute) - fields = fields[0] if fields.kind_of? Array - return [self.expand(object.member_attribute.type, fields)] + if history[object].include? fields + return history[object][fields] + end + history[object][fields] = [] + + new_fields = fields.kind_of?(Array) ? fields[0] : fields + + result = [self.expand(object.member_attribute.type, new_fields)] + history[object][fields].push(*result) + + return result else return true end end @@ -93,12 +109,14 @@ if history[object].include? fields return history[object][fields] end - history[object][fields] = expand_fields(object.attributes, fields) do |dumpable, sub_fields| + history[object][fields] = {} + result = expand_fields(object.attributes, fields) do |dumpable, sub_fields| self.expand(dumpable.type, sub_fields) end + history[object][fields].merge!(result) end end end