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 ADDED
@@ -0,0 +1,3 @@
1
+ == 0.1.0 / 2007-06-16
2
+
3
+ * Initial release
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
@@ -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
@@ -0,0 +1,3 @@
1
+ require "helper/util"
2
+ require "helper/rake"
3
+ require "helper/rake_sh_filter"
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