lib/pbbuilder/template.rb in pbbuilder-0.16.1 vs lib/pbbuilder/template.rb in pbbuilder-0.16.2

- old
+ new

@@ -28,61 +28,49 @@ else _render_explicit_partial(*args) end end + # Set the value in the message field. + # + # @example + # pb.friends @friends, partial: "friend", as: :friend + # pb.friends partial: "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])] + # pb.best_friend partial: "person", person: @best_friend + # pb.friends "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])] + def set!(field, *args, **kwargs, &block) # If partial options are being passed, we render a submessage with a partial if kwargs.has_key?(:partial) if args.one? && kwargs.has_key?(:as) - # pb.friends @friends, partial: "friend", as: :friend + # example syntax that should end up here: + # pb.friends @friends, partial: "friend", as: :friend # Call set! on the super class, passing in a block that renders a partial for every element super(field, *args) do |element| _set_inline_partial(element, kwargs) end elsif kwargs.has_key?(:collection) && kwargs.has_key?(:as) - # pb.friends partial: "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])] - # collection renderer - options = kwargs.deep_dup + # example syntax that should end up here: + # pb.friends partial: "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])] - options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached) - options.reverse_merge! ::PbbuilderTemplate.template_lookup_options - - collection = options[:collection] || [] - partial = options[:partial] - - # The way recursive rendering works is that CollectionRenderer needs to be aware of node its currently rendering and parent node, - # these is no need to know entire "stack" of nodes. CollectionRenderer would traverse to bottom node render that first and then go up in stack. - - # CollectionRenderer uses locals[:pb] to render the partial as a protobuf message, - # but also needs locals[:pb_parent] to apply rendered partial to top level protobuf message. - - # This logic could be found in CollectionRenderer#build_rendered_collection method that we over wrote. - options[:locals].merge!(pb: ::PbbuilderTemplate.new(@context, new_message_for(field))) - options[:locals].merge!(pb_parent: self) - options[:locals].merge!(field: field) - - if options.has_key?(:layout) - raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering." - end - - if options.has_key?(:spacer_template) - raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering." - end - - CollectionRenderer - .new(@context.lookup_context, options) { |&block| _scope(message[field.to_s],&block) } - .render_collection_with_partial(collection, partial, @context, nil) + _render_collection_with_options(field, kwargs[:collection], kwargs) else + # # example syntax that should end up here: # pb.best_friend partial: "person", person: @best_friend - # Call set! as a submessage, passing in the kwargs as partial options + super(field, *args) do _render_partial_with_options(kwargs) end end else - super + if args.one? && kwargs.has_key?(:collection) && kwargs.has_key?(:as) + # example syntax that should end up here: + # pb.friends "racers/racer", as: :racer, collection: [Racer.new(1, "Johnny Test", []), Racer.new(2, "Max Verstappen", [])] + _render_collection_with_options(field, kwargs[:collection], kwargs.merge(partial: args.first)) + else + super + end end end # Caches fragment of message. Can be called like the following: # 'pb.cache! "cache-key" do; end' @@ -117,13 +105,45 @@ condition ? cache!(*args, &block) : yield end private + # Uses ActionView::CollectionRenderer to render collection effectively and to use rails built in fragment caching support. + # + # The way recursive rendering works is that the CollectionRenderer needs to be aware of the node its currently rendering and parent node. + # There is no need to know the entire "stack" of nodes. ActionView::CollectionRenderer would traverse to bottom node render it first and then go one leve up in stack, + # rince and repeat until entire stack is rendered. + + # CollectionRenderer uses locals[:pb] to render the partial as a protobuf message, + # but also needs locals[:pb_parent] to apply the rendered partial to the top level protobuf message. + + # This logic can be found in CollectionRenderer#build_rendered_collection method that we overwrote. + def _render_collection_with_options(field, collection, options) + partial = options[:partial] + + options.reverse_merge! locals: options.except(:partial, :as, :collection, :cached) + options.reverse_merge! ::PbbuilderTemplate.template_lookup_options + + options[:locals].merge!(pb: ::PbbuilderTemplate.new(@context, new_message_for(field))) + options[:locals].merge!(pb_parent: self) + options[:locals].merge!(field: field) + + if options.has_key?(:layout) + raise ::NotImplementedError, "The `:layout' option is not supported in collection rendering." + end + + if options.has_key?(:spacer_template) + raise ::NotImplementedError, "The `:spacer_template' option is not supported in collection rendering." + end + + CollectionRenderer + .new(@context.lookup_context, options) { |&block| _scope(message[field.to_s],&block) } + .render_collection_with_partial(collection, partial, @context, nil) + end + # Writes to cache, if cache with keys is missing. # # @return fragment value - def _cache_fragment_for(key, options, &block) key = _cache_key(key, options) _read_fragment_cache(key, options) || _write_fragment_cache(key, options, &block) end