arbre2 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +30 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +6 -0
  6. data/CHANGELOG.md +75 -0
  7. data/Gemfile +2 -0
  8. data/Gemfile.lock +93 -0
  9. data/LICENSE +20 -0
  10. data/README.md +92 -0
  11. data/Rakefile +7 -0
  12. data/arbre.gemspec +28 -0
  13. data/lib/arbre/child_element_collection.rb +86 -0
  14. data/lib/arbre/container.rb +20 -0
  15. data/lib/arbre/context.rb +83 -0
  16. data/lib/arbre/element/building.rb +151 -0
  17. data/lib/arbre/element.rb +194 -0
  18. data/lib/arbre/element_collection.rb +93 -0
  19. data/lib/arbre/html/attributes.rb +91 -0
  20. data/lib/arbre/html/class_list.rb +53 -0
  21. data/lib/arbre/html/comment.rb +47 -0
  22. data/lib/arbre/html/document.rb +93 -0
  23. data/lib/arbre/html/html_tags.rb +67 -0
  24. data/lib/arbre/html/querying.rb +256 -0
  25. data/lib/arbre/html/tag.rb +317 -0
  26. data/lib/arbre/rails/layouts.rb +126 -0
  27. data/lib/arbre/rails/legacy_document.rb +29 -0
  28. data/lib/arbre/rails/rendering.rb +76 -0
  29. data/lib/arbre/rails/rspec/arbre_support.rb +61 -0
  30. data/lib/arbre/rails/rspec.rb +2 -0
  31. data/lib/arbre/rails/template_handler.rb +32 -0
  32. data/lib/arbre/rails.rb +35 -0
  33. data/lib/arbre/rspec/be_rendered_as_matcher.rb +103 -0
  34. data/lib/arbre/rspec/be_scripted_as_matcher.rb +68 -0
  35. data/lib/arbre/rspec/contain_script_matcher.rb +64 -0
  36. data/lib/arbre/rspec.rb +3 -0
  37. data/lib/arbre/text_node.rb +35 -0
  38. data/lib/arbre/version.rb +3 -0
  39. data/lib/arbre.rb +27 -0
  40. data/spec/arbre/integration/html_document_spec.rb +90 -0
  41. data/spec/arbre/integration/html_spec.rb +283 -0
  42. data/spec/arbre/integration/querying_spec.rb +187 -0
  43. data/spec/arbre/integration/rails_spec.rb +183 -0
  44. data/spec/arbre/rails/rspec/arbre_support_spec.rb +75 -0
  45. data/spec/arbre/rspec/be_rendered_as_matcher_spec.rb +80 -0
  46. data/spec/arbre/rspec/be_scripted_as_matcher_spec.rb +61 -0
  47. data/spec/arbre/rspec/contain_script_matcher_spec.rb +40 -0
  48. data/spec/arbre/support/arbre_example_group.rb +0 -0
  49. data/spec/arbre/unit/child_element_collection_spec.rb +146 -0
  50. data/spec/arbre/unit/container_spec.rb +23 -0
  51. data/spec/arbre/unit/context_spec.rb +95 -0
  52. data/spec/arbre/unit/element/building_spec.rb +300 -0
  53. data/spec/arbre/unit/element_collection_spec.rb +169 -0
  54. data/spec/arbre/unit/element_spec.rb +297 -0
  55. data/spec/arbre/unit/html/attributes_spec.rb +219 -0
  56. data/spec/arbre/unit/html/class_list_spec.rb +109 -0
  57. data/spec/arbre/unit/html/comment_spec.rb +42 -0
  58. data/spec/arbre/unit/html/querying_spec.rb +32 -0
  59. data/spec/arbre/unit/html/tag_spec.rb +300 -0
  60. data/spec/arbre/unit/rails/layouts_spec.rb +127 -0
  61. data/spec/arbre/unit/text_node_spec.rb +40 -0
  62. data/spec/rails/app/controllers/example_controller.rb +18 -0
  63. data/spec/rails/app/views/example/_arbre_partial.html.arb +7 -0
  64. data/spec/rails/app/views/example/_erb_partial.html.erb +1 -0
  65. data/spec/rails/app/views/example/arbre.html.arb +1 -0
  66. data/spec/rails/app/views/example/arbre_partial_result.html.arb +3 -0
  67. data/spec/rails/app/views/example/erb.html.erb +5 -0
  68. data/spec/rails/app/views/example/erb_partial_result.html.arb +3 -0
  69. data/spec/rails/app/views/example/partials.html.arb +11 -0
  70. data/spec/rails/app/views/layouts/empty.html.arb +1 -0
  71. data/spec/rails/app/views/layouts/with_title.html.arb +5 -0
  72. data/spec/rails/config/routes.rb +4 -0
  73. data/spec/rails_spec_helper.rb +13 -0
  74. data/spec/spec_helper.rb +20 -0
  75. data/spec/support/arbre_example_group.rb +19 -0
  76. metadata +254 -0
@@ -0,0 +1,95 @@
1
+ require 'spec_helper'
2
+ include Arbre
3
+
4
+ describe Context do
5
+
6
+ ######
7
+ # Attributes
8
+
9
+ it "should not allow a parent to be set" do
10
+ expect{ Context.new.parent = Element.new }.to raise_error(NotImplementedError)
11
+ end
12
+
13
+ it "should always have an indentation level of -1" do
14
+ context = Context.new
15
+ expect(context.indent_level).to eql(-1)
16
+ end
17
+
18
+ describe '#assigns' do
19
+ it "should be its own assigns" do
20
+ expect(Context.new.assigns).to eql({})
21
+ expect(Context.new(:one => :two).assigns).to eql(:one => :two)
22
+ end
23
+ it "should have symbolic keys only" do
24
+ expect(Context.new('one' => :two).assigns).to eql(:one => :two)
25
+ end
26
+ end
27
+
28
+ describe '#helpers' do
29
+ it "should be its own helpers" do
30
+ expect(Context.new.helpers).to eql(nil)
31
+ helpers = double()
32
+ expect(Context.new({}, helpers).helpers).to be(helpers)
33
+ end
34
+ end
35
+
36
+ ######
37
+ # Element & flow stack
38
+
39
+ let(:context) { Context.new }
40
+
41
+ it "should have the context itself as the current element" do
42
+ expect(context.current_element).to be(context)
43
+ end
44
+
45
+ it "should have :append as the current flow" do
46
+ expect(context.current_flow).to be(:append)
47
+ end
48
+
49
+ it "should change the current element and flow temporarily using #with_current" do
50
+ element1 = Element.new
51
+ element2 = Element.new
52
+
53
+ expect(context.current_element).to be(context)
54
+ expect(context.current_flow).to be(:append)
55
+ context.with_current element: element1, flow: :prepend do
56
+ expect(context.current_element).to be(element1)
57
+ expect(context.current_flow).to be(:prepend)
58
+ context.with_current element: element2, flow: [ :after, element1 ] do
59
+ expect(context.current_element).to be(element2)
60
+ expect(context.current_flow).to eql([ :after, element1 ])
61
+ end
62
+ expect(context.current_element).to be(element1)
63
+ expect(context.current_flow).to be(:prepend)
64
+ end
65
+ expect(context.current_element).to be(context)
66
+ expect(context.current_flow).to be(:append)
67
+ end
68
+
69
+ it "should replace the original element if an error occurs" do
70
+ begin
71
+ context.with_current(element: Element.new, flow: :prepend) { raise 'test' }
72
+ rescue
73
+ expect(context.current_element).to be(context)
74
+ expect(context.current_flow).to be(:append)
75
+ end
76
+ end
77
+
78
+ describe '#replace_current_flow' do
79
+ # Note - this method is for internal purposes only.
80
+
81
+ it "should replace the current flow" do
82
+ element = Element.new
83
+
84
+ expect(context.current_flow).to be(:append)
85
+ context.with_current element: element, flow: :prepend do
86
+ expect(context.current_flow).to be(:prepend)
87
+ context.replace_current_flow [ :after, element ]
88
+ expect(context.current_flow).to eql([:after, element])
89
+ end
90
+ expect(context.current_flow).to be(:append)
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,300 @@
1
+ require 'spec_helper'
2
+ include Arbre
3
+
4
+ describe Element::Building do
5
+
6
+ # Note - builder methods are specced in integration/element_building_spec.rb.
7
+
8
+ let(:element_class) { Class.new(Element) }
9
+ let(:element) { element_class.new(arbre) }
10
+
11
+ ######
12
+ # Build & insert element
13
+
14
+ describe '#build' do
15
+
16
+ it "should create an element from the given class and build it using the given arguments and block" do
17
+ block = proc {}
18
+
19
+ expect(element_class).to receive(:new).with(arbre).and_return(element)
20
+ expect(element).to receive(:build!).with(:arg1, :arg2) do |&blk|
21
+ expect(blk).to be(block)
22
+ expect(element.current_element).to be(element)
23
+ end
24
+
25
+ result = arbre.build(element_class, :arg1, :arg2, &block)
26
+ expect(result).to be(element)
27
+ end
28
+
29
+ end
30
+
31
+ describe '#insert' do
32
+
33
+ it "should create an element from the given class, insert it, and build it using the given arguments and block" do
34
+ block = proc {}
35
+ parent = Element.new
36
+
37
+ expect(element_class).to receive(:new).with(arbre).and_return(element)
38
+ expect(element).to receive(:build!).with(:arg1, :arg2) do |&blk|
39
+ # Note: the parent should be known when the build method is called!
40
+ expect(element.parent).to be(parent)
41
+ expect(blk).to be(block)
42
+ expect(element.current_element).to be(element)
43
+ end
44
+
45
+ result = arbre.within(parent) { arbre.insert(element_class, :arg1, :arg2, &block) }
46
+ expect(result).to be(element)
47
+ expect(parent.children).to eq([element])
48
+ end
49
+
50
+ end
51
+
52
+ ######
53
+ # Within
54
+
55
+ describe '#append_within' do
56
+ it "should call within_element on to arbre_context" do
57
+ block = proc{}
58
+ element = Element.new
59
+ expect(arbre).to receive(:with_current).with(element: element, flow: :append) do |&blk|
60
+ expect(blk).to be(block)
61
+ end
62
+
63
+ Element.new(arbre).instance_exec do
64
+ append_within element, &block
65
+ end
66
+ end
67
+
68
+ it "should resolve any string into an element using 'find'" do
69
+ block = proc{}
70
+ element = Element.new
71
+ expect(arbre).to receive(:with_current).with(element: element, flow: :append)
72
+
73
+ context_element = Element.new(arbre)
74
+ expect(context_element).to receive(:find).with('fieldset#username').and_return([element])
75
+ context_element.instance_exec do
76
+ within 'fieldset#username', &block
77
+ end
78
+ end
79
+ end
80
+
81
+ describe '#prepend_within' do
82
+ it "should call within and with_flow(:prepend) on the context" do
83
+ block = proc {}
84
+ element = Element.new
85
+ expect(arbre).to receive(:with_current).with(element: element, flow: :prepend) do |&blk|
86
+ expect(blk).to be(block)
87
+ end
88
+
89
+ Element.new(arbre).instance_exec do
90
+ prepend_within element, &block
91
+ end
92
+ end
93
+
94
+ it "should resolve any string into an element using 'find'" do
95
+ block = proc{}
96
+ element = Element.new
97
+ expect(arbre).to receive(:with_current).with(element: element, flow: :prepend)
98
+
99
+ context_element = Element.new(arbre)
100
+ expect(context_element).to receive(:find).with('fieldset#username').and_return([element])
101
+ context_element.instance_exec do
102
+ prepend_within 'fieldset#username', &block
103
+ end
104
+ end
105
+ end
106
+
107
+ ######
108
+ # Append / prepend
109
+
110
+ describe '#append' do
111
+
112
+ it "should insert an element of the given class using the :append flow" do
113
+ block = proc {}
114
+ expect(arbre).to receive(:insert).with(element_class, :one, :two) do |&blk|
115
+ expect(blk).to be(block)
116
+ expect(arbre.current_flow).to be(:append)
117
+ end
118
+
119
+ arbre.append element_class, :one, :two, &block
120
+ end
121
+
122
+ it "should run the given block :append flow if no block is given" do
123
+ block = proc do
124
+ expect(arbre.current_flow).to be(:append)
125
+ end
126
+
127
+ arbre.append &block
128
+ end
129
+
130
+ end
131
+
132
+ describe '#prepend' do
133
+
134
+ it "should insert an element of the given class using the :prepend flow" do
135
+ block = proc {}
136
+ expect(arbre).to receive(:insert).with(element_class, :one, :two) do |&blk|
137
+ expect(blk).to be(block)
138
+ expect(arbre.current_flow).to be(:prepend)
139
+ end
140
+
141
+ arbre.prepend element_class, :one, :two, &block
142
+ end
143
+
144
+ it "should run the given block :prepend flow if no block is given" do
145
+ block = proc do
146
+ expect(arbre.current_flow).to be(:prepend)
147
+ end
148
+
149
+ arbre.prepend &block
150
+ end
151
+
152
+ end
153
+
154
+ ######
155
+ # After / before
156
+
157
+ describe '#after' do
158
+ let(:parent) { Element.new }
159
+ let(:element) { Element.new }
160
+ before { parent << element }
161
+
162
+ it "should insert an element of the given class using the :after flow" do
163
+ block = proc {}
164
+ expect(arbre).to receive(:insert).with(element_class, :one, :two) do |&blk|
165
+ expect(blk).to be(block)
166
+ expect(arbre.current_element).to be(parent)
167
+ expect(arbre.current_flow).to eql([:after, element])
168
+ end
169
+
170
+ arbre.after element, element_class, :one, :two, &block
171
+ end
172
+
173
+ it "should run the given block :after flow if no block is given" do
174
+ block = proc do
175
+ expect(arbre.current_flow).to eql([:after, element])
176
+ end
177
+
178
+ arbre.after element, &block
179
+ end
180
+
181
+ end
182
+
183
+ describe '#before' do
184
+ let(:parent) { Element.new }
185
+ let(:element) { Element.new }
186
+ before { parent << element }
187
+
188
+ it "should insert an element of the given class using the :before flow" do
189
+ block = proc {}
190
+ expect(arbre).to receive(:insert).with(element_class, :one, :two) do |&blk|
191
+ expect(blk).to be(block)
192
+ expect(arbre.current_element).to be(parent)
193
+ expect(arbre.current_flow).to eql([:before, element])
194
+ end
195
+
196
+ arbre.before element, element_class, :one, :two, &block
197
+ end
198
+
199
+ it "should run the given block :before flow if no block is given" do
200
+ block = proc do
201
+ expect(arbre.current_flow).to eql([:before, element])
202
+ end
203
+
204
+ arbre.before element, &block
205
+ end
206
+
207
+ end
208
+
209
+ ######
210
+ # Insert child
211
+
212
+ describe '#insert_child' do
213
+
214
+ let(:element) { Element.new(arbre) }
215
+ let(:existing) { Element.new(arbre) }
216
+ let(:child) { Element.new(arbre) }
217
+
218
+ context "flow :append" do
219
+ before { allow(arbre).to receive(:current_flow).and_return(:append) }
220
+
221
+ it "should add the child to the element" do
222
+ expect(element.children).to receive(:<<).with(child)
223
+ element.insert_child child
224
+ end
225
+ end
226
+
227
+ context "flow :prepend" do
228
+ before { allow(arbre).to receive(:current_flow).and_return(:prepend) }
229
+
230
+ it "should insert the child at the beginning of the element's children" do
231
+ expect(element.children).to receive(:insert_at).with(0, child)
232
+ element.insert_child child
233
+ end
234
+
235
+ it "should change the flow after inserting the first element" do
236
+ expect(element.children).to receive(:insert_at).with(0, child)
237
+ expect(arbre).to receive(:replace_current_flow).with([ :after, child ])
238
+ element.insert_child child
239
+ end
240
+ end
241
+
242
+ context "flow :after" do
243
+ before { allow(arbre).to receive(:current_flow).and_return([:after, existing]) }
244
+
245
+ it "should insert the child after the existing child" do
246
+ expect(element.children).to receive(:insert_after).with(existing, child)
247
+ element.insert_child child
248
+ end
249
+
250
+ it "should change the flow after inserting the first element" do
251
+ expect(element.children).to receive(:insert_after).with(existing, child)
252
+ expect(arbre).to receive(:replace_current_flow).with([ :after, child ])
253
+ element.insert_child child
254
+ end
255
+ end
256
+
257
+ context "flow :before" do
258
+ before { allow(arbre).to receive(:current_flow).and_return([:before, existing]) }
259
+
260
+ it "should insert the child before the existing child" do
261
+ expect(element.children).to receive(:insert_before).with(existing, child)
262
+ element.insert_child child
263
+ end
264
+ end
265
+
266
+ end
267
+
268
+
269
+ ######
270
+ # Support
271
+
272
+ describe '#temporary' do
273
+ it "should build an element with the given block and return it" do
274
+ block = proc {}
275
+ expect(arbre).to receive(:build).with(Element) do |&blk|
276
+ expect(blk).to be(block)
277
+ element
278
+ end
279
+ expect(arbre.temporary(&block)).to be(element)
280
+ expect(element).to be_orphan
281
+ end
282
+ end
283
+
284
+ it "should delegate #current_element to the context" do
285
+ current_element = Element.new
286
+ expect(arbre).to receive(:current_element).and_return(current_element)
287
+
288
+ element = Element.new(arbre)
289
+ expect(element.current_element).to be(current_element)
290
+ end
291
+
292
+ it "should delegate #current_flow to the context" do
293
+ current_flow = double(:flow)
294
+ expect(arbre).to receive(:current_flow).and_return(current_flow)
295
+
296
+ element = Element.new(arbre)
297
+ expect(element.current_flow).to be(current_flow)
298
+ end
299
+
300
+ end
@@ -0,0 +1,169 @@
1
+ require 'spec_helper'
2
+ include Arbre
3
+
4
+ describe ElementCollection do
5
+
6
+ ######
7
+ # Collection stuff
8
+
9
+ let(:element1) { Element.new }
10
+ let(:element2) { Element.new }
11
+ let(:element3) { Element.new }
12
+
13
+ it "should initialize as an empty collection by default" do
14
+ elements = ElementCollection.new
15
+ expect(elements).to be_empty
16
+ end
17
+
18
+ it "should behave like an array" do
19
+ elements = ElementCollection.new([element1])
20
+ expect(elements).to have(1).item
21
+ expect(elements[0]).to be(element1)
22
+
23
+ elements << element2
24
+ expect(elements).to have(2).item
25
+ expect(elements[0]).to be(element1)
26
+ expect(elements[1]).to be(element2)
27
+
28
+ elements = ElementCollection.new
29
+ elements.concat [ element1, element2 ]
30
+ expect(elements).to have(2).item
31
+ expect(elements[0]).to be(element1)
32
+ expect(elements[1]).to be(element2)
33
+
34
+ elements.clear
35
+ expect(elements).to be_empty
36
+ end
37
+
38
+ it "should wrap any enumerable indexing result in another element collection" do
39
+ collection = ElementCollection.new([element1, element2, element3])
40
+
41
+ expect(collection[0]).to be_a(Element)
42
+
43
+ expect(collection[0..1]).to be_a(ElementCollection)
44
+ expect(collection[0..1]).to have(2).items
45
+ expect(collection[0..1][0]).to be(element1)
46
+ expect(collection[0..1][1]).to be(element2)
47
+
48
+ expect(collection[0, 1]).to be_a(ElementCollection)
49
+ expect(collection[0, 1]).to have(1).items
50
+ expect(collection[0, 1][0]).to be(element1)
51
+ end
52
+
53
+ it "should equate to an array" do
54
+ expect(ElementCollection.new([element1, element2])).to eq([element1, element2])
55
+ expect(ElementCollection.new([element1, element2])).not_to eq([element2, element1])
56
+ expect(ElementCollection.new([element1, element2])).not_to eq([element1])
57
+ end
58
+
59
+ it "should equate to another collection with the same elements" do
60
+ collection = ElementCollection.new([element1, element2])
61
+ expect(collection).to eq(ElementCollection.new([element1, element2]))
62
+ expect(collection).not_to eq(ElementCollection.new([element2, element1]))
63
+ expect(collection).not_to eq(ElementCollection.new([element1]))
64
+ end
65
+
66
+ it "should not be eql? an array" do
67
+ expect(ElementCollection.new([element1, element2])).not_to eql([element1, element2])
68
+ end
69
+
70
+ it "should be eql? to another collection with the same elements" do
71
+ collection = ElementCollection.new([element1, element2])
72
+ expect(collection).to eq(ElementCollection.new([element1, element2]))
73
+ expect(collection).not_to eq(ElementCollection.new([element2, element1]))
74
+ expect(collection).not_to eq(ElementCollection.new([element1]))
75
+ end
76
+
77
+ it "should rename 'delete' to 'remove'" do
78
+ elements = ElementCollection.new([element1, element2])
79
+ elements.remove element2
80
+ expect(elements).to eq([element1])
81
+ end
82
+
83
+ describe '#+' do
84
+
85
+ it "should combine itself with another collection" do
86
+ collection1 = ElementCollection.new([element1, element2])
87
+ collection2 = ElementCollection.new([element2, element3])
88
+ expect(collection1 + collection2).to be_a(ElementCollection)
89
+ expect(collection1 + collection2).to eq([element1, element2, element3])
90
+ end
91
+
92
+ it "should combine itself with an array" do
93
+ collection = ElementCollection.new([element1, element2])
94
+ expect(collection + [element2, element3]).to be_a(ElementCollection)
95
+ expect(collection + [element2, element3]).to eq([element1, element2, element3])
96
+ end
97
+
98
+ end
99
+
100
+ describe '#-' do
101
+
102
+ it "should subtract another collection from itself" do
103
+ collection1 = ElementCollection.new([element1, element2])
104
+ collection2 = ElementCollection.new([element2, element3])
105
+ expect(collection1 - collection2).to be_a(ElementCollection)
106
+ expect(collection1 - collection2).to eq([element1])
107
+ end
108
+
109
+ it "should combine itself with an array" do
110
+ collection = ElementCollection.new([element1, element2])
111
+ expect(collection - [element2, element3]).to be_a(ElementCollection)
112
+ expect(collection - [element2, element3]).to eq([element1])
113
+ end
114
+
115
+ end
116
+
117
+ describe '#&' do
118
+
119
+ it "should intersect itself with another collection" do
120
+ collection1 = ElementCollection.new([element1, element2])
121
+ collection2 = ElementCollection.new([element2, element3])
122
+ expect(collection1 & collection2).to be_a(ElementCollection)
123
+ expect(collection1 & collection2).to eq([element2])
124
+ end
125
+
126
+ it "should intersect itself with an array" do
127
+ collection = ElementCollection.new([element1, element2])
128
+ expect(collection & [element2, element3]).to be_a(ElementCollection)
129
+ expect(collection & [element2, element3]).to eq([element2])
130
+ end
131
+
132
+ end
133
+
134
+ it "should not add the same element more than once" do
135
+ collection = ElementCollection.new
136
+ element = Element.new
137
+ collection << element << element
138
+ expect(collection).to have(1).element
139
+ end
140
+
141
+ specify "#to_a should create a copy of the elements and #to_ary not" do
142
+ collection = ElementCollection.new([element1, element2])
143
+ expect(collection.to_ary).to be(collection.to_ary)
144
+ expect(collection.to_a).not_to be(collection.to_a)
145
+ expect(collection.to_a).to eql(collection.to_a)
146
+ end
147
+
148
+ ######
149
+ # Rendering
150
+
151
+ describe '#to_s' do
152
+
153
+ let(:collection) { ElementCollection.new([element1, element2]) }
154
+
155
+ it "should join all elements' to_s result with a return" do
156
+ expect(element1).to receive(:to_s).and_return('(ELEMENT1)')
157
+ expect(element2).to receive(:to_s).and_return('(ELEMENT2)')
158
+ expect(collection.to_s).to eql("(ELEMENT1)\n(ELEMENT2)")
159
+ end
160
+
161
+ it "should be HTML-safe" do
162
+ expect(element1).to receive(:to_s).and_return('<span>')
163
+ expect(element2).to receive(:to_s).and_return('<span>'.html_safe)
164
+ expect(collection.to_s).to eql("&lt;span&gt;\n<span>")
165
+ end
166
+
167
+ end
168
+
169
+ end