express_templates 0.2.7 → 0.3.0

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/core_extensions/proc.rb +72 -20
  3. data/lib/express_templates/compiler.rb +9 -1
  4. data/lib/express_templates/components/base.rb +1 -1
  5. data/lib/express_templates/components/capabilities/building.rb +8 -0
  6. data/lib/express_templates/components/capabilities/conditionality.rb +8 -6
  7. data/lib/express_templates/components/capabilities/configurable.rb +3 -4
  8. data/lib/express_templates/components/capabilities/iterating.rb +18 -23
  9. data/lib/express_templates/components/capabilities/parenting.rb +4 -18
  10. data/lib/express_templates/components/capabilities/rendering.rb +2 -65
  11. data/lib/express_templates/components/capabilities/templating.rb +24 -22
  12. data/lib/express_templates/components/capabilities/wrapping.rb +23 -39
  13. data/lib/express_templates/components/column.rb +1 -1
  14. data/lib/express_templates/components/for_each.rb +28 -0
  15. data/lib/express_templates/components/form_for.rb +19 -0
  16. data/lib/express_templates/components/form_rails_support.rb +1 -1
  17. data/lib/express_templates/components/null_wrap.rb +9 -0
  18. data/lib/express_templates/components/row.rb +1 -1
  19. data/lib/express_templates/components/table_for.rb +119 -0
  20. data/lib/express_templates/components/tree_for.rb +41 -0
  21. data/lib/express_templates/components/unless_block.rb +40 -0
  22. data/lib/express_templates/components.rb +4 -0
  23. data/lib/express_templates/expander.rb +15 -4
  24. data/lib/express_templates/indenter.rb +8 -5
  25. data/lib/express_templates/markup/tag.rb +62 -30
  26. data/lib/express_templates/markup/wrapper.rb +1 -1
  27. data/lib/express_templates/version.rb +1 -1
  28. data/test/components/base_test.rb +5 -38
  29. data/test/components/conditionality_test.rb +1 -1
  30. data/test/components/configurable_test.rb +2 -2
  31. data/test/components/container_test.rb +1 -1
  32. data/test/components/iterating_test.rb +30 -9
  33. data/test/components/table_for_test.rb +116 -0
  34. data/test/core_extensions/proc_test.rb +35 -5
  35. data/test/dummy/log/test.log +645 -0
  36. data/test/fixtures/{a_big_page.html → a_big_page2.html} +0 -0
  37. data/test/indenter_test.rb +6 -4
  38. data/test/markup/tag_test.rb +15 -2
  39. data/test/performance_test.rb +1 -1
  40. data/test/test_helper.rb +2 -0
  41. metadata +26 -3
@@ -0,0 +1,119 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ # Create an html table from a collection of data.
4
+ #
5
+ # Typically this will be a collection of models
6
+ # of the same type. Each member of the collection must
7
+ # respond to the column names provided.
8
+ #
9
+ # Example:
10
+ #
11
+ # ```ruby
12
+ # table_for(:people) do |t|
13
+ # t.column :name
14
+ # t.column :email
15
+ # t.column :phone
16
+ # end
17
+ # ```
18
+ #
19
+ # This assumes that a @people variable will exist in the
20
+ # view and that it will be a collection whose members respond to
21
+ # :name, :email, and :phone
22
+ #
23
+ # This will result in markup like the following:
24
+ #
25
+ # <table id="people">
26
+ # <thead>
27
+ # <tr>
28
+ # <th class="name">Name</th>
29
+ # <th class="email">Email</th>
30
+ # <th class="phone">Phone</th>
31
+ # </tr>
32
+ # </thead>
33
+ # <tbody>
34
+ # <tr id="person-1">
35
+ # <td class="name">Steven Talcott Smith</td>
36
+ # <td class="email">steve@aelogica.com</td>
37
+ # <td class="phone">415-555-1212</td>
38
+ # </tr>
39
+ # </tbody>
40
+ # </table>
41
+ #
42
+ class TableFor < Base
43
+ include Capabilities::Configurable
44
+ include Capabilities::Building
45
+
46
+ def initialize(*args)
47
+ super(*args)
48
+ _process_args!(args) # from Configurable
49
+ yield(self) if block_given?
50
+ end
51
+
52
+ attr :columns
53
+
54
+ def column(name, options = {})
55
+ @columns ||= []
56
+ @columns << Column.new(name, options)
57
+ end
58
+
59
+ emits -> {
60
+ table(my[:id]) {
61
+ thead {
62
+ tr {
63
+ columns.each do |column|
64
+ th.send(column.name) {
65
+ column.title
66
+ }
67
+ end
68
+ }
69
+ }
70
+ tbody {
71
+ for_each(my[:id]) {
72
+
73
+ tr(id: -> {"item-#{item.id}"},
74
+ class: my[:id].to_s.singularize) {
75
+
76
+ columns.each do |column|
77
+ td(class: column.name) {
78
+ column.format(:item)
79
+ }
80
+ end
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+
87
+ def wrap_for_stack_trace(body)
88
+ "ExpressTemplates::Components::TableFor.render_in(self) {\n#{body}\n}"
89
+ end
90
+
91
+ def compile
92
+ wrap_for_stack_trace(lookup(:markup))
93
+ end
94
+
95
+ class Column
96
+ attr :name, :options
97
+ def initialize(name, options = {})
98
+ @name = name
99
+ @options = options
100
+ @formatter = options[:formatter]
101
+ end
102
+
103
+ def format(item_name)
104
+ if @formatter.nil?
105
+ "\#\{#{item_name}.#{name}\}"
106
+ elsif @formatter.kind_of?(Proc)
107
+ "\#\{(#{@formatter.source}).call(#{item_name}.#{name})\}"
108
+ end
109
+ end
110
+
111
+ def title
112
+ @name.to_s.try(:titleize)
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,41 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ #
4
+ # Create an html <tt>table</tt> or <tt>ol</tt> (ordered list) for
5
+ # a model object representing a tree of similar objects.
6
+ #
7
+ # The objects must respond to <tt>:children</tt>.
8
+ #
9
+ # The block is passed a NodeBuilder which may accept field names.
10
+ #
11
+ # Example:
12
+ #
13
+ # ```ruby
14
+ # tree_for(:roles) do |role|
15
+ # role.name
16
+ # end
17
+ # ```
18
+ #
19
+ # If the view has an @roles variable with a Role having children,
20
+ # this will turn into markup such as the following:
21
+ #
22
+ # <ul id="roles" class="roles tree">
23
+ # <li>SuperAdmin
24
+ # <ul>
25
+ # <li>Admin</li>
26
+ # <ul>
27
+ # <li>Publisher</li>
28
+ # <ul>
29
+ # <li>Author</li>
30
+ # </ul>
31
+ # <li>Auditor</li>
32
+ # </ol>
33
+ # </li>
34
+ # </ol>
35
+ # </li>
36
+ # </ol>
37
+ #
38
+ class TreeFor < Container
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,40 @@
1
+ module ExpressTemplates
2
+ module Components
3
+ class UnlessBlock < Components::Container
4
+
5
+ attr :conditional
6
+
7
+ def initialize(*args)
8
+ @conditional = args.shift
9
+ @alt = args.shift[:alt] if args.first.kind_of?(Hash)
10
+ parent = args.shift
11
+ if @conditional.kind_of?(Symbol)
12
+ @conditional = @conditional.to_s
13
+ elsif @conditional.kind_of?(Proc)
14
+ @conditional = "(#{@conditional.source}.call)"
15
+ elsif iterator.kind_of?(String)
16
+ @conditional = "(#{@conditional}.call)"
17
+ else
18
+ raise "UnlessBlock unknown conditional: #{@conditional.inspect}"
19
+ end
20
+
21
+ if @alt.kind_of?(Proc)
22
+ @alt = _compile_fragment @alt
23
+ elsif @alt.nil?
24
+ @alt = "''"
25
+ end
26
+ end
27
+
28
+ def compile
29
+ s = unless @alt
30
+ %Q((unless #{@conditional}#{compile_children}\nend))
31
+ else
32
+ %Q((unless #{@conditional}#{compile_children}\nelse #{@alt}\nend))
33
+ end
34
+ puts s if ENV['DEBUG'].eql?('true')
35
+ s
36
+ end
37
+
38
+ end
39
+ end
40
+ end
@@ -6,7 +6,11 @@ end
6
6
  require 'express_templates/expander'
7
7
  require 'express_templates/components/base'
8
8
  require 'express_templates/components/container'
9
+ require 'express_templates/components/null_wrap'
10
+ require 'express_templates/components/for_each'
11
+ require 'express_templates/components/unless_block'
9
12
  require 'express_templates/components/row'
10
13
  require 'express_templates/components/column'
11
14
  require 'express_templates/components/form_rails_support'
12
15
  require 'express_templates/components/content_for'
16
+ require 'express_templates/components/table_for'
@@ -6,11 +6,16 @@ module ExpressTemplates
6
6
 
7
7
  attr_accessor :stack, :handlers, :locals
8
8
 
9
- def initialize(template, handlers = {}, locals = {})
9
+ def initialize(*args)
10
+ initialize_expander(*args)
11
+ end
12
+
13
+ def initialize_expander(template, handlers = {}, locals = {})
10
14
  @template = template
11
15
  @stack = Stack.new
12
16
  @handlers = handlers
13
17
  @locals = locals
18
+ self
14
19
  end
15
20
 
16
21
  def expand(source=nil, &block)
@@ -47,8 +52,14 @@ module ExpressTemplates
47
52
  def self.register_macros_for(*components)
48
53
  components.each do |component|
49
54
  define_method(component.macro_name.to_sym) do |*args, &block|
50
- new_component = component.new(*(args.push(self)))
51
- process_children!(new_component, &block) unless block.nil?
55
+ new_component = nil
56
+ # this is a code smell here.
57
+ if component.ancestors.include?(Components::Capabilities::Building)
58
+ new_component = component.new(*(args.push(self)), &block)
59
+ else
60
+ new_component = component.new(*(args.push(self)))
61
+ process_children!(new_component, &block) unless block.nil?
62
+ end
52
63
  stack << new_component
53
64
  end
54
65
  end
@@ -68,7 +79,7 @@ module ExpressTemplates
68
79
  return locals[name] if locals.keys.include?(name)
69
80
 
70
81
  if handlers.keys.include?(name)
71
- stack << handlers[name].send(name, *args)
82
+ stack << handlers[name].send(name, *args, &block)
72
83
  else
73
84
  stack << ExpressTemplates::Markup::Wrapper.new(name.to_s, *args, &block)
74
85
  end
@@ -23,10 +23,13 @@ module ExpressTemplates
23
23
  indent = WHITESPACE * current_indenters[name]
24
24
  yield indent, "\n#{indent}"
25
25
  ensure
26
- current_indenters[name] -= 1
27
- # if we have long-lived threads for some reason
28
- # we want to clean up after ourselves
29
- current_indenters.delete(name) if current_indenters[name].eql?(0)
26
+ if current_indenters[name].eql?(-1)
27
+ # if we have long-lived threads for some reason
28
+ # we want to clean up after ourselves
29
+ current_indenters.delete(name)
30
+ else
31
+ current_indenters[name] -= 1
32
+ end
30
33
  end
31
34
  else
32
35
  return WHITESPACE * current_indenters[name]
@@ -36,7 +39,7 @@ module ExpressTemplates
36
39
  private
37
40
  # For thread safety, scope indentation to the current thread
38
41
  def self.current_indenters
39
- Thread.current[:indenters] ||= Hash.new {|hsh, key| hsh[key] = 0 }
42
+ Thread.current[:indenters] ||= Hash.new {|hsh, key| hsh[key] = -1 }
40
43
  end
41
44
 
42
45
  end
@@ -22,6 +22,8 @@ module ExpressTemplates
22
22
  case
23
23
  when name.to_sym.eql?(:data) && value.kind_of?(Hash)
24
24
  value.each_pair.map {|k,v| %Q(data-#{k}=\\"#{v}\\") }.join(" ")
25
+ when value.kind_of?(Proc)
26
+ %Q(#{name}=\\"\#{(#{value.source}).call}\\")
25
27
  when code = value.to_s.match(/^\{\{(.*)\}\}$/).try(:[], 1)
26
28
  %Q(#{name}=\\"\#{#{code}}\\")
27
29
  else
@@ -66,56 +68,86 @@ module ExpressTemplates
66
68
  end
67
69
 
68
70
  def compile
69
- ruby_fragments = @children.map do |child|
70
- if child.respond_to?(:compile)
71
- child.compile
72
- else
73
- if code = child.to_s.match(/\{\{(.*)\}\}/).try(:[], 1)
74
- %Q("\#\{#{code}\}")
71
+ ExpressTemplates::Indenter.for(:markup) do |whitespace|
72
+ ruby_fragments = @children.map do |child|
73
+ if child.respond_to?(:compile)
74
+ child.compile
75
75
  else
76
- %Q("#{child}")
76
+ if code = child.to_s.match(/\{\{(.*)\}\}/).try(:[], 1)
77
+ %Q("\#\{#{code}\}")
78
+ else
79
+ %Q("#{child}")
80
+ end
77
81
  end
78
82
  end
79
- end
80
- unless ruby_fragments.empty?
81
- _wrap_with_tags(ruby_fragments)
82
- else
83
- if should_not_abbreviate?
84
- _wrap_with_tags(ruby_fragments)
85
- elsif transform_close_tag?
86
- %Q("#{start_tag.gsub(/>$/, ' />')}")
83
+ unless ruby_fragments.empty?
84
+ _wrap_with_tags(ruby_fragments, whitespace)
87
85
  else
88
- %Q("#{start_tag}")
86
+ if should_not_abbreviate?
87
+ _wrap_with_tags(ruby_fragments, whitespace)
88
+ elsif transform_close_tag?
89
+ %Q("#{start_tag.gsub(/>$/, ' />')}")
90
+ else
91
+ %Q("#{start_tag}")
92
+ end
89
93
  end
90
94
  end
91
95
  end
92
96
 
93
- def to_template(depth = 0)
94
- template_fragments = @children.map do |child|
95
- if child.respond_to?(:to_template)
96
- child.to_template(depth+1)
97
- else
98
- child
97
+ def to_template
98
+ # ExpressTemplates::Indenter.for(:template) do
99
+ template_fragments = @children.map do |child|
100
+ if child.respond_to?(:to_template)
101
+ child.to_template
102
+ else
103
+ child
104
+ end
99
105
  end
106
+ macro_name + _blockify(template_fragments.join("\n"))
107
+ # end
108
+ end
109
+
110
+ def self.formatted
111
+ old_setting = Thread.current[:formatted]
112
+ begin
113
+ Thread.current[:formatted] = true
114
+ yield if block_given?
115
+ ensure
116
+ Thread.current[:formatted] = old_setting
100
117
  end
101
- indent = INDENT*(depth+1)
102
- macro_name + _blockify(template_fragments.join("\n#{indent}"), depth)
103
118
  end
104
119
 
105
120
  private
106
121
 
107
- def _wrap_with_tags(ruby_fragments)
108
- ruby_fragments.unshift %Q("#{start_tag}")
109
- ruby_fragments.push %Q("#{close_tag}")
122
+ def _wrap_with_tags(ruby_fragments, whitespace)
123
+ opening, closing = nil, nil
124
+ if !ENV['ET_NO_INDENT_MARKUP'].eql?('true') || #TODO: change to setting
125
+ Thread.current[:formatted]
126
+ child_code = ruby_fragments.join
127
+ should_format = ruby_fragments.size > 1 ||
128
+ (child_code.size > 40 && !child_code.match(/^"\#\{.*\}"$/)) ||
129
+ child_code.match(/\n/)
130
+
131
+ nl = should_format ? "\n" : nil
132
+ nl_after_start = !ruby_fragments.first.try(:match, /^"\n/) ? nl : nil
133
+ # binding.pry
134
+ nl_before_end = !ruby_fragments.last.try(:match, /\n"$/) ? nl : nil
135
+ opening = %Q("\n#{whitespace}#{start_tag}#{nl_after_start}")
136
+ closing = %Q("#{nl_before_end}#{should_format && whitespace}#{close_tag}#{nl}")
137
+ else
138
+ opening = %Q("#{start_tag}")
139
+ closing = %Q("#{close_tag}")
140
+ end
141
+ ruby_fragments.unshift opening
142
+ ruby_fragments.push closing
110
143
  ruby_fragments.reject {|frag| frag.empty? }.join("+")
111
144
  end
112
145
 
113
146
  def _indent(code)
114
- code.split("\n").map {|line| INDENT + line }.join("\n")
147
+ code.split("\n").map {|line| ExpressTemplates::Indenter::WHITESPACE + line }.join("\n")
115
148
  end
116
149
 
117
- def _blockify(code, depth)
118
- indent = INDENT*depth
150
+ def _blockify(code)
119
151
  code.empty? ? code : " {\n#{_indent(code)}\n}\n"
120
152
  end
121
153
 
@@ -67,7 +67,7 @@ module ExpressTemplates
67
67
  when value.is_a?(Hash)
68
68
  s << value.inspect
69
69
  when value.is_a?(Proc)
70
- s << "(-> #{value.source}).call"
70
+ s << "(#{value.source}).call"
71
71
  else
72
72
  s << value.inspect # immediate values 1, 2.0, true etc
73
73
  end
@@ -1,3 +1,3 @@
1
1
  module ExpressTemplates
2
- VERSION = "0.2.7"
2
+ VERSION = "0.3.0"
3
3
  end
@@ -3,55 +3,32 @@ require 'test_helper'
3
3
  class BaseTest < ActiveSupport::TestCase
4
4
 
5
5
  class NoLogic < ExpressTemplates::Components::Base
6
- has_markup {
6
+ has_markup -> {
7
7
  h1 { span "Some stuff" }
8
8
  }
9
9
  end
10
10
 
11
11
  test ".has_markup makes compile return the block passed through express compiled" do
12
- assert_equal %Q("<h1>"+"<span>"+"Some stuff"+"</span>"+"</h1>"), NoLogic.new.compile
12
+ assert_equal %Q("<h1><span>Some stuff</span></h1>"), NoLogic.new.compile
13
13
  end
14
14
 
15
15
  test "components register themselves as macros" do
16
16
  assert ExpressTemplates::Expander.instance_methods.include?(:no_logic)
17
17
  end
18
18
 
19
- test ".render accepts a fragment name" do
20
- assert_equal '<h1><span>Some stuff</span></h1>', NoLogic.render(self, :markup)
21
- end
22
-
23
-
24
- class SomeLogic < ECB
25
- emits markup: -> {
26
- span { foo }
27
- }
28
-
29
- using_logic { |component|
30
- @foo.map do |foo|
31
- eval(component[:markup])
32
- end.join
33
- }
34
- end
35
-
36
19
  class Context
37
20
  def initialize ; @foo = ['bar', 'baz'] ; end
38
21
  end
39
22
 
40
- test ".using_logic controls the markup generation" do
41
- compiled = SomeLogic.new.compile
42
- assert_equal 'BaseTest::SomeLogic.render(self)', compiled
43
- assert_equal '<span>bar</span><span>baz</span>', Context.new.instance_eval(compiled)
44
- end
45
-
46
23
  test "fragments and has_markup are synonyms for emits" do
47
- assert_equal SomeLogic.method(:emits), SomeLogic.method(:fragments)
48
- assert_equal SomeLogic.method(:emits), SomeLogic.method(:has_markup)
24
+ assert_equal NoLogic.method(:emits), NoLogic.method(:fragments)
25
+ assert_equal NoLogic.method(:emits), NoLogic.method(:has_markup)
49
26
  end
50
27
 
51
28
  class Helpers < ECB
52
29
  helper :title_helper, &-> { @foo.first }
53
30
 
54
- emits {
31
+ emits -> {
55
32
  h1 {
56
33
  title_helper
57
34
  }
@@ -64,14 +41,4 @@ class BaseTest < ActiveSupport::TestCase
64
41
  assert_equal "<h1>bar</h1>", Context.new.instance_eval(compiled)
65
42
  end
66
43
 
67
- class NullComponent < ECB
68
- using_logic {
69
- nil
70
- }
71
- end
72
-
73
- test "render should not return a nil" do
74
- compiled = NullComponent.new.compile
75
- assert_equal "", Context.new.instance_eval(compiled)
76
- end
77
44
  end
@@ -17,7 +17,7 @@ class ConditionalityTest < ActiveSupport::TestCase
17
17
  class ConditionalRenderer < ExpressTemplates::Components::Base
18
18
  include ExpressTemplates::Components::Capabilities::Conditionality
19
19
 
20
- emits {
20
+ emits -> {
21
21
  h1 "{{@title}}"
22
22
  }
23
23
 
@@ -6,7 +6,7 @@ class ConfigurableTest < ActiveSupport::TestCase
6
6
 
7
7
  class ConfigurableComponent < ETC::Base
8
8
  include ETC::Capabilities::Configurable
9
- emits {
9
+ emits -> {
10
10
  div.bar(my[:id])
11
11
  }
12
12
  end
@@ -27,7 +27,7 @@ class ConfigurableTest < ActiveSupport::TestCase
27
27
  # make sure a helper can take arguments
28
28
  helper(:name) {|name| name.to_s }
29
29
 
30
- emits {
30
+ emits -> {
31
31
  div(my[:id]) {
32
32
  h1 { name(my[:id]) }
33
33
  _yield
@@ -26,7 +26,7 @@ class ContainerTest < ActiveSupport::TestCase
26
26
  end
27
27
 
28
28
  class TestContainer < ETC::Container
29
- emits { p { _yield } }
29
+ emits -> { p { _yield } }
30
30
  end
31
31
 
32
32
  test "Container#compile calls #compile on its children" do
@@ -3,26 +3,47 @@ require 'test_helper'
3
3
  class IteratingTest < ActiveSupport::TestCase
4
4
 
5
5
  class Context
6
- def initialize ; @foo = ['bar', 'baz'] ; @empty = [] ; end
6
+ def initialize ; @things = ['bar', 'baz'] ; @empty = [] ; end
7
7
  end
8
8
 
9
9
  class ForEachLogic < ECB
10
10
  emits -> {
11
- span { foo }
11
+ for_each(:@things) {
12
+ span { thing }
13
+ }
12
14
  }
15
+ end
13
16
 
14
- for_each(:@foo)
17
+ test "#for_each expands to view logic" do
18
+ compiled = ForEachLogic.new.compile
19
+ assert_equal %q((@things.each_with_index.map do |thing, thing_index|
20
+ "<span>#{thing}</span>"
21
+ end).join), compiled
15
22
  end
16
23
 
17
- test ".for_each iterates markup for each value" do
24
+ test "#for_each iterates markup for each value" do
18
25
  compiled = ForEachLogic.new.compile
19
26
  assert_equal '<span>bar</span><span>baz</span>', Context.new.instance_eval(compiled)
20
27
  end
21
28
 
29
+ class ForEachDeclarativeForm < ECB
30
+ emits -> {
31
+ span { thing }
32
+ }
33
+
34
+ for_each(:@things)
35
+ end
36
+
37
+ test ".for_each offers declarative form" do
38
+ compiled = ForEachLogic.new.compile
39
+ assert_equal '<span>bar</span><span>baz</span>', Context.new.instance_eval(compiled)
40
+ end
41
+
42
+
22
43
  class MultiFragments < ECB
23
44
 
24
45
  fragments item: -> {
25
- li { foo }
46
+ li { thing }
26
47
  },
27
48
 
28
49
  wrapper: -> {
@@ -31,7 +52,7 @@ class IteratingTest < ActiveSupport::TestCase
31
52
  }
32
53
  }
33
54
 
34
- for_each -> { @foo }, as: 'foo', emit: :item
55
+ for_each -> { @things }, as: 'thing', emit: :item
35
56
 
36
57
  wrap_with :wrapper
37
58
 
@@ -45,7 +66,7 @@ class IteratingTest < ActiveSupport::TestCase
45
66
  class EmptyState < ECB
46
67
 
47
68
  fragments item: -> {
48
- li { foo }
69
+ li { thing }
49
70
  },
50
71
 
51
72
  wrapper: -> {
@@ -57,7 +78,7 @@ class IteratingTest < ActiveSupport::TestCase
57
78
  p "Nothing here"
58
79
  }
59
80
 
60
- for_each -> { @empty }, as: 'foo', emit: :item, empty: :empty_state
81
+ for_each -> { @empty }, as: 'thing', emit: :item, empty: :empty_state
61
82
 
62
83
  wrap_with :wrapper, dont_wrap_if: -> { @empty.empty? }
63
84
 
@@ -69,7 +90,7 @@ class IteratingTest < ActiveSupport::TestCase
69
90
  end
70
91
 
71
92
  class EmptyEmptyState < ECB
72
- emits {
93
+ emits -> {
73
94
  whatever
74
95
  }
75
96