express_templates 0.2.7 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|