livedoor-feeddiscover 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/History.txt +3 -0
- data/License.txt +20 -0
- data/Manifest.txt +23 -0
- data/README.txt +112 -0
- data/Rakefile +202 -0
- data/examples/benchmark.rb +64 -0
- data/examples/mkopml.rb +48 -0
- data/helper/helper.rb +3 -0
- data/helper/rake.rb +58 -0
- data/helper/rake_sh_filter.rb +23 -0
- data/helper/util.rb +19 -0
- data/lib/livedoor/api/feed_discover/client.rb +77 -0
- data/lib/livedoor/api/feed_discover/feed.rb +66 -0
- data/lib/livedoor/api/feed_discover/feed_list.rb +70 -0
- data/lib/livedoor/api/feed_discover/version.rb +13 -0
- data/lib/livedoor/api/feed_discover.rb +12 -0
- data/setup.rb +1585 -0
- data/spec/livedoor/api/feed_discover/client_spec.rb +37 -0
- data/spec/livedoor/api/feed_discover/feed_list_spec.rb +114 -0
- data/spec/livedoor/api/feed_discover/feed_spec.rb +114 -0
- data/spec/livedoor/api/feed_discover/version_spec.rb +21 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_helper.rb +28 -0
- metadata +83 -0
data/History.txt
ADDED
data/License.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2007 MIYAMUKO Katsuyuki <mailto:miyamuko@gmail.com>
|
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/Manifest.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
History.txt
|
2
|
+
License.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
examples/benchmark.rb
|
7
|
+
examples/mkopml.rb
|
8
|
+
helper/helper.rb
|
9
|
+
helper/rake.rb
|
10
|
+
helper/rake_sh_filter.rb
|
11
|
+
helper/util.rb
|
12
|
+
lib/livedoor/api/feed_discover.rb
|
13
|
+
lib/livedoor/api/feed_discover/client.rb
|
14
|
+
lib/livedoor/api/feed_discover/feed.rb
|
15
|
+
lib/livedoor/api/feed_discover/feed_list.rb
|
16
|
+
lib/livedoor/api/feed_discover/version.rb
|
17
|
+
setup.rb
|
18
|
+
spec/livedoor/api/feed_discover/client_spec.rb
|
19
|
+
spec/livedoor/api/feed_discover/feed_list_spec.rb
|
20
|
+
spec/livedoor/api/feed_discover/feed_spec.rb
|
21
|
+
spec/livedoor/api/feed_discover/version_spec.rb
|
22
|
+
spec/spec.opts
|
23
|
+
spec/spec_helper.rb
|
data/README.txt
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
== livedoor-feeddiscover - The fastest feed auto-discovery
|
2
|
+
|
3
|
+
=== DESCRIPTION
|
4
|
+
|
5
|
+
livedoor-feeddiscover performs feed autodiscovery using the livedoor Feed Discover API.
|
6
|
+
|
7
|
+
livedoor Feed Discover API find a Atom/RSS feed(s) from the livedoor Reader crawler database.
|
8
|
+
So, livedoor-feeddiscover do not access the target URL.
|
9
|
+
|
10
|
+
* {livedoor Feed Discover API}[http://wiki.livedoor.jp/staff_reader/d/Feed%20Discover%20API] (API Spec, Japanese)
|
11
|
+
* {livedoor Reader}[http://reader.livedoor.com/reader/] (Fastest RSS reader, Japanese)
|
12
|
+
|
13
|
+
|
14
|
+
=== SYNOPSIS
|
15
|
+
|
16
|
+
require "rubygems"
|
17
|
+
require "livedoor/api/feed_discover"
|
18
|
+
|
19
|
+
# find feed of matz blog.
|
20
|
+
matzblog = Livedoor::API::FeedDiscover.find(
|
21
|
+
"http://www.rubyist.net/~matz/",
|
22
|
+
"User-Agent" => "livedoor-feeddiscover/#{Livedoor::API::FeedDiscover::VERSION::STRING}")
|
23
|
+
if matzblog.feeds?
|
24
|
+
puts matzblog.feed.source # specified argument
|
25
|
+
puts matzblog.feed.link # blog link
|
26
|
+
puts matzblog.feed.feedlink # feed link
|
27
|
+
puts matzblog.feed.image # blog logo (channel image)
|
28
|
+
puts matzblog.feed.icon # favicon
|
29
|
+
puts matzblog.feed.title # blog title (UTF-8 string)
|
30
|
+
puts matzblog.feed.description # blog description (UTF-8 string)
|
31
|
+
puts matzblog.feed.official? # auto discover-able?
|
32
|
+
puts matzblog.feed.thirdparty? # thirdparty feeds? (not official)
|
33
|
+
puts matzblog.feed.subscribers_count # subscribers in livedoor Reader
|
34
|
+
puts matzblog.feed.avg_rate # average rate in livedoor Reader
|
35
|
+
end
|
36
|
+
|
37
|
+
# FeedDiscover.find can take multiple links (max 1000).
|
38
|
+
feedlist = Livedoor::API::FeedDiscover.find("http://rubyforge.org/", "http://raa.ruby-lang.org/")
|
39
|
+
puts feedlist.feedlinks
|
40
|
+
|
41
|
+
# generate OPML for Japanese rubyist blogs linked from Ruby hotlinks.
|
42
|
+
RUBY_HOT_LINKS = "http://www.rubyist.net/~kazu/samidare/"
|
43
|
+
rubyist_jp = Livedoor::API::FeedDiscover.find_from(RUBY_HOT_LINKS)
|
44
|
+
|
45
|
+
open("rubyist-jp.opml", "w") do |w|
|
46
|
+
w.puts rubyist_jp.opml
|
47
|
+
end
|
48
|
+
|
49
|
+
rubyist_jp.each do |feed|
|
50
|
+
puts feed.link
|
51
|
+
puts " ==> #{feed.feedlink} (#{feed.thirdparty? ? 'thirdpary' : 'official'})"
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
=== BENCHMARK
|
56
|
+
|
57
|
+
vs feed-discover[http://rubyforge.org/projects/feed-discover/].
|
58
|
+
|
59
|
+
> ruby examples\benchmark.rb
|
60
|
+
Start auto-discover for 4 blogs ------------------------------------
|
61
|
+
http://www.rubyist.net/~matz/
|
62
|
+
http://rubyforge.org/
|
63
|
+
http://raa.ruby-lang.org/
|
64
|
+
http://jruby.codehaus.org/
|
65
|
+
|
66
|
+
user system total real
|
67
|
+
feed-discover 5.234000 0.234000 5.468000 ( 13.797000)
|
68
|
+
livedoor-feed-discover 0.000000 0.000000 0.000000 ( 0.078000)
|
69
|
+
|
70
|
+
Results ------------------------------------------------------------
|
71
|
+
feed-discover: found 3 feeds.
|
72
|
+
livedoor-f-d: found 3 feeds.
|
73
|
+
|
74
|
+
Diffs --------------------------------------------------------------
|
75
|
+
http://www.rubyist.net/~matz/
|
76
|
+
feed-discover: http://www.rubyist.net/~matz/comments.rdf, http://www.rubyist.net/~matz/index.rdf
|
77
|
+
livedoor-f-d: http://www.rubyist.net/~matz/index.rdf
|
78
|
+
|
79
|
+
|
80
|
+
=== REQUIREMENTS
|
81
|
+
|
82
|
+
* json[http://rubyforge.org/projects/json/]
|
83
|
+
|
84
|
+
|
85
|
+
=== SEE ALSO
|
86
|
+
|
87
|
+
* feed-discover[http://rubyforge.org/projects/feed-discover/]
|
88
|
+
|
89
|
+
|
90
|
+
=== INSTALL
|
91
|
+
|
92
|
+
[Unix]
|
93
|
+
sudo gem install -y livedoor-feeddiscover
|
94
|
+
|
95
|
+
[Windows]
|
96
|
+
gem install -y livedoor-feeddiscover
|
97
|
+
|
98
|
+
|
99
|
+
=== COPYRIGHT
|
100
|
+
|
101
|
+
Copyright (c) 2007 MIYAMUKO Katsuyuki.
|
102
|
+
|
103
|
+
livedoor-feeddiscover is released under an MIT license.
|
104
|
+
See {License.txt}[link:files/License_txt.html] for full license.
|
105
|
+
|
106
|
+
|
107
|
+
=== OTHER STUFF
|
108
|
+
|
109
|
+
Author:: MIYAMUKO Katsuyuki <mailto:miyamuko@gmail.com>
|
110
|
+
Home URL:: http://feeddiscoverapi.rubyforge.org
|
111
|
+
Project URL:: http://rubyforge.org/projects/feeddiscoverapi
|
112
|
+
Blog (Japanese):: {id:miyamuko}[http://d.hatena.ne.jp/miyamuko/]
|
data/Rakefile
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'rake/testtask'
|
7
|
+
require 'rake/packagetask'
|
8
|
+
require 'rake/gempackagetask'
|
9
|
+
require 'rake/rdoctask'
|
10
|
+
require 'rake/contrib/rubyforgepublisher'
|
11
|
+
require 'fileutils'
|
12
|
+
require 'hoe'
|
13
|
+
begin
|
14
|
+
require 'spec/rake/spectask'
|
15
|
+
rescue LoadError
|
16
|
+
puts 'To use rspec for testing you must install rspec gem:'
|
17
|
+
puts '$ sudo gem install rspec'
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'helper/helper'
|
22
|
+
|
23
|
+
include FileUtils
|
24
|
+
require File.join(File.dirname(__FILE__), 'lib', 'livedoor', 'api', 'feed_discover', 'version')
|
25
|
+
|
26
|
+
AUTHOR = 'MIYAMUKO Katsuyuki' # can also be an array of Authors
|
27
|
+
EMAIL = "miyamuko@gmail.com"
|
28
|
+
DESCRIPTION = "Ruby interface to the livedoor Feed Discover API"
|
29
|
+
GEM_NAME = 'livedoor-feeddiscover'
|
30
|
+
NEWS_FILE = "news.txt"
|
31
|
+
|
32
|
+
@config_file = "~/.rubyforge/user-config.yml"
|
33
|
+
@config = nil
|
34
|
+
def rubyforge_username
|
35
|
+
unless @config
|
36
|
+
begin
|
37
|
+
@config = YAML.load(File.read(File.expand_path(@config_file)))
|
38
|
+
rescue
|
39
|
+
puts "ERROR: No rubyforge config file found: #{@config_file}"
|
40
|
+
puts "Run 'rubyforge setup' to prepare your env for access to Rubyforge"
|
41
|
+
exit
|
42
|
+
end
|
43
|
+
end
|
44
|
+
@rubyforge_username ||= @config["username"]
|
45
|
+
end
|
46
|
+
|
47
|
+
RUBYFORGE_PROJECT = 'feeddiscoverapi' # The unix name for your project
|
48
|
+
HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
|
49
|
+
DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
|
50
|
+
|
51
|
+
NAME = "livedoor-feeddiscover"
|
52
|
+
REV = nil
|
53
|
+
# UNCOMMENT IF REQUIRED:
|
54
|
+
# REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
|
55
|
+
VERS = Livedoor::API::FeedDiscover::VERSION::STRING + (REV ? ".#{REV}" : "")
|
56
|
+
CLEAN.include ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store', '**/.cache', NEWS_FILE]
|
57
|
+
RDOC_OPTS = ['--quiet', '--title', 'livedoor-feeddiscover documentation',
|
58
|
+
"--opname", "index.html",
|
59
|
+
"--line-numbers",
|
60
|
+
"--main", "README",
|
61
|
+
"--inline-source"]
|
62
|
+
|
63
|
+
class Hoe
|
64
|
+
def extra_deps
|
65
|
+
@extra_deps.reject!{|x| Array(x).first == 'hoe' }
|
66
|
+
@extra_deps
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Generate all the Rake tasks
|
71
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
72
|
+
hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
73
|
+
p.author = AUTHOR
|
74
|
+
p.email = EMAIL
|
75
|
+
p.url = HOMEPATH
|
76
|
+
|
77
|
+
p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
|
78
|
+
p.test_globs = ["spec/**/*_spec.rb"]
|
79
|
+
p.clean_globs |= CLEAN #An array of file patterns to delete on clean.
|
80
|
+
|
81
|
+
p.summary = p.paragraphs_of('README.txt', 2..2)[0]
|
82
|
+
p.description = p.paragraphs_of('README.txt', 2..3).join("\n\n")
|
83
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
84
|
+
|
85
|
+
p.extra_deps << "json"
|
86
|
+
p.need_zip = true
|
87
|
+
p.need_tar = true
|
88
|
+
end
|
89
|
+
|
90
|
+
CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\n\n")
|
91
|
+
desc 'Release the website and new gem version'
|
92
|
+
task :deploy => [:check_manifest!, :check_version, :publish_docs, :release] do
|
93
|
+
puts "Remember to create SVN tag:"
|
94
|
+
puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
|
95
|
+
"svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/#{VERS} "
|
96
|
+
puts "Suggested comment:"
|
97
|
+
puts "Tagging release #{CHANGES}"
|
98
|
+
end
|
99
|
+
|
100
|
+
task :check_manifest! => [:check_manifest] do
|
101
|
+
unless $?.success?
|
102
|
+
puts "----"
|
103
|
+
puts "Please update Manifest.txt."
|
104
|
+
exit 1
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
task :check_version do
|
109
|
+
unless ENV['VERSION']
|
110
|
+
puts 'Must pass a VERSION=x.y.z release version'
|
111
|
+
exit
|
112
|
+
end
|
113
|
+
unless ENV['VERSION'] == VERS
|
114
|
+
puts "Please update your version.rb to match the release version, currently #{VERS}"
|
115
|
+
exit
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
desc "Run the specs under spec/models"
|
120
|
+
Spec::Rake::SpecTask.new do |t|
|
121
|
+
t.spec_opts = ['--options', "spec/spec.opts"]
|
122
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
123
|
+
end
|
124
|
+
|
125
|
+
desc "Default task is to run specs"
|
126
|
+
task :default => :spec
|
127
|
+
|
128
|
+
#
|
129
|
+
# new task
|
130
|
+
#
|
131
|
+
|
132
|
+
desc 'Uninstall the gem package'
|
133
|
+
task_for_windows :uninstall_gem do
|
134
|
+
sh "gem.bat uninstall #{GEM_NAME}"
|
135
|
+
end
|
136
|
+
|
137
|
+
|
138
|
+
#
|
139
|
+
# overwrite hoe defined tasks.
|
140
|
+
#
|
141
|
+
|
142
|
+
task_for_windows :install_gem do
|
143
|
+
sh "gem.bat install pkg/*.gem"
|
144
|
+
end
|
145
|
+
|
146
|
+
task_for_windows :ridocs do
|
147
|
+
sh "rdoc.bat --ri -o ri ."
|
148
|
+
end
|
149
|
+
|
150
|
+
# remove HTML comment for stupid IE6.
|
151
|
+
task :docs do
|
152
|
+
Dir.glob("**/*.html").each do |html|
|
153
|
+
c = File.read(html)
|
154
|
+
File.open(html, "w") do |w|
|
155
|
+
w.puts c.gsub(/<!--.*?-->\n/m, "")
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
task_for_windows :publish_docs do
|
161
|
+
config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
|
162
|
+
with_temporary_rename("doc", "html") {
|
163
|
+
Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, config["username"]).upload
|
164
|
+
}
|
165
|
+
end
|
166
|
+
|
167
|
+
# rake publish_docs SCP=pscp
|
168
|
+
if ENV["SCP"] and ENV["SCP"] != "scp"
|
169
|
+
add_sh_filter_for(/\Ascp /) {|cmd|
|
170
|
+
cmd[0].sub!(/\Ascp/, ENV["SCP"])
|
171
|
+
cmd[0].sub!(/-rq/, "-r")
|
172
|
+
cmd
|
173
|
+
}
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
task :create_news do
|
178
|
+
subject, title, body, urls = hoe.announcement
|
179
|
+
open(NEWS_FILE, "w") do |w|
|
180
|
+
w.puts subject
|
181
|
+
w.puts "#{title}\n\n#{body}\n\n"
|
182
|
+
w.puts "--"
|
183
|
+
w.puts "Home URL: #{HOMEPATH}"
|
184
|
+
w.puts "Project URL: #{DOWNLOAD_PATH}"
|
185
|
+
end
|
186
|
+
puts File.read(NEWS_FILE)
|
187
|
+
end
|
188
|
+
|
189
|
+
override_task :post_news do
|
190
|
+
subject, body = File.read(NEWS_FILE).split(/\n/, 2)
|
191
|
+
require 'rubyforge'
|
192
|
+
rf = RubyForge.new
|
193
|
+
rf.login
|
194
|
+
rf.post_news(RUBYFORGE_PROJECT, subject, body)
|
195
|
+
puts "Posted to rubyforge `#{subject}'."
|
196
|
+
rm_f NEWS_FILE
|
197
|
+
end
|
198
|
+
task :clean do
|
199
|
+
rm_f NEWS_FILE
|
200
|
+
end
|
201
|
+
|
202
|
+
# vim: syntax=Ruby
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "benchmark"
|
2
|
+
require "open-uri"
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
require "rubygems"
|
6
|
+
require "feed_discover"
|
7
|
+
|
8
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
9
|
+
require "livedoor/api/feed_discover"
|
10
|
+
|
11
|
+
|
12
|
+
def feed_discover(blogs, acc)
|
13
|
+
blogs.each do |blog|
|
14
|
+
acc[blog] = nil
|
15
|
+
begin
|
16
|
+
fd = FeedDiscover.new(blog)
|
17
|
+
acc[blog] = fd.feeds.join(", ") if fd.feeds?
|
18
|
+
rescue OpenURI::HTTPError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def livedoor_feed_discover(blogs, acc)
|
24
|
+
feedlist = Livedoor::API::FeedDiscover.find(*blogs)
|
25
|
+
feedlist.each do |feed|
|
26
|
+
acc[feed.source] = feed.feedlink
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def header(label)
|
31
|
+
puts "#{label} #{'-' * (68 - 1 - label.length)}"
|
32
|
+
end
|
33
|
+
|
34
|
+
blogs = %W{
|
35
|
+
http://www.rubyist.net/~matz/
|
36
|
+
http://rubyforge.org/
|
37
|
+
http://raa.ruby-lang.org/
|
38
|
+
http://jruby.codehaus.org/
|
39
|
+
}
|
40
|
+
feeds_a = blogs.inject({}) {|acc,e| acc[e] = nil; acc }
|
41
|
+
feeds_b = feeds_a.dup
|
42
|
+
|
43
|
+
header("Start auto-discover for #{blogs.size} blogs")
|
44
|
+
puts blogs
|
45
|
+
puts
|
46
|
+
Benchmark.bm(25) do |x|
|
47
|
+
x.report("feed-discover") { feed_discover(blogs, feeds_a) }
|
48
|
+
x.report("livedoor-feed-discover") { livedoor_feed_discover(blogs, feeds_b) }
|
49
|
+
end
|
50
|
+
puts
|
51
|
+
|
52
|
+
header("Results")
|
53
|
+
puts "feed-discover: found #{feeds_a.values.compact.size} feeds."
|
54
|
+
puts "livedoor-f-d: found #{feeds_b.values.compact.size} feeds."
|
55
|
+
puts
|
56
|
+
|
57
|
+
header("Diffs")
|
58
|
+
blogs.each do |blog|
|
59
|
+
if feeds_a[blog] != feeds_b[blog]
|
60
|
+
puts blog
|
61
|
+
puts " feed-discover: #{feeds_a[blog]}"
|
62
|
+
puts " livedoor-f-d: #{feeds_b[blog]}"
|
63
|
+
end
|
64
|
+
end
|
data/examples/mkopml.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), "../lib")
|
4
|
+
require "livedoor/api/feed_discover"
|
5
|
+
|
6
|
+
def with_output_stream(out)
|
7
|
+
case out
|
8
|
+
when "-"
|
9
|
+
yield $stdout
|
10
|
+
when String
|
11
|
+
open(out, "w"){|w| yield w }
|
12
|
+
else
|
13
|
+
yield out
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def main
|
18
|
+
find_from = nil
|
19
|
+
output = $stdout
|
20
|
+
header = {}
|
21
|
+
|
22
|
+
ARGV.options do |opt|
|
23
|
+
opt.banner = "Usage: #{File.basename($0)} [options] [URL...]"
|
24
|
+
opt.on("-f", "--find-from URL"){|v| find_from = v }
|
25
|
+
opt.on("-o", "--output OUTPUT"){|v| output = v }
|
26
|
+
opt.on("-U", "--user-agent AGENT"){|v| header["User-Agent"] = v }
|
27
|
+
opt.parse!
|
28
|
+
end
|
29
|
+
|
30
|
+
if find_from
|
31
|
+
feedlist = Livedoor::API::FeedDiscover.find_from(find_from, header)
|
32
|
+
elsif not ARGV.empty?
|
33
|
+
feedlist = Livedoor::API::FeedDiscover.find(ARGV, header)
|
34
|
+
else
|
35
|
+
puts ARGV.options
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
unless feedlist.feeds?
|
40
|
+
exit 2
|
41
|
+
end
|
42
|
+
|
43
|
+
with_output_stream(output) do |w|
|
44
|
+
w.puts feedlist.opml
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
main
|
data/helper/helper.rb
ADDED
data/helper/rake.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rake"
|
3
|
+
|
4
|
+
def tasks
|
5
|
+
Rake.application.instance_eval { @tasks }
|
6
|
+
end
|
7
|
+
|
8
|
+
def current_scope
|
9
|
+
Rake.application.instance_eval { @scope.last }
|
10
|
+
end
|
11
|
+
|
12
|
+
def task_defined?(task_name)
|
13
|
+
Rake::Task.task_defined?(task_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove_tasks(*task_names)
|
17
|
+
task_names.flatten.each do |task_name|
|
18
|
+
remove_task(task_name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove_task(task_name)
|
23
|
+
tasks.delete(task_name.to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
def lookup_task(task_name)
|
27
|
+
Rake::Task[task_name] rescue nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def rakecall(task_name)
|
31
|
+
lookup_task(task_name).invoke
|
32
|
+
end
|
33
|
+
|
34
|
+
def override_task(task_args, &block)
|
35
|
+
task_name, deps = Rake.application.resolve_args(task_args)
|
36
|
+
original = lookup_task(task_name)
|
37
|
+
orgproc = lambda {} # nop
|
38
|
+
if original
|
39
|
+
Rake.application.last_comment = original.comment
|
40
|
+
deps |= original.prerequisites
|
41
|
+
orgproc = lambda{ original.execute }
|
42
|
+
end
|
43
|
+
|
44
|
+
remove_task(task_name)
|
45
|
+
Rake::Task.define_task(task_name => deps) do |t|
|
46
|
+
block.call(t, orgproc)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def task_for_windows(task_args, &block)
|
51
|
+
override_task(task_args) do |t, org|
|
52
|
+
if windows?
|
53
|
+
block.call(t)
|
54
|
+
else
|
55
|
+
org.call
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FileUtils
|
2
|
+
SHELL_COMMAND_FILTER = []
|
3
|
+
|
4
|
+
alias sh_original sh
|
5
|
+
def sh(*cmd, &block)
|
6
|
+
cmd = SHELL_COMMAND_FILTER.inject(cmd){|c,filter| filter.call(c) or c }
|
7
|
+
sh_original(*cmd, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
def add_sh_filter(&block)
|
11
|
+
SHELL_COMMAND_FILTER << block
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_sh_filter_for(pattern, &block)
|
15
|
+
add_sh_filter {|cmd|
|
16
|
+
if cmd[0] =~ pattern
|
17
|
+
block.call(cmd)
|
18
|
+
else
|
19
|
+
cmd
|
20
|
+
end
|
21
|
+
}
|
22
|
+
end
|
23
|
+
end
|
data/helper/util.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
def windows?
|
2
|
+
RUBY_PLATFORM =~ /win/
|
3
|
+
end
|
4
|
+
|
5
|
+
def with_temporary_rename(from, to)
|
6
|
+
mv from, to
|
7
|
+
yield
|
8
|
+
ensure
|
9
|
+
mv to, from
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_dot?
|
13
|
+
if windows?
|
14
|
+
v = `dot -V 2>&1` rescue nil
|
15
|
+
v and v =~ /Graphviz/
|
16
|
+
else
|
17
|
+
`which dot` =~ /\/dot/
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'cgi'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'json'
|
7
|
+
rescue LoadError
|
8
|
+
require 'rubygems'
|
9
|
+
require 'json'
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
require 'livedoor/api/feed_discover/feed'
|
14
|
+
require 'livedoor/api/feed_discover/feed_list'
|
15
|
+
|
16
|
+
|
17
|
+
module Livedoor::API::FeedDiscover
|
18
|
+
class Client
|
19
|
+
|
20
|
+
BASE_URI = URI("http://rpc.reader.livedoor.com/feed/discover").freeze
|
21
|
+
|
22
|
+
def initialize(header = nil)
|
23
|
+
@http_header = (header || {}).dup
|
24
|
+
end
|
25
|
+
|
26
|
+
def http_header
|
27
|
+
@http_header.dup
|
28
|
+
end
|
29
|
+
|
30
|
+
def find(*args)
|
31
|
+
urls = (args || []).flatten
|
32
|
+
header = (Hash === urls.last ? urls.pop : {})
|
33
|
+
raise ArgumentError, "empty link" if urls.empty?
|
34
|
+
raise ArgumentError, "to many links `#{urls.size}' (max 1000)" if 1000 < urls.size
|
35
|
+
FeedList.new(discover_lazy(http_header.update(header), :links => urls.join("\n")))
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_from(url, header = nil)
|
39
|
+
raise ArgumentError, "nil url" if url.nil?
|
40
|
+
header ||= {}
|
41
|
+
FeedList.new(discover_lazy(http_header.update(header), :url => url))
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def discover_lazy(header, param)
|
47
|
+
{
|
48
|
+
:json => lambda { request_json(header, param) },
|
49
|
+
:opml => lambda { request_opml(header, param) }
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def request_json(header, param)
|
54
|
+
JSON.parse(request("json", header, param))
|
55
|
+
end
|
56
|
+
|
57
|
+
def request_opml(header, param)
|
58
|
+
request("opml", header, param)
|
59
|
+
end
|
60
|
+
|
61
|
+
def request(format, header, param)
|
62
|
+
query = param.dup
|
63
|
+
query[:format] = format
|
64
|
+
get(build_uri(query), header)
|
65
|
+
end
|
66
|
+
|
67
|
+
def get(uri, header)
|
68
|
+
open(uri, header){|f| f.read }
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_uri(query)
|
72
|
+
r = BASE_URI.dup
|
73
|
+
r.query = query.map {|k,v| "#{k}=#{CGI.escape(v.to_s)}"}.join('&')
|
74
|
+
r
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|