arbo 1.2.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 +7 -0
- data/.github/workflows/ci.yaml +21 -0
- data/.github/workflows/daily.yaml +23 -0
- data/.gitignore +11 -0
- data/CHANGELOG.md +95 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +17 -0
- data/LICENSE +20 -0
- data/README.md +29 -0
- data/Rakefile +18 -0
- data/arbo.gemspec +25 -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/arbo/component.rb +22 -0
- data/lib/arbo/context.rb +118 -0
- data/lib/arbo/element/builder_methods.rb +83 -0
- data/lib/arbo/element/proxy.rb +28 -0
- data/lib/arbo/element.rb +225 -0
- data/lib/arbo/element_collection.rb +31 -0
- data/lib/arbo/html/attributes.rb +41 -0
- data/lib/arbo/html/class_list.rb +28 -0
- data/lib/arbo/html/document.rb +31 -0
- data/lib/arbo/html/html5_elements.rb +47 -0
- data/lib/arbo/html/tag.rb +220 -0
- data/lib/arbo/html/text_node.rb +43 -0
- data/lib/arbo/rails/forms.rb +101 -0
- data/lib/arbo/rails/rendering.rb +17 -0
- data/lib/arbo/rails/template_handler.rb +35 -0
- data/lib/arbo/rails.rb +5 -0
- data/lib/arbo/version.rb +3 -0
- data/lib/arbo.rb +21 -0
- data/spec/arbo/integration/html_spec.rb +307 -0
- data/spec/arbo/unit/component_spec.rb +54 -0
- data/spec/arbo/unit/context_spec.rb +35 -0
- data/spec/arbo/unit/element_finder_methods_spec.rb +116 -0
- data/spec/arbo/unit/element_spec.rb +272 -0
- data/spec/arbo/unit/html/class_list_spec.rb +16 -0
- data/spec/arbo/unit/html/tag_attributes_spec.rb +104 -0
- data/spec/arbo/unit/html/tag_spec.rb +124 -0
- data/spec/arbo/unit/html/text_node_spec.rb +5 -0
- data/spec/rails/integration/forms_spec.rb +117 -0
- data/spec/rails/integration/rendering_spec.rb +98 -0
- data/spec/rails/rails_spec_helper.rb +46 -0
- data/spec/rails/stub_app/config/database.yml +3 -0
- data/spec/rails/stub_app/config/routes.rb +3 -0
- data/spec/rails/stub_app/db/schema.rb +3 -0
- data/spec/rails/stub_app/log/.gitignore +1 -0
- data/spec/rails/stub_app/public/favicon.ico +0 -0
- data/spec/rails/support/mock_person.rb +15 -0
- data/spec/rails/templates/arbo/_partial.arb +1 -0
- data/spec/rails/templates/arbo/_partial_with_assignment.arb +1 -0
- data/spec/rails/templates/arbo/empty.arb +0 -0
- data/spec/rails/templates/arbo/page_with_arb_partial_and_assignment.arb +3 -0
- data/spec/rails/templates/arbo/page_with_assignment.arb +1 -0
- data/spec/rails/templates/arbo/page_with_erb_partial.arb +3 -0
- data/spec/rails/templates/arbo/page_with_helpers.arb +7 -0
- data/spec/rails/templates/arbo/page_with_partial.arb +3 -0
- data/spec/rails/templates/arbo/simple_page.arb +8 -0
- data/spec/rails/templates/erb/_partial.erb +1 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/support/bundle.rb +4 -0
- metadata +169 -0
@@ -0,0 +1,307 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Arbo do
|
4
|
+
|
5
|
+
let(:helpers){ nil }
|
6
|
+
let(:assigns){ {} }
|
7
|
+
|
8
|
+
def output_buffer(actx)
|
9
|
+
actx.render_in(actx) && actx.output_buffer
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should render a single element" do
|
13
|
+
actx = arbo {
|
14
|
+
span "Hello World"
|
15
|
+
}
|
16
|
+
html = "<span>Hello World</span>\n"
|
17
|
+
expect(actx.to_s).to eq(html)
|
18
|
+
expect(output_buffer actx).to eq(html)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should render a child element" do
|
22
|
+
actx = arbo {
|
23
|
+
span do
|
24
|
+
span "Hello World"
|
25
|
+
end
|
26
|
+
}
|
27
|
+
html = <<-HTML
|
28
|
+
<span>
|
29
|
+
<span>Hello World</span>
|
30
|
+
</span>
|
31
|
+
HTML
|
32
|
+
expect(actx.to_s).to eq(html)
|
33
|
+
expect(output_buffer actx).to eq(html)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should render an unordered list" do
|
37
|
+
actx = arbo {
|
38
|
+
ul do
|
39
|
+
li "First"
|
40
|
+
li "Second"
|
41
|
+
li "Third"
|
42
|
+
end
|
43
|
+
}
|
44
|
+
html = <<-HTML
|
45
|
+
<ul>
|
46
|
+
<li>First</li>
|
47
|
+
<li>Second</li>
|
48
|
+
<li>Third</li>
|
49
|
+
</ul>
|
50
|
+
HTML
|
51
|
+
expect(actx.to_s).to eq(html)
|
52
|
+
expect(output_buffer actx).to eq(html)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should allow local variables inside the tags" do
|
56
|
+
actx = arbo {
|
57
|
+
first = "First"
|
58
|
+
second = "Second"
|
59
|
+
ul do
|
60
|
+
li first
|
61
|
+
li second
|
62
|
+
end
|
63
|
+
}
|
64
|
+
html = <<-HTML
|
65
|
+
<ul>
|
66
|
+
<li>First</li>
|
67
|
+
<li>Second</li>
|
68
|
+
</ul>
|
69
|
+
HTML
|
70
|
+
expect(actx.to_s).to eq(html)
|
71
|
+
expect(output_buffer actx).to eq(html)
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
it "should add children and nested" do
|
76
|
+
actx = arbo {
|
77
|
+
div do
|
78
|
+
ul
|
79
|
+
li do
|
80
|
+
li
|
81
|
+
end
|
82
|
+
end
|
83
|
+
}
|
84
|
+
html = <<-HTML
|
85
|
+
<div>
|
86
|
+
<ul></ul>
|
87
|
+
<li>
|
88
|
+
<li></li>
|
89
|
+
</li>
|
90
|
+
</div>
|
91
|
+
HTML
|
92
|
+
expect(actx.to_s).to eq(html)
|
93
|
+
expect(output_buffer actx).to eq(html)
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
it "should pass the element in to the block if asked for" do
|
98
|
+
actx = arbo {
|
99
|
+
div do |d|
|
100
|
+
d.ul do
|
101
|
+
li
|
102
|
+
end
|
103
|
+
end
|
104
|
+
}
|
105
|
+
html = <<-HTML
|
106
|
+
<div>
|
107
|
+
<ul>
|
108
|
+
<li></li>
|
109
|
+
</ul>
|
110
|
+
</div>
|
111
|
+
HTML
|
112
|
+
expect(actx.to_s).to eq(html)
|
113
|
+
expect(output_buffer actx).to eq(html)
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
it "should move content tags between parents" do
|
118
|
+
actx = arbo {
|
119
|
+
div do
|
120
|
+
span(ul(li))
|
121
|
+
end
|
122
|
+
}
|
123
|
+
html = <<-HTML
|
124
|
+
<div>
|
125
|
+
<span>
|
126
|
+
<ul>
|
127
|
+
<li></li>
|
128
|
+
</ul>
|
129
|
+
</span>
|
130
|
+
</div>
|
131
|
+
HTML
|
132
|
+
expect(actx.to_s).to eq(html)
|
133
|
+
expect(output_buffer actx).to eq(html)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should add content to the parent if the element is passed into block" do
|
137
|
+
actx = arbo {
|
138
|
+
div do |d|
|
139
|
+
d.id = "my-tag"
|
140
|
+
ul do
|
141
|
+
li
|
142
|
+
end
|
143
|
+
end
|
144
|
+
}
|
145
|
+
html = <<-HTML
|
146
|
+
<div id="my-tag">
|
147
|
+
<ul>
|
148
|
+
<li></li>
|
149
|
+
</ul>
|
150
|
+
</div>
|
151
|
+
HTML
|
152
|
+
expect(actx.to_s).to eq(html)
|
153
|
+
expect(output_buffer actx).to eq(html)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should have the parent set on it" do
|
157
|
+
list, item = nil
|
158
|
+
arbo {
|
159
|
+
list = ul do
|
160
|
+
li "Hello"
|
161
|
+
item = li "World"
|
162
|
+
end
|
163
|
+
}
|
164
|
+
expect(item.parent).to eq list
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should set a string content return value with no children" do
|
168
|
+
actx = arbo {
|
169
|
+
li do
|
170
|
+
"Hello World"
|
171
|
+
end
|
172
|
+
}
|
173
|
+
html = <<-HTML
|
174
|
+
<li>Hello World</li>
|
175
|
+
HTML
|
176
|
+
expect(actx.to_s).to eq(html)
|
177
|
+
expect(output_buffer actx).to eq(html)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should turn string return values into text nodes" do
|
181
|
+
node = nil
|
182
|
+
arbo {
|
183
|
+
list = li do
|
184
|
+
"Hello World"
|
185
|
+
end
|
186
|
+
node = list.children.first
|
187
|
+
}
|
188
|
+
expect(node).to be_a Arbo::HTML::TextNode
|
189
|
+
end
|
190
|
+
|
191
|
+
it "should not render blank arrays" do
|
192
|
+
actx = arbo {
|
193
|
+
tbody do
|
194
|
+
[]
|
195
|
+
end
|
196
|
+
}
|
197
|
+
html = <<-HTML
|
198
|
+
<tbody></tbody>
|
199
|
+
HTML
|
200
|
+
expect(actx.to_s).to eq(html)
|
201
|
+
expect(output_buffer actx).to eq(html)
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "self-closing nodes" do
|
205
|
+
|
206
|
+
it "should not self-close script tags" do
|
207
|
+
actx = arbo {
|
208
|
+
script type: 'text/javascript'
|
209
|
+
}
|
210
|
+
html = "<script type=\"text/javascript\"></script>\n"
|
211
|
+
expect(actx.to_s).to eq(html)
|
212
|
+
expect(output_buffer actx).to eq(html)
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should self-close meta tags" do
|
216
|
+
actx = arbo {
|
217
|
+
meta content: "text/html; charset=utf-8"
|
218
|
+
}
|
219
|
+
html = "<meta content=\"text/html; charset=utf-8\"/>\n"
|
220
|
+
expect(actx.to_s).to eq(html)
|
221
|
+
expect(output_buffer actx).to eq(html)
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should self-close link tags" do
|
225
|
+
actx = arbo {
|
226
|
+
link rel: "stylesheet"
|
227
|
+
}
|
228
|
+
html = "<link rel=\"stylesheet\"/>\n"
|
229
|
+
expect(actx.to_s).to eq(html)
|
230
|
+
expect(output_buffer actx).to eq(html)
|
231
|
+
end
|
232
|
+
|
233
|
+
Arbo::HTML::Tag::SELF_CLOSING_ELEMENTS.each do |tag|
|
234
|
+
it "should self-close #{tag} tags" do
|
235
|
+
actx = arbo {
|
236
|
+
send(tag)
|
237
|
+
}
|
238
|
+
html = "<#{tag}/>\n"
|
239
|
+
expect(actx.to_s).to eq(html)
|
240
|
+
expect(output_buffer actx).to eq(html)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
describe "html safe" do
|
247
|
+
|
248
|
+
it "should escape the contents" do
|
249
|
+
actx = arbo {
|
250
|
+
span("<br />")
|
251
|
+
}
|
252
|
+
html = <<-HTML
|
253
|
+
<span><br /></span>
|
254
|
+
HTML
|
255
|
+
expect(actx.to_s).to eq(html)
|
256
|
+
expect(output_buffer actx).to eq(html)
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should return html safe strings" do
|
260
|
+
expect(arbo {
|
261
|
+
span("<br />")
|
262
|
+
}.to_s).to be_html_safe
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should not escape html passed in" do
|
266
|
+
actx = arbo {
|
267
|
+
span(span("<br />"))
|
268
|
+
}
|
269
|
+
html = <<-HTML
|
270
|
+
<span>
|
271
|
+
<span><br /></span>
|
272
|
+
</span>
|
273
|
+
HTML
|
274
|
+
expect(actx.to_s).to eq(html)
|
275
|
+
expect(output_buffer actx).to eq(html)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should escape string contents when passed in block" do
|
279
|
+
actx = arbo {
|
280
|
+
span {
|
281
|
+
span {
|
282
|
+
"<br />"
|
283
|
+
}
|
284
|
+
}
|
285
|
+
}
|
286
|
+
html = <<-HTML
|
287
|
+
<span>
|
288
|
+
<span><br /></span>
|
289
|
+
</span>
|
290
|
+
HTML
|
291
|
+
expect(actx.to_s).to eq(html)
|
292
|
+
expect(output_buffer actx).to eq(html)
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should escape the contents of attributes" do
|
296
|
+
actx = arbo {
|
297
|
+
span(class: "<br />")
|
298
|
+
}
|
299
|
+
html = <<-HTML
|
300
|
+
<span class="<br />"></span>
|
301
|
+
HTML
|
302
|
+
expect(actx.to_s).to eq(html)
|
303
|
+
end
|
304
|
+
|
305
|
+
end
|
306
|
+
|
307
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# A mock subclass to play with
|
4
|
+
class MockComponent < Arbo::Component
|
5
|
+
|
6
|
+
builder_method :mock_component
|
7
|
+
|
8
|
+
def build
|
9
|
+
h2 "Hello World"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Arbo::Component do
|
15
|
+
|
16
|
+
let(:assigns) { {} }
|
17
|
+
let(:helpers) { nil }
|
18
|
+
|
19
|
+
let(:component_class){ MockComponent }
|
20
|
+
let(:component){ component_class.new }
|
21
|
+
|
22
|
+
it "should be a subclass of an html div" do
|
23
|
+
expect(Arbo::Component.ancestors).to include(Arbo::HTML::Div)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should render to a div, even as a subclass" do
|
27
|
+
expect(component.tag_name).to eq('div')
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should add a class by default" do
|
31
|
+
expect(component.class_list).to include("mock_component")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should render (to_s) the object using the builder method name" do
|
35
|
+
comp = expect(arbo {
|
36
|
+
mock_component
|
37
|
+
}.to_s).to eq <<-HTML
|
38
|
+
<div class="mock_component">
|
39
|
+
<h2>Hello World</h2>
|
40
|
+
</div>
|
41
|
+
HTML
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should render (render_in) the object using the builder method name" do
|
45
|
+
context = arbo { mock_component }
|
46
|
+
output_buffer = context.render_in(context)
|
47
|
+
|
48
|
+
expect(output_buffer).to eq <<-HTML
|
49
|
+
<div class="mock_component">
|
50
|
+
<h2>Hello World</h2>
|
51
|
+
</div>
|
52
|
+
HTML
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe Arbo::Context do
|
5
|
+
|
6
|
+
let(:context) do
|
7
|
+
Arbo::Context.new do
|
8
|
+
h1 "札幌市北区" # Add some HTML to the context
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should not increment the indent_level" do
|
13
|
+
expect(context.indent_level).to eq(-1)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return a bytesize" do
|
17
|
+
expect(context.bytesize).to eq(25)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return a length" do
|
21
|
+
expect(context.length).to eq(25)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should delegate missing methods to the html string" do
|
25
|
+
expect(context).to respond_to(:index)
|
26
|
+
expect(context.index('<')).to eq(0)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should use a cached version of the HTML for method delegation" do
|
30
|
+
expect(context).to receive(:render_in).once.and_return("<h1>札幌市北区</h1>")
|
31
|
+
expect(context.index('<')).to eq(0)
|
32
|
+
expect(context.index('<')).to eq(0)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Arbo::Element, "Finder Methods" do
|
4
|
+
let(:assigns){ {} }
|
5
|
+
let(:helpers){ {} }
|
6
|
+
|
7
|
+
describe "finding elements by tag name" do
|
8
|
+
|
9
|
+
it "should return 0 when no elements exist" do
|
10
|
+
expect(arbo {
|
11
|
+
div
|
12
|
+
}.get_elements_by_tag_name("li").size).to eq(0)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should return a child element" do
|
16
|
+
html = arbo do
|
17
|
+
ul
|
18
|
+
li
|
19
|
+
ul
|
20
|
+
end
|
21
|
+
elements = html.get_elements_by_tag_name("li")
|
22
|
+
expect(elements.size).to eq(1)
|
23
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Li)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return multple child elements" do
|
27
|
+
html = arbo do
|
28
|
+
ul
|
29
|
+
li
|
30
|
+
ul
|
31
|
+
li
|
32
|
+
end
|
33
|
+
elements = html.get_elements_by_tag_name("li")
|
34
|
+
expect(elements.size).to eq(2)
|
35
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Li)
|
36
|
+
expect(elements[1]).to be_instance_of(Arbo::HTML::Li)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return children's child elements" do
|
40
|
+
html = arbo do
|
41
|
+
ul
|
42
|
+
li do
|
43
|
+
li
|
44
|
+
end
|
45
|
+
end
|
46
|
+
elements = html.get_elements_by_tag_name("li")
|
47
|
+
expect(elements.size).to eq(2)
|
48
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Li)
|
49
|
+
expect(elements[1]).to be_instance_of(Arbo::HTML::Li)
|
50
|
+
expect(elements[1].parent).to eq(elements[0])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#TODO: describe "finding an element by id"
|
55
|
+
|
56
|
+
describe "finding an element by a class name" do
|
57
|
+
|
58
|
+
it "should return 0 when no elements exist" do
|
59
|
+
expect(arbo {
|
60
|
+
div
|
61
|
+
}.get_elements_by_class_name("my_class").size).to eq(0)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should allow text nodes on tree" do
|
65
|
+
expect(arbo {
|
66
|
+
text_node "text"
|
67
|
+
}.get_elements_by_class_name("my_class").size).to eq(0)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should return a child element" do
|
71
|
+
html = arbo do
|
72
|
+
div class: "some_class"
|
73
|
+
div class: "my_class"
|
74
|
+
end
|
75
|
+
elements = html.get_elements_by_class_name("my_class")
|
76
|
+
expect(elements.size).to eq(1)
|
77
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Div)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return multple child elements" do
|
81
|
+
html = arbo do
|
82
|
+
div class: "some_class"
|
83
|
+
div class: "my_class"
|
84
|
+
div class: "my_class"
|
85
|
+
end
|
86
|
+
elements = html.get_elements_by_class_name("my_class")
|
87
|
+
expect(elements.size).to eq(2)
|
88
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Div)
|
89
|
+
expect(elements[1]).to be_instance_of(Arbo::HTML::Div)
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should return elements that match one of several classes" do
|
93
|
+
html = arbo do
|
94
|
+
div class: "some_class this_class"
|
95
|
+
div class: "some_class"
|
96
|
+
div class: "other_class"
|
97
|
+
|
98
|
+
end
|
99
|
+
elements = html.get_elements_by_class_name("this_class")
|
100
|
+
expect(elements.size).to eq(1)
|
101
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Div)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return a grandchild element" do
|
105
|
+
html = arbo do
|
106
|
+
div class: "some_class" do
|
107
|
+
div class: "my_class"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
elements = html.get_elements_by_class_name("my_class")
|
111
|
+
expect(elements.size).to eq(1)
|
112
|
+
expect(elements[0]).to be_instance_of(Arbo::HTML::Div)
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|