microfiche 1.0.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.
- data/ProjectInfo +31 -0
- data/README +24 -0
- data/Rakefile +2 -0
- data/VERSION +1 -0
- data/lib/facets/json.rb +917 -0
- data/lib/facets/xoxo.rb +541 -0
- data/test/lib/facets/test_json.rb +232 -0
- data/test/lib/facets/test_xoxo.rb +288 -0
- metadata +61 -0
data/lib/facets/xoxo.rb
ADDED
@@ -0,0 +1,541 @@
|
|
1
|
+
# = xoxo.rb
|
2
|
+
#
|
3
|
+
# == Copyright (C) 2006 Christian Neukirchen
|
4
|
+
#
|
5
|
+
# Ruby License
|
6
|
+
#
|
7
|
+
# This module is free software. You may use, modify, and/or redistribute this
|
8
|
+
# software under the same terms as Ruby.
|
9
|
+
#
|
10
|
+
# This program is distributed in the hope that it will be useful, but WITHOUT
|
11
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
12
|
+
# FOR A PARTICULAR PURPOSE.
|
13
|
+
#
|
14
|
+
# == Special Thanks
|
15
|
+
#
|
16
|
+
# Special thanks go to Christian Neukirchen for xoxo.rb.
|
17
|
+
# * http://chneukirchen.org/repos/xoxo-rb/.
|
18
|
+
#
|
19
|
+
# == Author(s)
|
20
|
+
#
|
21
|
+
# * Christian Neukirchen
|
22
|
+
|
23
|
+
# Author:: Christian Neukirchen
|
24
|
+
# Copyright:: Copyright (c) 2006 Christian Neukirchen
|
25
|
+
# License:: Ruby License
|
26
|
+
|
27
|
+
require 'rexml/parsers/pullparser'
|
28
|
+
|
29
|
+
# = XOXO
|
30
|
+
#
|
31
|
+
# XOXO is a Ruby XOXO parser and generator. It provides
|
32
|
+
# a Ruby API similar to Marshal and YAML (though more
|
33
|
+
# specific) to load and dump XOXO[http://microformats.org/wiki/xoxo],
|
34
|
+
# an simple, open outline format written in standard XHTML and
|
35
|
+
# suitable for embedding in (X)HTML, Atom, RSS, and arbitrary XML.
|
36
|
+
|
37
|
+
module XOXO
|
38
|
+
|
39
|
+
# xoxo.rb version number
|
40
|
+
#VERSION = "0.1"
|
41
|
+
|
42
|
+
# Load and return a XOXO structure from the String, IO or StringIO or _xoxo_.
|
43
|
+
#
|
44
|
+
def self.load(xoxo)
|
45
|
+
structs = Parser.new(xoxo).parse.structs
|
46
|
+
while structs.kind_of?(Array) && structs.size == 1
|
47
|
+
structs = structs.first
|
48
|
+
end
|
49
|
+
structs
|
50
|
+
end
|
51
|
+
|
52
|
+
# Return a XOXO string corresponding to the Ruby object +struct+,
|
53
|
+
# translated to the following rules:
|
54
|
+
#
|
55
|
+
# * Arrays become ordered lists <tt><ol></tt>.
|
56
|
+
# * Hashes become definition lists <tt><dl></tt>, keys are
|
57
|
+
# stringified with +to_s+.
|
58
|
+
# * Everything else becomes stringified with +to_s+ and wrapped in
|
59
|
+
# appropriate list elements (<tt><li></tt> or <tt><dt></tt>/<tt><dd></tt>).
|
60
|
+
#
|
61
|
+
# Additionally, you can pass these options on the _options_ hash:
|
62
|
+
# <tt>:html_wrap</tt> => +true+:: Wrap the XOXO with a basic XHTML 1.0
|
63
|
+
# Transitional header.
|
64
|
+
# <tt>:css</tt> => _css_:: Reference _css_ as stylesheet for the
|
65
|
+
# wrapped XOXO document.
|
66
|
+
#
|
67
|
+
def self.dump(struct, options={})
|
68
|
+
struct = [struct] unless struct.kind_of? Array
|
69
|
+
|
70
|
+
if options[:html_wrap]
|
71
|
+
result = <<EOF.strip
|
72
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN
|
73
|
+
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
74
|
+
<html xmlns="http://www.w3.org/1999/xhtml"><head profile=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
75
|
+
EOF
|
76
|
+
if options[:css]
|
77
|
+
result << %Q[<style type="text/css" >@import "#{options[:css]}";</style>]
|
78
|
+
end
|
79
|
+
|
80
|
+
result << "</head><body>" << make_xoxo(struct, 'xoxo') << "</body></html>"
|
81
|
+
else
|
82
|
+
result = make_xoxo(struct, 'xoxo')
|
83
|
+
end
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def self.make_xoxo(struct, class_name=nil)
|
91
|
+
s = ''
|
92
|
+
case struct
|
93
|
+
when Array
|
94
|
+
if class_name
|
95
|
+
s << %Q[<ol class="#{class_name}">]
|
96
|
+
else
|
97
|
+
s << "<ol>"
|
98
|
+
end
|
99
|
+
struct.each { |item|
|
100
|
+
s << "<li>" << make_xoxo(item) << "</li>"
|
101
|
+
}
|
102
|
+
s << "</ol>"
|
103
|
+
|
104
|
+
when Hash
|
105
|
+
d = struct.dup
|
106
|
+
if d.has_key? 'url'
|
107
|
+
s << '<a href="' << d['url'].to_s << '" '
|
108
|
+
text = d.fetch('text') { d.fetch('title', d['url']) }
|
109
|
+
%w[title rel type].each { |tag|
|
110
|
+
if d.has_key? tag
|
111
|
+
s << tag.to_s << '="' << make_xoxo(d.delete(tag)) << '" '
|
112
|
+
end
|
113
|
+
}
|
114
|
+
s << '>' << make_xoxo(text) << '</a>'
|
115
|
+
d.delete 'text'
|
116
|
+
d.delete 'url'
|
117
|
+
end
|
118
|
+
|
119
|
+
unless d.empty?
|
120
|
+
s << "<dl>"
|
121
|
+
d.each { |key, value|
|
122
|
+
s << "<dt>" << key.to_s << "</dt><dd>" << make_xoxo(value) << "</dd>"
|
123
|
+
}
|
124
|
+
s << "</dl>"
|
125
|
+
end
|
126
|
+
|
127
|
+
when String
|
128
|
+
s << struct
|
129
|
+
|
130
|
+
else
|
131
|
+
s << struct.to_s # too gentle?
|
132
|
+
end
|
133
|
+
|
134
|
+
s
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
class XOXO::Parser # :nodoc:
|
139
|
+
CONTAINER_TAGS = %w{dl ol ul}
|
140
|
+
|
141
|
+
attr_reader :structs
|
142
|
+
|
143
|
+
def initialize(xoxo)
|
144
|
+
@parser = REXML::Parsers::PullParser.new(xoxo)
|
145
|
+
|
146
|
+
@textstack = ['']
|
147
|
+
@xostack = []
|
148
|
+
@structs = []
|
149
|
+
@tags = []
|
150
|
+
end
|
151
|
+
|
152
|
+
def parse
|
153
|
+
while @parser.has_next?
|
154
|
+
res = @parser.pull
|
155
|
+
|
156
|
+
if res.start_element?
|
157
|
+
@tags << res[0]
|
158
|
+
|
159
|
+
case res[0]
|
160
|
+
when "a"
|
161
|
+
attrs = normalize_attrs res[1]
|
162
|
+
attrs['url'] = attrs['href']
|
163
|
+
attrs.delete 'href'
|
164
|
+
push attrs
|
165
|
+
@textstack << ''
|
166
|
+
|
167
|
+
when "dl"
|
168
|
+
push({})
|
169
|
+
|
170
|
+
when "ol", "ul"
|
171
|
+
push []
|
172
|
+
|
173
|
+
when "li", "dt", "dd"
|
174
|
+
@textstack << ''
|
175
|
+
|
176
|
+
end
|
177
|
+
elsif res.end_element?
|
178
|
+
@tags.pop
|
179
|
+
|
180
|
+
case res[0]
|
181
|
+
when "a"
|
182
|
+
val = @textstack.pop
|
183
|
+
unless val.empty?
|
184
|
+
val = '' if @xostack.last['title'] == val
|
185
|
+
val = '' if @xostack.last['url'] == val
|
186
|
+
@xostack.last['text'] = val unless val.empty?
|
187
|
+
end
|
188
|
+
@xostack.pop
|
189
|
+
|
190
|
+
when "dl", "ol", "ul"
|
191
|
+
@xostack.pop
|
192
|
+
|
193
|
+
when "li"
|
194
|
+
val = @textstack.pop
|
195
|
+
while @structs.last != @xostack.last
|
196
|
+
val = @structs.pop
|
197
|
+
@xostack.last << val
|
198
|
+
end
|
199
|
+
@xostack.last << val if val.kind_of? String
|
200
|
+
|
201
|
+
when "dt"
|
202
|
+
# skip
|
203
|
+
|
204
|
+
when "dd"
|
205
|
+
val = @textstack.pop
|
206
|
+
key = @textstack.pop
|
207
|
+
|
208
|
+
val = @structs.pop if @structs.last != @xostack.last
|
209
|
+
@xostack.last[key] = val
|
210
|
+
|
211
|
+
end
|
212
|
+
elsif res.text?
|
213
|
+
unless @tags.empty? || CONTAINER_TAGS.include?(@tags.last)
|
214
|
+
@textstack.last << res[0]
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
self
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def normalize_attrs(attrs)
|
225
|
+
attrs.keys.find_all { |k, v| k != k.downcase }.each { |k, v|
|
226
|
+
v = v.downcase if k == "rel" || k == "type"
|
227
|
+
attrs.delete k
|
228
|
+
attrs[k.downcase] = v
|
229
|
+
}
|
230
|
+
attrs
|
231
|
+
end
|
232
|
+
|
233
|
+
def push(struct)
|
234
|
+
if struct == {} && @structs.last.kind_of?(Hash) &&
|
235
|
+
@structs.last.has_key?('url') &&
|
236
|
+
@structs.last != @xostack.last
|
237
|
+
# put back the <a>-made one for extra def's
|
238
|
+
@xostack << @structs.last
|
239
|
+
else
|
240
|
+
@structs << struct
|
241
|
+
@xostack << @structs.last
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
class Object
|
248
|
+
|
249
|
+
# Dump object as XOXO.
|
250
|
+
|
251
|
+
def to_xoxo(*args)
|
252
|
+
XOXO.dump(self,*args)
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
# _____ _
|
259
|
+
# |_ _|__ ___| |_
|
260
|
+
# | |/ _ \/ __| __|
|
261
|
+
# | | __/\__ \ |_
|
262
|
+
# |_|\___||___/\__|
|
263
|
+
#
|
264
|
+
|
265
|
+
=begin test
|
266
|
+
|
267
|
+
require 'test/unit'
|
268
|
+
|
269
|
+
class TCXOXO < Test::Unit::TestCase
|
270
|
+
|
271
|
+
def test_simple_list
|
272
|
+
l = ['1', '2', '3']
|
273
|
+
html = XOXO.dump(l)
|
274
|
+
assert_equal '<ol class="xoxo"><li>1</li><li>2</li><li>3</li></ol>', html
|
275
|
+
end
|
276
|
+
|
277
|
+
def test_nested_list
|
278
|
+
l = ['1', ['2', '3']]
|
279
|
+
assert_equal '<ol class="xoxo"><li>1</li><li><ol><li>2</li><li>3</li></ol></li></ol>', XOXO.dump(l)
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_hash
|
283
|
+
h = {'test' => '1', 'name' => 'Kevin'}
|
284
|
+
# Changed since Ruby sorts the hash differently.
|
285
|
+
assert_equal '<ol class="xoxo"><li><dl><dt>name</dt><dd>Kevin</dd><dt>test</dt><dd>1</dd></dl></li></ol>', XOXO.dump(h)
|
286
|
+
end
|
287
|
+
|
288
|
+
def test_single_item
|
289
|
+
l = 'test'
|
290
|
+
assert_equal '<ol class="xoxo"><li>test</li></ol>', XOXO.dump(l)
|
291
|
+
end
|
292
|
+
|
293
|
+
def test_wrap_differs
|
294
|
+
l = 'test'
|
295
|
+
html = XOXO.dump(l)
|
296
|
+
html_wrap = XOXO.dump(l, :html_wrap => true)
|
297
|
+
assert_not_equal html, html_wrap
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_wrap_single_item
|
301
|
+
l = 'test'
|
302
|
+
html = XOXO.dump(l, :html_wrap => true)
|
303
|
+
assert_equal <<EOF.strip, html
|
304
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN
|
305
|
+
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
306
|
+
<html xmlns="http://www.w3.org/1999/xhtml"><head profile=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head><body><ol class="xoxo"><li>test</li></ol></body></html>
|
307
|
+
EOF
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_wrap_item_with_css
|
311
|
+
l = 'test'
|
312
|
+
html = XOXO.dump(l, :html_wrap => true, :css => 'reaptest.css')
|
313
|
+
assert_equal <<EOF.strip, html
|
314
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN
|
315
|
+
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
316
|
+
<html xmlns="http://www.w3.org/1999/xhtml"><head profile=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><style type="text/css" >@import "reaptest.css";</style></head><body><ol class="xoxo"><li>test</li></ol></body></html>
|
317
|
+
EOF
|
318
|
+
end
|
319
|
+
|
320
|
+
def test_hash_roundtrip
|
321
|
+
h = {'test' => '1', 'name' => 'Kevin'}
|
322
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_hash_with_url_roundtrip
|
326
|
+
h = {'url' => 'http://example.com', 'name' => 'Kevin'}
|
327
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_nested_hash_roundtrip
|
331
|
+
h = {'test' => '1', 'inner' => {'name' => 'Kevin'}}
|
332
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
333
|
+
end
|
334
|
+
|
335
|
+
def test_nested_hash_with_url_roundtrip
|
336
|
+
h = {'url' => 'http://example.com', 'inner' => {
|
337
|
+
'url' => 'http://slashdot.org', 'name' => 'Kevin'}}
|
338
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
339
|
+
end
|
340
|
+
|
341
|
+
def test_list_round_trip
|
342
|
+
l = ['3', '2', '1']
|
343
|
+
assert_equal l, XOXO.load(XOXO.dump(l))
|
344
|
+
end
|
345
|
+
|
346
|
+
def test_list_of_hashes_round_trip
|
347
|
+
l = ['3', {'a' => '2'}, {'b' => '1', 'c' => '4'}]
|
348
|
+
assert_equal l, XOXO.load(XOXO.dump(l))
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_list_of_lists_round_trip
|
352
|
+
l = ['3', ['a', '2'], ['b', ['1', ['c', '4']]]]
|
353
|
+
assert_equal l, XOXO.load(XOXO.dump(l))
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_hashes_of_lists_roundtrip
|
357
|
+
h = {
|
358
|
+
'test' => ['1', '2'],
|
359
|
+
'name' => 'Kevin',
|
360
|
+
'nestlist' => ['a', ['b', 'c']],
|
361
|
+
'nestdict' => {'e' => '6', 'f' => '7'}
|
362
|
+
}
|
363
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
364
|
+
end
|
365
|
+
|
366
|
+
def test_xoxo_junk_in_containers
|
367
|
+
h = XOXO.load '<ol>bad<li><dl>worse<dt>good</dt><dd>buy</dd> now</dl></li></ol>'
|
368
|
+
assert_equal({'good' => 'buy'}, h)
|
369
|
+
end
|
370
|
+
|
371
|
+
def test_xoxo_junk_in_elements
|
372
|
+
l = XOXO.load '<ol><li>bad<dl><dt>good</dt><dd>buy</dd></dl>worse</li><li>bag<ol><li>OK</li></ol>fish</li></ol>'
|
373
|
+
assert_equal([{'good' => 'buy'}, ['OK']], l)
|
374
|
+
end
|
375
|
+
|
376
|
+
def test_xoxo_with_spaces_and_newlines
|
377
|
+
xoxo_sample = <<EOF.strip
|
378
|
+
<ol class='xoxo'>
|
379
|
+
<li>
|
380
|
+
<dl>
|
381
|
+
<dt>text</dt>
|
382
|
+
<dd>item 1</dd>
|
383
|
+
<dt>description</dt>
|
384
|
+
<dd> This item represents the main point we're trying to make.</dd>
|
385
|
+
<dt>url</dt>
|
386
|
+
<dd>http://example.com/more.xoxo</dd>
|
387
|
+
<dt>title</dt>
|
388
|
+
<dd>title of item 1</dd>
|
389
|
+
<dt>type</dt>
|
390
|
+
<dd>text/xml</dd>
|
391
|
+
<dt>rel</dt>
|
392
|
+
<dd>help</dd>
|
393
|
+
</dl>
|
394
|
+
</li>
|
395
|
+
</ol>
|
396
|
+
EOF
|
397
|
+
h = XOXO.load xoxo_sample
|
398
|
+
h2 = {
|
399
|
+
'text' => 'item 1',
|
400
|
+
'description' => " This item represents the main point we're trying to make.",
|
401
|
+
'url' => 'http://example.com/more.xoxo',
|
402
|
+
'title' => 'title of item 1',
|
403
|
+
'type' => 'text/xml',
|
404
|
+
'rel' => 'help'
|
405
|
+
}
|
406
|
+
assert_equal h2, XOXO.load(xoxo_sample)
|
407
|
+
end
|
408
|
+
|
409
|
+
def test_special_attribute_decoding
|
410
|
+
xoxo_sample = <<EOF.strip
|
411
|
+
<ol class='xoxo'>
|
412
|
+
<li>
|
413
|
+
<dl>
|
414
|
+
<dt>text</dt>
|
415
|
+
<dd>item 1</dd>
|
416
|
+
<dt>url</dt>
|
417
|
+
<dd>http://example.com/more.xoxo</dd>
|
418
|
+
<dt>title</dt>
|
419
|
+
<dd>title of item 1</dd>
|
420
|
+
<dt>type</dt>
|
421
|
+
<dd>text/xml</dd>
|
422
|
+
<dt>rel</dt>
|
423
|
+
<dd>help</dd>
|
424
|
+
</dl>
|
425
|
+
</li>
|
426
|
+
</ol>
|
427
|
+
EOF
|
428
|
+
smart_xoxo_sample = <<EOF.strip
|
429
|
+
<ol class='xoxo'>
|
430
|
+
<li><a href="http://example.com/more.xoxo"
|
431
|
+
title="title of item 1"
|
432
|
+
type="text/xml"
|
433
|
+
rel="help">item 1</a>
|
434
|
+
<!-- note how the "text" property is simply the contents of the <a> element -->
|
435
|
+
</li>
|
436
|
+
</ol>
|
437
|
+
EOF
|
438
|
+
assert_equal XOXO.load(xoxo_sample), XOXO.load(smart_xoxo_sample)
|
439
|
+
end
|
440
|
+
|
441
|
+
def test_special_attribute_and_dl_decoding
|
442
|
+
xoxo_sample = <<EOF.strip
|
443
|
+
<ol class="xoxo">
|
444
|
+
<li>
|
445
|
+
<dl>
|
446
|
+
<dt>text</dt>
|
447
|
+
<dd>item 1</dd>
|
448
|
+
<dt>description</dt>
|
449
|
+
<dd> This item represents the main point we're trying to make.</dd>
|
450
|
+
<dt>url</dt>
|
451
|
+
<dd>http://example.com/more.xoxo</dd>
|
452
|
+
<dt>title</dt>
|
453
|
+
<dd>title of item 1</dd>
|
454
|
+
<dt>type</dt>
|
455
|
+
<dd>text/xml</dd>
|
456
|
+
<dt>rel</dt>
|
457
|
+
<dd>help</dd>
|
458
|
+
</dl>
|
459
|
+
</li>
|
460
|
+
</ol>
|
461
|
+
EOF
|
462
|
+
smart_xoxo_sample = <<EOF.strip
|
463
|
+
<ol class="xoxo">
|
464
|
+
<li><a href="http://example.com/more.xoxo"
|
465
|
+
title="title of item 1"
|
466
|
+
type="text/xml"
|
467
|
+
rel="help">item 1</a>
|
468
|
+
<!-- note how the "text" property is simply the contents of the <a> element -->
|
469
|
+
<dl>
|
470
|
+
<dt>description</dt>
|
471
|
+
<dd> This item represents the main point we're trying to make.</dd>
|
472
|
+
</dl>
|
473
|
+
</li>
|
474
|
+
</ol>
|
475
|
+
EOF
|
476
|
+
assert_equal XOXO.load(xoxo_sample), XOXO.load(smart_xoxo_sample)
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_special_attribute_encode
|
480
|
+
h = {
|
481
|
+
'url' => 'http://example.com/more.xoxo',
|
482
|
+
'title' => 'sample url',
|
483
|
+
'type' => "text/xml",
|
484
|
+
'rel' => 'help',
|
485
|
+
'text' => 'an example'
|
486
|
+
}
|
487
|
+
assert_equal '<ol class="xoxo"><li><a href="http://example.com/more.xoxo" title="sample url" rel="help" type="text/xml" >an example</a></li></ol>', XOXO.dump(h)
|
488
|
+
end
|
489
|
+
|
490
|
+
def test_special_attribute_roundtrip_full
|
491
|
+
h = {
|
492
|
+
'url' => 'http://example.com/more.xoxo',
|
493
|
+
'title' => 'sample url',
|
494
|
+
'type' => "text/xml",
|
495
|
+
'rel' => 'help',
|
496
|
+
'text' => 'an example'
|
497
|
+
}
|
498
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
499
|
+
end
|
500
|
+
|
501
|
+
def test_special_attribute_roundtrip_no_text
|
502
|
+
h = {
|
503
|
+
'url' => 'http://example.com/more.xoxo',
|
504
|
+
'title' => 'sample url',
|
505
|
+
'type' => "text/xml",
|
506
|
+
'rel' => 'help'
|
507
|
+
}
|
508
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
509
|
+
end
|
510
|
+
|
511
|
+
def test_special_attribute_roundtrip_no_text_or_title
|
512
|
+
h = {'url' => 'http://example.com/more.xoxo'}
|
513
|
+
assert_equal h, XOXO.load(XOXO.dump(h))
|
514
|
+
end
|
515
|
+
|
516
|
+
def test_attention_roundtrip
|
517
|
+
kmattn = <<EOF.strip
|
518
|
+
<ol class="xoxo"><li><a href="http://www.boingboing.net/" title="Boing Boing Blog" >Boing Boing Blog</a><dl><dt>alturls</dt><dd><ol><li><a href="http://boingboing.net/rss.xml" >xmlurl</a></li></ol></dd><dt>description</dt><dd>Boing Boing Blog</dd></dl></li><li><a href="http://www.financialcryptography.com/" title="Financial Cryptography" >Financial Cryptography</a><dl><dt>alturls</dt><dd><ol><li><a href="http://www.financialcryptography.com/mt/index.rdf" >xmlurl</a></li></ol></dd><dt>description</dt><dd>Financial Cryptography</dd></dl></li><li><a href="http://hublog.hubmed.org/" title="HubLog" >HubLog</a><dl><dt>alturls</dt><dd><ol><li><a href="http://hublog.hubmed.org/index.xml" >xmlurl</a></li><li><a href="http://hublog.hubmed.org/foaf.rdf" >foafurl</a></li></ol></dd><dt>description</dt><dd>HubLog</dd></dl></li></ol>
|
519
|
+
EOF
|
520
|
+
assert_equal kmattn, XOXO.dump(XOXO.load(kmattn))
|
521
|
+
assert_equal XOXO.load(kmattn), XOXO.load(XOXO.dump(XOXO.load(kmattn)))
|
522
|
+
assert_equal XOXO.dump(XOXO.load(kmattn)),
|
523
|
+
XOXO.dump(XOXO.load(XOXO.dump(XOXO.load(kmattn))))
|
524
|
+
end
|
525
|
+
|
526
|
+
def test_unicode_roundtrip
|
527
|
+
unicode = "Tantek \xc3\x87elik and a snowman \xe2\x98\x83"
|
528
|
+
assert_equal unicode, XOXO.load(XOXO.dump(unicode))
|
529
|
+
end
|
530
|
+
|
531
|
+
# TBD: Implement proper encodings.
|
532
|
+
#
|
533
|
+
# def test_utf8_roundtrip
|
534
|
+
# end
|
535
|
+
# def test_windows1252_roundtrip
|
536
|
+
# end
|
537
|
+
end
|
538
|
+
|
539
|
+
=end
|
540
|
+
|
541
|
+
|