slotify 0.0.1.alpha.0 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,36 +1,26 @@
1
1
  module Slotify
2
2
  module Extensions
3
3
  module Base
4
- extend SlotifyHelpers
4
+ include SlotCompatability
5
5
 
6
- slotify_helpers(
7
- *ActionView::Helpers::UrlHelper.instance_methods(false),
8
- *ActionView::Helpers::TagHelper.instance_methods(false)
9
- )
6
+ attr_accessor :partial
10
7
 
11
- attr_reader :partial
12
-
13
- def render(target = {}, locals = {}, &block)
8
+ def render(options = {}, locals = {}, &block)
14
9
  @partial = Slotify::Partial.new(self)
15
10
  super
16
11
  ensure
17
12
  @partial = partial.outer_partial
18
13
  end
19
14
 
20
- def _layout_for(*args, &block)
21
- if block && args.first.is_a?(Symbol)
22
- capture_with_outer_partial_access(*args, &block)
23
- else
24
- super
25
- end
26
- end
27
-
28
15
  def capture_with_outer_partial_access(*args, &block)
29
16
  inner_partial, @partial = partial, partial.outer_partial
30
17
  inner_partial.capture(*args, &block)
31
18
  ensure
32
19
  @partial = inner_partial
33
20
  end
21
+
22
+ make_compatible_with_slots :url_for, :link_to, :button_to, :link_to_unless_current,
23
+ :link_to_unless, :link_to_if, :mail_to, :sms_to, :phone_to, :tag, :content_tag
34
24
  end
35
25
  end
36
26
  end
@@ -4,11 +4,10 @@ module Slotify
4
4
  def render_partial_template(view, locals, template, layout, block)
5
5
  return super unless template.strict_slots?
6
6
 
7
- partial = view.partial
7
+ view.partial.define_slots!(template.strict_slots_keys)
8
8
 
9
9
  view.capture_with_outer_partial_access(&block) if block
10
- partial.with_strict_slots(template.strict_slots_keys)
11
- locals = locals.merge(partial.slot_locals)
10
+ locals = locals.merge(view.partial.slot_locals)
12
11
 
13
12
  decorate_strict_slots_errors do
14
13
  super(view, locals, template, layout, block)
@@ -32,7 +31,7 @@ module Slotify
32
31
  end
33
32
 
34
33
  def missing_strict_locals_error?(error)
35
- (defined?(ActionView::StrictLocalsError) && error.cause.is_a?(ActionView::StrictLocalsError)) ||
34
+ error.template && (defined?(ActionView::StrictLocalsError) && error.cause.is_a?(ActionView::StrictLocalsError)) ||
36
35
  (error.cause.is_a?(ArgumentError) && error.cause.message.match(/missing local/))
37
36
  end
38
37
  end
@@ -3,16 +3,17 @@ require "action_view/template/error"
3
3
  module Slotify
4
4
  module Extensions
5
5
  module Template
6
+ STRICT_SLOTS_NONE = Object.new
6
7
  STRICT_SLOTS_REGEX = /\#\s+slots:\s+\((.*)\)/
7
8
  STRICT_SLOTS_KEYS_REGEX = /(\w+):(?=(?:[^"\\]*(?:\\.|"(?:[^"\\]*\\.)*[^"\\]*"))*[^"]*$)/
8
9
 
9
10
  def initialize(...)
10
11
  super
11
- @strict_slots = ActionView::Template::NONE
12
+ @strict_slots = STRICT_SLOTS_NONE
12
13
  end
13
14
 
14
15
  def strict_slots!
15
- if @strict_slots == ActionView::Template::NONE
16
+ if @strict_slots == STRICT_SLOTS_NONE
16
17
  source.sub!(STRICT_SLOTS_REGEX, "")
17
18
  strict_slots = $1
18
19
  @strict_slots = if strict_slots.nil?
@@ -30,7 +31,7 @@ module Slotify
30
31
  end
31
32
 
32
33
  def strict_slots_keys
33
- strict_slots!.scan(STRICT_SLOTS_KEYS_REGEX).map(&:first)
34
+ @strict_slots_keys ||= strict_slots!.scan(STRICT_SLOTS_KEYS_REGEX).map(&:first)
34
35
  end
35
36
 
36
37
  def strict_locals!
@@ -43,7 +44,7 @@ module Slotify
43
44
  return super unless strict_slots?
44
45
 
45
46
  strict_slots_keys.each_with_object(+super) do |key, code|
46
- code << "#{key} = partial.content_for(:#{key}, #{key});"
47
+ code << "partial.set_slot_default(:#{key}, binding.local_variable_get(:#{key})); #{key} = partial.public_send(:#{key});"
47
48
  end
48
49
  end
49
50
  end
@@ -1,33 +1,32 @@
1
1
  module Slotify
2
2
  class Partial
3
- include Utils
3
+ include InflectionHelper
4
+
5
+ RESERVED_SLOT_NAMES = [
6
+ :content, :slot, :value, :content_for,
7
+ :capture, :yield, :partial
8
+ ]
4
9
 
5
10
  attr_reader :outer_partial
6
11
 
7
12
  def initialize(view_context)
8
13
  @view_context = view_context
9
14
  @outer_partial = view_context.partial
10
- @entries = []
11
- @strict_slots = nil
15
+ @values = ValueStore.new(@view_context)
16
+ @defined_slots = nil
12
17
  end
13
18
 
14
- def content_for(slot_name, fallback_value = nil)
15
- raise SlotsAccessError, "slot content cannot be accessed from outside the partial" unless slots_defined?
16
- raise UnknownSlotError, "unknown slot :#{slot_name}" unless slot_defined?(slot_name)
17
-
18
- entries = slot_entries(slot_name)
19
- if entries.none? && !fallback_value.nil?
20
- entries = add_entries(slot_name, to_array(fallback_value))
21
- end
19
+ def content_for(slot_name)
20
+ raise UnknownSlotError, "unknown slot :#{slot_name}" unless slot?(slot_name)
22
21
 
23
- singular?(slot_name) ? entries.first : EntryCollection.new(entries)
22
+ slot_values = values.for(slot_name)
23
+ singular?(slot_name) ? slot_values.first : ValueCollection.new(slot_values)
24
24
  end
25
25
 
26
26
  def content_for?(slot_name)
27
- raise SlotsAccessError, "slot content cannot be accessed from outside the partial" unless slots_defined?
28
- raise UnknownSlotError, "unknown slot :#{slot_name}" unless slot_defined?(slot_name)
27
+ raise UnknownSlotError, "unknown slot :#{slot_name}" unless slot?(slot_name)
29
28
 
30
- slot_entries(slot_name).any?
29
+ values.for(slot_name).any?
31
30
  end
32
31
 
33
32
  def capture(*args, &block)
@@ -35,87 +34,81 @@ module Slotify
35
34
  end
36
35
 
37
36
  def yield(*args)
38
- if args.empty?
39
- @captured_buffer
40
- else
41
- content_for(args.first)
42
- end
37
+ args.empty? ? @captured_buffer : content_for(args.first)
43
38
  end
44
39
 
45
- def slot_locals
46
- @strict_slots.map { [_1, content_for(_1).presence] }.to_h.compact
40
+ def content
41
+ self.yield
47
42
  end
48
43
 
49
- def with_strict_slots(strict_slot_names)
50
- @strict_slots = strict_slot_names.map(&:to_sym)
44
+ def set_slot_default(slot_name, default_value)
45
+ raise UnknownSlotError, "unknown slot :#{slot_name}" unless slot?(slot_name)
46
+
47
+ if values.for(slot_name).none? && !default_value.nil?
48
+ values.add(slot_name, Array.wrap(default_value))
49
+ end
50
+ end
51
+
52
+ def slot_locals
51
53
  validate_slots!
54
+
55
+ pairs = @defined_slots.map do |slot_name|
56
+ slot_values = values.for(slot_name)
57
+ slot_values = singular?(slot_name) ? slot_values&.first : slot_values
58
+ [slot_name, slot_values]
59
+ end
60
+
61
+ pairs.filter do |key, value|
62
+ # keep empty strings as local value but filter out empty arrays
63
+ # and objects so they don't override any default values set via strict slots.
64
+ value.is_a?(String) || value&.present?
65
+ end.to_h
52
66
  end
53
67
 
54
- def helpers
55
- @helpers || Helpers.new(@view_context)
68
+ def define_slots!(slot_names)
69
+ raise SlotsDefinedError, "Slots cannot be redefined" unless @defined_slots.nil?
70
+
71
+ @defined_slots = slot_names.map(&:to_sym).each do |slot_name|
72
+ if RESERVED_SLOT_NAMES.include?(singularize(slot_name))
73
+ raise ReservedSlotNameError, ":#{slot_name} is a reserved word and cannot be used as a slot name"
74
+ end
75
+ end
56
76
  end
57
77
 
58
78
  def respond_to_missing?(name, include_private = false)
59
- name.start_with?("with_") || helpers.respond_to?(name)
79
+ name.start_with?("with_") || slot?(name)
60
80
  end
61
81
 
62
82
  def method_missing(name, *args, **options, &block)
63
83
  if name.start_with?("with_")
64
- slot_name = name.to_s.delete_prefix("with_")
65
- if singular?(slot_name)
66
- add_entry(slot_name, args, options, block)
67
- else
68
- add_entries(slot_name, args.first, options, block)
69
- end
84
+ values.add(name.to_s.delete_prefix("with_"), args, options, block)
85
+ elsif slot?(name)
86
+ content_for(name)
70
87
  else
71
- helpers.public_send(name, *args, **options, &block)
88
+ super
72
89
  end
73
90
  end
74
91
 
75
92
  private
76
93
 
77
- def slots_defined?
78
- !@strict_slots.nil?
79
- end
80
-
81
- def slot_defined?(slot_name)
82
- slot_name && slots_defined? && @strict_slots.include?(slot_name.to_sym)
83
- end
94
+ attr_reader :values
84
95
 
85
- def slot_entries(slot_name)
86
- @entries.filter { _1.slot_name == singularize(slot_name) }
87
- end
88
-
89
- def add_entries(slot_name, collection, options = {}, block = nil)
90
- unless collection.respond_to?(:each)
91
- raise ArgumentError, "expected array to be passed to slot :#{slot_name} (received #{collection.class.name})"
92
- end
93
-
94
- collection.map { add_entry(slot_name, _1, options, block) }
95
- end
96
-
97
- def add_entry(slot_name, args = [], options = {}, block = nil)
98
- with_resolved_args(args, options, block) do |rargs, roptions, rblock|
99
- @entries << Entry.new(@view_context, singularize(slot_name), rargs, roptions, rblock)
100
- end
101
-
102
- @entries.last
96
+ def slot?(slot_name)
97
+ slot_name && @defined_slots.include?(slot_name.to_sym)
103
98
  end
104
99
 
105
100
  def validate_slots!
106
- return if @strict_slots.nil?
107
-
108
- singular_slots = @strict_slots.map { singularize(_1) }
109
- slots_called = @entries.map(&:slot_name).uniq
110
- undefined_slots = slots_called - singular_slots
101
+ return if @defined_slots.nil?
111
102
 
103
+ undefined_slots = values.slot_names - @defined_slots.map { singularize(_1) }
112
104
  if undefined_slots.any?
113
- raise UndefinedSlotError, "missing slot #{"definition".pluralize(undefined_slots.size)} for `#{undefined_slots.map { ":#{_1}(s)" }.join(", ")}`"
105
+ raise UndefinedSlotError,
106
+ "missing slot #{"definition".pluralize(undefined_slots.size)} for `#{undefined_slots.map { ":#{_1}(s)" }.join(", ")}`"
114
107
  end
115
108
 
116
- @strict_slots.filter { singular?(_1) }.each do |slot_name|
117
- entries = slot_entries(slot_name)
118
- raise MultipleSlotEntriesError, "slot :#{slot_name} called #{entries.size} times (expected 1)" if entries.many?
109
+ @defined_slots.filter { singular?(_1) }.each do |slot_name|
110
+ slot_values = values.for(slot_name)
111
+ raise MultipleSlotEntriesError, "slot :#{slot_name} called #{slot_values.size} times (expected 1)" if slot_values.many?
119
112
  end
120
113
  end
121
114
  end
@@ -0,0 +1,26 @@
1
+ module Slotify
2
+ module MethodArgsResolver
3
+ class << self
4
+ def call(args = [], options = {}, block = nil)
5
+ args = args.is_a?(Array) ? args.clone : [args]
6
+ value_index = args.index { _1.is_a?(ValueCollection) || _1.is_a?(Value) }
7
+ if value_index.nil?
8
+ [yield(args, options, block)]
9
+ else
10
+ target = args[value_index]
11
+ values = target.is_a?(ValueCollection) ? target : [target]
12
+ values.map do |value|
13
+ cloned_args = args.clone
14
+ cloned_args[value_index, 1] = value.args.clone
15
+
16
+ yield(
17
+ cloned_args,
18
+ TagOptionsMerger.call(options, value.options),
19
+ value.block || block
20
+ )
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,84 @@
1
+ module Slotify
2
+ class Value
3
+ include InflectionHelper
4
+
5
+ attr_reader :slot_name, :args, :block
6
+
7
+ delegate :presence, :to_s, :to_str, to: :content
8
+
9
+ def initialize(view_context, args = [], options = {}, block = nil, slot_name: nil, partial_path: nil)
10
+ @view_context = view_context
11
+ @slot_name = slot_name&.to_sym
12
+ @args = args
13
+ @options = options.to_h
14
+ @block = block
15
+ @partial_path = partial_path
16
+ end
17
+
18
+ def options
19
+ ValueOptions.new(@view_context, @options)
20
+ end
21
+
22
+ def content
23
+ if @block && @block.arity == 0
24
+ body = @view_context.capture(&@block)
25
+ ActiveSupport::SafeBuffer.new(body.presence || "")
26
+ elsif args.first.is_a?(String)
27
+ ActiveSupport::SafeBuffer.new(args.first)
28
+ else
29
+ args.first
30
+ end
31
+ end
32
+
33
+ def present?
34
+ @args.present? || @options.present? || @block
35
+ end
36
+
37
+ def empty?
38
+ @args.empty? || @options.empty? || !@block
39
+ end
40
+
41
+ alias_method :blank?, :empty?
42
+
43
+ def to_h
44
+ @options
45
+ end
46
+
47
+ alias_method :to_hash, :to_h
48
+
49
+ def with_partial_path(partial_path)
50
+ Value.new(@view_context, @args, options, @block, slot_name: @slot_name, partial_path:)
51
+ end
52
+
53
+ def with_default_options(default_options)
54
+ options = TagOptionsMerger.call(default_options, @options)
55
+ Value.new(@view_context, @args, options, @block, slot_name: @slot_name)
56
+ end
57
+
58
+ def respond_to_missing?(name, include_private = false)
59
+ name.start_with?("to_") || super
60
+ end
61
+
62
+ def method_missing(name, ...)
63
+ if name.start_with?("to_")
64
+ @args.first.public_send(name, ...)
65
+ else
66
+ super
67
+ end
68
+ end
69
+
70
+ def [](key)
71
+ key.is_a?(Integer) ? @args[key] : super
72
+ end
73
+
74
+ def render_in(view_context, &block)
75
+ view_context.render partial_path, **@options.to_h, &@block || block
76
+ end
77
+
78
+ private
79
+
80
+ def partial_path
81
+ @partial_path || @slot_name.to_s
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,31 @@
1
+ module Slotify
2
+ class ValueCollection
3
+ include Enumerable
4
+
5
+ delegate_missing_to :@values
6
+
7
+ def initialize(values = [])
8
+ @values = values.is_a?(Value) ? [values] : values
9
+ end
10
+
11
+ def with_default_options(...)
12
+ ValueCollection.new(map { _1.with_default_options(...) })
13
+ end
14
+
15
+ def with_partial_path(...)
16
+ ValueCollection.new(map { _1.with_partial_path(...) })
17
+ end
18
+
19
+ def to_s
20
+ @values.reduce(ActiveSupport::SafeBuffer.new) do |buffer, value|
21
+ buffer << value.to_s
22
+ end
23
+ end
24
+
25
+ def render_in(view_context, &block)
26
+ @values.reduce(ActiveSupport::SafeBuffer.new) do |buffer, value|
27
+ buffer << value.render_in(view_context, &block)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,16 +1,16 @@
1
1
  module Slotify
2
- class EntryOptions < ActiveSupport::OrderedOptions
2
+ class ValueOptions < ActiveSupport::OrderedOptions
3
3
  def initialize(view_context, options = {})
4
4
  @view_context = view_context
5
5
  merge!(options)
6
6
  end
7
7
 
8
8
  def except(...)
9
- EntryOptions.new(@view_context, to_h.except(...))
9
+ ValueOptions.new(@view_context, to_h.except(...))
10
10
  end
11
11
 
12
12
  def slice(...)
13
- EntryOptions.new(@view_context, to_h.slice(...))
13
+ ValueOptions.new(@view_context, to_h.slice(...))
14
14
  end
15
15
 
16
16
  def to_s
@@ -0,0 +1,28 @@
1
+ module Slotify
2
+ class ValueStore
3
+ include InflectionHelper
4
+
5
+ def initialize(view_context)
6
+ @view_context = view_context
7
+ @values = []
8
+ end
9
+
10
+ def for(slot_name)
11
+ @values.select { _1.slot_name == singularize(slot_name) }
12
+ end
13
+
14
+ def add(slot_name, args = [], options = {}, block = nil)
15
+ if plural?(slot_name)
16
+ Array.wrap(args.first).map { add(singularize(slot_name), _1, options, block) }
17
+ else
18
+ MethodArgsResolver.call(args, options, block) do
19
+ @values << Value.new(@view_context, _1, _2, _3, slot_name: singularize(slot_name))
20
+ end
21
+ end
22
+ end
23
+
24
+ def slot_names
25
+ @values.map(&:slot_name).uniq
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module Slotify
2
- VERSION = "0.0.1.alpha.0"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/slotify.rb CHANGED
@@ -6,14 +6,16 @@ require_relative "slotify/error"
6
6
  loader = Zeitwerk::Loader.for_gem
7
7
  loader.tag = "slotify"
8
8
  loader.push_dir("#{__dir__}/slotify", namespace: Slotify)
9
+ loader.collapse("#{__dir__}/slotify/concerns")
10
+ loader.collapse("#{__dir__}/slotify/services")
9
11
  loader.enable_reloading if ENV["RAILS_ENV"] == "development"
10
12
  loader.setup
11
13
 
12
- module Slotify
13
- end
14
-
15
14
  ActiveSupport.on_load :action_view do
16
15
  prepend Slotify::Extensions::Base
17
16
  ActionView::Template.prepend Slotify::Extensions::Template
18
17
  ActionView::PartialRenderer.prepend Slotify::Extensions::PartialRenderer
19
18
  end
19
+
20
+ module Slotify
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slotify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.alpha.0
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Perkins
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-04 00:00:00.000000000 Z
11
+ date: 2025-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zeitwerk
@@ -46,18 +46,19 @@ extra_rdoc_files: []
46
46
  files:
47
47
  - README.md
48
48
  - lib/slotify.rb
49
- - lib/slotify/entry.rb
50
- - lib/slotify/entry_collection.rb
51
- - lib/slotify/entry_options.rb
49
+ - lib/slotify/concerns/inflection_helper.rb
50
+ - lib/slotify/concerns/slot_compatability.rb
52
51
  - lib/slotify/error.rb
53
52
  - lib/slotify/extensions/base.rb
54
53
  - lib/slotify/extensions/partial_renderer.rb
55
54
  - lib/slotify/extensions/template.rb
56
- - lib/slotify/helpers.rb
57
55
  - lib/slotify/partial.rb
58
- - lib/slotify/slotify_helpers.rb
59
- - lib/slotify/tag_options_merger.rb
60
- - lib/slotify/utils.rb
56
+ - lib/slotify/services/method_args_resolver.rb
57
+ - lib/slotify/services/tag_options_merger.rb
58
+ - lib/slotify/value.rb
59
+ - lib/slotify/value_collection.rb
60
+ - lib/slotify/value_options.rb
61
+ - lib/slotify/value_store.rb
61
62
  - lib/slotify/version.rb
62
63
  homepage:
63
64
  licenses:
@@ -74,9 +75,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
75
  version: 3.1.0
75
76
  required_rubygems_version: !ruby/object:Gem::Requirement
76
77
  requirements:
77
- - - ">"
78
+ - - ">="
78
79
  - !ruby/object:Gem::Version
79
- version: 1.3.1
80
+ version: '0'
80
81
  requirements: []
81
82
  rubygems_version: 3.3.3
82
83
  signing_key:
data/lib/slotify/entry.rb DELETED
@@ -1,83 +0,0 @@
1
- module Slotify
2
- class Entry
3
- include Utils
4
-
5
- attr_reader :slot_name, :args, :block
6
-
7
- delegate :presence, to: :@content
8
-
9
- def initialize(view_context, slot_name, args = [], options = {}, block = nil, partial_path: nil, **kwargs)
10
- @view_context = view_context
11
- @slot_name = slot_name.to_sym
12
- @args = args
13
- @options = options
14
- @block = block
15
- @partial_path = partial_path
16
- end
17
-
18
- def options
19
- EntryOptions.new(@view_context, @options)
20
- end
21
-
22
- def content
23
- body = if @block && @block.arity == 0
24
- @view_context.capture(&@block)
25
- else
26
- begin
27
- args.first.to_str
28
- rescue NoMethodError
29
- ""
30
- end
31
- end
32
- ActiveSupport::SafeBuffer.new(body.presence || "")
33
- end
34
-
35
- alias_method :to_s, :content
36
- alias_method :to_str, :content
37
-
38
- def present?
39
- @args.present? || @options.present? || @block
40
- end
41
-
42
- def empty?
43
- @args.empty? || @options.empty? || !@block
44
- end
45
-
46
- alias_method :blank?, :empty?
47
-
48
- def to_h
49
- @options
50
- end
51
-
52
- alias_method :to_hash, :to_h
53
-
54
- def with_partial_path(partial_path)
55
- Entry.new(@view_context, @slot_name, @args, options.to_h, @block, partial_path:)
56
- end
57
-
58
- def with_default_options(default_options)
59
- options = merge_tag_options(default_options, @options)
60
- Entry.new(@view_context, @slot_name, @args, options.to_h, @block)
61
- end
62
-
63
- def respond_to_missing?(name, include_private = false)
64
- name.start_with?("to_") || super
65
- end
66
-
67
- def method_missing(name, *args, **options)
68
- if name.start_with?("to_") && args.none?
69
- @args.first.public_send(name)
70
- end
71
- end
72
-
73
- def render_in(view_context, &block)
74
- view_context.render partial_path, **@options.to_h, &@block || block
75
- end
76
-
77
- private
78
-
79
- def partial_path
80
- @partial_path || @slot_name.to_s
81
- end
82
- end
83
- end
@@ -1,31 +0,0 @@
1
- module Slotify
2
- class EntryCollection
3
- include Enumerable
4
-
5
- delegate_missing_to :@entries
6
-
7
- def initialize(entries = [])
8
- @entries = entries.is_a?(Entry) ? [entries] : entries
9
- end
10
-
11
- def with_default_options(...)
12
- EntryCollection.new(map { _1.with_default_options(...) })
13
- end
14
-
15
- def with_partial_path(...)
16
- EntryCollection.new(map { _1.with_partial_path(...) })
17
- end
18
-
19
- def to_s
20
- @entries.reduce(ActiveSupport::SafeBuffer.new) do |buffer, entry|
21
- buffer << entry.to_s
22
- end
23
- end
24
-
25
- def render_in(view_context, &block)
26
- @entries.reduce(ActiveSupport::SafeBuffer.new) do |buffer, entry|
27
- buffer << entry.render_in(view_context, &block)
28
- end
29
- end
30
- end
31
- end