arbre 0.0.1 → 1.0.0.rc1

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