rmsgen 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/acts_like/string.rb +13 -0
- data/lib/rmsgen.rb +15 -3
- data/lib/rmsgen/compresser.rb +6 -7
- data/lib/rmsgen/fs_polnote_group.rb +13 -3
- data/lib/rmsgen/imap_client.rb +60 -0
- data/lib/rmsgen/imap_polnote_group.rb +14 -47
- data/lib/rmsgen/inquirer.rb +4 -10
- data/lib/rmsgen/part.rb +19 -0
- data/lib/rmsgen/part_group.rb +41 -13
- data/lib/rmsgen/parts/duration.rb +7 -0
- data/lib/rmsgen/parts/footer.rb +7 -0
- data/lib/rmsgen/parts/header.rb +9 -0
- data/lib/rmsgen/parts/indented_line.rb +7 -0
- data/lib/rmsgen/parts/plain_text.rb +5 -0
- data/lib/rmsgen/parts/polnote_url_request.rb +8 -0
- data/lib/rmsgen/parts/url.rb +5 -0
- data/lib/rmsgen/polnote.rb +16 -4
- data/lib/rmsgen/polnote_group.rb +19 -0
- data/lib/rmsgen/runtime.rb +17 -22
- data/lib/rmsgen/titleizer.rb +5 -10
- data/lib/rmsgen/version.rb +1 -1
- data/spec/fixtures/urgent_note +1 -2
- data/spec/imap_client_spec.rb +70 -0
- data/spec/imap_polnote_group_spec.rb +13 -24
- data/spec/part_group_spec.rb +3 -6
- data/spec/part_spec.rb +51 -0
- data/spec/polnote_group.rb +24 -0
- data/spec/polnote_spec.rb +2 -7
- data/spec/runtime_spec.rb +3 -13
- metadata +16 -2
data/lib/rmsgen.rb
CHANGED
@@ -2,6 +2,17 @@ require 'yaml'
|
|
2
2
|
require 'erb'
|
3
3
|
|
4
4
|
module Rmsgen
|
5
|
+
%w{ header
|
6
|
+
footer
|
7
|
+
plain_text
|
8
|
+
url
|
9
|
+
polnote_url_request
|
10
|
+
indented_line
|
11
|
+
duration
|
12
|
+
}.each do |fname|
|
13
|
+
require File.join(File.dirname(__FILE__), 'rmsgen', 'parts', fname)
|
14
|
+
end
|
15
|
+
|
5
16
|
%w{ part_group
|
6
17
|
polnote
|
7
18
|
titleizer
|
@@ -9,13 +20,14 @@ module Rmsgen
|
|
9
20
|
script
|
10
21
|
inquirer
|
11
22
|
runtime
|
23
|
+
part
|
12
24
|
link
|
25
|
+
imap_client
|
13
26
|
imap_polnote_group
|
14
27
|
fs_polnote_group
|
28
|
+
polnote_group
|
29
|
+
|
15
30
|
}.each do |fname|
|
16
31
|
require File.join(File.dirname(__FILE__), 'rmsgen', fname)
|
17
32
|
end
|
18
33
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
data/lib/rmsgen/compresser.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Rmsgen
|
2
2
|
class Compresser
|
3
|
-
def initialize(
|
4
|
-
@
|
5
|
-
@parts = polnote.parts
|
3
|
+
def initialize(part_group=[])
|
4
|
+
@part_group = part_group
|
6
5
|
run!
|
7
6
|
end
|
8
7
|
|
9
8
|
def body
|
10
|
-
@
|
9
|
+
@part_group.join PartGroup::DELIMETER
|
11
10
|
end
|
12
11
|
|
13
12
|
private
|
@@ -19,15 +18,15 @@ module Rmsgen
|
|
19
18
|
end
|
20
19
|
|
21
20
|
def rm_header
|
22
|
-
@
|
21
|
+
@part_group.delete_if { |x| x.is_a?(Rmsgen::Parts::Header) }
|
23
22
|
end
|
24
23
|
|
25
24
|
def rm_footer
|
26
|
-
@
|
25
|
+
@part_group.delete_if { |x| x.is_a?(Rmsgen::Parts::Footer) }
|
27
26
|
end
|
28
27
|
|
29
28
|
def single_line_paragraphs
|
30
|
-
@
|
29
|
+
@part_group.each { |part| part.gsub!("\n", ' ') }
|
31
30
|
end
|
32
31
|
end
|
33
32
|
end
|
@@ -1,12 +1,22 @@
|
|
1
1
|
module Rmsgen
|
2
2
|
class FsPolnoteGroup
|
3
3
|
def initialize(dir=nil)
|
4
|
-
|
5
|
-
@
|
6
|
-
@notes = @raw_notes.map { |note| Rmsgen::Polnote.new(:body => note) }
|
4
|
+
@note_bodies = note_bodies_from_directory(dir)
|
5
|
+
@notes = build_many_polnotes(@note_bodies)
|
7
6
|
end
|
7
|
+
|
8
8
|
def all
|
9
9
|
@notes
|
10
10
|
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def note_bodies_from_directory(dir)
|
15
|
+
Dir["#{dir}/*"].map { |f| File.read(f) }
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_many_polnotes(note_bodies)
|
19
|
+
note_bodies.map { |body| Rmsgen::Polnote.new(:body => body) }
|
20
|
+
end
|
11
21
|
end
|
12
22
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rmsgen'
|
2
|
+
require 'net/imap'
|
3
|
+
require 'forwardable'
|
4
|
+
|
5
|
+
module Rmsgen
|
6
|
+
class IMAPClient
|
7
|
+
INBOX = 'INBOX'
|
8
|
+
RMS_EMAIL = 'rms@gnu.org'
|
9
|
+
RFC822 = 'RFC822'
|
10
|
+
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
def initialize(options)
|
14
|
+
@server = options['imap_server']
|
15
|
+
@login = options['imap_login']
|
16
|
+
@password = options['imap_password']
|
17
|
+
@imap_client = Net::IMAP.new(@server)
|
18
|
+
end
|
19
|
+
|
20
|
+
def_delegators :@imap_client, :select, :search, :fetch, :copy, :store, :expunge
|
21
|
+
|
22
|
+
def authenticate
|
23
|
+
@imap_client.authenticate('LOGIN', @login, @password)
|
24
|
+
end
|
25
|
+
|
26
|
+
def fetch_polnote_messages_from_inbox(&block)
|
27
|
+
authenticate
|
28
|
+
select INBOX
|
29
|
+
find_all_from_rms(&block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def find_by_id(id)
|
33
|
+
select INBOX
|
34
|
+
fetch_message_body(id)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def find_all_from_rms
|
40
|
+
search_for_notes.map do |id|
|
41
|
+
if block_given?
|
42
|
+
yield(fetch_message_body(id), id)
|
43
|
+
else
|
44
|
+
fetch_message_body(id)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def search_for_notes(&block)
|
50
|
+
search(["FROM", RMS_EMAIL], &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
def fetch_message_body(id)
|
54
|
+
fetch_result = fetch id, RFC822
|
55
|
+
if fetch_result && fetch_result.any?
|
56
|
+
fetch_result[0].attr[RFC822]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -1,26 +1,14 @@
|
|
1
1
|
module Rmsgen
|
2
2
|
class IMAPPolnoteGroup
|
3
|
-
require 'net/imap'
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
def initialize(options={})
|
8
|
-
@imap_options = options
|
9
|
-
@login = options['imap_login']
|
10
|
-
@password = options['imap_password']
|
11
|
-
@note_ids = init_note_ids || []
|
12
|
-
end
|
13
|
-
|
14
|
-
def fetch_notes
|
15
|
-
authenticate
|
16
|
-
follow_inbox
|
17
|
-
find_all_from_rms
|
4
|
+
def initialize(imap_client)
|
5
|
+
@imap_client = imap_client
|
18
6
|
end
|
19
7
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
8
|
+
def all
|
9
|
+
@imap_client.fetch_polnote_messages_from_inbox do |body, id|
|
10
|
+
Polnote.new :body => body, :id => id
|
11
|
+
end
|
24
12
|
end
|
25
13
|
|
26
14
|
def find(id)
|
@@ -29,42 +17,21 @@ module Rmsgen
|
|
29
17
|
end
|
30
18
|
|
31
19
|
def archive_polnote(id)
|
20
|
+
@imap_client.authenticate
|
32
21
|
follow_inbox
|
33
|
-
|
34
|
-
imap.search(["FROM", 'rms@gnu.org']).each do |note_id|
|
35
|
-
if note_id.to_i == id.to_i
|
36
|
-
imap.copy id.to_i, 'INBOX.old-messages'
|
37
|
-
imap.store(id.to_i, "+FLAGS", [:Deleted])
|
38
|
-
imap.expunge
|
39
|
-
archived = true
|
40
|
-
end
|
41
|
-
end
|
42
|
-
archived
|
22
|
+
move_to_archives(id)
|
43
23
|
end
|
44
24
|
|
45
25
|
private
|
46
|
-
|
47
|
-
def
|
48
|
-
@
|
49
|
-
|
50
|
-
|
51
|
-
def authenticate
|
52
|
-
imap.authenticate 'LOGIN', @login, @password
|
26
|
+
|
27
|
+
def move_to_archives(id)
|
28
|
+
@imap_client.copy id.to_i, 'INBOX.old-messages'
|
29
|
+
@imap_client.store(id.to_i, "+FLAGS", [:Deleted])
|
30
|
+
@imap_client.expunge
|
53
31
|
end
|
54
32
|
|
55
33
|
def follow_inbox
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
def find_all_from_rms
|
60
|
-
@note_ids.map { |id| fetch_message_body(id) }
|
61
|
-
end
|
62
|
-
|
63
|
-
def fetch_message_body(id)
|
64
|
-
fetch_result = imap.fetch id, 'RFC822'
|
65
|
-
if fetch_result && fetch_result.any?
|
66
|
-
fetch_result[0].attr['RFC822']
|
67
|
-
end
|
34
|
+
@imap_client.select 'INBOX'
|
68
35
|
end
|
69
36
|
end
|
70
37
|
end
|
data/lib/rmsgen/inquirer.rb
CHANGED
@@ -1,11 +1,5 @@
|
|
1
1
|
module Rmsgen
|
2
2
|
class Inquirer
|
3
|
-
PARTS = { :url => /^http/,
|
4
|
-
:note =>/\[Link/,
|
5
|
-
:duration => /^For.*week.*$/,
|
6
|
-
:indendation => /^ /
|
7
|
-
}
|
8
|
-
|
9
3
|
attr_reader :polnote
|
10
4
|
|
11
5
|
def initialize polnote, stdout=$stdout, answers=nil
|
@@ -35,13 +29,13 @@ module Rmsgen
|
|
35
29
|
|
36
30
|
def run!
|
37
31
|
@parts.each do |part|
|
38
|
-
if part
|
32
|
+
if part.is_a?(Rmsgen::Parts::Duration)
|
39
33
|
inquire_about_expiration
|
40
|
-
elsif part
|
34
|
+
elsif part.is_a?(Rmsgen::Parts::Url)
|
41
35
|
inquire_about_link part
|
42
|
-
elsif part
|
36
|
+
elsif part.is_a?(Rmsgen::Parts::PolnoteUrlRequest)
|
43
37
|
inquire_about_polnote_link part
|
44
|
-
elsif part
|
38
|
+
elsif part.is_a?(Rmsgen::Parts::IndentedLine)
|
45
39
|
append_to_previous_paragraph part
|
46
40
|
else
|
47
41
|
@parts_seen << part
|
data/lib/rmsgen/part.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rmsgen
|
2
|
+
module Part
|
3
|
+
|
4
|
+
TOKEN_PARTS = {
|
5
|
+
/^http/ => Rmsgen::Parts::Url,
|
6
|
+
/Return-Path:/ => Rmsgen::Parts::Header,
|
7
|
+
/\[Link/i => Rmsgen::Parts::PolnoteUrlRequest,
|
8
|
+
/Dr Richard Stallman/ => Rmsgen::Parts::Footer,
|
9
|
+
/^ / => Rmsgen::Parts::IndentedLine,
|
10
|
+
/^For.*week.*$/ => Rmsgen::Parts::Duration
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.parse(raw)
|
14
|
+
token_part = TOKEN_PARTS.find { |pattern, part| raw =~ pattern }
|
15
|
+
return Rmsgen::Parts::PlainText.new(raw) unless token_part
|
16
|
+
token_part[1].new(raw)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rmsgen/part_group.rb
CHANGED
@@ -1,23 +1,51 @@
|
|
1
|
-
|
2
|
-
attr_reader :text
|
1
|
+
require 'forwardable'
|
3
2
|
|
4
|
-
|
3
|
+
class PartGroup
|
4
|
+
extend Forwardable
|
5
|
+
include Comparable
|
6
|
+
|
7
|
+
# Carriage return new line.
|
8
|
+
#
|
9
|
+
CRNL = /\r\n/
|
10
|
+
CRNL_CRNL = /\r\n\r\n/
|
11
|
+
DELIMETER = "\n\n"
|
12
|
+
NL = /\n/
|
13
|
+
NL_NL = /\n\n/
|
14
|
+
NL_PLACEHOLDER = '[newline]'
|
15
|
+
SPACE = ' '
|
16
|
+
|
17
|
+
attr_reader :text, :parts
|
18
|
+
|
19
|
+
def_delegators :@parts, :delete_if, :<<, :each, :join,
|
20
|
+
:inject, :each_with_index, :[], :map, :size
|
5
21
|
|
6
22
|
def initialize(text)
|
7
23
|
@text = text
|
24
|
+
@parts = []
|
8
25
|
assign_parts!
|
9
26
|
end
|
10
27
|
|
28
|
+
def <=>(other)
|
29
|
+
parts.map(&:to_s) <=> other.map(&:to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
11
34
|
def assign_parts!
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
35
|
+
massage_linebreaks
|
36
|
+
parts = @text.split(DELIMETER)
|
37
|
+
assign_parsed_parts(parts)
|
38
|
+
@parts.delete_if(&:empty?)
|
39
|
+
end
|
40
|
+
|
41
|
+
def assign_parsed_parts(parts)
|
42
|
+
parts.each { |p| @parts << Rmsgen::Part.parse(p) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def massage_linebreaks
|
46
|
+
@text.gsub!(CRNL_CRNL, DELIMETER)
|
47
|
+
@text.gsub!(CRNL, SPACE)
|
48
|
+
@text.gsub!(NL_NL, NL_PLACEHOLDER)
|
49
|
+
@text.gsub!(NL_PLACEHOLDER, DELIMETER)
|
22
50
|
end
|
23
51
|
end
|
data/lib/rmsgen/polnote.rb
CHANGED
@@ -19,15 +19,23 @@ module Rmsgen
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def titleize
|
22
|
-
@title = Titleizer.new(self).
|
22
|
+
@title = Titleizer.new(self).to_html
|
23
23
|
end
|
24
24
|
|
25
25
|
def inquire
|
26
26
|
@body = Inquirer.new(self).body
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
|
29
|
+
def include?(pattern)
|
30
|
+
@body.include?(pattern)
|
31
|
+
end
|
32
|
+
|
33
|
+
def gsub!(x, y)
|
34
|
+
@body.gsub!(x, y)
|
35
|
+
end
|
36
|
+
|
37
|
+
def split(x)
|
38
|
+
@body.split(x)
|
31
39
|
end
|
32
40
|
|
33
41
|
def to_html
|
@@ -38,10 +46,14 @@ module Rmsgen
|
|
38
46
|
ERB.new(File.read(URGENT_TEMPLATE)).result(binding)
|
39
47
|
end
|
40
48
|
|
49
|
+
def parts
|
50
|
+
PartGroup.new(@body)
|
51
|
+
end
|
52
|
+
|
41
53
|
private
|
42
54
|
|
43
55
|
def compress!
|
44
|
-
@body = Compresser.new(
|
56
|
+
@body = Compresser.new(parts).body
|
45
57
|
end
|
46
58
|
|
47
59
|
def sanitize_urgent_attribute(attribute)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rmsgen
|
2
|
+
module PolnoteGroup
|
3
|
+
def self.fetch(source)
|
4
|
+
polnote_group = group(source)
|
5
|
+
polnote_group.all
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def self.group(source)
|
12
|
+
case source
|
13
|
+
when String then Rmsgen::FsPolnoteGroup.new(source)
|
14
|
+
else
|
15
|
+
Rmsgen::IMAPPolnoteGroup.new(source)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rmsgen/runtime.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Rmsgen
|
2
2
|
class Runtime
|
3
|
+
|
3
4
|
def initialize(config)
|
4
5
|
@config = config
|
5
6
|
raise "Ensure you have populated a config file" unless @config
|
6
|
-
@output =
|
7
|
-
@notes =
|
7
|
+
@output = config['output_file']
|
8
|
+
@notes = PolnoteGroup.fetch(polnote_source)
|
8
9
|
run!
|
9
10
|
end
|
10
11
|
|
@@ -12,13 +13,26 @@ module Rmsgen
|
|
12
13
|
puts 'no polnotes in queue' if @notes.empty?
|
13
14
|
@notes.each do |note|
|
14
15
|
system('clear')
|
15
|
-
polnote = Rmsgen::
|
16
|
+
polnote = Rmsgen::Polnote.new(:body => note)
|
17
|
+
Rmsgen::Inquirer.inquire_about_note(polnote)
|
16
18
|
write(polnote)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
22
|
private
|
21
23
|
|
24
|
+
def polnote_source
|
25
|
+
@config['email_dir'] || Rmsgen::IMAPClient.new(imap_options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def imap_options
|
29
|
+
{
|
30
|
+
'imap_server' => @config['imap_server'],
|
31
|
+
'imap_login' => @config['imap_login'],
|
32
|
+
'imap_password' => @config['imap_password']
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
22
36
|
def write(note)
|
23
37
|
if @output
|
24
38
|
File.open(@output, 'a') do |file|
|
@@ -29,24 +43,5 @@ module Rmsgen
|
|
29
43
|
puts
|
30
44
|
end
|
31
45
|
end
|
32
|
-
|
33
|
-
def fetch_notes
|
34
|
-
if @config['email_dir']
|
35
|
-
notes = Dir["#{@config['email_dir']}/*"].map { |f| File.read(f) }
|
36
|
-
else
|
37
|
-
notes = fetch_notes_from_imap
|
38
|
-
end
|
39
|
-
notes.map { |note| Rmsgen::Polnote.new(:body => note) } if notes
|
40
|
-
end
|
41
|
-
|
42
|
-
def fetch_notes_from_imap
|
43
|
-
options = {
|
44
|
-
'imap_server' => @config['imap_server'],
|
45
|
-
'imap_login' => @config['imap_login'],
|
46
|
-
'imap_password' => @config['imap_password']
|
47
|
-
}
|
48
|
-
|
49
|
-
Rmsgen::IMAPPolnoteGroup.new(options).fetch_notes
|
50
|
-
end
|
51
46
|
end
|
52
47
|
end
|
data/lib/rmsgen/titleizer.rb
CHANGED
@@ -11,16 +11,11 @@ module Rmsgen
|
|
11
11
|
@title = options[:title]
|
12
12
|
@body = polnote.body
|
13
13
|
@script = Script.new($stdout)
|
14
|
-
|
15
14
|
run!
|
16
15
|
end
|
17
16
|
|
18
|
-
def body
|
19
|
-
ERB.new(File.read(TEMPLATE)).result(binding)
|
20
|
-
end
|
21
|
-
|
22
17
|
def to_html
|
23
|
-
|
18
|
+
ERB.new(File.read(TEMPLATE)).result(binding)
|
24
19
|
end
|
25
20
|
|
26
21
|
private
|
@@ -29,12 +24,12 @@ module Rmsgen
|
|
29
24
|
@title = capitalize(get_title_from_options_or_script)
|
30
25
|
end
|
31
26
|
|
32
|
-
def
|
33
|
-
|
27
|
+
def capitalize(str)
|
28
|
+
str.split(SPACE).map(&:capitalize).join(SPACE)
|
34
29
|
end
|
35
30
|
|
36
|
-
def
|
37
|
-
title.
|
31
|
+
def get_title_from_options_or_script
|
32
|
+
@title || @script.prompt_for_title
|
38
33
|
end
|
39
34
|
|
40
35
|
def today_format
|
data/lib/rmsgen/version.rb
CHANGED
data/spec/fixtures/urgent_note
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rmsgen'
|
2
|
+
|
3
|
+
describe Rmsgen::IMAPClient do
|
4
|
+
let(:imap_options) do
|
5
|
+
{
|
6
|
+
'imap_server' => 'mail.example.com',
|
7
|
+
'imap_login' => 'login',
|
8
|
+
'imap_password' => 'password'
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'authenticates with the server' do
|
13
|
+
net_imap_instance = mock
|
14
|
+
Net::IMAP.should_receive(:new).with('mail.example.com').and_return(net_imap_instance)
|
15
|
+
net_imap_instance.should_receive(:authenticate).with('LOGIN', 'login', 'password').and_return(nil)
|
16
|
+
imap_client = Rmsgen::IMAPClient.new(imap_options)
|
17
|
+
imap_client.authenticate
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'fetches messages from the inbox' do
|
21
|
+
before do
|
22
|
+
@net_imap_instance = mock(:search => [], :select => [])
|
23
|
+
@message_collection = mock(:message_collection)
|
24
|
+
Net::IMAP.should_receive(:new).with('mail.example.com').and_return(@net_imap_instance)
|
25
|
+
@client = Rmsgen::IMAPClient.new(imap_options)
|
26
|
+
@client.should_receive(:authenticate).once
|
27
|
+
end
|
28
|
+
|
29
|
+
after do
|
30
|
+
@client.fetch_polnote_messages_from_inbox
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'delegates select to the imap client' do
|
34
|
+
@net_imap_instance.should_receive(:select).once.with('INBOX')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'delegates search to ' do
|
38
|
+
@net_imap_instance.should_receive(:search).once.with(["FROM", 'rms@gnu.org'])
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'delegates fetch to imap client and uses RFC822' do
|
42
|
+
@net_imap_instance.should_receive(:search).and_return([1])
|
43
|
+
fetch_result = [mock(:notes, :attr => { "RFC822" => 'Hello World'} )]
|
44
|
+
@net_imap_instance.should_receive(:fetch).once.with(1, 'RFC822').and_return(fetch_result)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'finding a single message body' do
|
49
|
+
let(:net_imap_instance) { mock(:net_imap, :select => nil, :fetch => []) }
|
50
|
+
let(:client) do
|
51
|
+
Rmsgen::IMAPClient.new(imap_options)
|
52
|
+
end
|
53
|
+
|
54
|
+
before do
|
55
|
+
Net::IMAP.should_receive(:new).with('mail.example.com').and_return(net_imap_instance)
|
56
|
+
end
|
57
|
+
|
58
|
+
after do
|
59
|
+
client.find_by_id(1)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'delegates select to imap client' do
|
63
|
+
net_imap_instance.should_receive(:select).once.with('INBOX')
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'calls fetch for the id' do
|
67
|
+
net_imap_instance.should_receive(:fetch).with(1, 'RFC822').once
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -1,45 +1,34 @@
|
|
1
1
|
require 'rmsgen'
|
2
2
|
|
3
3
|
describe Rmsgen::IMAPPolnoteGroup do
|
4
|
-
context 'fetching notes' do
|
5
|
-
let(:imap) { double('
|
6
|
-
let(:options) do {
|
7
|
-
'imap_server' => 'foo.bar.com',
|
8
|
-
'imap_login' => 'login',
|
9
|
-
'imap_password' => 'password'}
|
10
|
-
end
|
4
|
+
context 'fetching notes from an imap server' do
|
5
|
+
let(:imap) { double('imap client') }
|
11
6
|
|
12
|
-
let(:
|
13
|
-
imap.should_receive(:
|
7
|
+
let(:set_imap_expectations_and_get_all) do
|
8
|
+
imap.should_receive(:fetch_polnote_messages_from_inbox).any_number_of_times
|
14
9
|
imap.should_receive(:authenticate).any_number_of_times
|
10
|
+
imap.should_receive(:search).any_number_of_times
|
15
11
|
Net::IMAP.should_receive(:new).any_number_of_times.and_return(imap)
|
16
12
|
imap.should_receive(:select).any_number_of_times
|
17
|
-
Rmsgen::IMAPPolnoteGroup.new(
|
13
|
+
Rmsgen::IMAPPolnoteGroup.new(imap).all
|
18
14
|
end
|
19
15
|
|
20
|
-
|
21
|
-
|
22
|
-
do_fetch
|
16
|
+
after(:each) do
|
17
|
+
set_imap_expectations_and_get_all
|
23
18
|
end
|
24
19
|
|
25
20
|
it 'selects the inbox folder' do
|
26
21
|
imap.should_receive(:select).any_number_of_times.with('INBOX')
|
27
|
-
do_fetch
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'searches for messages from rms' do
|
31
|
-
imap.should_receive(:search).once.with(["FROM", 'rms@gnu.org'])
|
32
|
-
do_fetch
|
33
22
|
end
|
34
23
|
|
35
24
|
it 'fetches each message' do
|
36
|
-
message_id = double('message_id')
|
37
|
-
search_result = [message_id]
|
38
25
|
|
39
|
-
|
26
|
+
# message_id = double('message_id')
|
27
|
+
# search_result = [message_id]
|
28
|
+
|
29
|
+
# imap.stub(:search) { search_result }
|
40
30
|
|
41
|
-
|
42
|
-
do_fetch
|
31
|
+
# imap.should_receive(:fetch).with(message_id, 'RFC822')
|
43
32
|
end
|
44
33
|
end
|
45
34
|
end
|
data/spec/part_group_spec.rb
CHANGED
@@ -3,19 +3,16 @@ require 'rmsgen'
|
|
3
3
|
describe PartGroup do
|
4
4
|
it "accepts text as input" do
|
5
5
|
input = "hello\n\nworld"
|
6
|
-
|
7
|
-
p.text.should be == input
|
6
|
+
PartGroup.new(input).text.should be == input
|
8
7
|
end
|
9
8
|
|
10
9
|
it "output list of parts ordered by appearance" do
|
11
10
|
input = "\n\n\n\n1\n\n2\n\n3\n\n4"
|
12
|
-
|
13
|
-
p.should == ['1', '2', '3', '4']
|
11
|
+
PartGroup.new(input).should == ['1', '2', '3', '4']
|
14
12
|
end
|
15
13
|
|
16
14
|
it "splits input into parts based on carriage return and newline" do
|
17
15
|
input = "1\r\n\r\n2\r\n\r\n3\r\n\r\n4"
|
18
|
-
|
19
|
-
p.should == ['1', '2', '3', '4']
|
16
|
+
PartGroup.new(input).should == ['1', '2', '3', '4']
|
20
17
|
end
|
21
18
|
end
|
data/spec/part_spec.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rmsgen'
|
2
|
+
|
3
|
+
describe Rmsgen::Parts::PlainText do
|
4
|
+
context 'behaving like a string' do
|
5
|
+
it 'returns the input string' do
|
6
|
+
p = Rmsgen::Parts::PlainText.new('foo')
|
7
|
+
p.to_s.should == 'foo'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe Rmsgen::Parts::PolnoteUrlRequest do
|
13
|
+
context 'behaving like a string' do
|
14
|
+
it 'returns the input string' do
|
15
|
+
p = Rmsgen::Parts::PolnoteUrlRequest.new('foo')
|
16
|
+
p.to_s.should == 'foo'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Rmsgen::Part do
|
22
|
+
context 'parse' do
|
23
|
+
it 'detects a url' do
|
24
|
+
subject.parse('http').should be_instance_of(Rmsgen::Parts::Url)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'detects the headers' do
|
28
|
+
subject.parse('Return-Path:').should be_instance_of(Rmsgen::Parts::Header)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'detects an indented line' do
|
32
|
+
subject.parse(' hello world').should be_instance_of(Rmsgen::Parts::IndentedLine)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'detects a duration' do
|
36
|
+
subject.parse('For one week').should be_instance_of(Rmsgen::Parts::Duration)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'detects plain text' do
|
40
|
+
subject.parse('bla blah blah').should be_instance_of(Rmsgen::Parts::PlainText)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'detects a polnote url request' do
|
44
|
+
subject.parse('[Link to a polnote]').should be_instance_of(Rmsgen::Parts::PolnoteUrlRequest)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'detects a downcased polnote url request' do
|
48
|
+
subject.parse('[link').should be_instance_of(Rmsgen::Parts::PolnoteUrlRequest)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rmsgen'
|
2
|
+
|
3
|
+
describe Rmsgen::PolnoteGroup do
|
4
|
+
context '.fetch' do
|
5
|
+
context 'from a file system' do
|
6
|
+
it 'collects file contents' do
|
7
|
+
file_system_polnote_group = mock
|
8
|
+
file_system_polnote_group.should_receive(:all)
|
9
|
+
Rmsgen::PolnoteGroup.should_receive(:group).and_return(file_system_polnote_group)
|
10
|
+
Rmsgen::PolnoteGroup.fetch('/some/path')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'from an imap server' do
|
15
|
+
it 'collects email contents' do
|
16
|
+
imap_polnote_group = mock
|
17
|
+
imap_polnote_group.should_receive(:all)
|
18
|
+
Rmsgen::PolnoteGroup.should_receive(:group).and_return(imap_polnote_group)
|
19
|
+
imap_options = { 'imap_server' => 'foo.test.com', 'imap_login' => 'login', 'imap_password' => 'password' }
|
20
|
+
Rmsgen::PolnoteGroup.fetch(imap_options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/spec/polnote_spec.rb
CHANGED
@@ -2,7 +2,6 @@ require 'rmsgen'
|
|
2
2
|
require 'fake_gets'
|
3
3
|
|
4
4
|
describe Rmsgen::Polnote do
|
5
|
-
|
6
5
|
def fixture(name)
|
7
6
|
File.read("spec/fixtures/#{name}")
|
8
7
|
end
|
@@ -21,7 +20,7 @@ describe Rmsgen::Polnote do
|
|
21
20
|
|
22
21
|
it "has parts" do
|
23
22
|
note = Rmsgen::Polnote.new(:body => imap_note)
|
24
|
-
note.parts.should ==
|
23
|
+
note.parts.size.should be == 2
|
25
24
|
end
|
26
25
|
end
|
27
26
|
|
@@ -29,12 +28,8 @@ describe Rmsgen::Polnote do
|
|
29
28
|
let(:note) { fixture(:link_to_polnote) }
|
30
29
|
|
31
30
|
it 'parses the body' do
|
32
|
-
text_a = "rainbow"
|
33
|
-
polnote_url = "http://somenote"
|
34
|
-
text_b = "blue"
|
35
|
-
|
36
31
|
$stdout = StringIO.new
|
37
|
-
$stdin = FakeGetMany.new(
|
32
|
+
$stdin = FakeGetMany.new('rainbow', 'http://somenote', 'blue')
|
38
33
|
polnote = Rmsgen::Polnote.new(:body => note)
|
39
34
|
polnote.inquire
|
40
35
|
polnote.to_html.should ==
|
data/spec/runtime_spec.rb
CHANGED
@@ -12,23 +12,13 @@ describe Rmsgen::Runtime do
|
|
12
12
|
|
13
13
|
context 'when and there is a note' do
|
14
14
|
let(:runtime) { Rmsgen::Runtime }
|
15
|
-
let(:imap) {
|
16
|
-
let(:search_result) { mock(:search_result) }
|
15
|
+
let(:imap) { stub(:imap) }
|
17
16
|
|
18
17
|
it 'fetches the note' do
|
19
18
|
$stdout = StringIO.new
|
20
19
|
$stdin = FakeGet.new('hello')
|
21
|
-
|
22
|
-
|
23
|
-
imap_note = mock(:note)
|
24
|
-
notes = [imap_note]
|
25
|
-
|
26
|
-
imap_note.stub(:attr) { {"RFC822"=>"hello world"} }
|
27
|
-
imap.stub(:authenticate)
|
28
|
-
imap.stub(:select)
|
29
|
-
|
30
|
-
imap.stub(:search) { [search_result] }
|
31
|
-
imap.stub(:fetch) { notes }
|
20
|
+
Rmsgen::IMAPClient.should_receive(:new).and_return(imap)
|
21
|
+
imap.should_receive(:fetch_polnote_messages_from_inbox).and_return([])
|
32
22
|
expect { runtime.new(config).run! }.to_not raise_error
|
33
23
|
end
|
34
24
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rmsgen
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-09-
|
12
|
+
date: 2011-09-30 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
14
|
description: A library to help generate html markup from RMS emails
|
15
15
|
email:
|
@@ -46,15 +46,26 @@ files:
|
|
46
46
|
- features/support/env.rb
|
47
47
|
- features/support/hooks.rb
|
48
48
|
- features/urgent_polnote.feature
|
49
|
+
- lib/acts_like/string.rb
|
49
50
|
- lib/rmsgen.rb
|
50
51
|
- lib/rmsgen/cli/main.rb
|
51
52
|
- lib/rmsgen/compresser.rb
|
52
53
|
- lib/rmsgen/fs_polnote_group.rb
|
54
|
+
- lib/rmsgen/imap_client.rb
|
53
55
|
- lib/rmsgen/imap_polnote_group.rb
|
54
56
|
- lib/rmsgen/inquirer.rb
|
55
57
|
- lib/rmsgen/link.rb
|
58
|
+
- lib/rmsgen/part.rb
|
56
59
|
- lib/rmsgen/part_group.rb
|
60
|
+
- lib/rmsgen/parts/duration.rb
|
61
|
+
- lib/rmsgen/parts/footer.rb
|
62
|
+
- lib/rmsgen/parts/header.rb
|
63
|
+
- lib/rmsgen/parts/indented_line.rb
|
64
|
+
- lib/rmsgen/parts/plain_text.rb
|
65
|
+
- lib/rmsgen/parts/polnote_url_request.rb
|
66
|
+
- lib/rmsgen/parts/url.rb
|
57
67
|
- lib/rmsgen/polnote.rb
|
68
|
+
- lib/rmsgen/polnote_group.rb
|
58
69
|
- lib/rmsgen/runtime.rb
|
59
70
|
- lib/rmsgen/script.rb
|
60
71
|
- lib/rmsgen/titleizer.rb
|
@@ -69,9 +80,12 @@ files:
|
|
69
80
|
- spec/fixtures/multiline_note
|
70
81
|
- spec/fixtures/urgent_note
|
71
82
|
- spec/fs_polnote_group_spec.rb
|
83
|
+
- spec/imap_client_spec.rb
|
72
84
|
- spec/imap_polnote_group_spec.rb
|
73
85
|
- spec/inqirer_spec.rb
|
74
86
|
- spec/part_group_spec.rb
|
87
|
+
- spec/part_spec.rb
|
88
|
+
- spec/polnote_group.rb
|
75
89
|
- spec/polnote_spec.rb
|
76
90
|
- spec/runtime_spec.rb
|
77
91
|
- spec/support/fake_gets.rb
|