arbre2 2.1.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.
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