eimxml 0.0.2 → 0.0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,7 @@
3
3
  # Copyright (C) 2006, KURODA Hiraku <hiraku@hinet.mydns.jp>
4
4
  # You can redistribute it and/or modify it under GPL2.
5
5
 
6
+ $:.unshift "#{File.dirname(File.dirname(File.expand_path(__FILE__)))}/lib"
6
7
  require "test/unit"
7
8
  require "eim_xml/assertions"
8
9
 
@@ -0,0 +1,217 @@
1
+ require "eim_xml/dsl"
2
+
3
+ module Module.new::M
4
+ include EimXML
5
+ EDSL = EimXML::DSL
6
+
7
+ describe EimXML::DSL do
8
+ it "scope is in instance of DSL" do
9
+ outer = inner = nil
10
+ e3 = e2 = nil
11
+ block_executed = false
12
+ e = EDSL.element(:out, :k1=>"v1") do
13
+ outer = self
14
+ e2 = element(:in, :k2=>"v2") do
15
+ block_executed = true
16
+ inner = self
17
+ e3 = element(:deep)
18
+ end
19
+ end
20
+
21
+ block_executed.should == true
22
+ outer.should be_kind_of(EDSL)
23
+ inner.should be_kind_of(EDSL)
24
+ outer.should be_equal(inner)
25
+
26
+ e.name.should == :out
27
+ e[:k1].should == "v1"
28
+ e[0].name.should == :in
29
+ e[0][:k2].should == "v2"
30
+ e[0][0].name.should == :deep
31
+ e2.should be_equal(e[0])
32
+ e3.should be_equal(e[0][0])
33
+ end
34
+
35
+ it "#comment" do
36
+ Comment.should_receive(:new).with("comment").and_return(:success)
37
+ EDSL.comment("comment").should == :success
38
+ end
39
+
40
+ it "#import_variables" do
41
+ d = EDSL.new
42
+ o = Object.new
43
+ o.instance_variable_set("@v1", 1)
44
+ o.instance_variable_set("@v2", "2")
45
+ o.instance_variable_set("@_v3", :t)
46
+ o.instance_variable_set("@__v4", 4)
47
+ o.instance_variable_set("@_container", :t)
48
+ orig_c = d.instance_variable_get("@_container")
49
+
50
+ d.import_variables(o).should be_equal(d)
51
+
52
+ d.instance_variable_get("@_container").should == orig_c
53
+ d.instance_variables.map(&:to_s).sort.should == ["@v1", "@v2", "@__v4"].sort
54
+ d.instance_variable_get("@v1").should == 1
55
+ d.instance_variable_get("@v2").should == "2"
56
+ d.instance_variable_get("@__v4").should == 4
57
+ end
58
+
59
+ describe "#_push" do
60
+ before do
61
+ m = Module.new
62
+ class m::D < EimXML::DSL
63
+ def call_push(c)
64
+ _push(c) do
65
+ element(:e)
66
+ end
67
+ end
68
+
69
+ def exec
70
+ element(:e) do
71
+ element(:f)
72
+ end
73
+ end
74
+ end
75
+ @D = m::D
76
+ end
77
+
78
+ it "should return given container" do
79
+ a = []
80
+ @D.new.call_push(a).should be_equal(a)
81
+ a.should == [EimXML::Element.new(:e)]
82
+
83
+ @D.new.exec.should == EimXML::Element.new(:e).add(EimXML::Element.new(:f))
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "Subclass of BaseDSL" do
89
+ class DSL1 < EimXML::BaseDSL
90
+ register([EimXML::Element, "call"])
91
+ register(Hash)
92
+ register(String, Array, Object)
93
+ end
94
+
95
+ it "register" do
96
+ lambda{EDSL.call(:dummy)}.should raise_error(NoMethodError)
97
+ lambda{BaseDSL.call(:dummy)}.should raise_error(NoMethodError)
98
+ lambda{DSL1.element(:dummy)}.should raise_error(NoMethodError)
99
+ DSL1.call(:dummy).should be_kind_of(Element)
100
+ DSL1.hash.should be_kind_of(Hash)
101
+ DSL1.string.should be_kind_of(String)
102
+ DSL1.array.should be_kind_of(Array)
103
+ DSL1.object.should be_kind_of(Object)
104
+ end
105
+ end
106
+
107
+ describe EimXML::OpenDSL do
108
+ it "scope of block is one of outside" do
109
+ @scope_checker_variable = 1
110
+ block_executed = false
111
+ d = OpenDSL.new do |d|
112
+ block_executed = true
113
+ d.should be_kind_of(OpenDSL)
114
+ d.container.should be_nil
115
+ d.element(:base, :key1=>"v1") do
116
+ @scope_checker_variable.should == 1
117
+ self.should_not be_kind_of(Element)
118
+ d.container.should be_kind_of(Element)
119
+ d.container.should == Element.new(:base, :key1=>"v1")
120
+ d.element(:sub, :key2=>"v2") do
121
+ d.container.should be_kind_of(Element)
122
+ d.container.should == Element.new(:sub, :key2=>"v2")
123
+ end
124
+ d.element(:sub2).should == Element.new(:sub2)
125
+ end
126
+ end
127
+ block_executed.should be_true
128
+ end
129
+
130
+ it "DSL methods return element" do
131
+ d = OpenDSL.new
132
+ d.container.should be_nil
133
+ r = d.element(:base, :key1=>"v1") do
134
+ d.element(:sub, :key2=>"v2")
135
+ end
136
+ r.should == EDSL.element(:base, :key1=>"v1") do
137
+ element(:sub, :key2=>"v2")
138
+ end
139
+ end
140
+
141
+ it "DSL method's block given instance of OpenDSL" do
142
+ e = OpenDSL.new.element(:base) do |d|
143
+ d.should be_kind_of(OpenDSL)
144
+ d.container.name.should == :base
145
+ d.element(:sub) do |d2|
146
+ d2.should be_equal(d)
147
+ end
148
+ end
149
+
150
+ e.should == EDSL.element(:base) do
151
+ element(:sub)
152
+ end
153
+ end
154
+
155
+ it "ensure reset container when error raised" do
156
+ OpenDSL.new do |d|
157
+ begin
158
+ d.element(:base) do
159
+ begin
160
+ d.element(:sub) do
161
+ raise "OK"
162
+ end
163
+ rescue RuntimeError => e
164
+ raise unless e.message=="OK"
165
+ d.container.name.should == :base
166
+ raise
167
+ end
168
+ end
169
+ rescue RuntimeError => e
170
+ raise unless e.message=="OK"
171
+ d.container.should == nil
172
+ end
173
+ end
174
+ end
175
+
176
+ it "respond to add" do
177
+ r = OpenDSL.new.element(:base) do |d|
178
+ d.add "text"
179
+ d.element(:sub) do
180
+ s = Element.new(:sub)
181
+ s.add("sub text")
182
+ d.add("sub text").should == s
183
+ end
184
+ end
185
+
186
+ r.should == EDSL.element(:base) do
187
+ add "text"
188
+ element(:sub) do
189
+ add "sub text"
190
+ end
191
+ end
192
+ end
193
+
194
+ it "respond to <<" do
195
+ r = OpenDSL.new.element(:base) do |d|
196
+ b = Element.new(:base)
197
+ b << "text" << "next"
198
+ (d << "text" << "next").should == b
199
+ end
200
+ r.should == EDSL.element(:base) do
201
+ add "text"
202
+ add "next"
203
+ end
204
+ end
205
+
206
+ it "can call directly element method" do
207
+ r = OpenDSL.element(:base) do |d|
208
+ d.element(:sub)
209
+ d.element(:sub2)
210
+ end
211
+ r.should == EDSL.element(:base) do
212
+ element(:sub)
213
+ element(:sub2)
214
+ end
215
+ end
216
+ end
217
+ end
@@ -0,0 +1,441 @@
1
+ require "eim_xml/dsl"
2
+
3
+ module Module.new::M
4
+ include EimXML
5
+ EDSL = EimXML::DSL
6
+
7
+ describe PCString do
8
+ it ".encode" do
9
+ PCString.encode("<>\"'&").should == "&lt;&gt;&quot;&apos;&amp;"
10
+ PCString.encode("&test;").should == "&amp;test;"
11
+ PCString.encode("&amp;").should == "&amp;amp;"
12
+ PCString.encode(:'sym&').should == "sym&amp;"
13
+ end
14
+
15
+ it ".new" do
16
+ PCString.new("&").encoded_string.should == "&amp;"
17
+ PCString.new("&", true).encoded_string.should == "&"
18
+ pcs = PCString.new(:'sym&')
19
+ pcs.encoded_string.should == "sym&amp;"
20
+ pcs.src.should == :'sym&'
21
+ end
22
+
23
+ describe ".[]" do
24
+ it "should return itself when given object is a PCString" do
25
+ pcs = PCString.new("s")
26
+ PCString[pcs].should equal(pcs)
27
+ end
28
+
29
+ it "should return PCString.new(obj) if given obj is not a PCString" do
30
+ o = "str"
31
+ r = PCString[o]
32
+ r.is_a?(EimXML::PCString)
33
+ r.src.should == o
34
+ end
35
+ end
36
+
37
+ it "#==" do
38
+ PCString.new("str").should == PCString.new("str")
39
+ PCString.new("&").should == "&"
40
+ PCString.new("&", true).should_not == "&"
41
+ PCString.new("&", true).should == PCString.new("&", true)
42
+ PCString.new("&").should == PCString.new("&amp;", true)
43
+ end
44
+
45
+ describe "#write_to" do
46
+ before do
47
+ @pc = PCString.new("&amp;")
48
+ end
49
+
50
+ it "should return encoded string" do
51
+ @pc.write_to.should == "&amp;amp;"
52
+ end
53
+
54
+ it "should return given destination" do
55
+ s = ""
56
+ @pc.write_to(s).should be_equal(s)
57
+ end
58
+ end
59
+ end
60
+
61
+ describe Comment do
62
+ it ".new should raise error if given string include '--'" do
63
+ lambda{Comment.new("--")}.should raise_error(ArgumentError)
64
+ end
65
+
66
+ describe "#write_to" do
67
+ it "should return comment with markup" do
68
+ Comment.new("flat comment").write_to.should == "<!-- flat comment -->"
69
+ Comment.new("multi-line\ncomment").write_to.should == "<!-- multi-line\ncomment -->"
70
+ Comment.new("&").write_to.should == "<!-- & -->"
71
+ end
72
+
73
+ it "should return given destination" do
74
+ s = ""
75
+ Comment.new("dummy").write_to(s).should be_equal(s)
76
+ end
77
+ end
78
+ end
79
+
80
+ describe Element do
81
+ class Dummy < Element
82
+ def chgname(name)
83
+ self.name = name
84
+ end
85
+ end
86
+
87
+ it "#name" do
88
+ e = Element.new("el")
89
+ e.name.should == :el
90
+ lambda{e.name="changed"}.should raise_error(NoMethodError)
91
+
92
+ d = Dummy.new("el1")
93
+ d.name.should == :el1
94
+ d.chgname(:el2)
95
+ d.name.should == :el2
96
+ d.chgname("el3")
97
+ d.name.should == :el3
98
+ end
99
+
100
+ it "#attributes should return hash whose keys are Symbol" do
101
+ e = Element.new("el", "a1"=>"v1", :a2=>"v2", "a3"=>nil)
102
+ e.name.should == :el
103
+ e.attributes.should == {:a1=>"v1", :a2=>"v2", :a3=>nil}
104
+ end
105
+
106
+ it "#[]" do
107
+ e = Element.new(:el, :attr=>"value")
108
+ e << "test"
109
+ e[:attr].should == "value"
110
+ e[0].should == "test"
111
+ end
112
+
113
+ it "#add_attribute" do
114
+ e = Element.new("el")
115
+ e.add_attribute("key_str", "value1")
116
+ e.add_attribute(:key_sym, "value2")
117
+ e.attributes.should == {:key_str=>"value1", :key_sym=>"value2"}
118
+ e.add_attribute(:nil, nil)
119
+ e.attributes.should == {:key_str=>"value1", :key_sym=>"value2", :nil=>nil}
120
+ end
121
+
122
+ it "#del_attribute" do
123
+ e = Element.new("el", {:a1=>"v1", :a2=>"v2"})
124
+ e.del_attribute("a1")
125
+ e.attributes.should == {:a2=>"v2"}
126
+ e.del_attribute(:a2)
127
+ e.attributes.should == {}
128
+ end
129
+
130
+ it "#contents" do
131
+ sub = Element.new("sub")
132
+ e = Element.new("el") << "String1" << "String2" << sub
133
+ e.contents.should == ["String1", "String2", sub]
134
+ end
135
+
136
+ it "#add" do
137
+ e = Element.new("el").add(Element.new("sub"))
138
+ e.should be_kind_of(Element)
139
+ e.name.should == :el
140
+
141
+ e = Element.new("el")
142
+ e.add(Element.new("sub1"))
143
+ e.add([Element.new("sub2").add("text"), "string"])
144
+ e.contents.should == [Element.new("sub1"), Element.new("sub2").add("text"), "string"]
145
+
146
+ e = Element.new("el")
147
+ e.add(nil)
148
+ e.contents.size.should == 0
149
+
150
+ e = Element.new("el").add(:symbol)
151
+ e.contents.should == [:symbol]
152
+ e.to_s.should == "<el>symbol</el>"
153
+
154
+ e = Element.new("super") << Element.new("sub")
155
+ e.name.should == :super
156
+ e.contents.should == [Element.new("sub")]
157
+ end
158
+
159
+ describe "#write_to" do
160
+ it "should return flatten string" do
161
+ Element.new("e").write_to.should == "<e />"
162
+
163
+ e = Element.new("super")
164
+ e << Element.new("sub")
165
+ e.write_to.should == "<super><sub /></super>"
166
+ e << Element.new("sub2")
167
+ e.write_to.should == "<super><sub /><sub2 /></super>"
168
+
169
+ e = Element.new("super") << "content1"
170
+ s = Element.new("sub")
171
+ s << "content2"
172
+ e << s
173
+ e.write_to.should == "<super>content1<sub>content2</sub></super>"
174
+
175
+ e = Element.new("el")
176
+ e.attributes["a1"] = "v1"
177
+ e.attributes["a2"] = "'\"<>&"
178
+ s = e.write_to
179
+ s.should =~ /\A<el ([^>]*) \/>\z/
180
+ s.should =~ /a1='v1'/
181
+ s.should =~ /a2='&apos;&quot;&lt;&gt;&amp;'/
182
+ end
183
+
184
+ it "should return string without attribute whose value is nil or false" do
185
+ s = EimXML::Element.new("e", :attr1=>"1", :attr2=>true, :attr3=>nil, :attr4=>false).write_to
186
+ re = /\A<e attr(.*?)='(.*?)' attr(.*?)='(.*?)' \/>\z/
187
+ s.should match(re)
188
+ s =~ /\A<e attr(.*?)='(.*?)' attr(.*?)='(.*?)' \/>\z/
189
+ [[$1, $2], [$3, $4]].sort.should == [["1", "1"], ["2", "true"]]
190
+ end
191
+
192
+ it "should return same string whenever name of element given with string or symbol" do
193
+ sym = Element.new(:tag, :attr=>"value")
194
+ str_name = Element.new("tag", :attr=>"value")
195
+ str_attr = Element.new(:tag, "attr"=>"value")
196
+
197
+ str_name.write_to.should == sym.write_to
198
+ str_attr.write_to.should == sym.write_to
199
+ end
200
+ end
201
+
202
+ it "encode special characters" do
203
+ e = Element.new("el") << "&\"'<>"
204
+ e << PCString.new("&\"'<>", true)
205
+ e.attributes["key"] = PCString.new("&\"'<>", true)
206
+ e.to_s.should == %[<el key='&\"'<>'>&amp;&quot;&apos;&lt;&gt;&\"'<></el>]
207
+ end
208
+
209
+ it "#dup" do
210
+ e = Element.new("el")
211
+ e.attributes["key"] = "value"
212
+ e << "String"
213
+ e << "Freeze".freeze
214
+ s = Element.new("sub")
215
+ s.attributes["subkey"] = "subvalue"
216
+ e << s
217
+ f = e.dup
218
+
219
+ f.attributes.object_id.should == e.attributes.object_id
220
+ f.contents.object_id.should == e.contents.object_id
221
+
222
+ f.to_s.should == e.to_s
223
+ end
224
+
225
+ it "#clone" do
226
+ e = Element.new("el")
227
+ e.attributes["key"] = "value"
228
+ e << "String"
229
+ e << "Freeze".freeze
230
+ s = Element.new("sub")
231
+ s.attributes["subkey"] = "subvalue"
232
+ e << s
233
+ f = e.clone
234
+
235
+ f.attributes.object_id.should == e.attributes.object_id
236
+ f.contents.object_id.should == e.contents.object_id
237
+
238
+ f.to_s.should == e.to_s
239
+ end
240
+
241
+ it "#==" do
242
+ e1 = Element.new("el")
243
+ e1.attributes["key"] = "value"
244
+ s = Element.new("sub")
245
+ s << "String"
246
+ e1 << s
247
+ e2 = e1.dup
248
+ e2.should == e1
249
+
250
+ e3 = Element.new("e")
251
+ e3.attributes["key"] = "value"
252
+ s = Element.new("sub")
253
+ s << "String"
254
+ e3 << s
255
+ e3.should_not == e1
256
+
257
+ e3 = Element.new("e")
258
+ e3.attributes["k"] = "value"
259
+ s = Element.new("sub")
260
+ s << "String"
261
+ e3 << s
262
+ e3.should_not == e1
263
+
264
+ e3 = Element.new("e")
265
+ e3.attributes["key"] = "v"
266
+ s = Element.new("sub")
267
+ s << "String"
268
+ e3 << s
269
+ e3.should_not == e1
270
+
271
+ e3 = Element.new("e")
272
+ e3.attributes["key"] = "value"
273
+ s = Element.new("sub")
274
+ s << "S"
275
+ e3 << s
276
+ e3.should_not == e1
277
+
278
+ e3 = Element.new("e")
279
+ e3.attributes["key"] = "value"
280
+ s = Element.new("s")
281
+ s << "String"
282
+ e3 << s
283
+ e3.should_not == e1
284
+
285
+ "string".should_not == e1
286
+ end
287
+
288
+ describe ".new" do
289
+ it "should convert name of attributes to Symbol" do
290
+ e = Element.new(:e, "a"=>"v")
291
+ e.attributes.keys.should == [:a]
292
+ e[:a].should == "v"
293
+ end
294
+
295
+ it "with block" do
296
+ base = nil
297
+ e = Element.new("base") do |b|
298
+ b["attr"]="value"
299
+ b << Element.new("sub")
300
+ base = b
301
+ end
302
+ base.object_id.should == e.object_id
303
+
304
+ e2 = Element.new("base", :attr=>"value")
305
+ e2 << Element.new("sub")
306
+ e2.should == e
307
+
308
+ e = Element.new("base") do |e|
309
+ e <<= Element.new("sub1") do |e|
310
+ e <<= Element.new("sub12")
311
+ end
312
+ e <<= Element.new("sub2")
313
+ end
314
+ base = Element.new("base")
315
+ sub1 = Element.new("sub1")
316
+ sub1 << Element.new("sub12")
317
+ sub2 = Element.new("sub2")
318
+ base << sub1 << sub2
319
+ e.should == base
320
+ end
321
+ end
322
+
323
+ it "#match" do
324
+ e = Element.new(:tag, :attr=>"value")
325
+ e.match(:tag).should be_true
326
+ e.match(:tag, :attr=>"value").should be_true
327
+ e.match(:t).should be_false
328
+ e.match(:tag, :attr2=>"value").should be_false
329
+ e.match(:tag, :attr=>"value2").should be_false
330
+ e.match(:tag, :attr=>/val/).should be_true
331
+
332
+ e.match(Element.new(:tag)).should be_true
333
+ e.match(Element.new(:tag, :attr=>"value")).should be_true
334
+ e.match(Element.new(:tag, :attr=>/alu/)).should be_true
335
+ e.match(Element.new(:t)).should be_false
336
+ e.match(Element.new(:tag, :attr2=>"value")).should be_false
337
+ e.match(Element.new(:tag, :attr=>"value2")).should be_false
338
+ e.match(Element.new(:tag, :attr=>/aul/)).should be_false
339
+ e.match(Element.new(:tag, :attr=>PCString.new("value"))).should be_true
340
+ Element.new(:tag, :attr=>PCString.new("value")).should match(e)
341
+
342
+ e.match(Element.new(:tag, :attr=>nil)).should be_false
343
+ e.match(Element.new(:tag, :nonattr=>nil)).should be_true
344
+
345
+ (!!e.match(/ag/)).should be_true
346
+ (!!e.match(/elem/)).should be_false
347
+
348
+ e.match(Element).should be_true
349
+ e.match(Dummy).should be_false
350
+ e.match(String).should be_false
351
+
352
+ e = Element.new(:element)
353
+ e << Element.new(:sub)
354
+ e << "text"
355
+ e.match(EDSL.element(:element){element(:sub)}).should be_true
356
+ e.match(EDSL.element(:element){element(:other)}).should be_false
357
+ e.match(EDSL.element(:element){add("text")}).should be_true
358
+ e.match(EDSL.element(:element){add("other")}).should be_false
359
+ e.match(EDSL.element(:element){add(/ex/)}).should be_true
360
+ e.match(EDSL.element(:element){add(/th/)}).should be_false
361
+ e.match(EDSL.element(:element){add(/sub/)}).should be_false
362
+
363
+ e = Element.new(:t, :a=>"&")
364
+ e.should match(Element.new(:t, :a=>"&"))
365
+ e.should match(Element.new(:t, :a=>PCString.new("&amp;", true)))
366
+ e.should match(Element.new(:t, :a=>PCString.new("&")))
367
+
368
+ Element.new(:t, "a"=>"v").should match(Element.new(:t, :a=>"v"))
369
+ end
370
+
371
+ it "#=~" do
372
+ e = Element.new(:tag, :attr=>"value", :a2=>"v2")
373
+ e.should =~ :tag
374
+ e.should =~ Element.new(:tag)
375
+ e.should =~ Element.new(:tag, :a2=>"v2")
376
+ e.should =~ Element.new(:tag, :attr=>/alu/)
377
+ e.should =~ Element.new(:tag, :attr=>PCString.new("value"))
378
+ e.should_not =~ :t
379
+ e.should_not =~ Element.new(:t)
380
+ e.should_not =~ Element.new(:tag, :attr=>/aul/)
381
+
382
+ e = Element.new(:t, :a=>"&")
383
+ e.should =~ Element.new(:t, :a=>"&")
384
+ e.should =~ Element.new(:t, :a=>PCString.new("&amp;", true))
385
+ e.should =~ Element.new(:t, :a=>PCString.new("&"))
386
+ end
387
+
388
+ %w[has? has_element? include?].each do |method|
389
+ it "##{method}" do
390
+ e = Element.new(:base) do |b|
391
+ b <<= Element.new(:sub) do |s|
392
+ s <<= Element.new(:deep) do |d|
393
+ d << "text"
394
+ d << PCString.new("&amp;", true)
395
+ d << "<"
396
+ end
397
+ end
398
+ b <<= Element.new(:sub, :attr=>"value")
399
+ end
400
+
401
+ e.send(method, :sub).should be_true
402
+ e.send(method, :sub, :attr=>"value").should be_true
403
+ e.send(method, :sub, :attr=>"value", :attr2=>"").should be_false
404
+ e.send(method, :deep).should be_true
405
+
406
+ e.send(method, String).should be_true
407
+ e.send(method, PCString).should be_true
408
+
409
+ d = Element.new(:deep)
410
+ d << "text"
411
+ d << PCString.new("&amp;", true)
412
+ d << "<"
413
+ e.send(method, d).should be_true
414
+
415
+ d = Element.new(:deep)
416
+ d << PCString.new("text", true)
417
+ d << "&"
418
+ d << PCString.new("&lt;", true)
419
+ e.send(method, d).should be_true
420
+ end
421
+ end
422
+
423
+ it "#find" do
424
+ s1 = Element.new(:sub)
425
+ d = Element.new(:deep)
426
+ d << "3rd"
427
+ s1 << "2nd" << d
428
+ s2 = Element.new(:sub, :attr=>"value")
429
+ e = Element.new(:base)
430
+ e << "1st" << s1 << s2
431
+
432
+ e.find(:deep).should be_kind_of(Element)
433
+ e.find(:deep).name.should == :found
434
+ e.find(:deep).contents.should == [d]
435
+ e.find(:sub).contents.should == [s1, s2]
436
+ e.find(//).contents.should == [e, s1, d, s2]
437
+ e.find(:sub, :attr=>"value").contents.should == [s2]
438
+ e.find(String).contents.should == ["1st", "2nd", "3rd"]
439
+ end
440
+ end
441
+ end