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.
- checksums.yaml +4 -4
- data/lib/core_extensions/proc.rb +72 -20
- data/lib/express_templates/compiler.rb +9 -1
- data/lib/express_templates/components/base.rb +1 -1
- data/lib/express_templates/components/capabilities/building.rb +8 -0
- data/lib/express_templates/components/capabilities/conditionality.rb +8 -6
- data/lib/express_templates/components/capabilities/configurable.rb +3 -4
- data/lib/express_templates/components/capabilities/iterating.rb +18 -23
- data/lib/express_templates/components/capabilities/parenting.rb +4 -18
- data/lib/express_templates/components/capabilities/rendering.rb +2 -65
- data/lib/express_templates/components/capabilities/templating.rb +24 -22
- data/lib/express_templates/components/capabilities/wrapping.rb +23 -39
- data/lib/express_templates/components/column.rb +1 -1
- data/lib/express_templates/components/for_each.rb +28 -0
- data/lib/express_templates/components/form_for.rb +19 -0
- data/lib/express_templates/components/form_rails_support.rb +1 -1
- data/lib/express_templates/components/null_wrap.rb +9 -0
- data/lib/express_templates/components/row.rb +1 -1
- data/lib/express_templates/components/table_for.rb +119 -0
- data/lib/express_templates/components/tree_for.rb +41 -0
- data/lib/express_templates/components/unless_block.rb +40 -0
- data/lib/express_templates/components.rb +4 -0
- data/lib/express_templates/expander.rb +15 -4
- data/lib/express_templates/indenter.rb +8 -5
- data/lib/express_templates/markup/tag.rb +62 -30
- data/lib/express_templates/markup/wrapper.rb +1 -1
- data/lib/express_templates/version.rb +1 -1
- data/test/components/base_test.rb +5 -38
- data/test/components/conditionality_test.rb +1 -1
- data/test/components/configurable_test.rb +2 -2
- data/test/components/container_test.rb +1 -1
- data/test/components/iterating_test.rb +30 -9
- data/test/components/table_for_test.rb +116 -0
- data/test/core_extensions/proc_test.rb +35 -5
- data/test/dummy/log/test.log +645 -0
- data/test/fixtures/{a_big_page.html → a_big_page2.html} +0 -0
- data/test/indenter_test.rb +6 -4
- data/test/markup/tag_test.rb +15 -2
- data/test/performance_test.rb +1 -1
- data/test/test_helper.rb +2 -0
- 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(
|
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 =
|
51
|
-
|
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]
|
27
|
-
|
28
|
-
|
29
|
-
|
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] =
|
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
|
-
|
70
|
-
|
71
|
-
child.compile
|
72
|
-
|
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
|
-
|
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
|
-
|
80
|
-
|
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
|
-
|
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
|
94
|
-
|
95
|
-
|
96
|
-
child.to_template
|
97
|
-
|
98
|
-
|
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
|
-
|
109
|
-
|
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|
|
147
|
+
code.split("\n").map {|line| ExpressTemplates::Indenter::WHITESPACE + line }.join("\n")
|
115
148
|
end
|
116
149
|
|
117
|
-
def _blockify(code
|
118
|
-
indent = INDENT*depth
|
150
|
+
def _blockify(code)
|
119
151
|
code.empty? ? code : " {\n#{_indent(code)}\n}\n"
|
120
152
|
end
|
121
153
|
|
@@ -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
|
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
|
48
|
-
assert_equal
|
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
|
@@ -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
|
@@ -3,26 +3,47 @@ require 'test_helper'
|
|
3
3
|
class IteratingTest < ActiveSupport::TestCase
|
4
4
|
|
5
5
|
class Context
|
6
|
-
def initialize ; @
|
6
|
+
def initialize ; @things = ['bar', 'baz'] ; @empty = [] ; end
|
7
7
|
end
|
8
8
|
|
9
9
|
class ForEachLogic < ECB
|
10
10
|
emits -> {
|
11
|
-
|
11
|
+
for_each(:@things) {
|
12
|
+
span { thing }
|
13
|
+
}
|
12
14
|
}
|
15
|
+
end
|
13
16
|
|
14
|
-
|
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 "
|
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 {
|
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 -> { @
|
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 {
|
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: '
|
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
|
|