rubypodder 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README +69 -0
- data/Rakefile +27 -0
- data/bin/rubypodder +2 -0
- data/lib/rubypodder.rb +113 -0
- data/tests/tc_rubypodder.rb +199 -0
- metadata +57 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 Lex Miller
|
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,69 @@
|
|
1
|
+
= rubypodder - A podcast aggregator without an interface
|
2
|
+
|
3
|
+
This package contains rubypodder, a simple podcast receiver
|
4
|
+
inspired by bashpodder (http://linc.homeunix.org:8080/scripts/bashpodder/).
|
5
|
+
|
6
|
+
== Download
|
7
|
+
|
8
|
+
The latest version of rubypodder can be found at
|
9
|
+
|
10
|
+
http://rubyforge.org/projects/rubypodder/
|
11
|
+
|
12
|
+
== Installation
|
13
|
+
|
14
|
+
Place the rubypodder gem in your local repository and install with
|
15
|
+
the following:
|
16
|
+
|
17
|
+
gem install rubypodder
|
18
|
+
|
19
|
+
== Quick Start
|
20
|
+
|
21
|
+
Type
|
22
|
+
|
23
|
+
rubypodder
|
24
|
+
|
25
|
+
When it finishes, you should see a ~/.rubypodder directory.
|
26
|
+
This should contain an example rp.conf configuration file with a feed in
|
27
|
+
it to get you started. If there were any podcasts to download in the feed
|
28
|
+
they will be in a directory named after the date (e.g. 2007-01-20).
|
29
|
+
You can see what happened by looking in rp.log.
|
30
|
+
|
31
|
+
== Running the rubypodder Test Suite
|
32
|
+
|
33
|
+
If you wish to run the unit tests that come with rubypodder:
|
34
|
+
|
35
|
+
gem check rubypodder --test
|
36
|
+
|
37
|
+
A message will be given if any of the tests fail.
|
38
|
+
|
39
|
+
=== Uninstallation
|
40
|
+
|
41
|
+
To uninstall the rubypodder gem use:
|
42
|
+
|
43
|
+
gem uninstall rubypodder
|
44
|
+
|
45
|
+
== Configuration
|
46
|
+
|
47
|
+
Create a file +~/.rubypodder/rp.conf+ containing podcast feeds, one per line.
|
48
|
+
|
49
|
+
== Usage
|
50
|
+
|
51
|
+
Type
|
52
|
+
|
53
|
+
rubypodder
|
54
|
+
|
55
|
+
and if there are any podcast episodes from your feeds that have not yet
|
56
|
+
been downloaded, they will be downloaded into a "date" directory such as
|
57
|
+
+~/.rubypodder/2007-01-18/+
|
58
|
+
|
59
|
+
A good idea is to use +crontab -e+ and add a line like
|
60
|
+
+0 5 * * * rubypodder+
|
61
|
+
which will set up a cron job which will do
|
62
|
+
this regularly.
|
63
|
+
|
64
|
+
== License
|
65
|
+
|
66
|
+
rubypodder is available under an MIT-style license.
|
67
|
+
|
68
|
+
:include: MIT-LICENSE
|
69
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
Gem::manage_gems
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
spec = Gem::Specification.new do |s|
|
5
|
+
s.platform = Gem::Platform::RUBY
|
6
|
+
s.name = "rubypodder"
|
7
|
+
s.version = "0.1.0"
|
8
|
+
s.author = "Lex Miller"
|
9
|
+
s.email = "lex.miller @nospam@ gmail.com"
|
10
|
+
s.summary = "A podcast aggregator without an interface"
|
11
|
+
s.files = FileList['lib/*.rb', 'tests/*', 'Rakefile'].to_a
|
12
|
+
s.require_path = "lib"
|
13
|
+
s.bindir = "bin"
|
14
|
+
s.executables = ["rubypodder"]
|
15
|
+
s.default_executable = "rubypodder"
|
16
|
+
s.autorequire = "rubypodder"
|
17
|
+
s.add_dependency("rio")
|
18
|
+
s.test_files = Dir.glob('tests/*.rb')
|
19
|
+
s.has_rdoc = true
|
20
|
+
s.extra_rdoc_files = ["README", "MIT-LICENSE"]
|
21
|
+
end
|
22
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
23
|
+
pkg.need_tar = true
|
24
|
+
end
|
25
|
+
task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
|
26
|
+
puts "generated latest version"
|
27
|
+
end
|
data/bin/rubypodder
ADDED
data/lib/rubypodder.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rss/1.0'
|
2
|
+
require 'rss/2.0'
|
3
|
+
require 'net/http'
|
4
|
+
require 'uri'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'rio'
|
7
|
+
require 'logger'
|
8
|
+
require 'ftools'
|
9
|
+
|
10
|
+
class File
|
11
|
+
|
12
|
+
def self.touch(fn)
|
13
|
+
File.open(fn, "w").close unless File.exist?(fn)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class RubyPodder
|
19
|
+
|
20
|
+
attr_reader :conf_file, :log_file, :done_file, :date_dir
|
21
|
+
|
22
|
+
def initialize(file_base="~/.rubypodder/rp")
|
23
|
+
@file_base = File.expand_path(file_base)
|
24
|
+
@rp_dir = File.dirname(@file_base)
|
25
|
+
@conf_file = @file_base + ".conf"
|
26
|
+
@log_file = @file_base + ".log"
|
27
|
+
@done_file = @file_base + ".done"
|
28
|
+
create_default_config_file
|
29
|
+
@log = Logger.new(@log_file)
|
30
|
+
File.touch @done_file
|
31
|
+
@date_dir = create_date_dir
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_default_config_file
|
35
|
+
expanded_path = File.expand_path(@conf_file)
|
36
|
+
return if File.exists?(expanded_path)
|
37
|
+
make_dirname(expanded_path)
|
38
|
+
rio(expanded_path) < "http://downloads.bbc.co.uk/rmhttp/downloadtrial/radio4/thenowshow/rss.xml"
|
39
|
+
end
|
40
|
+
|
41
|
+
def make_dirname(full_filename)
|
42
|
+
dirname = File.dirname(full_filename)
|
43
|
+
File.makedirs dirname
|
44
|
+
end
|
45
|
+
|
46
|
+
def date_string(time)
|
47
|
+
time.strftime("%Y-%m-%d")
|
48
|
+
end
|
49
|
+
|
50
|
+
def create_date_dir
|
51
|
+
date_dir = @rp_dir + "/" + date_string(Time.now)
|
52
|
+
File.makedirs date_dir
|
53
|
+
date_dir
|
54
|
+
end
|
55
|
+
|
56
|
+
def read_feeds
|
57
|
+
IO.readlines(@conf_file).each {|l| l.chomp!}
|
58
|
+
end
|
59
|
+
|
60
|
+
def parse_rss(rss_source)
|
61
|
+
RSS::Parser.parse(rss_source, false)
|
62
|
+
end
|
63
|
+
|
64
|
+
def dest_file_name(url)
|
65
|
+
@date_dir + "/" + File.basename(URI.parse(url).path)
|
66
|
+
end
|
67
|
+
|
68
|
+
def record_download(url)
|
69
|
+
rio(@done_file) << "#{url}\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
def already_downloaded(url)
|
73
|
+
url_regexp = Regexp.new(url)
|
74
|
+
File.open(@done_file).grep(url_regexp).length > 0
|
75
|
+
end
|
76
|
+
|
77
|
+
def download(url)
|
78
|
+
return if already_downloaded(url)
|
79
|
+
@log.info(" Downloading: #{url}")
|
80
|
+
file_name = dest_file_name(url)
|
81
|
+
rio(file_name) < rio(url)
|
82
|
+
record_download(url)
|
83
|
+
end
|
84
|
+
|
85
|
+
def remove_dir_if_empty(dirname)
|
86
|
+
begin
|
87
|
+
Dir.rmdir(dirname)
|
88
|
+
rescue SystemCallError
|
89
|
+
@log.info("#{dirname} has contents, not removed")
|
90
|
+
else
|
91
|
+
@log.info("#{dirname} was empty, removed")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def run
|
96
|
+
@log.info("Starting")
|
97
|
+
read_feeds.each do |url|
|
98
|
+
http_body = rio(url).contents
|
99
|
+
rss = parse_rss(http_body)
|
100
|
+
@log.info("Channel: #{rss.channel.title}")
|
101
|
+
rss.items.each do |item|
|
102
|
+
download(item.enclosure.url)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
remove_dir_if_empty(@date_dir)
|
106
|
+
@log.info("Finished")
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
if $0 == __FILE__
|
112
|
+
RubyPodder.new.run
|
113
|
+
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubypodder'
|
4
|
+
|
5
|
+
class TC_RubyPodder < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
system("rm -rf " + "/tmp/test_rp.conf")
|
9
|
+
system("rm -rf " + "/tmp/test_rp.done")
|
10
|
+
File.open("/tmp/test_rp.conf", "w") do |file|
|
11
|
+
file.write("http://downloads.bbc.co.uk/rmhttp/downloadtrial/radio4/thenowshow/rss.xml\n")
|
12
|
+
file.write("http://www.guardian.co.uk/podcasts/comedy/rickygervais/mp3.xml")
|
13
|
+
end
|
14
|
+
@subdir = "/tmp/subdir"
|
15
|
+
system("rm -rf " + @subdir)
|
16
|
+
@rp = RubyPodder.new("/tmp/test_rp")
|
17
|
+
end
|
18
|
+
|
19
|
+
def teardown
|
20
|
+
system("rm -rf " + "/tmp/test_rp.conf")
|
21
|
+
system("rm -rf " + "/tmp/test_rp.done")
|
22
|
+
system("rm -rf " + "/tmp/test_rp.log")
|
23
|
+
system("rm -rf " + "/tmp/#{@rp.date_string(Time.now)}")
|
24
|
+
system("rm -rf " + @subdir)
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_initialize_with_test_config_file
|
29
|
+
assert_kind_of(RubyPodder, @rp)
|
30
|
+
assert_equal("/tmp/test_rp.conf", @rp.conf_file)
|
31
|
+
assert_equal("/tmp/test_rp.log", @rp.log_file)
|
32
|
+
assert_equal("/tmp/test_rp.done", @rp.done_file)
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_initialize_with_default_config_file
|
36
|
+
ENV['HOME'] = "/tmp"
|
37
|
+
@rp = RubyPodder.new()
|
38
|
+
assert_kind_of(RubyPodder, @rp)
|
39
|
+
assert_equal(ENV['HOME'] + "/.rubypodder/rp.conf", @rp.conf_file)
|
40
|
+
assert_equal(ENV['HOME'] + "/.rubypodder/rp.log", @rp.log_file)
|
41
|
+
assert_equal(ENV['HOME'] + "/.rubypodder/rp.done", @rp.done_file)
|
42
|
+
system("rm -rf " + "/tmp/.rubypodder")
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_initialize_with_absent_config_file
|
46
|
+
file_base = "/tmp/test_rp"
|
47
|
+
file_conf = file_base + ".conf"
|
48
|
+
system("rm -rf " + file_conf)
|
49
|
+
@rp = RubyPodder.new(file_base)
|
50
|
+
assert(File.exists?(file_conf))
|
51
|
+
system("rm -rf " + file_conf)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_make_dirname_one_subdir
|
55
|
+
filename = @subdir + "/file"
|
56
|
+
@rp.make_dirname(filename)
|
57
|
+
assert(File.exists?(@subdir))
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_make_dirname_many_subdir
|
61
|
+
subsubdirs = "/subsubdir/subsubsubdir"
|
62
|
+
filename = @subdir + subsubdirs + "/file"
|
63
|
+
@rp.make_dirname(filename)
|
64
|
+
assert(File.exists?(@subdir + subsubdirs))
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_date_string
|
68
|
+
t = Time.gm(2006,"dec",18,21,0,0)
|
69
|
+
date_string = @rp.date_string(t)
|
70
|
+
assert_equal(date_string, "2006-12-18")
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_initialize_with_absent_config_file_dir
|
74
|
+
file_base = @subdir + "/test_rp"
|
75
|
+
file_conf = file_base + ".conf"
|
76
|
+
@rp = RubyPodder.new(file_base)
|
77
|
+
assert(File.exists?(file_conf))
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_initialize_creates_date_dir
|
81
|
+
file_base = @subdir + "/test_rp"
|
82
|
+
@rp = RubyPodder.new(file_base)
|
83
|
+
date_dir = @subdir + "/" + @rp.date_string(Time.now)
|
84
|
+
assert_equal(date_dir, @rp.date_dir)
|
85
|
+
assert(File.exists?(date_dir), "Subdirectory #{date_dir} not created")
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_read_feeds
|
89
|
+
feed_list = @rp.read_feeds
|
90
|
+
assert_kind_of(Array, feed_list)
|
91
|
+
assert_equal(2, feed_list.length)
|
92
|
+
assert_equal("http://downloads.bbc.co.uk/rmhttp/downloadtrial/radio4/thenowshow/rss.xml", feed_list[0])
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_parse_rss
|
96
|
+
#rss_source = IO.read("test_feed.xml")
|
97
|
+
rss_source = <<-END_OF_STRING
|
98
|
+
<?xml version="1.0" encoding="utf-8"?>
|
99
|
+
<rss xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
|
100
|
+
<channel>
|
101
|
+
<lastBuildDate>Fri, 27 Oct 2006 16:50:15 +0100</lastBuildDate>
|
102
|
+
<title>The Ricky Gervais Show</title>
|
103
|
+
<itunes:author>Guardian Unlimited</itunes:author>
|
104
|
+
<link>http://www.guardian.co.uk/rickygervais</link>
|
105
|
+
<generator>Podcast Maker v1.2.4 - http://www.potionfactory.com/podcastmaker</generator>
|
106
|
+
<description>Ricky Gervais, Steve Merchant and Karl Pilkington are back yada yada</description>
|
107
|
+
<itunes:subtitle />
|
108
|
+
<itunes:summary>Ricky Gervais, Steve Merchant and Karl Pilkington are back yada yada</itunes:summary>
|
109
|
+
<language>en</language>
|
110
|
+
<copyright>Ricky Gervais, Steve Merchant, Karl Pilkington</copyright>
|
111
|
+
<itunes:owner>
|
112
|
+
<itunes:name>Glyn Hughes</itunes:name>
|
113
|
+
<itunes:email>glyn@rickygervais.com</itunes:email>
|
114
|
+
</itunes:owner>
|
115
|
+
<image>
|
116
|
+
<url>http://podcast.rickygervais.com/gu_p123_300_144.jpg</url>
|
117
|
+
<title>The Ricky Gervais Show</title>
|
118
|
+
<link>http://www.guardian.co.uk/rickygervais</link>
|
119
|
+
<width>144</width>
|
120
|
+
<height>144</height>
|
121
|
+
</image>
|
122
|
+
<itunes:image href="http://podcast.rickygervais.com/gu_p123_300.jpg" />
|
123
|
+
<category>Comedy</category>
|
124
|
+
<itunes:category text="Comedy" />
|
125
|
+
<itunes:keywords>Ricky, Gervais, Steve, Merchant, Karl, Pilkington</itunes:keywords>
|
126
|
+
<itunes:explicit>yes</itunes:explicit>
|
127
|
+
<item>
|
128
|
+
<title>The Podfather Part I - Halloween</title>
|
129
|
+
<itunes:author>Guardian Unlimited</itunes:author>
|
130
|
+
<description>The first of three specials from Ricky, Steve and Karl yada yada</description>
|
131
|
+
<itunes:subtitle>The first of three specials from Ricky, Steve and Karl yada yada</itunes:subtitle>
|
132
|
+
<itunes:summary />
|
133
|
+
<enclosure type="audio/mpeg" url="http://podcast.rickygervais.com/guspecials_halloween.mp3" length="15723925" />
|
134
|
+
<guid>http://podcast.rickygervais.com/guspecials_halloween.mp3</guid>
|
135
|
+
<pubDate>Tue, 31 Oct 2006 00:00:01 +0000</pubDate>
|
136
|
+
<category>Comedy</category>
|
137
|
+
<itunes:explicit>yes</itunes:explicit>
|
138
|
+
<itunes:duration>00:37:22</itunes:duration>
|
139
|
+
<itunes:keywords>Ricky, Gervais, Steve, Merchant, Karl, Pilkington</itunes:keywords>
|
140
|
+
</item>
|
141
|
+
</channel>
|
142
|
+
</rss>
|
143
|
+
END_OF_STRING
|
144
|
+
rss = @rp.parse_rss(rss_source)
|
145
|
+
assert_equal(1, rss.items.length)
|
146
|
+
assert_equal("http://podcast.rickygervais.com/guspecials_halloween.mp3", rss.items[0].enclosure.url)
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_dest_file_name(url)
|
150
|
+
correct_dest_file_name = @rp.date_dir + "/" + "podcast.mp3"
|
151
|
+
dest_file_name = @rp.dest_file_name("http://www.podcast.com/podcast.mp3")
|
152
|
+
assert_equal(correct_dest_file_name, dest_file_name)
|
153
|
+
dest_file_name = @rp.dest_file_name("http://www.podcast.com/subdir/podcast.mp3")
|
154
|
+
assert_equal(correct_dest_file_name, dest_file_name)
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_download
|
158
|
+
@rp.download("http://www.google.com/index.html")
|
159
|
+
dest_file = @rp.date_dir + "/" + "index.html"
|
160
|
+
assert(File.exists?(dest_file))
|
161
|
+
assert(File.open(dest_file).grep(/google/))
|
162
|
+
end
|
163
|
+
|
164
|
+
def test_download_recorded
|
165
|
+
@rp.download("http://www.google.com/index.html")
|
166
|
+
assert(File.exists?(@rp.done_file))
|
167
|
+
assert(File.open(@rp.done_file).grep(/^http:\/\/www.google.com\/index.html$/))
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_already_downloaded
|
171
|
+
url1 = "http://www.google.com/index.html"
|
172
|
+
assert(!@rp.already_downloaded(url1), "url1 should not be already downloaded before download of url1")
|
173
|
+
@rp.download(url1)
|
174
|
+
assert(@rp.already_downloaded(url1), "url1 should be already downloaded after download of url1")
|
175
|
+
url2 = "http://www.google.co.nz/index.html"
|
176
|
+
@rp.download(url2)
|
177
|
+
assert(@rp.already_downloaded(url2), "url2 should be already downloaded after download of url2")
|
178
|
+
assert(@rp.already_downloaded(url1), "url1 should still be already downloaded after download of url2")
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_download_omits_done_items
|
182
|
+
@rp.download("http://www.google.com/index.html")
|
183
|
+
dest_file = @rp.date_dir + "/" + "index.html"
|
184
|
+
system("rm -rf " + dest_file)
|
185
|
+
@rp.download("http://www.google.com/index.html")
|
186
|
+
assert(!File.exists?(dest_file))
|
187
|
+
end
|
188
|
+
|
189
|
+
def test_remove_dir_if_empty
|
190
|
+
system("mkdir -p " + @subdir)
|
191
|
+
@rp.remove_dir_if_empty(@subdir)
|
192
|
+
assert(!File.exists?(@subdir))
|
193
|
+
system("mkdir -p " + @subdir)
|
194
|
+
system("touch " + @subdir + "/fish")
|
195
|
+
@rp.remove_dir_if_empty(@subdir)
|
196
|
+
assert(File.exists?(@subdir))
|
197
|
+
end
|
198
|
+
|
199
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: rubypodder
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 0.1.0
|
7
|
+
date: 2007-01-20 00:00:00 +13:00
|
8
|
+
summary: A podcast aggregator without an interface
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: lex.miller @nospam@ gmail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: rubypodder
|
16
|
+
default_executable: rubypodder
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
-
|
22
|
+
- ">"
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.0
|
25
|
+
version:
|
26
|
+
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Lex Miller
|
31
|
+
files:
|
32
|
+
- lib/rubypodder.rb
|
33
|
+
- tests/tc_rubypodder.rb
|
34
|
+
- Rakefile
|
35
|
+
- README
|
36
|
+
- MIT-LICENSE
|
37
|
+
test_files:
|
38
|
+
- tests/tc_rubypodder.rb
|
39
|
+
rdoc_options: []
|
40
|
+
extra_rdoc_files:
|
41
|
+
- README
|
42
|
+
- MIT-LICENSE
|
43
|
+
executables:
|
44
|
+
- rubypodder
|
45
|
+
extensions: []
|
46
|
+
requirements: []
|
47
|
+
dependencies:
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rio
|
50
|
+
version_requirement:
|
51
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
52
|
+
requirements:
|
53
|
+
-
|
54
|
+
- ">"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: 0.0.0
|
57
|
+
version:
|