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 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
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - ruby-head
7
+ script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "https://rubygems.org"
3
+
4
+ gemspec
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
+ [![Build Status](https://travis-ci.org/kamaradclimber/rrimm.png?branch=master)](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
+
@@ -0,0 +1,5 @@
1
+ feed "http://planet.haskell.org/rss20.xml"
2
+ feed "XKCD" do
3
+ uri "http://xkcd.com/rss.xml"
4
+ category "webcomics"
5
+ end
data/lib/rrimm.rb ADDED
@@ -0,0 +1,7 @@
1
+ require_relative 'rrimm/feed'
2
+ require_relative 'rrimm/config'
3
+ require_relative 'rrimm/fetcher'
4
+ require_relative 'rrimm/item_formatter'
5
+ require_relative 'rrimm/cache'
6
+ require_relative 'rrimm/generic_item'
7
+ require_relative 'rrimm/generic_feed'
@@ -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
@@ -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,2 @@
1
+ require_relative 'item_formatter/default'
2
+ require_relative 'item_formatter/mail'
@@ -0,0 +1,10 @@
1
+ module RRImm
2
+ module ItemFormatter
3
+ class Default
4
+ def format(feed, item, feed_config, pipe)
5
+ pipe.write "#{feed.channel.title}: #{item.title} (#{item.date})"
6
+ pipe.write "\n"
7
+ end
8
+ end
9
+ end
10
+ 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
@@ -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
@@ -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