xoxo 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY ADDED
@@ -0,0 +1,14 @@
1
+ = HISTORY
2
+
3
+ == 1.0.0 // 2009-07-06
4
+
5
+ This is essentially the XOXO library written Christian Neukirchen.
6
+ While the library has been distributed as part of Facets for some
7
+ time, there is no separate gem avaialbe for it. So this then is
8
+ that stand-alone release. It differs from the original only in
9
+ that it provides #to_xoxo.
10
+
11
+ * 1 Major Enhancement
12
+
13
+ * Happy Birthday!
14
+
data/LICENSE ADDED
@@ -0,0 +1,61 @@
1
+ = RUBY LICENSE
2
+
3
+ xoxo.rb is copyrighted free software by Christian Neukirchen <chneukirchen@gmail.com>.
4
+ You can redistribute it and/or modify it under either the terms of the GPL
5
+ (see COPYING file), or the conditions below:
6
+
7
+ 1. You may make and give away verbatim copies of the source form of the
8
+ software without restriction, provided that you duplicate all of the
9
+ original copyright notices and associated disclaimers.
10
+
11
+ 2. You may modify your copy of the software in any way, provided that
12
+ you do at least ONE of the following:
13
+
14
+ a) place your modifications in the Public Domain or otherwise
15
+ make them Freely Available, such as by posting said
16
+ modifications to Usenet or an equivalent medium, or by allowing
17
+ the author to include your modifications in the software.
18
+
19
+ b) use the modified software only within your corporation or
20
+ organization.
21
+
22
+ c) rename any non-standard executables so the names do not conflict
23
+ with standard executables, which must also be provided.
24
+
25
+ d) make other distribution arrangements with the author.
26
+
27
+ 3. You may distribute the software in object code or executable
28
+ form, provided that you do at least ONE of the following:
29
+
30
+ a) distribute the executables and library files of the software,
31
+ together with instructions (in the manual page or equivalent)
32
+ on where to get the original distribution.
33
+
34
+ b) accompany the distribution with the machine-readable source of
35
+ the software.
36
+
37
+ c) give non-standard executables non-standard names, with
38
+ instructions on where to get the original software distribution.
39
+
40
+ d) make other distribution arrangements with the author.
41
+
42
+ 4. You may modify and include the part of the software into any other
43
+ software (possibly commercial). But some files in the distribution
44
+ are not written by the author, so that they are not under this terms.
45
+
46
+ They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
47
+ files under the ./missing directory. See each file for the copying
48
+ condition.
49
+
50
+ 5. The scripts and library files supplied as input to or produced as
51
+ output from the software do not automatically fall under the
52
+ copyright of the software, but belong to whomever generated them,
53
+ and may be sold commercially, and may be aggregated with this
54
+ software.
55
+
56
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
57
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
58
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59
+ PURPOSE.
60
+
61
+
@@ -0,0 +1,20 @@
1
+ test
2
+ test/test_xoxo.rb
3
+ RELEASE
4
+ LICENSE
5
+ README
6
+ HISTORY
7
+ meta
8
+ meta/created
9
+ meta/repository
10
+ meta/homepage
11
+ meta/summary
12
+ meta/abstract
13
+ meta/package
14
+ meta/released
15
+ meta/version
16
+ meta/license
17
+ meta/authors
18
+ meta/project
19
+ lib
20
+ lib/xoxo.rb
data/README ADDED
@@ -0,0 +1,58 @@
1
+ = XOXO
2
+
3
+ * http://death.rubyforge.org
4
+ * http://death.rubyforge.org/xoxo
5
+ * http://chneukirchen.org/repos/xoxo-rb/
6
+
7
+
8
+ == DESCRIPTION
9
+
10
+ XOXO is a Ruby XOXO parser and generator. It provides
11
+ a Ruby API similar to Marshal and YAML (though more
12
+ specific) to load and dump XOXO[http://microformats.org/wiki/xoxo],
13
+ an simple, open outline format written in standard XHTML and
14
+ suitable for embedding in (X)HTML, Atom, RSS, and arbitrary XML.
15
+
16
+
17
+ == FEATURES/ISSUES
18
+
19
+ * Uses REXML's pull parser.
20
+ * Serialize any object via to_xoxo.
21
+
22
+
23
+ == RELEASE NOTES
24
+
25
+ Please see RELEASE file.
26
+
27
+
28
+ == SYNOPSIS
29
+
30
+ Simple way to generate XOXO.
31
+
32
+ obj.to_xoxo
33
+
34
+
35
+ == HOW TO INSTALL
36
+
37
+ To install with RubyGems simply open a console and type:
38
+
39
+ gem install xoxo
40
+
41
+ Local installation requires Setup.rb (gem install setup),
42
+ then download the tarball package and type:
43
+
44
+ tar -xvzf xoxo-1.0.0.tgz
45
+ cd xoxo-1.0.0
46
+ sudo setup.rb all
47
+
48
+ Windows users use 'ruby setup.rb all'.
49
+
50
+
51
+ == COPYING
52
+
53
+ Copyright (C) 2006 Christian Neukirchen
54
+
55
+ This program is ditributed unser the terms of the Ruby license.
56
+
57
+ See LICENSE file for details.
58
+
data/RELEASE ADDED
@@ -0,0 +1,14 @@
1
+ = RELEASE NOTES
2
+
3
+ This is essentially the XOXO library written Christian Neukirchen.
4
+ While the library has been distributed as part of Facets for some
5
+ time, there is no separate gem avaialbe for it. So this then is
6
+ that stand-alone release. It differs from the original only in
7
+ that it provides #to_xoxo.
8
+
9
+ ### 1.0.0 // 2009-07-06
10
+
11
+ * 1 Major Enhancement
12
+
13
+ * Happy Birthday!
14
+
@@ -0,0 +1,241 @@
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
+ # See original version at http://chneukirchen.org/repos/xoxo-rb/.
15
+
16
+ require 'rexml/parsers/pullparser'
17
+
18
+ # XOXO is a Ruby XOXO parser and generator. It provides
19
+ # a Ruby API similar to Marshal and YAML (though more
20
+ # specific) to load and dump XOXO[http://microformats.org/wiki/xoxo],
21
+ # an simple, open outline format written in standard XHTML and
22
+ # suitable for embedding in (X)HTML, Atom, RSS, and arbitrary XML.
23
+ #
24
+ module XOXO
25
+ # xoxo.rb version number
26
+ #VERSION = "1.0.0"
27
+
28
+ # Load and return a XOXO structure from the String, IO or StringIO or _xoxo_.
29
+ #
30
+ def self.load(xoxo)
31
+ structs = Parser.new(xoxo).parse.structs
32
+ while structs.kind_of?(Array) && structs.size == 1
33
+ structs = structs.first
34
+ end
35
+ structs
36
+ end
37
+
38
+ # Return a XOXO string corresponding to the Ruby object +struct+,
39
+ # translated to the following rules:
40
+ #
41
+ # * Arrays become ordered lists <tt><ol></tt>.
42
+ # * Hashes become definition lists <tt><dl></tt>, keys are
43
+ # stringified with +to_s+.
44
+ # * Everything else becomes stringified with +to_s+ and wrapped in
45
+ # appropriate list elements (<tt><li></tt> or <tt><dt></tt>/<tt><dd></tt>).
46
+ #
47
+ # Additionally, you can pass these options on the _options_ hash:
48
+ # <tt>:html_wrap</tt> => +true+:: Wrap the XOXO with a basic XHTML 1.0
49
+ # Transitional header.
50
+ # <tt>:css</tt> => _css_:: Reference _css_ as stylesheet for the
51
+ # wrapped XOXO document.
52
+ #
53
+ def self.dump(struct, options={})
54
+ struct = [struct] unless struct.kind_of? Array
55
+
56
+ if options[:html_wrap]
57
+ result = <<EOF.strip
58
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN
59
+ http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
60
+ <html xmlns="http://www.w3.org/1999/xhtml"><head profile=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
61
+ EOF
62
+ if options[:css]
63
+ result << %Q[<style type="text/css" >@import "#{options[:css]}";</style>]
64
+ end
65
+
66
+ result << "</head><body>" << make_xoxo(struct, 'xoxo') << "</body></html>"
67
+ else
68
+ result = make_xoxo(struct, 'xoxo')
69
+ end
70
+
71
+ result
72
+ end
73
+
74
+ private
75
+
76
+ def self.make_xoxo(struct, class_name=nil)
77
+ s = ''
78
+ case struct
79
+ when Array
80
+ if class_name
81
+ s << %Q[<ol class="#{class_name}">]
82
+ else
83
+ s << "<ol>"
84
+ end
85
+ struct.each { |item|
86
+ s << "<li>" << make_xoxo(item) << "</li>"
87
+ }
88
+ s << "</ol>"
89
+
90
+ when Hash
91
+ d = struct.dup
92
+ if d.has_key? 'url'
93
+ s << '<a href="' << d['url'].to_s << '" '
94
+ text = d.fetch('text') { d.fetch('title', d['url']) }
95
+ %w[title rel type].each { |tag|
96
+ if d.has_key? tag
97
+ s << tag.to_s << '="' << make_xoxo(d.delete(tag)) << '" '
98
+ end
99
+ }
100
+ s << '>' << make_xoxo(text) << '</a>'
101
+ d.delete 'text'
102
+ d.delete 'url'
103
+ end
104
+
105
+ unless d.empty?
106
+ s << "<dl>"
107
+ d.each { |key, value|
108
+ s << "<dt>" << key.to_s << "</dt><dd>" << make_xoxo(value) << "</dd>"
109
+ }
110
+ s << "</dl>"
111
+ end
112
+
113
+ when String
114
+ s << struct
115
+
116
+ else
117
+ s << struct.to_s # too gentle?
118
+ end
119
+
120
+ s
121
+ end
122
+ end
123
+
124
+ class XOXO::Parser # :nodoc:
125
+ CONTAINER_TAGS = %w{dl ol ul}
126
+
127
+ attr_reader :structs
128
+
129
+ def initialize(xoxo)
130
+ @parser = REXML::Parsers::PullParser.new(xoxo)
131
+
132
+ @textstack = ['']
133
+ @xostack = []
134
+ @structs = []
135
+ @tags = []
136
+ end
137
+
138
+ def parse
139
+ while @parser.has_next?
140
+ res = @parser.pull
141
+
142
+ if res.start_element?
143
+ @tags << res[0]
144
+
145
+ case res[0]
146
+ when "a"
147
+ attrs = normalize_attrs res[1]
148
+ attrs['url'] = attrs['href']
149
+ attrs.delete 'href'
150
+ push attrs
151
+ @textstack << ''
152
+
153
+ when "dl"
154
+ push({})
155
+
156
+ when "ol", "ul"
157
+ push []
158
+
159
+ when "li", "dt", "dd"
160
+ @textstack << ''
161
+
162
+ end
163
+ elsif res.end_element?
164
+ @tags.pop
165
+
166
+ case res[0]
167
+ when "a"
168
+ val = @textstack.pop
169
+ unless val.empty?
170
+ val = '' if @xostack.last['title'] == val
171
+ val = '' if @xostack.last['url'] == val
172
+ @xostack.last['text'] = val unless val.empty?
173
+ end
174
+ @xostack.pop
175
+
176
+ when "dl", "ol", "ul"
177
+ @xostack.pop
178
+
179
+ when "li"
180
+ val = @textstack.pop
181
+ while @structs.last != @xostack.last
182
+ val = @structs.pop
183
+ @xostack.last << val
184
+ end
185
+ @xostack.last << val if val.kind_of? String
186
+
187
+ when "dt"
188
+ # skip
189
+
190
+ when "dd"
191
+ val = @textstack.pop
192
+ key = @textstack.pop
193
+
194
+ val = @structs.pop if @structs.last != @xostack.last
195
+ @xostack.last[key] = val
196
+
197
+ end
198
+ elsif res.text?
199
+ unless @tags.empty? || CONTAINER_TAGS.include?(@tags.last)
200
+ @textstack.last << res[0]
201
+ end
202
+ end
203
+ end
204
+
205
+ self
206
+ end
207
+
208
+ private
209
+
210
+ def normalize_attrs(attrs)
211
+ attrs.keys.find_all { |k, v| k != k.downcase }.each { |k, v|
212
+ v = v.downcase if k == "rel" || k == "type"
213
+ attrs.delete k
214
+ attrs[k.downcase] = v
215
+ }
216
+ attrs
217
+ end
218
+
219
+ def push(struct)
220
+ if struct == {} && @structs.last.kind_of?(Hash) &&
221
+ @structs.last.has_key?('url') &&
222
+ @structs.last != @xostack.last
223
+ # put back the <a>-made one for extra def's
224
+ @xostack << @structs.last
225
+ else
226
+ @structs << struct
227
+ @xostack << @structs.last
228
+ end
229
+ end
230
+ end
231
+
232
+
233
+ class Object
234
+
235
+ # Dump object as XOXO.
236
+
237
+ def to_xoxo(*args)
238
+ XOXO.dump(self,*args)
239
+ end
240
+
241
+ end
@@ -0,0 +1,5 @@
1
+ XOXO is a Ruby XOXO parser and generator. It provides
2
+ a Ruby API similar to Marshal and YAML (though more
3
+ specific) to load and dump XOXO[http://microformats.org/wiki/xoxo],
4
+ an simple, open outline format written in standard XHTML and
5
+ suitable for embedding in (X)HTML, Atom, RSS, and arbitrary XML.
@@ -0,0 +1 @@
1
+ Christian Neukirchen <chneukirchen@gmail.com>
@@ -0,0 +1 @@
1
+ 2006-01-01
@@ -0,0 +1 @@
1
+ http://death.rubyforge.org/
@@ -0,0 +1 @@
1
+ Ruby
@@ -0,0 +1 @@
1
+ xoxo
@@ -0,0 +1 @@
1
+ death
@@ -0,0 +1 @@
1
+ 2009-07-06
@@ -0,0 +1 @@
1
+ svn://rubyforge.org/var/svn/death/xoxo
@@ -0,0 +1 @@
1
+ XOXO Parser and Generator
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,272 @@
1
+ require 'xoxo'
2
+ require 'test/unit'
3
+
4
+ class TC_XOXO < Test::Unit::TestCase
5
+
6
+ def test_simple_list
7
+ l = ['1', '2', '3']
8
+ html = XOXO.dump(l)
9
+ assert_equal '<ol class="xoxo"><li>1</li><li>2</li><li>3</li></ol>', html
10
+ end
11
+
12
+ def test_nested_list
13
+ l = ['1', ['2', '3']]
14
+ assert_equal '<ol class="xoxo"><li>1</li><li><ol><li>2</li><li>3</li></ol></li></ol>', XOXO.dump(l)
15
+ end
16
+
17
+ def test_hash
18
+ h = {'test' => '1', 'name' => 'Kevin'}
19
+ # Changed since Ruby sorts the hash differently.
20
+ 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)
21
+ end
22
+
23
+ def test_single_item
24
+ l = 'test'
25
+ assert_equal '<ol class="xoxo"><li>test</li></ol>', XOXO.dump(l)
26
+ end
27
+
28
+ def test_wrap_differs
29
+ l = 'test'
30
+ html = XOXO.dump(l)
31
+ html_wrap = XOXO.dump(l, :html_wrap => true)
32
+ assert_not_equal html, html_wrap
33
+ end
34
+
35
+ def test_wrap_single_item
36
+ l = 'test'
37
+ html = XOXO.dump(l, :html_wrap => true)
38
+ assert_equal <<EOF.strip, html
39
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN
40
+ http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
41
+ <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>
42
+ EOF
43
+ end
44
+
45
+ def test_wrap_item_with_css
46
+ l = 'test'
47
+ html = XOXO.dump(l, :html_wrap => true, :css => 'reaptest.css')
48
+ assert_equal <<EOF.strip, html
49
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN
50
+ http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
51
+ <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>
52
+ EOF
53
+ end
54
+
55
+ def test_hash_roundtrip
56
+ h = {'test' => '1', 'name' => 'Kevin'}
57
+ assert_equal h, XOXO.load(XOXO.dump(h))
58
+ end
59
+
60
+ def test_hash_with_url_roundtrip
61
+ h = {'url' => 'http://example.com', 'name' => 'Kevin'}
62
+ assert_equal h, XOXO.load(XOXO.dump(h))
63
+ end
64
+
65
+ def test_nested_hash_roundtrip
66
+ h = {'test' => '1', 'inner' => {'name' => 'Kevin'}}
67
+ assert_equal h, XOXO.load(XOXO.dump(h))
68
+ end
69
+
70
+ def test_nested_hash_with_url_roundtrip
71
+ h = {'url' => 'http://example.com', 'inner' => {
72
+ 'url' => 'http://slashdot.org', 'name' => 'Kevin'}}
73
+ assert_equal h, XOXO.load(XOXO.dump(h))
74
+ end
75
+
76
+ def test_list_round_trip
77
+ l = ['3', '2', '1']
78
+ assert_equal l, XOXO.load(XOXO.dump(l))
79
+ end
80
+
81
+ def test_list_of_hashes_round_trip
82
+ l = ['3', {'a' => '2'}, {'b' => '1', 'c' => '4'}]
83
+ assert_equal l, XOXO.load(XOXO.dump(l))
84
+ end
85
+
86
+ def test_list_of_lists_round_trip
87
+ l = ['3', ['a', '2'], ['b', ['1', ['c', '4']]]]
88
+ assert_equal l, XOXO.load(XOXO.dump(l))
89
+ end
90
+
91
+ def test_hashes_of_lists_roundtrip
92
+ h = {
93
+ 'test' => ['1', '2'],
94
+ 'name' => 'Kevin',
95
+ 'nestlist' => ['a', ['b', 'c']],
96
+ 'nestdict' => {'e' => '6', 'f' => '7'}
97
+ }
98
+ assert_equal h, XOXO.load(XOXO.dump(h))
99
+ end
100
+
101
+ def test_xoxo_junk_in_containers
102
+ h = XOXO.load '<ol>bad<li><dl>worse<dt>good</dt><dd>buy</dd> now</dl></li></ol>'
103
+ assert_equal({'good' => 'buy'}, h)
104
+ end
105
+
106
+ def test_xoxo_junk_in_elements
107
+ 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>'
108
+ assert_equal([{'good' => 'buy'}, ['OK']], l)
109
+ end
110
+
111
+ def test_xoxo_with_spaces_and_newlines
112
+ xoxo_sample = <<EOF.strip
113
+ <ol class='xoxo'>
114
+ <li>
115
+ <dl>
116
+ <dt>text</dt>
117
+ <dd>item 1</dd>
118
+ <dt>description</dt>
119
+ <dd> This item represents the main point we're trying to make.</dd>
120
+ <dt>url</dt>
121
+ <dd>http://example.com/more.xoxo</dd>
122
+ <dt>title</dt>
123
+ <dd>title of item 1</dd>
124
+ <dt>type</dt>
125
+ <dd>text/xml</dd>
126
+ <dt>rel</dt>
127
+ <dd>help</dd>
128
+ </dl>
129
+ </li>
130
+ </ol>
131
+ EOF
132
+ h = XOXO.load xoxo_sample
133
+ h2 = {
134
+ 'text' => 'item 1',
135
+ 'description' => " This item represents the main point we're trying to make.",
136
+ 'url' => 'http://example.com/more.xoxo',
137
+ 'title' => 'title of item 1',
138
+ 'type' => 'text/xml',
139
+ 'rel' => 'help'
140
+ }
141
+ assert_equal h2, XOXO.load(xoxo_sample)
142
+ end
143
+
144
+ def test_special_attribute_decoding
145
+ xoxo_sample = <<EOF.strip
146
+ <ol class='xoxo'>
147
+ <li>
148
+ <dl>
149
+ <dt>text</dt>
150
+ <dd>item 1</dd>
151
+ <dt>url</dt>
152
+ <dd>http://example.com/more.xoxo</dd>
153
+ <dt>title</dt>
154
+ <dd>title of item 1</dd>
155
+ <dt>type</dt>
156
+ <dd>text/xml</dd>
157
+ <dt>rel</dt>
158
+ <dd>help</dd>
159
+ </dl>
160
+ </li>
161
+ </ol>
162
+ EOF
163
+ smart_xoxo_sample = <<EOF.strip
164
+ <ol class='xoxo'>
165
+ <li><a href="http://example.com/more.xoxo"
166
+ title="title of item 1"
167
+ type="text/xml"
168
+ rel="help">item 1</a>
169
+ <!-- note how the "text" property is simply the contents of the <a> element -->
170
+ </li>
171
+ </ol>
172
+ EOF
173
+ assert_equal XOXO.load(xoxo_sample), XOXO.load(smart_xoxo_sample)
174
+ end
175
+
176
+ def test_special_attribute_and_dl_decoding
177
+ xoxo_sample = <<EOF.strip
178
+ <ol class="xoxo">
179
+ <li>
180
+ <dl>
181
+ <dt>text</dt>
182
+ <dd>item 1</dd>
183
+ <dt>description</dt>
184
+ <dd> This item represents the main point we're trying to make.</dd>
185
+ <dt>url</dt>
186
+ <dd>http://example.com/more.xoxo</dd>
187
+ <dt>title</dt>
188
+ <dd>title of item 1</dd>
189
+ <dt>type</dt>
190
+ <dd>text/xml</dd>
191
+ <dt>rel</dt>
192
+ <dd>help</dd>
193
+ </dl>
194
+ </li>
195
+ </ol>
196
+ EOF
197
+ smart_xoxo_sample = <<EOF.strip
198
+ <ol class="xoxo">
199
+ <li><a href="http://example.com/more.xoxo"
200
+ title="title of item 1"
201
+ type="text/xml"
202
+ rel="help">item 1</a>
203
+ <!-- note how the "text" property is simply the contents of the <a> element -->
204
+ <dl>
205
+ <dt>description</dt>
206
+ <dd> This item represents the main point we're trying to make.</dd>
207
+ </dl>
208
+ </li>
209
+ </ol>
210
+ EOF
211
+ assert_equal XOXO.load(xoxo_sample), XOXO.load(smart_xoxo_sample)
212
+ end
213
+
214
+ def test_special_attribute_encode
215
+ h = {
216
+ 'url' => 'http://example.com/more.xoxo',
217
+ 'title' => 'sample url',
218
+ 'type' => "text/xml",
219
+ 'rel' => 'help',
220
+ 'text' => 'an example'
221
+ }
222
+ 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)
223
+ end
224
+
225
+ def test_special_attribute_roundtrip_full
226
+ h = {
227
+ 'url' => 'http://example.com/more.xoxo',
228
+ 'title' => 'sample url',
229
+ 'type' => "text/xml",
230
+ 'rel' => 'help',
231
+ 'text' => 'an example'
232
+ }
233
+ assert_equal h, XOXO.load(XOXO.dump(h))
234
+ end
235
+
236
+ def test_special_attribute_roundtrip_no_text
237
+ h = {
238
+ 'url' => 'http://example.com/more.xoxo',
239
+ 'title' => 'sample url',
240
+ 'type' => "text/xml",
241
+ 'rel' => 'help'
242
+ }
243
+ assert_equal h, XOXO.load(XOXO.dump(h))
244
+ end
245
+
246
+ def test_special_attribute_roundtrip_no_text_or_title
247
+ h = {'url' => 'http://example.com/more.xoxo'}
248
+ assert_equal h, XOXO.load(XOXO.dump(h))
249
+ end
250
+
251
+ def test_attention_roundtrip
252
+ kmattn = <<EOF.strip
253
+ <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>
254
+ EOF
255
+ assert_equal kmattn, XOXO.dump(XOXO.load(kmattn))
256
+ assert_equal XOXO.load(kmattn), XOXO.load(XOXO.dump(XOXO.load(kmattn)))
257
+ assert_equal XOXO.dump(XOXO.load(kmattn)),
258
+ XOXO.dump(XOXO.load(XOXO.dump(XOXO.load(kmattn))))
259
+ end
260
+
261
+ def test_unicode_roundtrip
262
+ unicode = "Tantek \xc3\x87elik and a snowman \xe2\x98\x83"
263
+ assert_equal unicode, XOXO.load(XOXO.dump(unicode))
264
+ end
265
+
266
+ # TBD: Implement proper encodings.
267
+ #
268
+ # def test_utf8_roundtrip
269
+ # end
270
+ # def test_windows1252_roundtrip
271
+ # end
272
+ end
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xoxo
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Christian Neukirchen <chneukirchen@gmail.com>
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-07-06 00:00:00 -04:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: |-
17
+ XOXO is a Ruby XOXO parser and generator. It provides
18
+ a Ruby API similar to Marshal and YAML (though more
19
+ specific) to load and dump XOXO[http://microformats.org/wiki/xoxo],
20
+ an simple, open outline format written in standard XHTML and
21
+ suitable for embedding in (X)HTML, Atom, RSS, and arbitrary XML.
22
+ email: chneukirchen@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ - MANIFEST
30
+ - RELEASE
31
+ - LICENSE
32
+ - HISTORY
33
+ files:
34
+ - test/test_xoxo.rb
35
+ - RELEASE
36
+ - LICENSE
37
+ - README
38
+ - HISTORY
39
+ - meta/created
40
+ - meta/repository
41
+ - meta/homepage
42
+ - meta/summary
43
+ - meta/abstract
44
+ - meta/package
45
+ - meta/released
46
+ - meta/version
47
+ - meta/license
48
+ - meta/authors
49
+ - meta/project
50
+ - lib/xoxo.rb
51
+ - MANIFEST
52
+ has_rdoc: true
53
+ homepage: http://death.rubyforge.org/
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --inline-source
59
+ - --title
60
+ - xoxo api
61
+ - --main
62
+ - README
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ version:
77
+ requirements: []
78
+
79
+ rubyforge_project: death
80
+ rubygems_version: 1.3.4
81
+ signing_key:
82
+ specification_version: 3
83
+ summary: XOXO is a Ruby XOXO parser and generator.
84
+ test_files:
85
+ - test/test_xoxo.rb