rrimm 0.1.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.
- checksums.yaml +7 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +28 -0
- data/README.md +67 -0
- data/bin/rrimm +52 -0
- data/examples/complete_config.rb +24 -0
- data/examples/most_simple_config.rb +5 -0
- data/lib/rrimm.rb +7 -0
- data/lib/rrimm/cache.rb +60 -0
- data/lib/rrimm/config.rb +79 -0
- data/lib/rrimm/feed.rb +55 -0
- data/lib/rrimm/fetcher.rb +42 -0
- data/lib/rrimm/generic_feed.rb +20 -0
- data/lib/rrimm/generic_item.rb +38 -0
- data/lib/rrimm/item_formatter.rb +2 -0
- data/lib/rrimm/item_formatter/default.rb +10 -0
- data/lib/rrimm/item_formatter/mail.rb +39 -0
- data/rrimm.gemspec +17 -0
- data/spec/cache_spec.rb +31 -0
- data/spec/config_spec.rb +13 -0
- data/spec/feed_spec.rb +13 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a4e9e1bbc213cefa46c98c7b54bbad044b6a9475
|
4
|
+
data.tar.gz: 4be8b7dec27cf1a18f527c44b625c2a215d9e6e3
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f0e3732e0467b531dd617b1d8c4b3a123d0e28e03f09c2d39aef9696eed479ec555084769a07a4992771b9fc2d8adc215e7da4e55640c84a5817c7ba7bc4901f
|
7
|
+
data.tar.gz: 1be89e81c363110f4a55b1f3a662abb04272472a782ceaa6bfab4f3c94a7a78c9eab2148da934e467d11ccc81b35b7d389eb259d3796830e5d03a107f37a05b9
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rrimm (0.1.0)
|
5
|
+
open_uri_redirections
|
6
|
+
parallel
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
diff-lcs (1.2.5)
|
12
|
+
open_uri_redirections (0.1.4)
|
13
|
+
parallel (0.9.2)
|
14
|
+
rspec (2.14.1)
|
15
|
+
rspec-core (~> 2.14.0)
|
16
|
+
rspec-expectations (~> 2.14.0)
|
17
|
+
rspec-mocks (~> 2.14.0)
|
18
|
+
rspec-core (2.14.7)
|
19
|
+
rspec-expectations (2.14.5)
|
20
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
21
|
+
rspec-mocks (2.14.6)
|
22
|
+
|
23
|
+
PLATFORMS
|
24
|
+
ruby
|
25
|
+
|
26
|
+
DEPENDENCIES
|
27
|
+
rrimm!
|
28
|
+
rspec
|
data/README.md
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
=========
|
2
|
+
About rrimm
|
3
|
+
=========
|
4
|
+
|
5
|
+
[](https://travis-ci.org/kamaradclimber/rrimm)
|
6
|
+
|
7
|
+
In a nutshell
|
8
|
+
-------------
|
9
|
+
|
10
|
+
**Technically**, *rrimm* is a little tool that retrieves a list of RSS/Atom feeds and send them by email.
|
11
|
+
|
12
|
+
**Functionally**, *rrimm* makes it possible to use mail readers for feeds, for the sake of *I-want-the-mutt-of-feed-readers* zealots.
|
13
|
+
|
14
|
+
**Originally**, *rrimm* is the ruby reboot of the excellent k0ral's *imm* (https://github.com/k0ral/imm).
|
15
|
+
The original concept, this README and a lot of ideas are extracted from *imm*.
|
16
|
+
|
17
|
+
*rrimm* is written and configured in *Ruby*.
|
18
|
+
|
19
|
+
Informations about versions, dependencies, source repositories and contacts can be found on rubygems.org_.
|
20
|
+
|
21
|
+
|
22
|
+
Need & purpose
|
23
|
+
--------------
|
24
|
+
|
25
|
+
Following numerous RSS/Atom feeds needs organization and aggregation.
|
26
|
+
Such needs are usually met by feed readers.
|
27
|
+
Although there are a lot of those, some people still feel unsatisfied with the existing implementations.
|
28
|
+
|
29
|
+
The expected features of a feed reader could be defined as follows:
|
30
|
+
|
31
|
+
- it retrieves items with the following attributes: an author, a date/time, a (possibly enriched) body;
|
32
|
+
- items can be sorted, categorized, marked as read/unread, tagged, shared/forwarded;
|
33
|
+
- items must be available from anywhere on the internet.
|
34
|
+
|
35
|
+
Luckily, there's already a widespread solution that provides such features: mail readers.
|
36
|
+
Considering that, *rrimm* aims at projecting the RSS/Atom paradigm onto the mail one; this way, all the existing tools that work on mails can be leveraged to work on RSS/Atom feeds as well, no wheel reinventing.
|
37
|
+
|
38
|
+
Such need is already covered by *imm*, a tool written and maintained by k0ral.
|
39
|
+
imm's code has grown and is now using powerful concepts for beauty sake. Its source code has lost its readability.
|
40
|
+
*rrimm* intends to keep it (really) simple both in features and source code.
|
41
|
+
|
42
|
+
|
43
|
+
Function
|
44
|
+
--------
|
45
|
+
|
46
|
+
*rrimm* does only one thing and does it well: it downloads an RSS/Atom feeds list, and for each new item it writes an email on the standard output. How to write mail is setup in *rrimm*'s configuration file.
|
47
|
+
|
48
|
+
No *SMTP* sending, no *IMAP* serving, no aggregating: those should be performed by external tools.
|
49
|
+
|
50
|
+
|
51
|
+
Example usage
|
52
|
+
-------------
|
53
|
+
|
54
|
+
It is possible to setup a Google Reader-like on a server using the following steps:
|
55
|
+
|
56
|
+
- schedule *rrimm* to check feeds regularly and write new items into mail format;
|
57
|
+
- pipe these emails into any smtp tool (msmtp, sendmail)
|
58
|
+
- setup a webmail, bound to the IMAP server above, to read feeds from any computer connected to the internet.
|
59
|
+
|
60
|
+
|
61
|
+
Getting started
|
62
|
+
---------------
|
63
|
+
|
64
|
+
To get started, please fill the configuration file at ``~/.config/rrimm/rrimm.rb`` with your feeds list and settings. An example configuration file is provided with the package. Configuring *rrimm* requires virtually no knowledge of *Ruby* language.
|
65
|
+
|
66
|
+
|
67
|
+
.. _rubygems: https://rubygems.org/rrimm
|
data/bin/rrimm
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
begin
|
4
|
+
load 'lib/rrimm.rb'
|
5
|
+
rescue LoadError
|
6
|
+
require 'rrimm'
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'optparse'
|
10
|
+
|
11
|
+
options = {
|
12
|
+
'action' => :sync,
|
13
|
+
'conf_file' => File.join(ENV['HOME'], '.config', 'rrimm', 'rrimm.rb'),
|
14
|
+
'concurrency' => 1,
|
15
|
+
}
|
16
|
+
|
17
|
+
OptionParser.new do |opts|
|
18
|
+
opts.banner = "Usage: rrimm "
|
19
|
+
opts.on('-c', '--config [file]',
|
20
|
+
'configuration file used by rrimm') do |conf_file|
|
21
|
+
options['conf_file'] = conf_file
|
22
|
+
end
|
23
|
+
|
24
|
+
opts.on('-C', '--concurrency N',
|
25
|
+
'concurrency level to fetch feeds. Default 1') do |c|
|
26
|
+
options['concurrency'] = c.to_i
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on('-a', '--action [action]', [:sync, :show],
|
30
|
+
'Specify what to do: "sync" feeds, "show" config') do |action|
|
31
|
+
options['action'] = action
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on_tail("-h", "--help", "You know what it does") do
|
35
|
+
puts opts
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
end.parse!(ARGV)
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
conf = RRImm::Config.new
|
43
|
+
conf.load(options['conf_file'])
|
44
|
+
|
45
|
+
fetcher = RRImm::Fetcher.new(conf)
|
46
|
+
|
47
|
+
case options['action']
|
48
|
+
when :sync
|
49
|
+
fetcher.parallel_fetch(options['concurrency'])
|
50
|
+
when :show
|
51
|
+
conf.show
|
52
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
default_formatter RRImm::ItemFormatter::Mail.new(
|
2
|
+
from: 'rrimm@example.com',
|
3
|
+
to: 'me@me.com'
|
4
|
+
)
|
5
|
+
pipe "msmtp -t --read-envelope-from"
|
6
|
+
#pipe "cat"
|
7
|
+
|
8
|
+
feed "http://planet.haskell.org/rss20.xml"
|
9
|
+
feed "http://www.archlinux.org/feeds/news/"
|
10
|
+
feed "http://alan.petitepomme.net/cwn/cwn.rss"
|
11
|
+
|
12
|
+
feed "xkcd" do
|
13
|
+
uri "http://xkcd.com/rss.xml"
|
14
|
+
category "webcomics"
|
15
|
+
end
|
16
|
+
feed 'Cartesian comics' do
|
17
|
+
uri 'http://feeds.feedburner.com/CartesianClosedComic?format=xml'
|
18
|
+
category "webcomics"
|
19
|
+
end
|
20
|
+
feed 'SMBC' do
|
21
|
+
uri "http://www.smbc-comics.com/rss.php"
|
22
|
+
category 'webcomics'
|
23
|
+
end
|
24
|
+
|
data/lib/rrimm.rb
ADDED
data/lib/rrimm/cache.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
module RRImm
|
2
|
+
class Cache
|
3
|
+
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :path
|
6
|
+
|
7
|
+
REMOVE_PATTERNS = [
|
8
|
+
/^.*:\/\/\/?/,
|
9
|
+
/^(http|ftp|file)s?___/,
|
10
|
+
/_+$/,
|
11
|
+
]
|
12
|
+
|
13
|
+
INVALID_PATTERNS = [
|
14
|
+
/[^\w]/,
|
15
|
+
]
|
16
|
+
|
17
|
+
DEFAULT_TIMESTAMP = 1
|
18
|
+
|
19
|
+
def initialize(name)
|
20
|
+
@name = name
|
21
|
+
@path = name
|
22
|
+
end
|
23
|
+
|
24
|
+
def path(arg=nil)
|
25
|
+
if arg
|
26
|
+
@path = arg
|
27
|
+
end
|
28
|
+
@path
|
29
|
+
end
|
30
|
+
|
31
|
+
def cache_file(feed)
|
32
|
+
filename = sanitize(feed.uri)
|
33
|
+
File.join(path, filename)
|
34
|
+
end
|
35
|
+
|
36
|
+
def read(feed)
|
37
|
+
file_path = cache_file(feed)
|
38
|
+
|
39
|
+
return DEFAULT_TIMESTAMP unless File.exists?(file_path)
|
40
|
+
timestamp = File.read(file_path)
|
41
|
+
timestamp.to_i
|
42
|
+
end
|
43
|
+
|
44
|
+
def save(feed, timestamp)
|
45
|
+
file_path = cache_file(feed)
|
46
|
+
File.write(file_path, timestamp)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
private
|
51
|
+
def sanitize(name)
|
52
|
+
cleaned_name = INVALID_PATTERNS.inject(name) do |memo,pattern|
|
53
|
+
memo.gsub(pattern, '_')
|
54
|
+
end
|
55
|
+
REMOVE_PATTERNS.inject(cleaned_name) do |memo,pattern|
|
56
|
+
memo.gsub(pattern, '')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/rrimm/config.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
module RRImm
|
2
|
+
class Config
|
3
|
+
attr :feeds, :cache
|
4
|
+
attr :default_formatter, :pipe
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@feeds = {}
|
8
|
+
cache "default cache" do
|
9
|
+
path File.join(ENV['HOME'], '.cache', 'rrimm')
|
10
|
+
end
|
11
|
+
@pipe = "cat"
|
12
|
+
end
|
13
|
+
|
14
|
+
def feeds
|
15
|
+
@feeds
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_cache
|
19
|
+
@cache
|
20
|
+
end
|
21
|
+
|
22
|
+
def show
|
23
|
+
puts "Cache: #{@cache.name}"
|
24
|
+
puts " path: #{@cache.path}" unless @cache.path.eql? @cache.name
|
25
|
+
|
26
|
+
puts "Default formatter: #{default_formatter}" if default_formatter
|
27
|
+
|
28
|
+
puts "Feeds:"
|
29
|
+
@feeds.values.group_by { |f| f.category }.map do |cat, feeds|
|
30
|
+
puts "#{cat}:" unless cat.nil? or cat.empty?
|
31
|
+
feeds.each do |feed|
|
32
|
+
fqdn = [feed.name]
|
33
|
+
fqdn << feed.uri unless feed.name.eql? feed.uri
|
34
|
+
puts "- #{fqdn.join ': '}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def evaluate_feed_definition(feed_name, &block)
|
40
|
+
#this allow to redefine feeds if necessary
|
41
|
+
existing_feed = @feeds[feed_name]
|
42
|
+
new_feed = (existing_feed || Feed.new(feed_name))
|
43
|
+
new_feed.formatter = default_formatter if default_formatter
|
44
|
+
new_feed.pipe = pipe if pipe
|
45
|
+
new_feed.instance_eval(&block) if block
|
46
|
+
new_feed
|
47
|
+
end
|
48
|
+
|
49
|
+
def default_formatter(arg=nil)
|
50
|
+
if arg
|
51
|
+
@default_formatter = arg
|
52
|
+
end
|
53
|
+
@default_formatter
|
54
|
+
end
|
55
|
+
|
56
|
+
def pipe(arg=nil)
|
57
|
+
if arg
|
58
|
+
@pipe = arg
|
59
|
+
end
|
60
|
+
@pipe
|
61
|
+
end
|
62
|
+
|
63
|
+
def feed(name, *args, &block)
|
64
|
+
feed_def = evaluate_feed_definition(name, *args, &block)
|
65
|
+
@feeds[name] = feed_def
|
66
|
+
end
|
67
|
+
|
68
|
+
def load(file)
|
69
|
+
instance_eval(File.read(file), file)
|
70
|
+
end
|
71
|
+
|
72
|
+
def cache(name, *args, &block)
|
73
|
+
@cache = Cache.new name
|
74
|
+
@cache.instance_eval(&block) if block
|
75
|
+
@cache
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
data/lib/rrimm/feed.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module RRImm
|
2
|
+
class Feed
|
3
|
+
|
4
|
+
attr_accessor :name
|
5
|
+
attr_accessor :uri
|
6
|
+
attr_accessor :formatter_class, :formatter
|
7
|
+
attr_accessor :category
|
8
|
+
attr_accessor :pipe
|
9
|
+
|
10
|
+
def initialize(name)
|
11
|
+
@name = name
|
12
|
+
@uri = name
|
13
|
+
@formatter_class = RRImm::ItemFormatter::Default
|
14
|
+
end
|
15
|
+
|
16
|
+
def format(feed, item)
|
17
|
+
@formatter ||= @formatter_class.new
|
18
|
+
cmd = %Q<#{pipe}>
|
19
|
+
IO.popen(cmd,'w+') do |pipe|
|
20
|
+
@formatter.format(feed, item, self, pipe)
|
21
|
+
pipe.close_write
|
22
|
+
pipe.read.split("\n").each { |l| puts l }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def category(arg=nil)
|
27
|
+
if arg
|
28
|
+
@category = arg
|
29
|
+
end
|
30
|
+
@category
|
31
|
+
end
|
32
|
+
|
33
|
+
def uri(arg=nil)
|
34
|
+
if arg
|
35
|
+
@uri = arg
|
36
|
+
end
|
37
|
+
@uri
|
38
|
+
end
|
39
|
+
|
40
|
+
def formatter_class(arg=nil)
|
41
|
+
if arg
|
42
|
+
@formatter_class = arg
|
43
|
+
end
|
44
|
+
@formatter_class
|
45
|
+
end
|
46
|
+
|
47
|
+
def pipe(arg=nil)
|
48
|
+
if arg
|
49
|
+
@pipe = arg
|
50
|
+
end
|
51
|
+
@pipe
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'rss'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'open_uri_redirections'
|
4
|
+
require 'parallel'
|
5
|
+
|
6
|
+
module RRImm
|
7
|
+
class Fetcher
|
8
|
+
|
9
|
+
attr_accessor :config
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def parallel_fetch(concurrency)
|
16
|
+
Parallel.map(@config.feeds, :in_threads => concurrency) do |name,feed_config|
|
17
|
+
fetch_feed(name, feed_config)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def fetch
|
22
|
+
@config.feeds.map do |name,feed_config|
|
23
|
+
fetch_feed(name, feed_config)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def fetch_feed(name, feed_config)
|
28
|
+
last_read = Time.at(@config.get_cache.read(feed_config))
|
29
|
+
puts name
|
30
|
+
open(feed_config.uri, :allow_redirections => :safe) do |rss|
|
31
|
+
feed = RSS::Parser.parse(rss)
|
32
|
+
feed = GenericFeed.new feed
|
33
|
+
items = feed.items.select { |item| item.date > last_read }
|
34
|
+
last_read = items.collect { |item| item.date }.max unless items.empty?
|
35
|
+
items.each do |item|
|
36
|
+
feed_config.format(feed, item)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
@config.get_cache.save(feed_config, last_read.to_i)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module RRImm
|
2
|
+
class GenericFeed
|
3
|
+
def initialize(feed)
|
4
|
+
@underlying = feed
|
5
|
+
@items = feed.items.map {|item| GenericItem.new item }
|
6
|
+
case feed
|
7
|
+
when RSS::Rss
|
8
|
+
@title = feed.channel.title
|
9
|
+
when RSS::Atom
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_accessor :underlying
|
14
|
+
attr_accessor :title
|
15
|
+
|
16
|
+
attr_accessor :items
|
17
|
+
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RRImm
|
2
|
+
class GenericItem
|
3
|
+
def initialize(item)
|
4
|
+
@underlying = item
|
5
|
+
case item
|
6
|
+
when RSS::Rss::Channel::Item
|
7
|
+
@date = item.date
|
8
|
+
@title = item.title
|
9
|
+
@link = item.link
|
10
|
+
@content = item.description
|
11
|
+
@author = item.author
|
12
|
+
when RSS::Atom::Feed::Entry
|
13
|
+
@date = item.date || item.updated.content
|
14
|
+
@title = item.title.content
|
15
|
+
@link = item.link
|
16
|
+
@content = item.content
|
17
|
+
@author = item.author
|
18
|
+
else
|
19
|
+
puts item.class
|
20
|
+
fail "Please code this case !"
|
21
|
+
@updated_date = item.updated_date
|
22
|
+
@content = item.content
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_accessor :underlying
|
27
|
+
|
28
|
+
attr_accessor :title
|
29
|
+
attr :updated_date, :date
|
30
|
+
attr_accessor :link
|
31
|
+
attr_accessor :content
|
32
|
+
attr_accessor :author
|
33
|
+
|
34
|
+
def date
|
35
|
+
@updated_date || @date
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module RRImm
|
2
|
+
module ItemFormatter
|
3
|
+
class Mail
|
4
|
+
|
5
|
+
attr_accessor :dest, :sender
|
6
|
+
|
7
|
+
def initialize(hash)
|
8
|
+
@dest = hash[:to]
|
9
|
+
@sender = hash[:from]
|
10
|
+
end
|
11
|
+
|
12
|
+
def from(item)
|
13
|
+
if item.author and item.author.include? '@'
|
14
|
+
item.author
|
15
|
+
else
|
16
|
+
@sender
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def subject(feed, item, feed_config)
|
21
|
+
subject = item.title
|
22
|
+
subject = "[#{feed_config.category}]#{item.title}" if feed_config.category
|
23
|
+
subject
|
24
|
+
end
|
25
|
+
|
26
|
+
def format(feed, item, feed_config, pipe)
|
27
|
+
pipe.write "From: #{from(item)}\n"
|
28
|
+
pipe.write "To: #{dest}\n"
|
29
|
+
pipe.write "Subject: #{subject(feed, item, feed_config)}\n"
|
30
|
+
pipe.write "Content-Type: text/html;\n"
|
31
|
+
pipe.write "\n"
|
32
|
+
pipe.write item.link
|
33
|
+
pipe.write "\n\n"
|
34
|
+
pipe.write item.content if item.content
|
35
|
+
pipe.write "\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/rrimm.gemspec
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rrimm'
|
3
|
+
s.version = '0.1.0'
|
4
|
+
s.licenses = ['Apache Licence v2']
|
5
|
+
s.summary = "RSS to email tool"
|
6
|
+
s.description = "imm reboot in ruby. Retrieve rss feeds and send them by email"
|
7
|
+
s.authors = ["Grégoire Seux"]
|
8
|
+
s.email = 'rrimm@familleseux.net'
|
9
|
+
s.homepage = "http://github.com/kamaradclimber/mosespa"
|
10
|
+
s.files = `git ls-files`.split("\n")
|
11
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
12
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
13
|
+
|
14
|
+
s.add_development_dependency 'rspec'
|
15
|
+
s.add_dependency 'open_uri_redirections'
|
16
|
+
s.add_dependency 'parallel'
|
17
|
+
end
|
data/spec/cache_spec.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../lib/rrimm'
|
3
|
+
|
4
|
+
require 'tmpdir'
|
5
|
+
|
6
|
+
describe RRImm::Cache do
|
7
|
+
describe '#new' do
|
8
|
+
it 'uses the name as default path' do
|
9
|
+
cache = RRImm::Cache.new 'default location'
|
10
|
+
expect(cache.path).to eq 'default location'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'reads default timestamp if cache is not present' do
|
15
|
+
feed = RRImm::Feed.new 'http://kernel.org/rss'
|
16
|
+
Dir.mktmpdir do |dir|
|
17
|
+
cache = RRImm::Cache.new dir
|
18
|
+
expect(cache.read(feed)).to eq RRImm::Cache::DEFAULT_TIMESTAMP
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'reads the correct timestamp' do
|
23
|
+
feed = RRImm::Feed.new 'http://kernel.org/rss'
|
24
|
+
now = Time.now.to_i
|
25
|
+
Dir.mktmpdir do |dir|
|
26
|
+
cache = RRImm::Cache.new dir
|
27
|
+
cache.save(feed, now)
|
28
|
+
expect(cache.read(feed)).to eq now
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../lib/rrimm'
|
3
|
+
|
4
|
+
describe RRImm::Config do
|
5
|
+
describe "#load" do
|
6
|
+
it 'loads feeds properly' do
|
7
|
+
conf = RRImm::Config.new
|
8
|
+
expect(conf.feeds.size).to be 0
|
9
|
+
conf.load(File.join(File.dirname(__FILE__), '..', 'examples', 'most_simple_config.rb'))
|
10
|
+
expect(conf.feeds.size).to be 2
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/spec/feed_spec.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require_relative '../lib/rrimm'
|
3
|
+
|
4
|
+
describe RRImm::Feed do
|
5
|
+
describe "#new" do
|
6
|
+
it 'uses the name as uri by default' do
|
7
|
+
f = RRImm::Feed.new 'a random feed'
|
8
|
+
expect(f.name).to eq('a random feed')
|
9
|
+
expect(f.uri).to eq('a random feed')
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rrimm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Grégoire Seux
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: open_uri_redirections
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: parallel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: imm reboot in ruby. Retrieve rss feeds and send them by email
|
56
|
+
email: rrimm@familleseux.net
|
57
|
+
executables:
|
58
|
+
- rrimm
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- .travis.yml
|
63
|
+
- Gemfile
|
64
|
+
- Gemfile.lock
|
65
|
+
- README.md
|
66
|
+
- bin/rrimm
|
67
|
+
- examples/complete_config.rb
|
68
|
+
- examples/most_simple_config.rb
|
69
|
+
- lib/rrimm.rb
|
70
|
+
- lib/rrimm/cache.rb
|
71
|
+
- lib/rrimm/config.rb
|
72
|
+
- lib/rrimm/feed.rb
|
73
|
+
- lib/rrimm/fetcher.rb
|
74
|
+
- lib/rrimm/generic_feed.rb
|
75
|
+
- lib/rrimm/generic_item.rb
|
76
|
+
- lib/rrimm/item_formatter.rb
|
77
|
+
- lib/rrimm/item_formatter/default.rb
|
78
|
+
- lib/rrimm/item_formatter/mail.rb
|
79
|
+
- rrimm.gemspec
|
80
|
+
- spec/cache_spec.rb
|
81
|
+
- spec/config_spec.rb
|
82
|
+
- spec/feed_spec.rb
|
83
|
+
homepage: http://github.com/kamaradclimber/mosespa
|
84
|
+
licenses:
|
85
|
+
- Apache Licence v2
|
86
|
+
metadata: {}
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options: []
|
89
|
+
require_paths:
|
90
|
+
- lib
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - '>='
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
requirements: []
|
102
|
+
rubyforge_project:
|
103
|
+
rubygems_version: 2.0.3
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: RSS to email tool
|
107
|
+
test_files:
|
108
|
+
- spec/cache_spec.rb
|
109
|
+
- spec/config_spec.rb
|
110
|
+
- spec/feed_spec.rb
|