rss2mail 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  == VERSION
4
4
 
5
- This documentation refers to rss2mail version 0.1.2
5
+ This documentation refers to rss2mail version 0.1.3
6
6
 
7
7
 
8
8
  == DESCRIPTION
data/lib/rss2mail/feed.rb CHANGED
@@ -25,6 +25,7 @@
25
25
  #++
26
26
 
27
27
  require 'erb'
28
+ require 'open3'
28
29
  require 'nuggets/file/which'
29
30
  require 'nuggets/string/evaluate'
30
31
 
@@ -34,9 +35,15 @@ module RSS2Mail
34
35
 
35
36
  include Util
36
37
 
37
- HOST = ENV['HOSTNAME'] || ENV['HOST'] || %x{hostname}.chomp
38
+ unless MAIL = File.which(mail = 'mail'.freeze)
39
+ class << MAIL; self; end.send(:define_method, :to_s) { mail }
40
+ end
41
+
42
+ HOST = ENV['HOSTNAME'] || ENV['HOST'] || %x{hostname}.chomp.freeze
43
+
44
+ FROM = "From: rss2mail@#{HOST}".freeze
38
45
 
39
- attr_reader :feed, :reload, :verbose, :debug, :simple, :updated, :content, :rss
46
+ KEEP = 100
40
47
 
41
48
  def initialize(feed, options = {})
42
49
  raise TypeError, "Hash expected, got #{feed.class}" unless feed.is_a?(Hash)
@@ -50,19 +57,21 @@ module RSS2Mail
50
57
  @debug = options[:debug]
51
58
 
52
59
  required = [:url, :to, :title]
53
- required.delete_if { |i| feed.has_key?(i) }
60
+ required.delete_if { |key| feed.has_key?(key) }
54
61
 
55
- raise ArgumentError, "Feed incomplete: #{required.join(', ')} missing" unless required.empty?
62
+ unless required.empty?
63
+ raise ArgumentError, "Feed incomplete: #{required.join(', ')} missing"
64
+ end
56
65
  end
57
66
 
58
- def deliver(templates)
59
- unless mail_cmd = File.which(_mail_cmd = 'mail')
60
- raise "Mail command not found: #{_mail_cmd}"
61
- end
67
+ attr_reader :feed, :simple, :updated,
68
+ :reload, :verbose, :debug,
69
+ :content, :rss
62
70
 
63
- to = [*feed[:to]]
71
+ def deliver(templates)
72
+ raise "Mail command not found: #{MAIL}" unless MAIL
64
73
 
65
- if to.empty?
74
+ if (to = Array(feed[:to])).empty?
66
75
  log 'No one to send to'
67
76
  return
68
77
  end
@@ -72,58 +81,38 @@ module RSS2Mail
72
81
  return
73
82
  end
74
83
 
75
- if rss.items.empty?
84
+ if (items = rss.items).empty?
76
85
  log 'No new items'
77
86
  return
78
87
  end
79
88
 
80
- content_type = feed[:content_type] || 'text/html'
81
- encoding = feed[:encoding] || 'UTF-8'
82
-
83
- feed[:sent] ||= []
89
+ type = feed[:content_type] || 'text/html'
90
+ encoding = feed[:encoding] || 'UTF-8'
84
91
 
85
- content_type_header = "Content-type: #{content_type}; charset=#{encoding}"
92
+ type_header = "Content-type: #{type}; charset=#{encoding}"
86
93
 
87
- unless template = templates[content_type[/\/(.*)/, 1]]
88
- log "Template not found: #{content_type}"
94
+ unless template = templates[type[/\/(.*)/, 1]]
95
+ log "Template not found: #{type}"
89
96
  return
90
97
  end
91
98
 
92
- cmd = [
93
- mail_cmd,
94
- '-e',
95
- "-a '#{content_type_header}'",
96
- "-a 'From: rss2mail@#{HOST}'",
97
- "-s '[#{feed[:title]}] \#{subject}'",
98
- *to
99
- ].join(' ')
100
-
101
- sent = 0
102
-
103
- rss.items.each { |item|
104
- title = item.title
105
- link = item.link
106
- description = item.description(feed[:unescape_html])
107
- date = item.date
108
- author = item.author
109
- body = item.body(feed[:body])
110
- subject = item.subject
111
-
112
- log "#{title} / #{date} [#{author}]", debug
113
- log "<#{link}>", debug
114
-
115
- send_mail(cmd.evaluate(binding), ERB.new(template).result(binding)) {
116
- feed[:sent] << link
117
- sent += 1
99
+ sent = feed[:sent] ||= []
100
+ count, title = 0, feed[:title]
101
+
102
+ items.each { |item|
103
+ link, subject, body = render(feed, item, template)
104
+
105
+ send_mail(type_header, to, title, subject, body) {
106
+ sent << link
107
+ count += 1
118
108
  }
119
109
  }
120
110
 
121
- # only keep the last 100 entries
122
- feed[:sent].uniq!
123
- feed[:sent].slice!(0...-100)
111
+ sent.uniq!
112
+ sent.slice!(0...-KEEP)
124
113
 
125
- log "#{sent} items sent"
126
- sent
114
+ log "#{count} items sent"
115
+ count
127
116
  end
128
117
 
129
118
  private
@@ -169,25 +158,25 @@ module RSS2Mail
169
158
  error err, 'while getting feed'
170
159
  end
171
160
 
172
- @content
161
+ content
173
162
  end
174
163
 
175
164
  def parse(reload = reload)
176
165
  @rss = nil if reload
177
166
 
178
- if content && @rss ||= begin
179
- RSS2Mail::RSS.new(content, simple)
180
- rescue ::SimpleRSSError, ::RSS::NotWellFormedError => err
181
- error err, 'while parsing feed'
182
- end
183
- sent = feed[:sent]
167
+ if content
168
+ @rss ||= RSS.feed(content, simple) { |err|
169
+ error err, 'while parsing feed'
170
+ }
171
+
172
+ if rss && !reload
173
+ sent = feed[:sent]
184
174
 
185
- unless reload
186
- @rss.items.delete_if { |item|
175
+ rss.items.delete_if { |item|
187
176
  if updated && date = item.date
188
177
  date <= updated
189
- else
190
- sent && sent.include?(item.link)
178
+ elsif sent
179
+ sent.include?(item.link)
191
180
  end
192
181
  }
193
182
  end
@@ -195,15 +184,35 @@ module RSS2Mail
195
184
  log 'Nothing to parse'
196
185
  end
197
186
 
198
- @rss
187
+ rss
199
188
  end
200
189
 
201
- def send_mail(cmd, body)
190
+ def render(feed, item, template)
191
+ title = item.title
192
+ link = item.link
193
+ description = item.description(feed[:unescape_html])
194
+ date = item.date
195
+ author = item.author
196
+ body = item.body(feed[:body])
197
+ subject = item.subject
198
+
199
+ log "#{title} / #{date} [#{author}]", debug
200
+ log "<#{link}>", debug
201
+
202
+ [link, subject, ERB.new(template).result(binding)]
203
+ end
204
+
205
+ def send_mail(type_header, to, title, subject, body)
202
206
  return if debug
203
207
 
204
- IO.popen(cmd, 'w') { |mail| mail.puts body }
208
+ Open3.popen3(MAIL, '-e', '-a', type_header, '-a', FROM,
209
+ '-s', "[#{title}] #{subject}", *to) { |mail, _, _|
210
+ mail.puts body
211
+ mail.close
212
+ }
213
+
205
214
  yield if block_given?
206
- rescue Errno::EPIPE => err
215
+ rescue Errno::EPIPE, IOError => err
207
216
  error err, 'while sending mail', cmd
208
217
  end
209
218
 
data/lib/rss2mail/rss.rb CHANGED
@@ -43,20 +43,28 @@ module RSS2Mail
43
43
 
44
44
  include Util
45
45
 
46
- SUBSTITUTIONS = {
46
+ SUB = {
47
47
  '–' => '--',
48
48
  '«' => '<<',
49
49
  '&amp;' => '&'
50
50
  }
51
51
 
52
- SUBSTITUTIONS_RE = Regexp.union(*SUBSTITUTIONS.keys)
52
+ SUB_RE = Regexp.union(*SUB.keys)
53
53
 
54
- TAGS_TO_KEEP = %w[a p br h1 h2 h3 h4]
54
+ KEEP = %w[a p br h1 h2 h3 h4]
55
55
 
56
- attr_reader :content, :rss
56
+ class << self
57
+
58
+ def parse(url, *args)
59
+ new(open_feed(url), *args)
60
+ end
61
+
62
+ def feed(*args)
63
+ new(*args)
64
+ rescue ::SimpleRSSError, ::RSS::NotWellFormedError => err
65
+ yield err if block_given?
66
+ end
57
67
 
58
- def self.parse(url, *args)
59
- new(open_feed(url), *args)
60
68
  end
61
69
 
62
70
  def initialize(content, simple = false)
@@ -66,6 +74,8 @@ module RSS2Mail
66
74
  @rss = simple ? simple_parse : parse
67
75
  end
68
76
 
77
+ attr_reader :content, :rss
78
+
69
79
  def simple?
70
80
  @simple
71
81
  end
@@ -172,7 +182,7 @@ module RSS2Mail
172
182
  else raise ArgumentError, "don't know how to handle tag of type #{tag.class}"
173
183
  end
174
184
 
175
- body.gsub!(/<\/?(.*?)>/) { |m| m if TAGS_TO_KEEP.include?($1.split.first.downcase) }
185
+ body.gsub!(/<\/?(.*?)>/) { |m| m if KEEP.include?($1.split.first.downcase) }
176
186
  body.gsub!(/<a\s+href=['"](?!http:).*?>(.*?)<\/a>/mi, '\1')
177
187
 
178
188
  encoding ? Iconv.conv('UTF-8', encoding, body) : body
@@ -189,8 +199,7 @@ module RSS2Mail
189
199
 
190
200
  def clean_subject(str)
191
201
  str.replace_diacritics!
192
- str.gsub!(SUBSTITUTIONS_RE) { |m| SUBSTITUTIONS[m] }
193
- str.gsub!(/'/, "'\\\\''")
202
+ str.gsub!(SUB_RE) { |m| SUB[m] }
194
203
  str.to_ascii
195
204
  end
196
205
 
@@ -4,7 +4,7 @@ module RSS2Mail
4
4
 
5
5
  MAJOR = 0
6
6
  MINOR = 1
7
- TINY = 2
7
+ TINY = 3
8
8
 
9
9
  class << self
10
10
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rss2mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -107,7 +107,7 @@ rdoc_options:
107
107
  - --line-numbers
108
108
  - --all
109
109
  - --title
110
- - rss2mail Application documentation (v0.1.2)
110
+ - rss2mail Application documentation (v0.1.3)
111
111
  - --main
112
112
  - README
113
113
  require_paths: