arbre 0.0.1 → 1.0.0.rc1

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 (49) hide show
  1. data/.DS_Store +0 -0
  2. data/.gitignore +3 -0
  3. data/Gemfile +10 -1
  4. data/README.rdoc +68 -2
  5. data/arbre.gemspec +2 -0
  6. data/lib/.DS_Store +0 -0
  7. data/lib/arbre.rb +18 -0
  8. data/lib/arbre/component.rb +22 -0
  9. data/lib/arbre/context.rb +81 -0
  10. data/lib/arbre/element.rb +182 -0
  11. data/lib/arbre/element/builder_methods.rb +92 -0
  12. data/lib/arbre/element_collection.rb +25 -0
  13. data/lib/arbre/html/attributes.rb +20 -0
  14. data/lib/arbre/html/class_list.rb +24 -0
  15. data/lib/arbre/html/document.rb +42 -0
  16. data/lib/arbre/html/html5_elements.rb +47 -0
  17. data/lib/arbre/html/tag.rb +175 -0
  18. data/lib/arbre/html/text_node.rb +35 -0
  19. data/lib/arbre/rails.rb +5 -0
  20. data/lib/arbre/rails/forms.rb +92 -0
  21. data/lib/arbre/rails/rendering.rb +17 -0
  22. data/lib/arbre/rails/template_handler.rb +15 -0
  23. data/lib/arbre/version.rb +1 -1
  24. data/spec/arbre/integration/html_spec.rb +241 -0
  25. data/spec/arbre/unit/component.rb +23 -0
  26. data/spec/arbre/unit/context_spec.rb +35 -0
  27. data/spec/arbre/unit/element_finder_methods_spec.rb +101 -0
  28. data/spec/arbre/unit/element_spec.rb +252 -0
  29. data/spec/arbre/unit/html/tag_attributes_spec.rb +60 -0
  30. data/spec/arbre/unit/html/tag_spec.rb +63 -0
  31. data/spec/arbre/unit/html/text_node_spec.rb +5 -0
  32. data/spec/rails/integration/forms_spec.rb +121 -0
  33. data/spec/rails/integration/rendering_spec.rb +73 -0
  34. data/spec/rails/rails_spec_helper.rb +45 -0
  35. data/spec/rails/stub_app/config/database.yml +3 -0
  36. data/spec/rails/stub_app/config/routes.rb +3 -0
  37. data/spec/rails/stub_app/db/schema.rb +3 -0
  38. data/spec/rails/stub_app/log/.gitignore +1 -0
  39. data/spec/rails/stub_app/public/favicon.ico +0 -0
  40. data/spec/rails/templates/arbre/_partial.arb +1 -0
  41. data/spec/rails/templates/arbre/empty.arb +0 -0
  42. data/spec/rails/templates/arbre/page_with_assignment.arb +1 -0
  43. data/spec/rails/templates/arbre/page_with_erb_partial.arb +3 -0
  44. data/spec/rails/templates/arbre/page_with_partial.arb +3 -0
  45. data/spec/rails/templates/arbre/simple_page.arb +8 -0
  46. data/spec/rails/templates/erb/_partial.erb +1 -0
  47. data/spec/spec_helper.rb +7 -0
  48. data/spec/support/bundle.rb +4 -0
  49. metadata +101 -45
@@ -0,0 +1,17 @@
1
+ module Arbre
2
+ module Rails
3
+ module Rendering
4
+
5
+ def render(*args)
6
+ rendered = helpers.render(*args)
7
+ case rendered
8
+ when Arbre::Context
9
+ current_arbre_element.add_child rendered
10
+ else
11
+ text_node rendered
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Arbre
2
+ module Rails
3
+
4
+ class TemplateHandler
5
+
6
+ def call(template)
7
+ "Arbre::Context.new(assigns, self){ #{template.source} }"
8
+ end
9
+
10
+ end
11
+
12
+ end
13
+ end
14
+
15
+ ActionView::Template.register_template_handler :arb, Arbre::Rails::TemplateHandler.new
@@ -1,3 +1,3 @@
1
1
  module Arbre
2
- VERSION = "0.0.1"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
@@ -0,0 +1,241 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arbre do
4
+
5
+ let(:helpers){ nil }
6
+ let(:assigns){ {} }
7
+
8
+ it "should render a single element" do
9
+ arbre {
10
+ span "Hello World"
11
+ }.to_s.should == "<span>Hello World</span>\n"
12
+ end
13
+
14
+ it "should render a child element" do
15
+ arbre {
16
+ span do
17
+ span "Hello World"
18
+ end
19
+ }.to_s.should == <<-HTML
20
+ <span>
21
+ <span>Hello World</span>
22
+ </span>
23
+ HTML
24
+ end
25
+
26
+ it "should render an unordered list" do
27
+ arbre {
28
+ ul do
29
+ li "First"
30
+ li "Second"
31
+ li "Third"
32
+ end
33
+ }.to_s.should == <<-HTML
34
+ <ul>
35
+ <li>First</li>
36
+ <li>Second</li>
37
+ <li>Third</li>
38
+ </ul>
39
+ HTML
40
+ end
41
+
42
+ it "should allow local variables inside the tags" do
43
+ arbre {
44
+ first = "First"
45
+ second = "Second"
46
+ ul do
47
+ li first
48
+ li second
49
+ end
50
+ }.to_s.should == <<-HTML
51
+ <ul>
52
+ <li>First</li>
53
+ <li>Second</li>
54
+ </ul>
55
+ HTML
56
+ end
57
+
58
+
59
+ it "should add children and nested" do
60
+ arbre {
61
+ div do
62
+ ul
63
+ li do
64
+ li
65
+ end
66
+ end
67
+ }.to_s.should == <<-HTML
68
+ <div>
69
+ <ul></ul>
70
+ <li>
71
+ <li></li>
72
+ </li>
73
+ </div>
74
+ HTML
75
+ end
76
+
77
+
78
+ it "should pass the element in to the block if asked for" do
79
+ arbre {
80
+ div do |d|
81
+ d.ul do
82
+ li
83
+ end
84
+ end
85
+ }.to_s.should == <<-HTML
86
+ <div>
87
+ <ul>
88
+ <li></li>
89
+ </ul>
90
+ </div>
91
+ HTML
92
+ end
93
+
94
+
95
+ it "should move content tags between parents" do
96
+ arbre {
97
+ div do
98
+ span(ul(li))
99
+ end
100
+ }.to_s.should == <<-HTML
101
+ <div>
102
+ <span>
103
+ <ul>
104
+ <li></li>
105
+ </ul>
106
+ </span>
107
+ </div>
108
+ HTML
109
+ end
110
+
111
+ it "should add content to the parent if the element is passed into block" do
112
+ arbre {
113
+ div do |d|
114
+ d.id = "my-tag"
115
+ ul do
116
+ li
117
+ end
118
+ end
119
+ }.to_s.should == <<-HTML
120
+ <div id="my-tag">
121
+ <ul>
122
+ <li></li>
123
+ </ul>
124
+ </div>
125
+ HTML
126
+ end
127
+
128
+ it "should have the parent set on it" do
129
+ arbre {
130
+ item = nil
131
+ list = ul do
132
+ li "Hello"
133
+ item = li "World"
134
+ end
135
+ item.parent.should == list
136
+ }
137
+ end
138
+
139
+ it "should set a string content return value with no children" do
140
+ arbre {
141
+ li do
142
+ "Hello World"
143
+ end
144
+ }.to_s.should == <<-HTML
145
+ <li>Hello World</li>
146
+ HTML
147
+ end
148
+
149
+ it "should turn string return values into text nodes" do
150
+ arbre {
151
+ list = li do
152
+ "Hello World"
153
+ end
154
+ node = list.children.first
155
+ node.class.should == Arbre::HTML::TextNode
156
+ }
157
+ end
158
+
159
+ it "should not render blank arrays" do
160
+ arbre {
161
+ tbody do
162
+ []
163
+ end
164
+ }.to_s.should == <<-HTML
165
+ <tbody></tbody>
166
+ HTML
167
+ end
168
+
169
+ describe "self-closing nodes" do
170
+
171
+ it "should not self-close script tags" do
172
+ arbre {
173
+ script :type => 'text/javascript'
174
+ }.to_s.should == "<script type=\"text/javascript\"></script>\n"
175
+ end
176
+
177
+ it "should self-close meta tags" do
178
+ arbre {
179
+ meta :content => "text/html; charset=utf-8"
180
+ }.to_s.should == "<meta content=\"text/html; charset=utf-8\"/>\n"
181
+ end
182
+
183
+ it "should self-close link tags" do
184
+ arbre {
185
+ link :rel => "stylesheet"
186
+ }.to_s.should == "<link rel=\"stylesheet\"/>\n"
187
+ end
188
+
189
+ end
190
+
191
+ describe "html safe" do
192
+
193
+ it "should escape the contents" do
194
+ arbre {
195
+ span("<br />")
196
+ }.to_s.should == <<-HTML
197
+ <span>&lt;br /&gt;</span>
198
+ HTML
199
+ end
200
+
201
+ it "should return html safe strings" do
202
+ arbre {
203
+ span("<br />")
204
+ }.to_s.should be_html_safe
205
+ end
206
+
207
+ it "should not escape html passed in" do
208
+ arbre {
209
+ span(span("<br />"))
210
+ }.to_s.should == <<-HTML
211
+ <span>
212
+ <span>&lt;br /&gt;</span>
213
+ </span>
214
+ HTML
215
+ end
216
+
217
+ it "should escape string contents when passed in block" do
218
+ arbre {
219
+ span {
220
+ span {
221
+ "<br />"
222
+ }
223
+ }
224
+ }.to_s.should == <<-HTML
225
+ <span>
226
+ <span>&lt;br /&gt;</span>
227
+ </span>
228
+ HTML
229
+ end
230
+
231
+ it "should escape the contents of attributes" do
232
+ arbre {
233
+ span(:class => "<br />")
234
+ }.to_s.should == <<-HTML
235
+ <span class="&lt;br /&gt;"></span>
236
+ HTML
237
+ end
238
+
239
+ end
240
+
241
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ # A mock subclass to play with
4
+ class MockComponent < Arbre::Component; end
5
+
6
+ describe Arbre::Component do
7
+
8
+ let(:component_class){ MockComponent }
9
+ let(:component){ component_class.new }
10
+
11
+ it "should be a subclass of an html div" do
12
+ Arbre::Component.ancestors.should include(Arbre::HTML::Div)
13
+ end
14
+
15
+ it "should render to a div, even as a subclass" do
16
+ component.tag_name.should == 'div'
17
+ end
18
+
19
+ it "should add a class by default" do
20
+ component.class_list.should include("mock_component")
21
+ end
22
+
23
+ end
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ require 'spec_helper'
3
+
4
+ describe Arbre::Context do
5
+
6
+ let(:context) do
7
+ Arbre::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
+ context.indent_level.should == -1
14
+ end
15
+
16
+ it "should return a bytesize" do
17
+ context.bytesize.should == 25
18
+ end
19
+
20
+ it "should return a length" do
21
+ context.length.should == 25
22
+ end
23
+
24
+ it "should delegate missing methods to the html string" do
25
+ context.should respond_to(:index)
26
+ context.index('<').should == 0
27
+ end
28
+
29
+ it "should use a cached version of the HTML for method delegation" do
30
+ context.should_receive(:to_s).once.and_return("<h1>札幌市北区</h1>")
31
+ context.index('<').should == 0
32
+ context.index('<').should == 0
33
+ end
34
+
35
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arbre::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
+ arbre {
11
+ div
12
+ }.get_elements_by_tag_name("li").size.should == 0
13
+ end
14
+
15
+ it "should return a child element" do
16
+ html = arbre do
17
+ ul
18
+ li
19
+ ul
20
+ end
21
+ elements = html.get_elements_by_tag_name("li")
22
+ elements.size.should == 1
23
+ elements[0].should be_instance_of(Arbre::HTML::Li)
24
+ end
25
+
26
+ it "should return multple child elements" do
27
+ html = arbre do
28
+ ul
29
+ li
30
+ ul
31
+ li
32
+ end
33
+ elements = html.get_elements_by_tag_name("li")
34
+ elements.size.should == 2
35
+ elements[0].should be_instance_of(Arbre::HTML::Li)
36
+ elements[1].should be_instance_of(Arbre::HTML::Li)
37
+ end
38
+
39
+ it "should return children's child elements" do
40
+ html = arbre do
41
+ ul
42
+ li do
43
+ li
44
+ end
45
+ end
46
+ elements = html.get_elements_by_tag_name("li")
47
+ elements.size.should == 2
48
+ elements[0].should be_instance_of(Arbre::HTML::Li)
49
+ elements[1].should be_instance_of(Arbre::HTML::Li)
50
+ elements[1].parent.should == 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
+ arbre {
60
+ div
61
+ }.get_elements_by_class_name("my_class").size.should == 0
62
+ end
63
+
64
+ it "should return a child element" do
65
+ html = arbre do
66
+ div :class => "some_class"
67
+ div :class => "my_class"
68
+ end
69
+ elements = html.get_elements_by_class_name("my_class")
70
+ elements.size.should == 1
71
+ elements[0].should be_instance_of(Arbre::HTML::Div)
72
+ end
73
+
74
+ it "should return multple child elements" do
75
+ html = arbre do
76
+ div :class => "some_class"
77
+ div :class => "my_class"
78
+ div :class => "my_class"
79
+ end
80
+ elements = html.get_elements_by_class_name("my_class")
81
+ elements.size.should == 2
82
+ elements[0].should be_instance_of(Arbre::HTML::Div)
83
+ elements[1].should be_instance_of(Arbre::HTML::Div)
84
+ end
85
+
86
+ it "should return elements that match one of several classes" do
87
+ html = arbre do
88
+ div :class => "some_class this_class"
89
+ div :class => "some_class"
90
+ div :class => "other_class"
91
+
92
+ end
93
+ elements = html.get_elements_by_class_name("this_class")
94
+ elements.size.should == 1
95
+ elements[0].should be_instance_of(Arbre::HTML::Div)
96
+ end
97
+
98
+ # TODO: find children's children by class name
99
+
100
+ end
101
+ end
@@ -0,0 +1,252 @@
1
+ require 'spec_helper'
2
+
3
+ describe Arbre::Element do
4
+
5
+ let(:element){ Arbre::Element.new }
6
+
7
+ context "when initialized" do
8
+
9
+ it "should have no children" do
10
+ element.children.should be_empty
11
+ end
12
+
13
+ it "should have no parent" do
14
+ element.parent.should be_nil
15
+ end
16
+
17
+ it "should respond to the HTML builder methods" do
18
+ element.should respond_to(:span)
19
+ end
20
+
21
+ it "should have a set of local assigns" do
22
+ context = Arbre::Context.new :hello => "World"
23
+ element = Arbre::Element.new(context)
24
+ element.assigns[:hello].should == "World"
25
+ end
26
+
27
+ it "should have an empty hash with no local assigns" do
28
+ element.assigns.should == {}
29
+ end
30
+
31
+ end
32
+
33
+ describe "passing in a helper object" do
34
+
35
+ let(:helper) do
36
+ Class.new do
37
+ def helper_method
38
+ "helper method"
39
+ end
40
+ end
41
+ end
42
+
43
+ let(:element){ Arbre::Element.new(Arbre::Context.new(nil, helper.new)) }
44
+
45
+ it "should call methods on the helper object and return TextNode objects" do
46
+ element.helper_method.should == "helper method"
47
+ end
48
+
49
+ it "should raise a NoMethodError if not found" do
50
+ lambda {
51
+ element.a_method_that_doesnt_exist
52
+ }.should raise_error(NoMethodError)
53
+ end
54
+
55
+ end
56
+
57
+ describe "passing in assigns" do
58
+ let(:post){ stub }
59
+ let(:assigns){ {:post => post} }
60
+
61
+ it "should be accessible via a method call" do
62
+ element = Arbre::Element.new(Arbre::Context.new(assigns))
63
+ element.post.should == post
64
+ end
65
+
66
+ end
67
+
68
+ describe "adding a child" do
69
+
70
+ let(:child){ Arbre::Element.new }
71
+
72
+ before do
73
+ element.add_child child
74
+ end
75
+
76
+ it "should add the child to the parent" do
77
+ element.children.first.should == child
78
+ end
79
+
80
+ it "should set the parent of the child" do
81
+ child.parent.should == element
82
+ end
83
+
84
+ context "when the child is nil" do
85
+
86
+ let(:child){ nil }
87
+
88
+ it "should not add the child" do
89
+ element.children.should be_empty
90
+ end
91
+
92
+ end
93
+
94
+ context "when the child is a string" do
95
+
96
+ let(:child){ "Hello World" }
97
+
98
+ it "should add as a TextNode" do
99
+ element.children.first.should be_instance_of(Arbre::HTML::TextNode)
100
+ element.children.first.to_s.should == "Hello World"
101
+ end
102
+
103
+ end
104
+ end
105
+
106
+ describe "setting the content" do
107
+
108
+ context "when a string" do
109
+
110
+ before do
111
+ element.add_child "Hello World"
112
+ element.content = "Goodbye"
113
+ end
114
+
115
+ it "should clear the existing children" do
116
+ element.children.size.should == 1
117
+ end
118
+
119
+ it "should add the string as a child" do
120
+ element.children.first.to_s.should == "Goodbye"
121
+ end
122
+
123
+ it "should html escape the string" do
124
+ string = "Goodbye <br />"
125
+ element.content = string
126
+ element.content.to_s.should == "Goodbye &lt;br /&gt;"
127
+ end
128
+ end
129
+
130
+ context "when an element" do
131
+ let(:content_element){ Arbre::Element.new }
132
+
133
+ before do
134
+ element.content = content_element
135
+ end
136
+
137
+ it "should set the content tag" do
138
+ element.children.first.should == content_element
139
+ end
140
+
141
+ it "should set the tags parent" do
142
+ content_element.parent.should == element
143
+ end
144
+ end
145
+
146
+ context "when an array of tags" do
147
+ let(:first){ Arbre::Element.new }
148
+ let(:second){ Arbre::Element.new }
149
+
150
+ before do
151
+ element.content = [first, second]
152
+ end
153
+
154
+ it "should set the content tag" do
155
+ element.children.first.should == first
156
+ end
157
+
158
+ it "should set the tags parent" do
159
+ element.children.first.parent.should == element
160
+ end
161
+ end
162
+
163
+ end
164
+
165
+ describe "rendering to html" do
166
+
167
+ it "should render the children collection" do
168
+ element.children.should_receive(:to_s).and_return("content")
169
+ element.to_s.should == "content"
170
+ end
171
+
172
+ end
173
+
174
+ describe "adding elements together" do
175
+
176
+ context "when both elements are tags" do
177
+ let(:first){ Arbre::Element.new }
178
+ let(:second){ Arbre::Element.new }
179
+ let(:collection){ first + second }
180
+
181
+ it "should return an instance of Collection" do
182
+ collection.should be_an_instance_of(Arbre::ElementCollection)
183
+ end
184
+
185
+ it "should return the elements in the collection" do
186
+ collection.size.should == 2
187
+ collection.first.should == first
188
+ collection[1].should == second
189
+ end
190
+ end
191
+
192
+ context "when the left is a collection and the right is a tag" do
193
+ let(:first){ Arbre::Element.new }
194
+ let(:second){ Arbre::Element.new }
195
+ let(:third){ Arbre::Element.new }
196
+ let(:collection){ Arbre::ElementCollection.new([first, second]) + third}
197
+
198
+ it "should return an instance of Collection" do
199
+ collection.should be_an_instance_of(Arbre::ElementCollection)
200
+ end
201
+
202
+ it "should return the elements in the collection flattened" do
203
+ collection.size.should == 3
204
+ collection[0].should == first
205
+ collection[1].should == second
206
+ collection[2].should == third
207
+ end
208
+ end
209
+
210
+ context "when the right is a collection and the left is a tag" do
211
+ let(:first){ Arbre::Element.new }
212
+ let(:second){ Arbre::Element.new }
213
+ let(:third){ Arbre::Element.new }
214
+ let(:collection){ first + Arbre::ElementCollection.new([second,third]) }
215
+
216
+ it "should return an instance of Collection" do
217
+ collection.should be_an_instance_of(Arbre::ElementCollection)
218
+ end
219
+
220
+ it "should return the elements in the collection flattened" do
221
+ collection.size.should == 3
222
+ collection[0].should == first
223
+ collection[1].should == second
224
+ collection[2].should == third
225
+ end
226
+ end
227
+
228
+ context "when the left is a tag and the right is a string" do
229
+ let(:element){ Arbre::Element.new }
230
+ let(:collection){ element + "Hello World"}
231
+
232
+ it "should return an instance of Collection" do
233
+ collection.should be_an_instance_of(Arbre::ElementCollection)
234
+ end
235
+
236
+ it "should return the elements in the collection" do
237
+ collection.size.should == 2
238
+ collection[0].should == element
239
+ collection[1].should be_an_instance_of(Arbre::HTML::TextNode)
240
+ end
241
+ end
242
+
243
+ context "when the left is a string and the right is a tag" do
244
+ let(:collection){ "hello World" + Arbre::Element.new}
245
+
246
+ it "should return a string" do
247
+ collection.strip.chomp.should == "hello World"
248
+ end
249
+ end
250
+ end
251
+
252
+ end