rss2mail 0.1.2 → 0.1.3

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