rss-client 2.0.9
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/MIT-LICENSE +21 -0
- data/README +79 -0
- data/Rakefile +83 -0
- data/bin/rssclient +206 -0
- data/install.rb +84 -0
- data/lib/rss-client.rb +109 -0
- data/lib/rss-client/http-access2.rb +2023 -0
- data/lib/rss-client/http-access2/cookie.rb +541 -0
- data/lib/rss-client/http-access2/http.rb +602 -0
- data/rake_tasks/annotations.rake +84 -0
- data/spec/helper.rb +10 -0
- data/spec/spec_http_access2.rb +13 -0
- data/spec/spec_rss_client.rb +22 -0
- metadata +88 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2007, 2008 Stoyan Zhekov
|
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.
|
21
|
+
|
data/README
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
= RSSClient: Fetching and parsing RSS feeds with easy
|
2
|
+
|
3
|
+
== Download
|
4
|
+
|
5
|
+
The latest version of rake can be found at
|
6
|
+
|
7
|
+
* http://rubyforge.org/project/...
|
8
|
+
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
|
12
|
+
=== Normal Installation
|
13
|
+
|
14
|
+
You can install rake with the following command.
|
15
|
+
|
16
|
+
% ruby install.rb
|
17
|
+
|
18
|
+
from its distribution directory.
|
19
|
+
|
20
|
+
=== GEM Installation
|
21
|
+
|
22
|
+
Download and install rss-client with the following.
|
23
|
+
|
24
|
+
gem install --remote rss-client
|
25
|
+
|
26
|
+
|
27
|
+
== Synopsis
|
28
|
+
|
29
|
+
Fetching RSS feeds.
|
30
|
+
|
31
|
+
|
32
|
+
== Examples
|
33
|
+
|
34
|
+
rssclient -q http://example.com/atom.xml
|
35
|
+
rssclient -r -f http://test:test@example.com/atom.xml
|
36
|
+
rssclient --verbose http://example.com/atom.xml
|
37
|
+
rssclient --giveup 20 -f http://example.com/atom.xml
|
38
|
+
rssclient --since 600 http://example.com/atom.xml
|
39
|
+
rssclient -f -p http://aa:bb@localhost:8088 http://example.com/atom.xml
|
40
|
+
|
41
|
+
|
42
|
+
== Usage
|
43
|
+
|
44
|
+
rssclient [options] feed_url
|
45
|
+
|
46
|
+
=== Options
|
47
|
+
|
48
|
+
-h, --help Displays help message
|
49
|
+
-V, --version Display the version, then exit
|
50
|
+
-q, --quiet Output as little as possible, overrides verbose
|
51
|
+
-v, --verbose Verbose output
|
52
|
+
-p, --proxy Use proxy (format http://user:pass@address:port )
|
53
|
+
-r, --raw Use raw RSS fetch (no error code processing)
|
54
|
+
-g, --giveup Giveup on fetching after timeout (seconds)
|
55
|
+
-f, --force Force fresh feed fetch (no 304 code processing)
|
56
|
+
-s, --since Only changes from {since} seconds ago
|
57
|
+
|
58
|
+
|
59
|
+
== Credits
|
60
|
+
|
61
|
+
[<b>Hiroshi Nakamura</b>] For the http-access2 library.
|
62
|
+
|
63
|
+
[<b>Todd Werth</b>] For the ruby command-line application skeleton
|
64
|
+
|
65
|
+
|
66
|
+
== License
|
67
|
+
|
68
|
+
rss-client is available under an MIT-style license.
|
69
|
+
|
70
|
+
:include: MIT-LICENSE
|
71
|
+
|
72
|
+
|
73
|
+
== Other stuff
|
74
|
+
|
75
|
+
Author:: Stoyan Zhekov <stoyan@gmail.com>
|
76
|
+
Requires:: Ruby 1.8.0 or later
|
77
|
+
License:: Copyright (c) 2007, 2008 Stoyan Zhekov
|
78
|
+
Released under an MIT-style license. See the MIT-LICENSE file
|
79
|
+
included in the distribution.
|
data/Rakefile
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
Gem::manage_gems
|
3
|
+
|
4
|
+
require 'rake'
|
5
|
+
require 'rake/clean'
|
6
|
+
require 'rake/packagetask'
|
7
|
+
require 'rake/gempackagetask'
|
8
|
+
require 'rake/rdoctask'
|
9
|
+
require 'fileutils'
|
10
|
+
include FileUtils
|
11
|
+
|
12
|
+
$:.unshift File.join(File.dirname(__FILE__), "lib")
|
13
|
+
|
14
|
+
NAME = "rss-client"
|
15
|
+
|
16
|
+
RDOC_FILES = %w[
|
17
|
+
lib
|
18
|
+
README
|
19
|
+
MIT-LICENSE
|
20
|
+
]
|
21
|
+
|
22
|
+
RDOC_OPTS = %w[
|
23
|
+
--line-numbers
|
24
|
+
--inline-source
|
25
|
+
--all
|
26
|
+
--quiet
|
27
|
+
--title RSSClient:\ Fetching\ and\ parsing\ RSS\ feeds\ with\ easy
|
28
|
+
--main README
|
29
|
+
--exclude "^(_darcs|.hg|.svn|spec|bin|pkg)/"
|
30
|
+
]
|
31
|
+
|
32
|
+
load 'rake_tasks/annotations.rake'
|
33
|
+
|
34
|
+
spec = Gem::Specification.new do |s|
|
35
|
+
s.name = NAME
|
36
|
+
s.version = "2.0.9"
|
37
|
+
s.author = "Stoyan Zhekov"
|
38
|
+
s.email = "stoyan@gmail.com"
|
39
|
+
s.rubyforge_project = NAME
|
40
|
+
s.homepage = "http://www.assembla.com/wiki/show/#{NAME}"
|
41
|
+
s.platform = Gem::Platform::RUBY
|
42
|
+
s.summary = "Fetching and parsing RSS feeds with easy"
|
43
|
+
s.files = (RDOC_FILES + %w[install.rb] + %w[Rakefile] + Dir["{bin,lib,rake_tasks,spec}/**/*"]).uniq
|
44
|
+
s.test_files = Dir['spec/spec_*.rb']
|
45
|
+
s.require_path = "lib"
|
46
|
+
s.bindir = "bin"
|
47
|
+
s.executables = ['rssclient']
|
48
|
+
s.default_executable = 'rssclient'
|
49
|
+
s.has_rdoc = true
|
50
|
+
s.extra_rdoc_files = RDOC_FILES
|
51
|
+
s.rdoc_options = RDOC_OPTS
|
52
|
+
s.add_dependency("feed-normalizer", ">= 1.4.0")
|
53
|
+
end
|
54
|
+
|
55
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
56
|
+
pkg.need_tar = true
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "package and the gem"
|
60
|
+
task :install do
|
61
|
+
name = "#{spec.name}-#{spec.version}.gem"
|
62
|
+
sh %{rake package}
|
63
|
+
sh %{sudo gem install pkg/#{spec.name}-#{spec.version}.gem}
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "uninstall the gem"
|
67
|
+
task :uninstall => [:clean] do
|
68
|
+
sh %{sudo gem uninstall #{spec.name}}
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "generate rdoc"
|
72
|
+
task :rdoc => [:clean] do
|
73
|
+
sh "rdoc #{(RDOC_OPTS + RDOC_FILES).join(' ')}"
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "Run all the tests"
|
77
|
+
task :test do
|
78
|
+
sh "specrb -Ilib:spec -w #{ENV['TEST'] || '-a'} #{ENV['TESTOPTS']}"
|
79
|
+
end
|
80
|
+
|
81
|
+
task :default => "pkg/#{spec.name}-#{spec.version}.gem" do
|
82
|
+
puts "generated latest version"
|
83
|
+
end
|
data/bin/rssclient
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# == Synopsis
|
3
|
+
# Fetching RSS feeds.
|
4
|
+
#
|
5
|
+
# == Examples
|
6
|
+
#
|
7
|
+
# rssclient -q http://example.com/atom.xml
|
8
|
+
# rssclient -r -f http://test:test@example.com/atom.xml
|
9
|
+
# rssclient --verbose http://example.com/atom.xml
|
10
|
+
# rssclient --giveup 20 -f http://example.com/atom.xml
|
11
|
+
# rssclient --since 600 http://example.com/atom.xml
|
12
|
+
# rssclient -f -p http://aa:bb@localhost:8088 http://example.com/atom.xml
|
13
|
+
#
|
14
|
+
# == Usage
|
15
|
+
# rssclient [options] feed_url
|
16
|
+
#
|
17
|
+
# == Options
|
18
|
+
# -h, --help Displays help message
|
19
|
+
# -V, --version Display the version, then exit
|
20
|
+
# -q, --quiet Output as little as possible, overrides verbose
|
21
|
+
# -v, --verbose Verbose output
|
22
|
+
# -p, --proxy Use proxy (format http://user:pass@address:port )
|
23
|
+
# -r, --raw Use raw RSS fetch (no error code processing)
|
24
|
+
# -g, --giveup Giveup on fetching after timeout (seconds)
|
25
|
+
# -f, --force Force fresh feed fetch (no 304 code processing)
|
26
|
+
# -s, --since Only changes from {since} seconds ago
|
27
|
+
#
|
28
|
+
# == Author
|
29
|
+
# Stoyan Zhekov <stoyan@gmail.com>
|
30
|
+
#
|
31
|
+
# == Copyright
|
32
|
+
# Copyright (c) 2007 Stoyan Zhekov <stoyan@gmail.com>. Licensed under the MIT License:
|
33
|
+
# http://www.opensource.org/licenses/mit-license.php
|
34
|
+
|
35
|
+
begin
|
36
|
+
require 'rss-client'
|
37
|
+
rescue LoadError
|
38
|
+
require 'rubygems'
|
39
|
+
require 'rss-client'
|
40
|
+
end
|
41
|
+
|
42
|
+
require 'optparse'
|
43
|
+
require 'rdoc/usage'
|
44
|
+
|
45
|
+
class App
|
46
|
+
VERSION = '2.0.9'
|
47
|
+
|
48
|
+
attr_reader :options
|
49
|
+
|
50
|
+
def initialize(arguments, stdin)
|
51
|
+
@arguments = arguments
|
52
|
+
@stdin = stdin
|
53
|
+
|
54
|
+
# Set defaults
|
55
|
+
@options = OpenStruct.new
|
56
|
+
@options.verbose = false
|
57
|
+
@options.quiet = false
|
58
|
+
@options.forceUpdate = false
|
59
|
+
@options.raw = false
|
60
|
+
@options.since = Time.new - (10*60) # only changes from 10 min ago
|
61
|
+
@options.giveup = 10 # giveup after 10 sec timeout
|
62
|
+
@options.proxy = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
# Parse options, check arguments, then process the command
|
66
|
+
def run
|
67
|
+
|
68
|
+
if parsed_options? && arguments_valid?
|
69
|
+
|
70
|
+
puts "Start at #{Time.new.to_s}\n\n" if @options.verbose
|
71
|
+
|
72
|
+
output_options if @options.verbose # [Optional]
|
73
|
+
|
74
|
+
process_arguments
|
75
|
+
process_command
|
76
|
+
|
77
|
+
puts "\nFinished at #{Time.new.to_s}" if @options.verbose
|
78
|
+
|
79
|
+
else
|
80
|
+
output_usage
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
protected
|
86
|
+
|
87
|
+
def parsed_options?
|
88
|
+
|
89
|
+
# Specify options
|
90
|
+
opts = OptionParser.new
|
91
|
+
opts.on('-V', '--version') { output_version ; exit 0 }
|
92
|
+
opts.on('-h', '--help') { output_help }
|
93
|
+
opts.on('-v', '--verbose') { @options.verbose = true }
|
94
|
+
opts.on('-q', '--quiet') { @options.quiet = true }
|
95
|
+
opts.on('-r', '--raw') { @options.raw = true }
|
96
|
+
opts.on('-f', '--force') { @options.forceUpdate = true }
|
97
|
+
opts.on('-p', '--proxy PROXY') { |v| @options.proxy = v }
|
98
|
+
opts.on('-g', '--giveup SEC') { |v| @options.giveup = v.to_i }
|
99
|
+
opts.on('-s', '--since SEC') { |v| @options.since = Time.new - v.to_i }
|
100
|
+
|
101
|
+
opts.parse!(@arguments) rescue return false
|
102
|
+
|
103
|
+
process_options
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
# Performs post-parse processing on options
|
108
|
+
def process_options
|
109
|
+
@options.verbose = false if @options.quiet
|
110
|
+
@options.forceUpdate = true unless Time.parse(@options.since.to_s)
|
111
|
+
end
|
112
|
+
|
113
|
+
def output_options
|
114
|
+
puts "Options:\n"
|
115
|
+
|
116
|
+
@options.marshal_dump.each do |name, val|
|
117
|
+
puts " #{name} = #{val}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# True if required arguments were provided
|
122
|
+
def arguments_valid?
|
123
|
+
# TO DO - implement some real logic here
|
124
|
+
true if @arguments.length == 1
|
125
|
+
end
|
126
|
+
|
127
|
+
# Setup the arguments
|
128
|
+
def process_arguments
|
129
|
+
# TO DO - place in local vars, etc
|
130
|
+
end
|
131
|
+
|
132
|
+
def output_help
|
133
|
+
output_version
|
134
|
+
RDoc::usage() #exits app
|
135
|
+
end
|
136
|
+
|
137
|
+
def output_usage
|
138
|
+
RDoc::usage('usage') # gets usage from comments above
|
139
|
+
end
|
140
|
+
|
141
|
+
def output_version
|
142
|
+
puts "#{File.basename(__FILE__)} version #{VERSION}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def process_command
|
146
|
+
feed = RSSFeed.new
|
147
|
+
if @options.raw
|
148
|
+
rss = feed.fetch_raw(@arguments[0], @options)
|
149
|
+
else
|
150
|
+
rss = feed.fetch(@arguments[0], @options)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
# My Modules, Classes, etc
|
157
|
+
|
158
|
+
class RSSFeed
|
159
|
+
include RSSClient
|
160
|
+
|
161
|
+
def fetch_raw(uri, options)
|
162
|
+
options.extra = Hash.new
|
163
|
+
options.extra["Connection"] = "close"
|
164
|
+
options.extra["User-Agent"] = "RSSClient/2.0.9"
|
165
|
+
# options.since is Time::
|
166
|
+
if not options.forceUpdate and options.since
|
167
|
+
time = Time.parse(options.since.to_s)
|
168
|
+
options.extra["If-Modified-Since"] = time.httpdate() if time
|
169
|
+
end
|
170
|
+
begin
|
171
|
+
rss = get_url(uri, options)
|
172
|
+
if rss
|
173
|
+
puts "Status code: #{rss.status}"
|
174
|
+
puts "Headers:"
|
175
|
+
rss.header.dump.each do |h|
|
176
|
+
puts "- " + h.to_s
|
177
|
+
end
|
178
|
+
end
|
179
|
+
rescue RuntimeError => error
|
180
|
+
puts "[E] #{error}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def fetch(uri, options)
|
185
|
+
# always fetch fresh feed
|
186
|
+
rss = get_feed(uri, options)
|
187
|
+
puts "Status code: #{@rssc_raw.status}" if @rssc_raw
|
188
|
+
if rss && rss != "304"
|
189
|
+
puts "Title: #{rss.channel.title.to_s}"
|
190
|
+
puts "Description: #{rss.channel.description}" if rss.channel.description
|
191
|
+
puts "Link: #{rss.channel.urls.first}" if rss.channel.urls
|
192
|
+
puts "News:"
|
193
|
+
rss.entries.each do |i|
|
194
|
+
puts "- " + i.title.to_s
|
195
|
+
end
|
196
|
+
else
|
197
|
+
puts "[E] #{@rssc_error}" if @rssc_error
|
198
|
+
exit
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
|
204
|
+
# Create and run the application
|
205
|
+
app = App.new(ARGV, STDIN)
|
206
|
+
app.run
|
data/install.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'find'
|
3
|
+
require 'ftools'
|
4
|
+
|
5
|
+
include Config
|
6
|
+
|
7
|
+
$ruby = CONFIG['ruby_install_name']
|
8
|
+
|
9
|
+
##
|
10
|
+
# Install a binary file. We patch in on the way through to
|
11
|
+
# insert a #! line. If this is a Unix install, we name
|
12
|
+
# the command (for example) 'rssclient' and let the shebang line
|
13
|
+
# handle running it. Under windows, we add a '.rb' extension
|
14
|
+
# and let file associations to their stuff
|
15
|
+
#
|
16
|
+
|
17
|
+
def installBIN(from, opfile)
|
18
|
+
|
19
|
+
tmp_dir = nil
|
20
|
+
for t in [".", "/tmp", "c:/temp", $bindir]
|
21
|
+
stat = File.stat(t) rescue next
|
22
|
+
if stat.directory? and stat.writable?
|
23
|
+
tmp_dir = t
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
fail "Cannot find a temporary directory" unless tmp_dir
|
29
|
+
tmp_file = File.join(tmp_dir, "_tmp")
|
30
|
+
|
31
|
+
File.open(from) do |ip|
|
32
|
+
File.open(tmp_file, "w") do |op|
|
33
|
+
ruby = File.join($realbindir, $ruby)
|
34
|
+
op.puts "#!#{ruby} -w"
|
35
|
+
op.write ip.read
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
opfile += ".rb" if CONFIG["target_os"] =~ /mswin/i
|
40
|
+
File::install(tmp_file, File.join($bindir, opfile), 0755, true)
|
41
|
+
File::unlink(tmp_file)
|
42
|
+
end
|
43
|
+
|
44
|
+
$sitedir = CONFIG["sitelibdir"]
|
45
|
+
unless $sitedir
|
46
|
+
version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
47
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
48
|
+
$sitedir = $:.find {|x| x =~ /site_ruby/}
|
49
|
+
if !$sitedir
|
50
|
+
$sitedir = File.join($libdir, "site_ruby")
|
51
|
+
elsif $sitedir !~ Regexp.quote(version)
|
52
|
+
$sitedir = File.join($sitedir, version)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
$bindir = CONFIG["bindir"]
|
57
|
+
|
58
|
+
$realbindir = $bindir
|
59
|
+
|
60
|
+
bindir = CONFIG["bindir"]
|
61
|
+
if (destdir = ENV['DESTDIR'])
|
62
|
+
$bindir = destdir + $bindir
|
63
|
+
$sitedir = destdir + $sitedir
|
64
|
+
|
65
|
+
File::makedirs($bindir)
|
66
|
+
File::makedirs($sitedir)
|
67
|
+
end
|
68
|
+
|
69
|
+
# The library files
|
70
|
+
|
71
|
+
files = Dir.chdir('lib') { Dir['**/*.rb'] }
|
72
|
+
|
73
|
+
for fn in files
|
74
|
+
fn_dir = File.dirname(fn)
|
75
|
+
target_dir = File.join($sitedir, fn_dir)
|
76
|
+
if ! File.exist?(target_dir)
|
77
|
+
File.makedirs(target_dir)
|
78
|
+
end
|
79
|
+
File::install(File.join('lib', fn), File.join($sitedir, fn), 0644, true)
|
80
|
+
end
|
81
|
+
|
82
|
+
# and the executable
|
83
|
+
|
84
|
+
installBIN("bin/rssclient", "rssclient")
|