feed2mail 0.0.1

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/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