opml 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 Joshua Peek
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,7 @@
1
+ Opml
2
+ ====
3
+
4
+ A simple wrapper for parsing OPML files.
5
+
6
+
7
+ Copyright (c) 2007 Joshua Peek, released under the MIT license
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/packagetask'
4
+ require 'rake/gempackagetask'
5
+ require File.join(File.dirname(__FILE__), 'lib', 'opml')
6
+
7
+ PKG_NAME = 'opml'
8
+ PKG_VERSION = Opml::VERSION::STRING
9
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
10
+ dist_dirs = [ "lib", "test", "examples", "dev-utils" ]
11
+
12
+ spec = Gem::Specification.new do |s|
13
+ s.name = PKG_NAME
14
+ s.version = PKG_VERSION
15
+ s.summary = "A simple wrapper for parsing OPML files."
16
+
17
+ s.files = [ "MIT-LICENSE", "Rakefile", "README" ]
18
+ %w( lib spec ).each do |dir|
19
+ s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
20
+ end
21
+
22
+ s.require_path = 'lib'
23
+ s.autorequire = 'opml'
24
+
25
+ s.author = "Joshua Peek"
26
+ s.email = "josh@joshpeek.com"
27
+ s.homepage = "http://rubyforge.org/projects/opml/"
28
+ end
29
+
30
+ Rake::GemPackageTask.new(spec) do |p|
31
+ p.gem_spec = spec
32
+ p.need_zip = true
33
+ p.need_tar = true
34
+ end
@@ -0,0 +1,99 @@
1
+ require 'rexml/document'
2
+
3
+ require 'rubygems'
4
+ require 'active_support'
5
+
6
+ class Opml
7
+ module VERSION #:nodoc:
8
+ MAJOR = 1
9
+ MINOR = 0
10
+ TINY = 0
11
+
12
+ STRING = [MAJOR, MINOR, TINY].join('.')
13
+ end
14
+
15
+ class Outline
16
+ attr_accessor :attributes, :outlines
17
+
18
+ def initialize(element)
19
+ @attributes = map_attributes_to_hash(element.attributes)
20
+ @outlines = element.elements.map { |element| Outline.new(element) }
21
+ end
22
+
23
+ def flatten
24
+ @flatten ||= @outlines.map(&:flatten).unshift(self)
25
+ end
26
+
27
+ def to_s
28
+ @to_s ||= attributes['text'] || super
29
+ end
30
+
31
+ def respond_to?(method)
32
+ return true if attributes[method.to_s]
33
+ super
34
+ end
35
+
36
+ def method_missing(method, *args, &block)
37
+ attributes[method.to_s] || super
38
+ end
39
+
40
+ private
41
+ def map_attributes_to_hash(attributes)
42
+ returning({}) do |hash|
43
+ attributes.each { |key, value| hash[key.underscore] = value }
44
+ end
45
+ end
46
+ end
47
+
48
+ attr_reader :outlines
49
+
50
+ def initialize(xml)
51
+ @doc = REXML::Document.new(xml)
52
+
53
+ parse_head_elements :title, :owner_name, :owner_email
54
+ parse_head_elements :date_created, :date_modified, :with => Proc.new { |e| Time.parse(e) }
55
+
56
+ @outlines = document_body ? initialize_outlines_from_document_body : []
57
+ end
58
+
59
+ def flatten
60
+ @flatten ||= @outlines.map(&:flatten).flatten
61
+ end
62
+
63
+ private
64
+ def parse_head_elements(*elements)
65
+ options = elements.last.is_a?(Hash) ? elements.pop : {}
66
+ elements.each do |attribute|
67
+ define_head_attr_reader(attribute)
68
+ set_head_value(attribute, options)
69
+ end
70
+ end
71
+
72
+ def define_head_attr_reader(attribute)
73
+ self.class.send(:attr_reader, attribute)
74
+ end
75
+
76
+ def get_head_value(attribute)
77
+ if element = @doc.elements["opml/head/#{attribute.to_s.camelize(:lower)}"]
78
+ element.text
79
+ end
80
+ end
81
+
82
+ def parse_value(value, options)
83
+ options[:with] ? options[:with].call(value) : value
84
+ end
85
+
86
+ def set_head_value(attribute, options)
87
+ if value = get_head_value(attribute)
88
+ instance_variable_set("@#{attribute}", parse_value(value, options))
89
+ end
90
+ end
91
+
92
+ def document_body
93
+ @document_body ||= @doc.elements['opml/body']
94
+ end
95
+
96
+ def initialize_outlines_from_document_body
97
+ document_body.elements.map { |element| Outline.new(element) }
98
+ end
99
+ end
@@ -0,0 +1,45 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <opml version="1.0">
3
+ <head>
4
+ <title>playlist.xml</title>
5
+ <dateCreated>Thu, 27 Jul 2000 03:24:18 GMT</dateCreated>
6
+ <dateModified>Fri, 15 Sep 2000 09:01:23 GMT</dateModified>
7
+ <ownerName>Dave Winer</ownerName>
8
+ <ownerEmail>dave@userland.com</ownerEmail>
9
+ <expansionState>1,3,17</expansionState>
10
+ <vertScrollState>1</vertScrollState>
11
+ <windowTop>164</windowTop>
12
+ <windowLeft>50</windowLeft>
13
+ <windowBottom>672</windowBottom>
14
+ <windowRight>455</windowRight>
15
+ </head>
16
+ <body>
17
+ <outline text="Background">
18
+ <outline text="I've started to note the songs I was listening to as I was writing DaveNet pieces. "/>
19
+ </outline>
20
+ <outline text="The Last Napster Sunday?">
21
+ <outline text="Heart of Glass.mp3" type="song" f="Blondie - Heart of Glass.mp3"/>
22
+ <outline text="Manic Monday.mp3" type="song" f="Bangles - Manic Monday.mp3"/>
23
+ <outline text="Everybody Have Fun Tonight.mp3" type="song" f="Wang Chung - Everybody Have Fun Tonight.mp3"/>
24
+ <outline text="She Blinded Me With Science.mp3" type="song" f="Thomas Dolby - She Blinded Me With Science.mp3"/>
25
+ <outline text="Rivers of Babylon (HTC).mp3" type="song" f="Jimmy Cliff - Rivers of Babylon (HTC).mp3"/>
26
+ <outline text="The Tide Is High.mp3" type="song" f="Blondie - The Tide Is High.mp3"/>
27
+ <outline text="Back to the Island.mp3" type="song" f="Leon Russell - Back to the Island.mp3"/>
28
+ <outline text="Lucky Man.mp3" type="song" f="Emerson Lake &amp; Palmer - Lucky Man.mp3"/>
29
+ <outline text="Up on Cripple Creek.mp3" type="song" f="The Band - Up on Cripple Creek.mp3"/>
30
+ <outline text="Crackerbox Palace.mp3" type="song" f="George Harrison - Crackerbox Palace.mp3"/>
31
+ <outline text="Taxi.Mp3" type="song" f="Harry Chapin - Taxi.Mp3"/>
32
+ <outline text="Thick As A Brick.mp3" type="song" f="Jethro Tull-Thick As A Brick.mp3"/>
33
+ <outline text="Riding With the King.mp3" type="song" f="B. B. King &amp; Eric Clapton - Riding With the King - 11 - Hold On Im Coming.mp3"/>
34
+ </outline>
35
+ <outline text="The Thrill is Gone?">
36
+ <outline text="Shaft.MP3" type="song" f="Isaac Hayes - Shaft.MP3"/>
37
+ <outline text="Superfly.mp3" type="song" f="Curtis Mayfield -- Superfly.mp3"/>
38
+ <outline text="Rivers of Babylon (HTC).mp3" type="song" f="Jimmy Cliff - Rivers of Babylon (HTC).mp3"/>
39
+ <outline text="The Harder They Come.mp3" type="song" f="Jimmy Cliff - The Harder They Come.mp3"/>
40
+ <outline text="The Revolution Will Not Be Televised.mp3" type="song" f="Gil Scott Heron - The Revolution Will Not Be Televised.mp3"/>
41
+ <outline text="The Thrill Is Gone.mp3" type="song" f="BB King - The Thrill Is Gone.mp3"/>
42
+ <outline text="Hit Me with Your Rhythm Stick.mp3" type="song" f="Ian Drury &amp; the Blockheads - Hit Me with Your Rhythm Stick.mp3"/>
43
+ </outline>
44
+ </body>
45
+ </opml>
@@ -0,0 +1,126 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <opml version="1.0">
3
+ <head>
4
+ <title>presentation.xml</title>
5
+ <dateCreated>Thu, 27 Jul 2000 01:35:52 GMT</dateCreated>
6
+ <dateModified>Fri, 15 Sep 2000 09:05:37 GMT</dateModified>
7
+ <ownerName>Dave Winer</ownerName>
8
+ <ownerEmail>dave@userland.com</ownerEmail>
9
+ <expansionState></expansionState>
10
+ <vertScrollState>1</vertScrollState>
11
+ <windowTop>317</windowTop>
12
+ <windowLeft>252</windowLeft>
13
+ <windowBottom>514</windowBottom>
14
+ <windowRight>634</windowRight>
15
+ </head>
16
+ <body>
17
+ <outline text="Welcome to Frontier 5!">
18
+ <outline text="What is Frontier?"/>
19
+ <outline text="It's a Content Management System"/>
20
+ </outline>
21
+ <outline text="Why Manage Content?">
22
+ <outline text="Form separated from content"/>
23
+ <outline text="Make it easy to change the look of a site"/>
24
+ <outline text="Keep the technical stuff out of the way of writers"/>
25
+ <outline text="Let designers work without having to deal with writers"/>
26
+ <outline text="Everyone works on what they do best"/>
27
+ </outline>
28
+ <outline text="Three groups">
29
+ <outline text="Writers write"/>
30
+ <outline text="Designers design"/>
31
+ <outline text="Geeks keep everything working"/>
32
+ <outline text="Frontier is for the geeks"/>
33
+ </outline>
34
+ <outline text="How does Content Flow?">
35
+ <outline text="Thru LANs, watched, shared folders"/>
36
+ <outline text="HTTP Put protocol"/>
37
+ <outline text="Email"/>
38
+ </outline>
39
+ <outline text="Cookie-cutter or workbench?">
40
+ <outline text="No two organizations work the same way"/>
41
+ <outline text="You need a highly customizable environment to make it work"/>
42
+ <outline text="A cookie-cutter approach is a dead-end"/>
43
+ <outline text="Frontier is &lt;i&gt;designed&lt;/i&gt; for customization"/>
44
+ <outline text="It's a website system workbench"/>
45
+ </outline>
46
+ <outline text="Frontier is an environment">
47
+ <outline text="Everything is integrated"/>
48
+ <outline text="Much more powerful"/>
49
+ <outline text="Much higher performance"/>
50
+ <outline text="Key point!"/>
51
+ </outline>
52
+ <outline text="The Object Database is the Center">
53
+ <outline text="Everything is built around a fast scalable object database"/>
54
+ <outline text="Millions of hours of burn-in"/>
55
+ <outline text="Hierarchical"/>
56
+ <outline text="It's also the symbol table for the language"/>
57
+ </outline>
58
+ <outline text="The scripting language">
59
+ <outline text="Patterned after C, totally dynamic"/>
60
+ <outline text="No need for structure symbols, semicolons or curly braces"/>
61
+ <outline text="Because it's integrated with a revolutionary script editor"/>
62
+ </outline>
63
+ <outline text="The script editor">
64
+ <outline text="Is an outliner"/>
65
+ <outline text="Expand a construct to see the detail"/>
66
+ <outline text="Collapse it to hide detail"/>
67
+ <outline text="When you move a statement, all the statements under it move too"/>
68
+ <outline text="This may be the single most revolutionary feature in Frontier"/>
69
+ </outline>
70
+ <outline text="Complete script debugger">
71
+ <outline text="Set a breakpoint"/>
72
+ <outline text="Step into and out of procedure calls"/>
73
+ <outline text="Easily examine all data while a script is running"/>
74
+ </outline>
75
+ <outline text="Object oriented website framework">
76
+ <outline text="Link management with hierarchical glossaries"/>
77
+ <outline text="Inherited and overridable attributes"/>
78
+ <outline text="Filter scripts also allow overrides and multiple content flows"/>
79
+ <outline text="All content is stored in database"/>
80
+ </outline>
81
+ <outline text="The runtime environment">
82
+ <outline text="Full built-in TCP support via inetd"/>
83
+ <outline text="Fully supports client and server HTTP"/>
84
+ <outline text="Fully multi-threaded"/>
85
+ <outline text="Large comprehensive verb set"/>
86
+ <outline text="Background processes, agents"/>
87
+ <outline text="Semaphores"/>
88
+ </outline>
89
+ <outline text="Editing tools">
90
+ <outline text="The object database editor is an outliner"/>
91
+ <outline text="Outlines are a great format for complex HTML"/>
92
+ <outline text="Simple text editor with easy HTML commands"/>
93
+ </outline>
94
+ <outline text="Key Components of Frontier">
95
+ <outline text="Integrated database storage system"/>
96
+ <outline text="Object oriented website framework"/>
97
+ <outline text="Powerful scripting environment with development tools, debugger"/>
98
+ <outline text="Outliner and text tools"/>
99
+ <outline text="Link management"/>
100
+ <outline text="Multithreaded runtime"/>
101
+ <outline text="Comprehensive verb set"/>
102
+ </outline>
103
+ <outline text="Frontier is content management">
104
+ <outline text="It's not an application development environment"/>
105
+ <outline text="It *is* a content management system"/>
106
+ <outline text="Suitable for a newspaper or magazine"/>
107
+ <outline text="A marketing department"/>
108
+ <outline text="A university department"/>
109
+ </outline>
110
+ <outline text="A brief history of Frontier">
111
+ <outline text="Automated DTP production with Quark and PageMaker on Mac (1992-93)"/>
112
+ <outline text="Transitioned to the web in 1996"/>
113
+ <outline text="Ships 1/28/98 for Win32 and Mac"/>
114
+ <outline text="Websites are cross platform!"/>
115
+ <outline text="So are many utility scripts"/>
116
+ <outline text="It's the first truly cross-platform web scripting environment"/>
117
+ </outline>
118
+ <outline text="A brief future of Frontier">
119
+ <outline text="Ease of use is our focus"/>
120
+ <outline text="Remote procedure calling"/>
121
+ <outline text="Sandboxes with scripted firewalls"/>
122
+ <outline text="Scalable content"/>
123
+ <outline text="XML"/>
124
+ </outline>
125
+ </body>
126
+ </opml>
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="ISO-8859-1"?>
2
+ <opml version="1.0">
3
+ <head>
4
+ <title>specification.xml</title>
5
+ <dateCreated>Thu, 27 Jul 2000 01:20:06 GMT</dateCreated>
6
+ <dateModified>Fri, 15 Sep 2000 09:04:03 GMT</dateModified>
7
+ <ownerName>Dave Winer</ownerName>
8
+ <ownerEmail>dave@userland.com</ownerEmail>
9
+ <expansionState></expansionState>
10
+ <vertScrollState>1</vertScrollState>
11
+ <windowTop>146</windowTop>
12
+ <windowLeft>107</windowLeft>
13
+ <windowBottom>468</windowBottom>
14
+ <windowRight>560</windowRight>
15
+ </head>
16
+ <body>
17
+ <outline text="It's XML, of course">
18
+ <outline text="This page documents the file formats used by Radio UserLand."/>
19
+ <outline text="There are two formats, outlineDocument and songList."/>
20
+ <outline text="There's a simple XML-RPC interface that allows a user to register with an aggregator. "/>
21
+ <outline text="All formats are open and public and may be used for any purpose whatsoever."/>
22
+ </outline>
23
+ <outline text="outlineDocument">
24
+ <outline text="All playlists are outlineDocuments. This is the main file format for Radio UserLand. When you create a new file it's saved as an outlineDocument. Because users can save them into the www folder, they can be accessed over the Web, either from a script or a Web browser such as MSIE. (Of course they could be served by any HTTP server, not just the Radio UserLand server.)"/>
25
+ <outline text="The outlineDocument format is &lt;a href=&quot;http://backend.userland.com/stories/storyReader$53&quot;&gt;documented&lt;/a&gt; on backend.userland.com. There will no doubt be changes and refinements to the format. One area that needs work is the format for the data attribute on a headline. Currently there are bugs in the way Radio UserLand uses this attribute. (Every headline gets a data attribute, whether or not it links to a song. We need to XMLize this and fit in data not as an attribute but as a legal sub-item. Shouldn't be hard to do, and with this caveat, breakage should be expected.)"/>
26
+ <outline text="Radio UserLand can be used to write any kind of document, not just a music playlist. Outlines are great for all kinds of structured documents, specifications, legal briefs, product plans, presentations and stories."/>
27
+ <outline text="Several examples of outlineDocuments created with Radio UserLand: play list, specification, presentation."/>
28
+ </outline>
29
+ <outline text="songList">
30
+ <outline text="As you're listening to music, Radio UserLand keeps track of what you listen to. Here's a &lt;a href=&quot;http://static.userland.com/images/radiodiscuss/userPlaylistSongs.gif&quot;&gt;screen shot&lt;/a&gt; of the table, user.playlist.songs, that keeps track of the stuff. "/>
31
+ <outline text="ctPlays is the number of times the song has been played. ctSeconds is the duration of the song, determined by a heuristic that's pretty accurate. f is the file that contains the MP3, on the local file system. whenFirstPlayed is the time/date the song was played for the first time, whenLastPlayed is the most recent time/date. whenLoaded is when Radio UserLand discovered the file in your MP3 folder."/>
32
+ <outline text="Every hour on the hour Radio UserLand generates an XMLization of this table and places it in the userland folder of your www folder, making it available over the Web. (There's no way to turn this feature off, there should be.)"/>
33
+ <outline text="Here's an &lt;a href=&quot;http://static.userland.com/gems/radiodiscuss/songs.xml&quot;&gt;example&lt;/a&gt; of the XML file. The mapping between the table and the XMLization should be fairly clear."/>
34
+ </outline>
35
+ <outline text="Rules of the road">
36
+ <outline text="Rules of the road will be determined later, since many of these files will be on users' machines, we want to provide guidelines for bots, aggregators and content systems; and whatever other kinds of applications people think of. Feel free to use the discussion group here to raise issues. "/>
37
+ </outline>
38
+ </body>
39
+ </opml>
@@ -0,0 +1,202 @@
1
+ require File.expand_path(File.dirname(__FILE__) + "/../lib/opml")
2
+
3
+ describe "a sample OPML file", :shared => true do
4
+
5
+ it "should have the owner of the document" do
6
+ @opml.owner_name.should == "Dave Winer"
7
+ end
8
+
9
+ it "should have the email address of the owner of the document" do
10
+ @opml.owner_email.should == "dave@userland.com"
11
+ end
12
+
13
+ end
14
+
15
+ describe "an empty OPML file", :shared => true do
16
+
17
+ it "should have no title" do
18
+ @opml.title.should be_nil
19
+ end
20
+
21
+ it "should have no outlines" do
22
+ @opml.outlines.size.should == 0
23
+ end
24
+
25
+ end
26
+
27
+
28
+ describe Opml, "playlist" do
29
+
30
+ before do
31
+ text = File.read(File.dirname(__FILE__) + "/files/playlist.opml")
32
+ @opml = Opml.new(text)
33
+ end
34
+
35
+ it_should_behave_like "a sample OPML file"
36
+
37
+ it "should have a title of the document" do
38
+ @opml.title.should == "playlist.xml"
39
+ end
40
+
41
+ it "should have a date-time, indicating when the document was created" do
42
+ @opml.date_created.should == Time.parse("Thu, 27 Jul 2000 03:24:18 GMT")
43
+ end
44
+
45
+ it "should have a date-time, indicating when the document was last modified" do
46
+ @opml.date_modified.should == Time.parse("Fri, 15 Sep 2000 09:01:23 GMT")
47
+ end
48
+
49
+ it "should have outlines" do
50
+ @opml.outlines.size.should == 3
51
+ @opml.outlines[0].outlines.size.should == 1
52
+ @opml.outlines[1].outlines.size.should == 13
53
+ @opml.outlines[2].outlines.size.should == 7
54
+ end
55
+
56
+ it "should return flattened outlines" do
57
+ @opml.flatten.size.should == 24
58
+ end
59
+
60
+ end
61
+
62
+ describe Opml, "presentation" do
63
+
64
+ before do
65
+ text = File.read(File.dirname(__FILE__) + "/files/presentation.opml")
66
+ @opml = Opml.new(text)
67
+ end
68
+
69
+ it_should_behave_like "a sample OPML file"
70
+
71
+ it "should have a title of the document" do
72
+ @opml.title.should == "presentation.xml"
73
+ end
74
+
75
+ it "should have a date-time, indicating when the document was created" do
76
+ @opml.date_created.should == Time.parse("Thu, 27 Jul 2000 01:35:52 GMT")
77
+ end
78
+
79
+ it "should have a date-time, indicating when the document was last modified" do
80
+ @opml.date_modified.should == Time.parse("Fri, 15 Sep 2000 09:05:37 GMT")
81
+ end
82
+
83
+ it "should have outlines" do
84
+ @opml.outlines.size.should == 17
85
+ @opml.outlines[0].outlines.size.should == 2
86
+ @opml.outlines[1].outlines.size.should == 5
87
+ @opml.outlines[2].outlines.size.should == 4
88
+ end
89
+
90
+ it "should return flattened outlines" do
91
+ @opml.flatten.size.should == 91
92
+ end
93
+
94
+ end
95
+
96
+ describe Opml, "specification" do
97
+
98
+ before do
99
+ text = File.read(File.dirname(__FILE__) + "/files/specification.opml")
100
+ @opml = Opml.new(text)
101
+ end
102
+
103
+ it_should_behave_like "a sample OPML file"
104
+
105
+ it "should have a title of the document" do
106
+ @opml.title.should == "specification.xml"
107
+ end
108
+
109
+ it "should have a date-time, indicating when the document was created" do
110
+ @opml.date_created.should == Time.parse("Thu, 27 Jul 2000 01:20:06 GMT")
111
+ end
112
+
113
+ it "should have a date-time, indicating when the document was last modified" do
114
+ @opml.date_modified.should == Time.parse("Fri, 15 Sep 2000 09:04:03 GMT")
115
+ end
116
+
117
+ it "should have outlines" do
118
+ @opml.outlines.size.should == 4
119
+ @opml.outlines[0].outlines.size.should == 4
120
+ @opml.outlines[1].outlines.size.should == 4
121
+ @opml.outlines[2].outlines.size.should == 4
122
+ end
123
+
124
+ it "should return flattened outlines" do
125
+ @opml.flatten.size.should == 17
126
+ end
127
+
128
+ end
129
+
130
+ describe Opml, "empty body" do
131
+
132
+ before do
133
+ @opml = Opml.new("<opml><body></body></opml>")
134
+ end
135
+
136
+ it_should_behave_like "an empty OPML file"
137
+
138
+ end
139
+
140
+ describe Opml, "empty outline" do
141
+
142
+ before do
143
+ @opml = Opml.new("<opml></opml>")
144
+ end
145
+
146
+ it_should_behave_like "an empty OPML file"
147
+
148
+ end
149
+
150
+ describe Opml, "empty file" do
151
+
152
+ before do
153
+ @opml = Opml.new("")
154
+ end
155
+
156
+ it_should_behave_like "an empty OPML file"
157
+
158
+ end
159
+
160
+ describe Opml::Outline, "in playlist" do
161
+
162
+ before do
163
+ text = File.read(File.dirname(__FILE__) + "/files/playlist.opml")
164
+ @outline = Opml.new(text).outlines[1]
165
+ end
166
+
167
+ it "should return all attributes" do
168
+ @outline.attributes.should == {"text" => "The Last Napster Sunday?"}
169
+ end
170
+
171
+ it "should return text attribute" do
172
+ @outline.text.should == "The Last Napster Sunday?"
173
+ end
174
+
175
+ it "should respond to text attribute" do
176
+ @outline.respond_to?(:text).should be_true
177
+ end
178
+
179
+ it "should return text when coerce into a string" do
180
+ @outline.to_s.should == "The Last Napster Sunday?"
181
+ end
182
+
183
+ it "should return flattened child outlines" do
184
+ @outline.flatten.map(&:to_s).should == [
185
+ "The Last Napster Sunday?",
186
+ "Heart of Glass.mp3",
187
+ "Manic Monday.mp3",
188
+ "Everybody Have Fun Tonight.mp3",
189
+ "She Blinded Me With Science.mp3",
190
+ "Rivers of Babylon (HTC).mp3",
191
+ "The Tide Is High.mp3",
192
+ "Back to the Island.mp3",
193
+ "Lucky Man.mp3",
194
+ "Up on Cripple Creek.mp3",
195
+ "Crackerbox Palace.mp3",
196
+ "Taxi.Mp3",
197
+ "Thick As A Brick.mp3",
198
+ "Riding With the King.mp3"
199
+ ]
200
+ end
201
+
202
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opml
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ""
6
+ authors:
7
+ - Joshua Peek
8
+ autorequire: opml
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2007-12-18 00:00:00 -06:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: josh@joshpeek.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - MIT-LICENSE
26
+ - Rakefile
27
+ - README
28
+ - lib/opml.rb
29
+ - spec/files
30
+ - spec/files/playlist.opml
31
+ - spec/files/presentation.opml
32
+ - spec/files/specification.opml
33
+ - spec/opml_spec.rb
34
+ has_rdoc: false
35
+ homepage: http://rubyforge.org/projects/opml/
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 0.9.5
57
+ signing_key:
58
+ specification_version: 2
59
+ summary: A simple wrapper for parsing OPML files.
60
+ test_files: []
61
+