feed2mail 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright 2011 Thibault Jouan. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions are met:
5
+ * Redistributions of source code must retain the above copyright notice, this
6
+ list of conditions and the following disclaimer.
7
+ * Redistributions in binary form must reproduce the above copyright notice,
8
+ this list of conditions and the following disclaimer in the documentation
9
+ and/or other materials provided with the distribution.
10
+ * Neither the name of the software nor the names of its contributors may be
11
+ used to endorse or promote products derived from this software without
12
+ specific prior written permission.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS "AS IS" AND ANY
15
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
18
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,20 @@
1
+ # feed2mail
2
+
3
+ Feed to mail gateway.
4
+
5
+
6
+ ## Usage
7
+
8
+ Create a `$HOME/.feed2mail/config.yaml` file in your home directory:
9
+
10
+ - uri: http://blog.example.net/feed.rss
11
+ - uri: http://another-blog.example.net/feed.rss
12
+
13
+ Now you can run:
14
+
15
+ feed2mail
16
+
17
+
18
+ ## Requirements
19
+
20
+ - ruby
@@ -0,0 +1,27 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+ require 'rspec/core/rake_task'
4
+
5
+ desc 'Run all specs'
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.rspec_opts = %w[--color]
8
+ end
9
+
10
+ namespace :rcov do
11
+ RSpec::Core::RakeTask.new :spec do |t|
12
+ t.rcov = true
13
+ t.rcov_opts = %w[-Ilib -Ispec --exclude "gems/*"]
14
+ t.rcov_opts << %w[--no-html --text-report]
15
+ end
16
+ end
17
+
18
+ gemspec = eval(File.read(Dir["*.gemspec"].first))
19
+
20
+ desc "Validate the gemspec"
21
+ task :gemspec do
22
+ gemspec.validate
23
+ end
24
+
25
+ Rake::GemPackageTask.new gemspec do |pkg|
26
+ pkg.need_tar = true
27
+ end
data/TODO ADDED
@@ -0,0 +1 @@
1
+ * add some tests!
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
+ require 'feed2mail'
5
+
6
+ Feed2Mail::CLI.run ARGV
@@ -0,0 +1,25 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/lib'
2
+ require 'feed2mail'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'feed2mail'
6
+ s.version = Feed2Mail::VERSION
7
+ s.summary = 'Read feeds and send items by mail'
8
+ s.description = <<-eoh
9
+ Feed2Mail is a feed to mail gateway. Feeds can be listed in a
10
+ config file, and new feed items will be reported by mail.
11
+ eoh
12
+
13
+ s.author = 'Thibault Jouan'
14
+ s.email = 'tj@a13.fr'
15
+
16
+ s.files = `git ls-files`.split "\n"
17
+ s.test_files = `git ls-files -- spec/*`.split "\n"
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
19
+
20
+ s.add_dependency 'htmlentities', '>= 4.2.4'
21
+ s.add_dependency 'pony', '>= 1.1'
22
+ s.add_dependency 'simple-rss', '>= 1.2.3'
23
+
24
+ s.add_development_dependency 'rspec', '>= 2.5.0'
25
+ end
@@ -0,0 +1,12 @@
1
+ require 'feed2mail/cli'
2
+ require 'feed2mail/config'
3
+ require 'feed2mail/feed'
4
+ require 'feed2mail/history'
5
+ require 'feed2mail/item'
6
+ require 'feed2mail/report'
7
+
8
+ module Feed2Mail
9
+ VERSION = '0.0.1'
10
+ CONFIG_PATH = '~/.feed2mail/config.yaml'
11
+ HIST_FILE = '~/.feed2mail/history.yaml'
12
+ end
@@ -0,0 +1,26 @@
1
+ require 'optparse'
2
+
3
+ module Feed2Mail
4
+ class CLI
5
+ def self.run(args)
6
+ config = Feed2Mail::Config.new
7
+ config.load
8
+
9
+ OptionParser.new do |o|
10
+ o.banner = "Usage: #{File.basename $0} [options]"
11
+ o.on '-v', '--verbose', 'verbose mode' do |v|
12
+ config.verbose = v
13
+ end
14
+ o.on_tail '-h', '--help', 'show this message' do
15
+ puts o
16
+ exit
17
+ end
18
+ end.parse!
19
+
20
+ report = Feed2Mail::Report.new config
21
+ report.update
22
+
23
+ report.mail :from => 'tj+from@a13.fr', :to => 'tj+to@a13.fr'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ require 'yaml'
2
+
3
+ module Feed2Mail
4
+ class Config
5
+ attr_reader :feeds
6
+ attr_accessor :verbose, :hist_file
7
+
8
+ def initialize
9
+ @feeds = []
10
+ end
11
+
12
+ def load(file = CONFIG_PATH)
13
+ @rc = YAML.load_file(File.expand_path(file))
14
+ @rc['feeds'].each do |f|
15
+ @feeds << Feed.new(f['uri'])
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ require 'simple-rss'
2
+ require 'open-uri'
3
+
4
+ module Feed2Mail
5
+ class Feed
6
+ attr_reader :uri
7
+
8
+ def initialize(uri)
9
+ @uri = uri
10
+ @data = nil
11
+ end
12
+
13
+ def items
14
+ @data ||= SimpleRSS.parse open @uri
15
+ @data.entries.collect { |e| Item.new e }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,28 @@
1
+ require 'yaml'
2
+
3
+ module Feed2Mail
4
+ class History
5
+ def initialize(config)
6
+ @hist_file = config.hist_file || HIST_FILE
7
+ begin
8
+ @hist = YAML.load_file(File.expand_path(@hist_file))
9
+ rescue Errno::ENOENT
10
+ @hist = []
11
+ end
12
+ end
13
+
14
+ def has?(uri)
15
+ @hist.include?(uri) ? true : false
16
+ end
17
+
18
+ def <<(other)
19
+ @hist << other
20
+ end
21
+
22
+ def save!
23
+ File.open File.expand_path(@hist_file), 'w' do |h|
24
+ h.write @hist.to_yaml
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,16 @@
1
+ require 'htmlentities'
2
+
3
+ module Feed2Mail
4
+ class Item
5
+ attr_reader :uri, :title, :description
6
+
7
+ def initialize(entry)
8
+ @uri = entry[:guid] || entry[:link]
9
+
10
+ coder = HTMLEntities.new
11
+
12
+ @title = coder.decode entry[:title]
13
+ @description = coder.decode entry[:description]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,53 @@
1
+ require 'pony'
2
+
3
+ module Feed2Mail
4
+ class Report
5
+ attr_reader :items
6
+
7
+ def initialize(config)
8
+ @feeds = config.feeds
9
+ @items = []
10
+ @history = History.new config
11
+ end
12
+
13
+ def to_s
14
+ out = ''
15
+ @items.each do |i|
16
+ out << <<-eoh
17
+ #{i.title}
18
+ #{i.uri}
19
+
20
+ eoh
21
+ end
22
+
23
+ out
24
+ end
25
+
26
+ def mail(opts)
27
+ Pony.mail(
28
+ :via_options => { :arguments => '-i' },
29
+ :charset => 'UTF-8',
30
+ :from => opts[:from],
31
+ :to => opts[:to],
32
+ :subject => 'Feed2Mail: new feed items published',
33
+ :body => to_s
34
+ )
35
+ end
36
+
37
+ def update
38
+ @feeds.each do |f|
39
+ f.items.each do |i|
40
+ unless seen? i
41
+ @items << i
42
+ @history << i.uri
43
+ end
44
+ end
45
+ end
46
+ @history.save!
47
+ end
48
+
49
+ def seen?(item)
50
+ @history.has?(item.uri) ? true : false
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ describe Config do
4
+ before do
5
+ @config = Feed2Mail::Config.new
6
+ end
7
+
8
+ context '#new' do
9
+ it 'has no feed when created' do
10
+ @config.feeds.should be_empty
11
+ end
12
+ end
13
+
14
+ context 'attribute storing' do
15
+ it 'stores feed' do
16
+ uri = 'http://example.net/feed.rss'
17
+ @config.feeds << Feed2Mail::Feed.new(uri)
18
+ @config.should have(1).feeds
19
+ @config.feeds.first.uri.should == uri
20
+ end
21
+ end
22
+
23
+ context '#load' do
24
+ it 'parses config file' do
25
+ @config.load(File.expand_path(File.dirname(__FILE__) + '/data/config.yaml'))
26
+ @config.feeds[0].uri.should == 'http://example.net/feed.rss'
27
+ @config.feeds[1].uri.should == 'http://example.example.net/other_feed.rss'
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,3 @@
1
+ feeds:
2
+ - uri: http://example.net/feed.rss
3
+ - uri: http://example.example.net/other_feed.rss
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0"?>
2
+ <rss version="2.0">
3
+ <channel>
4
+ <title>Feed sample</title>
5
+ <link>http://feed-sample.example.net/</link>
6
+ <description>Feed description.</description>
7
+ <item>
8
+ <title>Item 1 title</title>
9
+ <link>http://feed-sample.example.net/item/1</link>
10
+ <description><![CDATA[Item 1 description]]></description>
11
+ </item>
12
+ <item>
13
+ <title>Item 2 title &#171;&#160;&amp;&#160;&#187;</title>
14
+ <link>http://feed-sample.example.net/item/2</link>
15
+ <description>
16
+ Item 2 description with entity &#171;&#160;test&#160;&#187;
17
+ </description>
18
+ </item>
19
+ </channel>
20
+ </rss>
@@ -0,0 +1,2 @@
1
+ - http://example.net/sample-uri-1
2
+ - http://example.net/sample-uri-2
@@ -0,0 +1,20 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Feed' do
4
+ before do
5
+ @feed_uri = File.expand_path(File.dirname(__FILE__) + '/data/feed.rss')
6
+ @feed = Feed2Mail::Feed.new(@feed_uri)
7
+ end
8
+
9
+ context '#new' do
10
+ it 'has an URI when created' do
11
+ @feed.uri.should == @feed_uri
12
+ end
13
+ end
14
+
15
+ context 'feeds' do
16
+ it 'load all items' do
17
+ @feed.should have(2).items
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'History' do
4
+ before do
5
+ @config = Feed2Mail::Config.new
6
+ @hist_file = Tempfile.new 'hist'
7
+ FileUtils.cp File.expand_path(File.dirname(__FILE__) + '/data/history.yaml'),
8
+ @hist_file.path
9
+ @config.hist_file = @hist_file.path
10
+ @history = Feed2Mail::History.new @config
11
+ end
12
+
13
+ after do
14
+ @hist_file.close
15
+ @hist_file.unlink
16
+ end
17
+
18
+ it 'load history file' do
19
+ @history.has?('http://example.net/sample-uri-1').should be_true
20
+ @history.has?('http://example.net/sample-uri-2').should be_true
21
+ @history.has?('http://example.net/sample-uri-3').should be_false
22
+ end
23
+
24
+ it 'save history file' do
25
+ @history << 'http://example.net/sample-uri-new'
26
+ @history.save!
27
+
28
+ @new_history = Feed2Mail::History.new @config
29
+ @new_history.has?('http://example.net/sample-uri-1').should be_true
30
+ @new_history.has?('http://example.net/sample-uri-2').should be_true
31
+ @new_history.has?('http://example.net/sample-uri-new').should be_true
32
+ end
33
+
34
+ context 'no history file' do
35
+ before do
36
+ config = Feed2Mail::Config.new
37
+ hist_file = File.expand_path(File.dirname(__FILE__) + '/data/NONE.yaml')
38
+ config.hist_file = hist_file
39
+ @history = Feed2Mail::History.new config
40
+ end
41
+
42
+ it 'has empty history when no history file' do
43
+ @history.instance_variable_get('@hist').should be_empty
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Item' do
4
+ before do
5
+ feed_uri = File.expand_path(File.dirname(__FILE__) + '/data/feed.rss')
6
+ feed = Feed2Mail::Feed.new feed_uri
7
+ @item_0 = feed.items[0]
8
+ @item_1 = feed.items[1]
9
+ end
10
+
11
+ context '#new' do
12
+ it 'has an URI when created' do
13
+ @item_0.uri.should == 'http://feed-sample.example.net/item/1'
14
+ end
15
+
16
+ it 'has a title when created' do
17
+ @item_0.title.should == 'Item 1 title'
18
+ end
19
+
20
+ it 'has a description when created' do
21
+ @item_0.description.should == 'Item 1 description'
22
+ end
23
+ end
24
+
25
+ context 'entities' do
26
+ it 'convert in title' do
27
+ @item_1.title.should == 'Item 2 title « & »'
28
+ end
29
+
30
+ it 'convert in description' do
31
+ @item_1.description.should == 'Item 2 description with entity « test »'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Report' do
4
+ before do
5
+ @config = Feed2Mail::Config.new
6
+ @hist_file = Tempfile.new 'hist'
7
+ FileUtils.cp File.expand_path(File.dirname(__FILE__) + '/data/history.yaml'),
8
+ @hist_file.path
9
+ @config.hist_file = @hist_file.path
10
+ end
11
+
12
+ after do
13
+ @hist_file.close
14
+ @hist_file.unlink
15
+ end
16
+
17
+ context '#new' do
18
+ it 'return empty output with no items' do
19
+ report = Feed2Mail::Report.new @config
20
+ report.to_s.should == ''
21
+ end
22
+ end
23
+
24
+ context 'reporting' do
25
+ before do
26
+ feed_uri = File.expand_path(File.dirname(__FILE__) + '/data/feed.rss')
27
+ @config.feeds << Feed2Mail::Feed.new(feed_uri)
28
+ @report = Feed2Mail::Report.new @config
29
+ @report.update
30
+ end
31
+
32
+ it 'contains feed items' do
33
+ @report.to_s.should match('Item 1 title')
34
+ @report.to_s.should match('Item 2 title « & »')
35
+ end
36
+
37
+ it 'contains feed items links' do
38
+ @report.to_s.should match('http://feed-sample.example.net/item/1')
39
+ @report.to_s.should match('http://feed-sample.example.net/item/2')
40
+ end
41
+
42
+ it 'mails the content' do
43
+ Pony.stub!(:deliver)
44
+ Pony.should_receive(:deliver) do |mail|
45
+ mail.to_s.should match /^From: from@example.net\r$/
46
+ mail.to_s.should match /^To: to@example.net\r$/
47
+ mail.to_s.should match /^Subject: Feed2Mail: new feed items published\r$/
48
+ mail.to_s.should match /^http:\/\/feed-sample\.example\.net\/item\/1\r$/
49
+ #FIXME use 8bit instead of quoted-printable?
50
+ #mail.to_s.should match /^Item 2 title « & »\r$/
51
+ end
52
+ @report.mail :from => 'from@example.net', :to => 'to@example.net'
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,4 @@
1
+ require 'rspec'
2
+ require 'tempfile'
3
+ require 'fileutils'
4
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/feed2mail')
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feed2mail
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Thibault Jouan
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-08 00:00:00 +00:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: htmlentities
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 63
30
+ segments:
31
+ - 4
32
+ - 2
33
+ - 4
34
+ version: 4.2.4
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: pony
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 13
46
+ segments:
47
+ - 1
48
+ - 1
49
+ version: "1.1"
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: simple-rss
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 25
61
+ segments:
62
+ - 1
63
+ - 2
64
+ - 3
65
+ version: 1.2.3
66
+ type: :runtime
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: rspec
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ hash: 27
77
+ segments:
78
+ - 2
79
+ - 5
80
+ - 0
81
+ version: 2.5.0
82
+ type: :development
83
+ version_requirements: *id004
84
+ description: " Feed2Mail is a feed to mail gateway. Feeds can be listed in a\n config file, and new feed items will be reported by mail.\n"
85
+ email: tj@a13.fr
86
+ executables:
87
+ - feed2mail.rb
88
+ extensions: []
89
+
90
+ extra_rdoc_files: []
91
+
92
+ files:
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - TODO
97
+ - bin/feed2mail.rb
98
+ - feed2mail.gemspec
99
+ - lib/feed2mail.rb
100
+ - lib/feed2mail/cli.rb
101
+ - lib/feed2mail/config.rb
102
+ - lib/feed2mail/feed.rb
103
+ - lib/feed2mail/history.rb
104
+ - lib/feed2mail/item.rb
105
+ - lib/feed2mail/report.rb
106
+ - spec/config_spec.rb
107
+ - spec/data/config.yaml
108
+ - spec/data/feed.rss
109
+ - spec/data/history.yaml
110
+ - spec/feed_spec.rb
111
+ - spec/history_spec.rb
112
+ - spec/item_spec.rb
113
+ - spec/report_spec.rb
114
+ - spec/spec_helper.rb
115
+ has_rdoc: true
116
+ homepage:
117
+ licenses: []
118
+
119
+ post_install_message:
120
+ rdoc_options: []
121
+
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ hash: 3
130
+ segments:
131
+ - 0
132
+ version: "0"
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ none: false
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ hash: 3
139
+ segments:
140
+ - 0
141
+ version: "0"
142
+ requirements: []
143
+
144
+ rubyforge_project:
145
+ rubygems_version: 1.3.7
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: Read feeds and send items by mail
149
+ test_files:
150
+ - spec/config_spec.rb
151
+ - spec/data/config.yaml
152
+ - spec/data/feed.rss
153
+ - spec/data/history.yaml
154
+ - spec/feed_spec.rb
155
+ - spec/history_spec.rb
156
+ - spec/item_spec.rb
157
+ - spec/report_spec.rb
158
+ - spec/spec_helper.rb