arbre 1.1.1 → 1.2.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -1
- data/.rubocop.yml +15 -0
- data/.travis.yml +12 -2
- data/CHANGELOG.md +25 -2
- data/Gemfile +10 -3
- data/Gemfile.lock +221 -0
- data/README.md +25 -92
- data/Rakefile +4 -1
- data/arbre.gemspec +2 -0
- data/docs/Gemfile +2 -0
- data/docs/_config.yml +7 -0
- data/docs/_includes/footer.html +8 -0
- data/docs/_includes/google-analytics.html +16 -0
- data/docs/_includes/head.html +7 -0
- data/docs/_includes/toc.html +12 -0
- data/docs/_includes/top-menu.html +8 -0
- data/docs/_layouts/default.html +21 -0
- data/docs/index.md +106 -0
- data/docs/stylesheets/main.css +1152 -0
- data/lib/arbre/context.rb +1 -1
- data/lib/arbre/element.rb +12 -2
- data/lib/arbre/element/builder_methods.rb +4 -5
- data/lib/arbre/rails/template_handler.rb +22 -2
- data/lib/arbre/version.rb +1 -1
- data/spec/arbre/integration/html_spec.rb +80 -81
- data/spec/arbre/unit/component_spec.rb +5 -5
- data/spec/changelog_spec.rb +27 -0
- data/spec/rails/integration/rendering_spec.rb +47 -16
- data/spec/rails/rails_spec_helper.rb +1 -5
- data/spec/rails/stub_app/log/.gitignore +1 -1
- data/spec/rails/templates/arbre/page_with_helpers.arb +7 -0
- data/tasks/lint.rake +69 -0
- data/tasks/release.rake +6 -0
- metadata +23 -37
data/lib/arbre/context.rb
CHANGED
data/lib/arbre/element.rb
CHANGED
@@ -7,12 +7,13 @@ module Arbre
|
|
7
7
|
class Element
|
8
8
|
include BuilderMethods
|
9
9
|
|
10
|
-
|
10
|
+
attr_reader :parent
|
11
11
|
attr_reader :children, :arbre_context
|
12
12
|
|
13
13
|
def initialize(arbre_context = Arbre::Context.new)
|
14
14
|
@arbre_context = arbre_context
|
15
15
|
@children = ElementCollection.new
|
16
|
+
@parent = nil
|
16
17
|
end
|
17
18
|
|
18
19
|
def assigns
|
@@ -177,11 +178,20 @@ module Arbre
|
|
177
178
|
elsif assigns && assigns.has_key?(name)
|
178
179
|
assigns[name]
|
179
180
|
elsif helpers.respond_to?(name)
|
180
|
-
|
181
|
+
helper_capture(name, *args, &block)
|
181
182
|
else
|
182
183
|
super
|
183
184
|
end
|
184
185
|
end
|
185
186
|
|
187
|
+
# The helper might have a block that builds Arbre elements
|
188
|
+
# which will be rendered (#to_s) inside ActionView::Base#capture.
|
189
|
+
# We do not want such elements added to self, so we push a dummy
|
190
|
+
# current_arbre_element.
|
191
|
+
def helper_capture(name, *args, &block)
|
192
|
+
s = ""
|
193
|
+
within(Element.new) { s = helpers.send(name, *args, &block) }
|
194
|
+
s.is_a?(Element) ? s.to_s : s
|
195
|
+
end
|
186
196
|
end
|
187
197
|
end
|
@@ -65,17 +65,16 @@ module Arbre
|
|
65
65
|
# Returns true if the object should be converted into a text node
|
66
66
|
# and appended into the DOM.
|
67
67
|
def appendable_tag?(tag)
|
68
|
-
|
69
|
-
|
70
|
-
# In ruby 1.9, Arraay.new.to_s prints out an empty array ("[]"). In
|
68
|
+
# Array.new.to_s prints out an empty array ("[]"). In
|
71
69
|
# Arbre, we append the return value of blocks to the output, which
|
72
70
|
# can cause empty arrays to show up within the output. To get
|
73
71
|
# around this, we check if the object responds to #empty?
|
74
72
|
if tag.respond_to?(:empty?) && tag.empty?
|
75
|
-
|
73
|
+
false
|
74
|
+
else
|
75
|
+
!tag.is_a?(Arbre::Element) && tag.respond_to?(:to_s)
|
76
76
|
end
|
77
77
|
|
78
|
-
is_appendable
|
79
78
|
end
|
80
79
|
end
|
81
80
|
|
@@ -1,10 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
ActionView::Base.class_eval do
|
4
|
+
def capture(*args)
|
5
|
+
value = nil
|
6
|
+
buffer = with_output_buffer { value = yield(*args) }
|
7
|
+
|
8
|
+
# Override to handle Arbre elements inside helper blocks.
|
9
|
+
# See https://github.com/rails/rails/issues/17661
|
10
|
+
# and https://github.com/rails/rails/pull/18024#commitcomment-8975180
|
11
|
+
value = value.to_s if value.is_a?(Arbre::Element)
|
12
|
+
|
13
|
+
if (string = buffer.presence || value) && string.is_a?(String)
|
14
|
+
ERB::Util.html_escape string
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
1
19
|
module Arbre
|
2
20
|
module Rails
|
3
21
|
class TemplateHandler
|
4
|
-
def call(template)
|
22
|
+
def call(template, source = nil)
|
23
|
+
source = template.source unless source
|
24
|
+
|
5
25
|
<<-END
|
6
26
|
Arbre::Context.new(assigns, self) {
|
7
|
-
#{
|
27
|
+
#{source}
|
8
28
|
}.to_s
|
9
29
|
END
|
10
30
|
end
|
data/lib/arbre/version.rb
CHANGED
@@ -16,11 +16,11 @@ describe Arbre do
|
|
16
16
|
span do
|
17
17
|
span "Hello World"
|
18
18
|
end
|
19
|
-
}.to_s).to eq
|
20
|
-
<span>
|
21
|
-
|
22
|
-
</span>
|
23
|
-
HTML
|
19
|
+
}.to_s).to eq <<~HTML
|
20
|
+
<span>
|
21
|
+
<span>Hello World</span>
|
22
|
+
</span>
|
23
|
+
HTML
|
24
24
|
end
|
25
25
|
|
26
26
|
it "should render an unordered list" do
|
@@ -30,31 +30,30 @@ HTML
|
|
30
30
|
li "Second"
|
31
31
|
li "Third"
|
32
32
|
end
|
33
|
-
}.to_s).to eq
|
34
|
-
<ul>
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
</ul>
|
39
|
-
HTML
|
33
|
+
}.to_s).to eq <<~HTML
|
34
|
+
<ul>
|
35
|
+
<li>First</li>
|
36
|
+
<li>Second</li>
|
37
|
+
<li>Third</li>
|
38
|
+
</ul>
|
39
|
+
HTML
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
<ul>
|
52
|
-
|
53
|
-
|
54
|
-
</ul>
|
55
|
-
HTML
|
56
|
-
|
57
|
-
|
42
|
+
it "should allow local variables inside the tags" do
|
43
|
+
expect(arbre {
|
44
|
+
first = "First"
|
45
|
+
second = "Second"
|
46
|
+
ul do
|
47
|
+
li first
|
48
|
+
li second
|
49
|
+
end
|
50
|
+
}.to_s).to eq <<~HTML
|
51
|
+
<ul>
|
52
|
+
<li>First</li>
|
53
|
+
<li>Second</li>
|
54
|
+
</ul>
|
55
|
+
HTML
|
56
|
+
end
|
58
57
|
|
59
58
|
it "should add children and nested" do
|
60
59
|
expect(arbre {
|
@@ -64,14 +63,14 @@ HTML
|
|
64
63
|
li
|
65
64
|
end
|
66
65
|
end
|
67
|
-
}.to_s).to eq
|
68
|
-
<div>
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
</div>
|
74
|
-
HTML
|
66
|
+
}.to_s).to eq <<~HTML
|
67
|
+
<div>
|
68
|
+
<ul></ul>
|
69
|
+
<li>
|
70
|
+
<li></li>
|
71
|
+
</li>
|
72
|
+
</div>
|
73
|
+
HTML
|
75
74
|
end
|
76
75
|
|
77
76
|
|
@@ -82,13 +81,13 @@ HTML
|
|
82
81
|
li
|
83
82
|
end
|
84
83
|
end
|
85
|
-
}.to_s).to eq
|
86
|
-
<div>
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
</div>
|
91
|
-
HTML
|
84
|
+
}.to_s).to eq <<~HTML
|
85
|
+
<div>
|
86
|
+
<ul>
|
87
|
+
<li></li>
|
88
|
+
</ul>
|
89
|
+
</div>
|
90
|
+
HTML
|
92
91
|
end
|
93
92
|
|
94
93
|
|
@@ -97,15 +96,15 @@ HTML
|
|
97
96
|
div do
|
98
97
|
span(ul(li))
|
99
98
|
end
|
100
|
-
}.to_s).to eq
|
101
|
-
<div>
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
</div>
|
108
|
-
HTML
|
99
|
+
}.to_s).to eq <<~HTML
|
100
|
+
<div>
|
101
|
+
<span>
|
102
|
+
<ul>
|
103
|
+
<li></li>
|
104
|
+
</ul>
|
105
|
+
</span>
|
106
|
+
</div>
|
107
|
+
HTML
|
109
108
|
end
|
110
109
|
|
111
110
|
it "should add content to the parent if the element is passed into block" do
|
@@ -116,13 +115,13 @@ HTML
|
|
116
115
|
li
|
117
116
|
end
|
118
117
|
end
|
119
|
-
}.to_s).to eq
|
120
|
-
<div id="my-tag">
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
</div>
|
125
|
-
HTML
|
118
|
+
}.to_s).to eq <<~HTML
|
119
|
+
<div id="my-tag">
|
120
|
+
<ul>
|
121
|
+
<li></li>
|
122
|
+
</ul>
|
123
|
+
</div>
|
124
|
+
HTML
|
126
125
|
end
|
127
126
|
|
128
127
|
it "should have the parent set on it" do
|
@@ -141,9 +140,9 @@ HTML
|
|
141
140
|
li do
|
142
141
|
"Hello World"
|
143
142
|
end
|
144
|
-
}.to_s).to eq
|
145
|
-
<li>Hello World</li>
|
146
|
-
HTML
|
143
|
+
}.to_s).to eq <<~HTML
|
144
|
+
<li>Hello World</li>
|
145
|
+
HTML
|
147
146
|
end
|
148
147
|
|
149
148
|
it "should turn string return values into text nodes" do
|
@@ -162,9 +161,9 @@ HTML
|
|
162
161
|
tbody do
|
163
162
|
[]
|
164
163
|
end
|
165
|
-
}.to_s).to eq
|
166
|
-
<tbody></tbody>
|
167
|
-
HTML
|
164
|
+
}.to_s).to eq <<~HTML
|
165
|
+
<tbody></tbody>
|
166
|
+
HTML
|
168
167
|
end
|
169
168
|
|
170
169
|
describe "self-closing nodes" do
|
@@ -202,9 +201,9 @@ HTML
|
|
202
201
|
it "should escape the contents" do
|
203
202
|
expect(arbre {
|
204
203
|
span("<br />")
|
205
|
-
}.to_s).to eq
|
206
|
-
<span><br /></span>
|
207
|
-
HTML
|
204
|
+
}.to_s).to eq <<~HTML
|
205
|
+
<span><br /></span>
|
206
|
+
HTML
|
208
207
|
end
|
209
208
|
|
210
209
|
it "should return html safe strings" do
|
@@ -216,11 +215,11 @@ HTML
|
|
216
215
|
it "should not escape html passed in" do
|
217
216
|
expect(arbre {
|
218
217
|
span(span("<br />"))
|
219
|
-
}.to_s).to eq
|
220
|
-
<span>
|
221
|
-
|
222
|
-
</span>
|
223
|
-
HTML
|
218
|
+
}.to_s).to eq <<~HTML
|
219
|
+
<span>
|
220
|
+
<span><br /></span>
|
221
|
+
</span>
|
222
|
+
HTML
|
224
223
|
end
|
225
224
|
|
226
225
|
it "should escape string contents when passed in block" do
|
@@ -230,19 +229,19 @@ HTML
|
|
230
229
|
"<br />"
|
231
230
|
}
|
232
231
|
}
|
233
|
-
}.to_s).to eq
|
234
|
-
<span>
|
235
|
-
|
236
|
-
</span>
|
237
|
-
HTML
|
232
|
+
}.to_s).to eq <<~HTML
|
233
|
+
<span>
|
234
|
+
<span><br /></span>
|
235
|
+
</span>
|
236
|
+
HTML
|
238
237
|
end
|
239
238
|
|
240
239
|
it "should escape the contents of attributes" do
|
241
240
|
expect(arbre {
|
242
241
|
span(class: "<br />")
|
243
|
-
}.to_s).to eq
|
244
|
-
<span class="<br />"></span>
|
245
|
-
HTML
|
242
|
+
}.to_s).to eq <<~HTML
|
243
|
+
<span class="<br />"></span>
|
244
|
+
HTML
|
246
245
|
end
|
247
246
|
|
248
247
|
end
|
@@ -34,11 +34,11 @@ describe Arbre::Component do
|
|
34
34
|
it "should render the object using the builder method name" do
|
35
35
|
comp = expect(arbre {
|
36
36
|
mock_component
|
37
|
-
}.to_s).to eq
|
38
|
-
<div class="mock_component">
|
39
|
-
|
40
|
-
</div>
|
41
|
-
HTML
|
37
|
+
}.to_s).to eq <<~HTML
|
38
|
+
<div class="mock_component">
|
39
|
+
<h2>Hello World</h2>
|
40
|
+
</div>
|
41
|
+
HTML
|
42
42
|
end
|
43
43
|
|
44
44
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Changelog" do
|
4
|
+
subject(:changelog) do
|
5
|
+
path = File.join(File.dirname(__dir__), "CHANGELOG.md")
|
6
|
+
File.read(path)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'has definitions for all implicit links' do
|
10
|
+
implicit_link_names = changelog.scan(/\[([^\]]+)\]\[\]/).flatten.uniq
|
11
|
+
implicit_link_names.each do |name|
|
12
|
+
expect(changelog).to include("[#{name}]: https")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'entry' do
|
17
|
+
let(:lines) { changelog.each_line }
|
18
|
+
|
19
|
+
subject(:entries) { lines.grep(/^\*/) }
|
20
|
+
|
21
|
+
it 'does not end with a punctuation' do
|
22
|
+
entries.each do |entry|
|
23
|
+
expect(entry).not_to match(/\.$/)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -30,54 +30,85 @@ class TestController < ActionController::Base
|
|
30
30
|
@my_instance_var = "From Instance Var"
|
31
31
|
render "arbre/page_with_arb_partial_and_assignment"
|
32
32
|
end
|
33
|
+
|
34
|
+
def render_page_with_helpers
|
35
|
+
render "arbre/page_with_helpers"
|
36
|
+
end
|
33
37
|
end
|
34
38
|
|
35
39
|
|
36
40
|
describe TestController, "Rendering with Arbre", type: :request do
|
37
41
|
let(:body){ response.body }
|
38
42
|
|
43
|
+
before do
|
44
|
+
Rails.application.routes.draw do
|
45
|
+
get 'test/render_empty', controller: "test"
|
46
|
+
get 'test/render_simple_page', controller: "test"
|
47
|
+
get 'test/render_partial', controller: "test"
|
48
|
+
get 'test/render_erb_partial', controller: "test"
|
49
|
+
get 'test/render_with_instance_variable', controller: "test"
|
50
|
+
get 'test/render_partial_with_instance_variable', controller: "test"
|
51
|
+
get 'test/render_page_with_helpers', controller: "test"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
after do
|
56
|
+
Rails.application.reload_routes!
|
57
|
+
end
|
58
|
+
|
39
59
|
it "should render the empty template" do
|
40
60
|
get "/test/render_empty"
|
41
|
-
expect(response).to
|
61
|
+
expect(response).to be_successful
|
42
62
|
end
|
43
63
|
|
44
64
|
it "should render a simple page" do
|
45
65
|
get "/test/render_simple_page"
|
46
|
-
expect(response).to
|
66
|
+
expect(response).to be_successful
|
47
67
|
expect(body).to have_selector("h1", text: "Hello World")
|
48
68
|
expect(body).to have_selector("p", text: "Hello again!")
|
49
69
|
end
|
50
70
|
|
51
71
|
it "should render an arb partial" do
|
52
72
|
get "/test/render_partial"
|
53
|
-
expect(response).to
|
54
|
-
expect(body).to eq
|
55
|
-
<h1>Before Partial</h1>
|
56
|
-
<p>Hello from a partial</p>
|
57
|
-
<h2>After Partial</h2>
|
58
|
-
|
73
|
+
expect(response).to be_successful
|
74
|
+
expect(body).to eq <<~HTML
|
75
|
+
<h1>Before Partial</h1>
|
76
|
+
<p>Hello from a partial</p>
|
77
|
+
<h2>After Partial</h2>
|
78
|
+
HTML
|
59
79
|
end
|
60
80
|
|
61
81
|
it "should render an erb (or other) partial" do
|
62
82
|
get "/test/render_erb_partial"
|
63
|
-
expect(response).to
|
64
|
-
expect(body).to eq
|
65
|
-
<h1>Before Partial</h1>
|
66
|
-
<p>Hello from an erb partial</p>
|
67
|
-
<h2>After Partial</h2>
|
68
|
-
|
83
|
+
expect(response).to be_successful
|
84
|
+
expect(body).to eq <<~HTML
|
85
|
+
<h1>Before Partial</h1>
|
86
|
+
<p>Hello from an erb partial</p>
|
87
|
+
<h2>After Partial</h2>
|
88
|
+
HTML
|
69
89
|
end
|
70
90
|
|
71
91
|
it "should render with instance variables" do
|
72
92
|
get "/test/render_with_instance_variable"
|
73
|
-
expect(response).to
|
93
|
+
expect(response).to be_successful
|
74
94
|
expect(body).to have_selector("h1", text: "From Instance Var")
|
75
95
|
end
|
76
96
|
|
77
97
|
it "should render an arbre partial with assignments" do
|
78
98
|
get "/test/render_partial_with_instance_variable"
|
79
|
-
expect(response).to
|
99
|
+
expect(response).to be_successful
|
80
100
|
expect(body).to have_selector("p", text: "Partial: From Instance Var")
|
81
101
|
end
|
82
102
|
|
103
|
+
it "should render a page with helpers" do
|
104
|
+
get "/test/render_page_with_helpers"
|
105
|
+
expect(response).to be_successful
|
106
|
+
expect(body).to eq <<~HTML
|
107
|
+
<span>before h1 link</span>
|
108
|
+
<h1><a href="/h1_link_path">h1 link text</a></h1>
|
109
|
+
<span>before link_to block</span>
|
110
|
+
<a href="/link_path"> <i class=\"link-class\">Link text</i>
|
111
|
+
</a><span>at end</span>
|
112
|
+
HTML
|
113
|
+
end
|
83
114
|
end
|