mail2frontmatter 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +0 -1
- data/README.md +26 -3
- data/Rakefile +3 -7
- data/bin/mail2frontmatter +17 -17
- data/fixtures/mail2frontmatter/broken-processor.rb +2 -2
- data/fixtures/mail2frontmatter/fake-processor-with-options.rb +1 -1
- data/fixtures/mail2frontmatter/fake-processor.rb +1 -1
- data/lib/mail2frontmatter.rb +2 -1
- data/lib/mail2frontmatter/committer.rb +68 -0
- data/lib/mail2frontmatter/configuration.rb +10 -11
- data/lib/mail2frontmatter/parser.rb +7 -8
- data/lib/mail2frontmatter/preprocessor.rb +5 -7
- data/lib/mail2frontmatter/version.rb +1 -1
- data/lib/mail2frontmatter/watcher.rb +13 -7
- data/lib/mail2frontmatter/writer.rb +9 -10
- data/mail2frontmatter.gemspec +16 -15
- data/spec/committer_spec.rb +27 -0
- data/spec/configuration_spec.rb +18 -20
- data/spec/installation/data/.gitkeep +0 -0
- data/spec/installation/media/.gitkeep +0 -0
- data/spec/parser_spec.rb +14 -16
- data/spec/preprocessor_spec.rb +28 -29
- data/spec/remote/.gitkeep +0 -0
- data/spec/spec_helper.rb +62 -1
- data/spec/writer_spec.rb +21 -0
- metadata +32 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0ca545c2952a483060ba2c7b90aa0aeed1c85891
|
4
|
+
data.tar.gz: 96be89bc2de5e5cc89d2daecd2cf0633a8d0fdcd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2af70109d10996401cb9b20bf429af5493ef41da128352350d5e31a793aa7a5cc8cf3dfe1b5ef3d824936f57742325e706163df48bb1fdc81990bfd8f3b18e39
|
7
|
+
data.tar.gz: 124aa40da8be4e7bb23199384b0b375046c4f057ca0355999ac1f7a7d4f2f863307946db6b9c76ea25d150d2e59ad740142367ed9b97815d6830c1b98245f366
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,9 @@
|
|
4
4
|
|
5
5
|
Email-to-blog parser which creates YAML FrontMatter and saves your attachments.
|
6
6
|
|
7
|
-
Designed to be used with either Middleman or Jekyll
|
7
|
+
Designed to be used with either Middleman or Jekyll.
|
8
|
+
|
9
|
+
This project is actively being developed. I wrap the executable with the [eye](https://github.com/kostya/eye) gem at the moment.
|
8
10
|
|
9
11
|
## Installation
|
10
12
|
|
@@ -147,6 +149,27 @@ You should always always return metadata and body as shown since this will be pa
|
|
147
149
|
|
148
150
|
### TODO
|
149
151
|
|
150
|
-
*
|
151
|
-
|
152
|
+
* core plugins
|
153
|
+
|
154
|
+
Core plugins should be included out of the box and disabled upon request. It's just simpler to use
|
155
|
+
|
156
|
+
* zero config for Jekyll
|
157
|
+
|
158
|
+
current we 'detect' the directory structure to see if the executable is run from Middleman,
|
159
|
+
do the same for Jekyll in order to support it out of the box with zero configuration
|
160
|
+
|
161
|
+
* remove dependency on Mailman, use Mail directly
|
162
|
+
|
163
|
+
no need to use Mailman if I intend to manage the process myself. Use Mail directly
|
164
|
+
|
165
|
+
* detach runner
|
166
|
+
|
167
|
+
incoming mail checks in the main thread, processing, writing, commiting should be handled in a separate process to discard leaks
|
168
|
+
|
169
|
+
|
170
|
+
|
171
|
+
|
172
|
+
|
173
|
+
|
174
|
+
|
152
175
|
|
data/Rakefile
CHANGED
data/bin/mail2frontmatter
CHANGED
@@ -13,34 +13,34 @@ options = {
|
|
13
13
|
}
|
14
14
|
|
15
15
|
OptionParser.new do |opts|
|
16
|
-
opts.banner =
|
16
|
+
opts.banner = 'Usage: mail2frontmatter [options]'
|
17
17
|
|
18
|
-
opts.on(
|
18
|
+
opts.on('-k', '--stop', 'stop the running process if any') do
|
19
19
|
stop = true
|
20
20
|
end
|
21
21
|
|
22
|
-
opts.on(
|
22
|
+
opts.on('-cCONFIG', '--config=CONFIG', 'path to configuration file, defaults to ./data/mail2frontmatter.yml') do |config_file|
|
23
23
|
config = config_file
|
24
24
|
end
|
25
25
|
|
26
|
-
opts.on(
|
26
|
+
opts.on('-d', '--detach', 'detach process and run in the background') do
|
27
27
|
options[:background] = true
|
28
28
|
end
|
29
29
|
|
30
|
-
opts.on(
|
30
|
+
opts.on('-lLOGFILE', '--log=LOGFILE', 'path to log file, defaults to STDOUT in the foreground or ./log/mail2frontmatter.log when daemonized') do |log_file|
|
31
31
|
config[:log_file] = log_file
|
32
32
|
end
|
33
33
|
|
34
|
-
opts.on(
|
34
|
+
opts.on('-pPIDFILE', '--pid=PIDFILE', 'path to pid file, defaults to ./tmp/pids/mail2frontmatter.pid') do |pid_file|
|
35
35
|
options[:pid_file] = pid_file
|
36
36
|
end
|
37
37
|
|
38
|
-
opts.on(
|
38
|
+
opts.on('-h', '--help', 'Prints this help') do
|
39
39
|
puts opts
|
40
40
|
exit
|
41
41
|
end
|
42
42
|
|
43
|
-
opts.on_tail(
|
43
|
+
opts.on_tail('-v', '--version', 'Prints version') do
|
44
44
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'mail2frontmatter', 'version')
|
45
45
|
puts Mail2FrontMatter::VERSION
|
46
46
|
exit
|
@@ -50,8 +50,8 @@ end.parse!
|
|
50
50
|
# TRY TO KILL
|
51
51
|
if stop
|
52
52
|
|
53
|
-
|
54
|
-
puts
|
53
|
+
unless File.exist?(options[:pid_file])
|
54
|
+
puts 'no pidfile! are you sure mail2frontmatter is running?'
|
55
55
|
exit 1
|
56
56
|
end
|
57
57
|
|
@@ -63,13 +63,13 @@ if stop
|
|
63
63
|
Process.kill('TERM', pid)
|
64
64
|
exit 0
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
# FUTURE: library intercepts TERM,
|
67
|
+
# waits to finish processing if it is
|
68
|
+
# or if kill exits dirty.
|
69
69
|
|
70
70
|
# CATCH STALE PID
|
71
71
|
rescue Errno::ESRCH
|
72
|
-
puts
|
72
|
+
puts 'stale pidfile... cleaning'
|
73
73
|
|
74
74
|
# also exit here! but don't move exit 0 to ensure block
|
75
75
|
# because "in the future" we may intelligently intercept pkill above
|
@@ -90,7 +90,7 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'mail2frontmatter')
|
|
90
90
|
if options[:background]
|
91
91
|
|
92
92
|
# CHECKING ALREADY RUNNING / CHECK STALE
|
93
|
-
if File.
|
93
|
+
if File.exist?(options[:pid_file])
|
94
94
|
pid = File.read(options[:pid_file]).to_i
|
95
95
|
|
96
96
|
begin
|
@@ -99,12 +99,12 @@ if options[:background]
|
|
99
99
|
exit 1
|
100
100
|
|
101
101
|
rescue Errno::ESRCH
|
102
|
-
puts
|
102
|
+
puts 'stale pidfile... cleaning'
|
103
103
|
File.delete(options[:pid_file])
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
puts
|
107
|
+
puts 'daemonizing...'
|
108
108
|
|
109
109
|
# SET CONFIG...
|
110
110
|
Mail2FrontMatter.set_config(config)
|
data/lib/mail2frontmatter.rb
CHANGED
@@ -2,5 +2,6 @@ require 'mail2frontmatter/version'
|
|
2
2
|
require 'mail2frontmatter/configuration'
|
3
3
|
require 'mail2frontmatter/watcher'
|
4
4
|
require 'mail2frontmatter/parser'
|
5
|
-
require 'mail2frontmatter/writer'
|
6
5
|
require 'mail2frontmatter/preprocessor'
|
6
|
+
require 'mail2frontmatter/writer'
|
7
|
+
require 'mail2frontmatter/committer'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
# Commits Changes to git
|
3
|
+
#
|
4
|
+
module Mail2FrontMatter
|
5
|
+
class Committer
|
6
|
+
begin
|
7
|
+
require 'rugged'
|
8
|
+
@@available = true
|
9
|
+
|
10
|
+
rescue LoadError
|
11
|
+
@@available = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.available?
|
15
|
+
@@available
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.commit(metadata, _body)
|
19
|
+
repo = Rugged::Repository.new(Mail2FrontMatter.config[:git][:path])
|
20
|
+
index = repo.index
|
21
|
+
|
22
|
+
# stage frontmatter/erb
|
23
|
+
relative_path = metadata[:filepath].gsub(Mail2FrontMatter.config[:git][:path] + '/', '')
|
24
|
+
|
25
|
+
index.add(path: relative_path,
|
26
|
+
oid: (Rugged::Blob.from_workdir repo, relative_path),
|
27
|
+
mode: 0100644)
|
28
|
+
|
29
|
+
# stage attachments
|
30
|
+
metadata[:attachments].each_pair do |_k, filemeta|
|
31
|
+
relative_path = filemeta[:filepath].gsub(Mail2FrontMatter.config[:git][:path] + '/', '')
|
32
|
+
|
33
|
+
index.add(path: relative_path,
|
34
|
+
oid: (Rugged::Blob.from_workdir repo, relative_path),
|
35
|
+
mode: 0100644)
|
36
|
+
end
|
37
|
+
|
38
|
+
# commit
|
39
|
+
tree = index.write_tree(repo)
|
40
|
+
index.write
|
41
|
+
|
42
|
+
author = {
|
43
|
+
email: Mail2FrontMatter.config[:git][:email] || metadata[:from].match(/\<(.*)\>/)[1],
|
44
|
+
name: Mail2FrontMatter.config[:git][:name] || metadata[:from].match(/(.*) \<.*\>/)[1],
|
45
|
+
time: Time.now
|
46
|
+
}
|
47
|
+
|
48
|
+
Rugged::Commit.create(repo, author: author,
|
49
|
+
committer: author,
|
50
|
+
message: "post via email, #{metadata[:subject]}",
|
51
|
+
parents: [repo.head.target],
|
52
|
+
tree: tree,
|
53
|
+
update_ref: 'HEAD')
|
54
|
+
|
55
|
+
# push
|
56
|
+
begin
|
57
|
+
credentials = Rugged::Credentials::SshKeyFromAgent.new(username: 'git')
|
58
|
+
repo.push 'origin', ['refs/heads/master'], { credentials: credentials }
|
59
|
+
rescue StandardError => e
|
60
|
+
Mail2FrontMatter.logger.info("Could not push!")
|
61
|
+
Mail2FrontMatter.logger.error(e)
|
62
|
+
end
|
63
|
+
|
64
|
+
# return sha
|
65
|
+
repo.references['refs/heads/master'].target_id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -3,15 +3,11 @@ module Mail2FrontMatter
|
|
3
3
|
require 'active_support/inflector'
|
4
4
|
|
5
5
|
class << self
|
6
|
-
|
7
|
-
@logger
|
8
|
-
end
|
6
|
+
attr_reader :logger
|
9
7
|
|
10
|
-
|
11
|
-
@config
|
12
|
-
end
|
8
|
+
attr_reader :config
|
13
9
|
|
14
|
-
def set_config(passed_config = nil, &
|
10
|
+
def set_config(passed_config = nil, &_block)
|
15
11
|
# load config from file
|
16
12
|
if passed_config.is_a?(String)
|
17
13
|
@config = YAML.load_file(passed_config).deep_symbolize_keys!
|
@@ -24,14 +20,14 @@ module Mail2FrontMatter
|
|
24
20
|
if File.exist?(default_config)
|
25
21
|
@config = YAML.load_file(default_config).deep_symbolize_keys!
|
26
22
|
else
|
27
|
-
|
23
|
+
fail LoadError, 'no configuration given or found at ./data/mail2frontmatter.yml'
|
28
24
|
end
|
29
25
|
|
30
26
|
elsif passed_config.is_a?(Hash)
|
31
27
|
@config = passed_config
|
32
28
|
|
33
29
|
else
|
34
|
-
|
30
|
+
fail ArgumentError, 'not a valid configuration type'
|
35
31
|
end
|
36
32
|
|
37
33
|
# setup logger, use provided location
|
@@ -47,6 +43,10 @@ module Mail2FrontMatter
|
|
47
43
|
@logger = Logger.new(STDOUT)
|
48
44
|
end
|
49
45
|
|
46
|
+
@config[:git] ||= {
|
47
|
+
path: Dir.pwd
|
48
|
+
}
|
49
|
+
|
50
50
|
# set default for data directory unless already specified
|
51
51
|
# the data directory is where the posts will be written to
|
52
52
|
unless @config[:data_directory]
|
@@ -83,9 +83,8 @@ module Mail2FrontMatter
|
|
83
83
|
raise e
|
84
84
|
end
|
85
85
|
|
86
|
-
|
86
|
+
"Mail2FrontMatter::#{processor[:key].underscore.camelize}".constantize.register(processor[:options] || {})
|
87
87
|
end
|
88
|
-
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
@@ -8,19 +8,19 @@ module Mail2FrontMatter
|
|
8
8
|
attr_accessor :message, :metadata, :body
|
9
9
|
|
10
10
|
ALLOWED_TYPES = {
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
'audio' => 'audio',
|
12
|
+
'video' => 'videos',
|
13
|
+
'image' => 'images'
|
14
14
|
}
|
15
15
|
|
16
16
|
def initialize(message)
|
17
17
|
@message = message
|
18
18
|
raw_parsed_html = Nokogiri::HTML.parse(@message.html_part.decoded.strip)
|
19
19
|
|
20
|
-
@body = raw_parsed_html.at(
|
20
|
+
@body = raw_parsed_html.at('body')
|
21
21
|
|
22
22
|
# remove extraneous nesting
|
23
|
-
while
|
23
|
+
while @body.children.count == 1 && @body.children.first.name == 'div'
|
24
24
|
@body = @body.children.first
|
25
25
|
end
|
26
26
|
|
@@ -33,10 +33,10 @@ module Mail2FrontMatter
|
|
33
33
|
media_type_directory = File.join(Mail2FrontMatter.config[:media_directory], Parser::ALLOWED_TYPES[attachment.main_type])
|
34
34
|
FileUtils.mkdir_p(media_type_directory)
|
35
35
|
|
36
|
-
filepath = File.join(media_type_directory, attachment.filename)
|
36
|
+
filepath = File.join(media_type_directory, attachment.filename)
|
37
37
|
|
38
38
|
# save attachment
|
39
|
-
File.open(filepath,
|
39
|
+
File.open(filepath, 'w+b', 0644) { |f| f.write attachment.body.decoded }
|
40
40
|
|
41
41
|
# retain metadata
|
42
42
|
attachments[attachment.cid] = {
|
@@ -67,7 +67,6 @@ module Mail2FrontMatter
|
|
67
67
|
subject: message.subject,
|
68
68
|
attachments: attachments
|
69
69
|
}
|
70
|
-
|
71
70
|
end
|
72
71
|
end
|
73
72
|
end
|
@@ -1,11 +1,10 @@
|
|
1
|
-
|
2
1
|
# Pre-processes blog data, allows hooks
|
3
2
|
|
4
3
|
module Mail2FrontMatter
|
5
4
|
class PreProcessor
|
6
5
|
require 'set'
|
7
6
|
|
8
|
-
class InvalidProcessor < StandardError
|
7
|
+
class InvalidProcessor < StandardError; end
|
9
8
|
|
10
9
|
@@processors = Set.new
|
11
10
|
|
@@ -14,8 +13,8 @@ module Mail2FrontMatter
|
|
14
13
|
end
|
15
14
|
|
16
15
|
def self.register(options = {})
|
17
|
-
|
18
|
-
|
16
|
+
fail InvalidProcessor, "run method not defined on #{self}" unless self.respond_to?(:run)
|
17
|
+
fail ArgumentError, 'options must be a hash' unless options.is_a? Hash
|
19
18
|
@options = options
|
20
19
|
|
21
20
|
@@processors << self
|
@@ -26,13 +25,12 @@ module Mail2FrontMatter
|
|
26
25
|
begin
|
27
26
|
metadata, body = processor.run(metadata, body)
|
28
27
|
rescue StandardError => e
|
29
|
-
Mail2FrontMatter.logger.error(
|
28
|
+
Mail2FrontMatter.logger.error('processor failed!')
|
30
29
|
Mail2FrontMatter.logger.error(e)
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
|
-
|
33
|
+
[metadata, body]
|
35
34
|
end
|
36
|
-
|
37
35
|
end
|
38
36
|
end
|
@@ -4,24 +4,22 @@ module Mail2FrontMatter
|
|
4
4
|
require 'mailman'
|
5
5
|
|
6
6
|
class Watcher
|
7
|
-
|
8
7
|
def self.run
|
9
8
|
mail_protocol = Mail2FrontMatter.config[:protocol] || :imap
|
10
9
|
poll_interval = Mail2FrontMatter.config[:interval] || 60
|
11
10
|
|
12
|
-
@receiver = Mail2FrontMatter.config[:receiver]
|
13
|
-
@senders = Mail2FrontMatter.config[:senders]
|
14
|
-
|
15
11
|
Mailman.config.poll_interval = poll_interval
|
16
12
|
Mailman.config.ignore_stdin = true
|
17
13
|
|
18
14
|
Mailman.config.send("#{mail_protocol}=", Mail2FrontMatter.config[:mailman])
|
19
15
|
Mailman.config.logger = Mail2FrontMatter.logger
|
20
16
|
|
17
|
+
Mail2FrontMatter.logger.info("Mail2FrontMatter v#{Mail2FrontMatter::VERSION} is starting...")
|
18
|
+
|
21
19
|
Mailman::Application.run do
|
22
|
-
|
23
|
-
logger = Mailman.config.logger
|
20
|
+
logger = Mail2FrontMatter.logger
|
24
21
|
|
22
|
+
from(Mail2FrontMatter.config[:senders]).to(Mail2FrontMatter.config[:receiver]) do
|
25
23
|
logger.info('parsing message...')
|
26
24
|
parser = Mail2FrontMatter::Parser.new(message)
|
27
25
|
|
@@ -30,9 +28,17 @@ module Mail2FrontMatter
|
|
30
28
|
|
31
29
|
logger.info('saving processed post...')
|
32
30
|
Mail2FrontMatter::Writer.write(metadata, body)
|
31
|
+
|
32
|
+
logger.info('commiting written post and attachments...')
|
33
|
+
Mail2FrontMatter::Committer.commit(metadata, body)
|
34
|
+
|
35
|
+
logger.info('done...')
|
36
|
+
end
|
37
|
+
|
38
|
+
default do
|
39
|
+
logger.error("received and discarded email from unknown address!")
|
33
40
|
end
|
34
41
|
end
|
35
42
|
end
|
36
|
-
|
37
43
|
end
|
38
44
|
end
|
@@ -1,20 +1,19 @@
|
|
1
1
|
|
2
2
|
# Writes YAML FrontMatter & Article Content in ERB
|
3
|
-
#
|
4
|
-
# TODO How do I support other templating solutions here?
|
5
|
-
#
|
6
|
-
#
|
3
|
+
#
|
4
|
+
# TODO: How do I support other templating solutions here?
|
5
|
+
# Same plugin style as processors?
|
6
|
+
# Is processor and writer doing the same thing?
|
7
7
|
# --- probably just let anyone specify the extension.. keep it simple
|
8
|
-
#
|
8
|
+
#
|
9
9
|
module Mail2FrontMatter
|
10
10
|
class Writer
|
11
|
-
|
12
11
|
require 'yaml'
|
13
12
|
require 'active_support/inflector'
|
14
13
|
|
15
14
|
def self.write(metadata, body)
|
16
15
|
# MAPPINGS!
|
17
|
-
#
|
16
|
+
#
|
18
17
|
# Play nice with programs which will read this data
|
19
18
|
# And set sensible defaults as fall throughs
|
20
19
|
|
@@ -22,12 +21,12 @@ module Mail2FrontMatter
|
|
22
21
|
metadata[:title] ||= metadata[:subject]
|
23
22
|
|
24
23
|
# make a sensible standard blog filename unless one is given
|
25
|
-
metadata[:filename] ||= [metadata[:received].strftime(
|
24
|
+
metadata[:filename] ||= [metadata[:received].strftime('%Y-%m-%d'), '-', metadata[:subject].parameterize, '.html.erb'].join
|
25
|
+
metadata[:filepath] ||= File.join(Mail2FrontMatter.config[:data_directory], metadata[:filename])
|
26
26
|
|
27
27
|
data = metadata.to_yaml + "---\n" + body
|
28
28
|
|
29
|
-
File.write(
|
29
|
+
File.write(metadata[:filepath], data)
|
30
30
|
end
|
31
|
-
|
32
31
|
end
|
33
32
|
end
|
data/mail2frontmatter.gemspec
CHANGED
@@ -4,26 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'mail2frontmatter/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'mail2frontmatter'
|
8
8
|
spec.version = Mail2FrontMatter::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.description = spec.summary +
|
13
|
-
spec.homepage =
|
14
|
-
spec.license =
|
9
|
+
spec.authors = ['Kunal Shah']
|
10
|
+
spec.email = ['me@kunalashah.com']
|
11
|
+
spec.summary = 'email-in for static blogs like Middleman'
|
12
|
+
spec.description = spec.summary + '. Uses Mailman to poll an account. '
|
13
|
+
spec.homepage = 'https://github.com/whistlerbrk/Mail2FrontMatter'
|
14
|
+
spec.license = 'MIT'
|
15
15
|
|
16
16
|
spec.files = `git ls-files -z`.split("\x0")
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = [
|
19
|
+
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_dependency
|
22
|
-
spec.add_dependency
|
23
|
-
spec.add_dependency
|
21
|
+
spec.add_dependency 'mailman', '~> 0.7.3'
|
22
|
+
spec.add_dependency 'nokogiri', '~> 1.6'
|
23
|
+
spec.add_dependency 'activesupport', '~> 4'
|
24
|
+
spec.add_dependency 'rugged', '~> 0.21'
|
24
25
|
|
25
|
-
spec.add_development_dependency
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.1'
|
27
|
+
spec.add_development_dependency 'byebug', '~> 3.5'
|
28
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
29
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
29
30
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mail2FrontMatter::Committer, 'committing' do
|
4
|
+
require 'rugged'
|
5
|
+
|
6
|
+
let(:config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.simple.yml') }
|
7
|
+
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
8
|
+
|
9
|
+
it 'should commit new posts' do
|
10
|
+
Mail2FrontMatter.set_config(config) do |config|
|
11
|
+
config[:data_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'data')
|
12
|
+
config[:media_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'media')
|
13
|
+
config[:git] = { path: File.join(M2FM_GEM_PATH, 'spec', 'installation') }
|
14
|
+
end
|
15
|
+
|
16
|
+
repo = Rugged::Repository.new(Mail2FrontMatter.config[:git][:path])
|
17
|
+
opening_sha = repo.references['refs/heads/master'].target_id
|
18
|
+
|
19
|
+
parser = Mail2FrontMatter::Parser.new(message_one)
|
20
|
+
Mail2FrontMatter::Writer.write(parser.metadata, parser.body)
|
21
|
+
Mail2FrontMatter::Committer.commit(parser.metadata, parser.body)
|
22
|
+
|
23
|
+
closing_sha = repo.references['refs/heads/master'].target_id
|
24
|
+
|
25
|
+
expect(opening_sha == closing_sha).to be(false)
|
26
|
+
end
|
27
|
+
end
|
data/spec/configuration_spec.rb
CHANGED
@@ -1,42 +1,40 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Mail2FrontMatter,
|
4
|
-
|
3
|
+
describe Mail2FrontMatter, 'configuration' do
|
5
4
|
let(:simple_config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.simple.yml') }
|
6
5
|
let(:complex_config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.complex.yml') }
|
7
6
|
let(:malformed_config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.malformed.yml') }
|
8
7
|
|
9
|
-
it
|
10
|
-
expect
|
8
|
+
it 'should load a configuration by passing a YAML file location' do
|
9
|
+
expect do
|
11
10
|
Mail2FrontMatter.set_config(simple_config)
|
12
|
-
|
11
|
+
end.to_not raise_error
|
13
12
|
end
|
14
13
|
|
15
|
-
it
|
16
|
-
expect
|
17
|
-
Mail2FrontMatter.set_config(
|
18
|
-
|
14
|
+
it 'should load a configuration by passing a hash' do
|
15
|
+
expect do
|
16
|
+
Mail2FrontMatter.set_config(foo: 'bar')
|
17
|
+
end.to_not raise_error
|
19
18
|
end
|
20
19
|
|
21
|
-
it
|
22
|
-
expect
|
20
|
+
it 'should raise an error for other types' do
|
21
|
+
expect do
|
23
22
|
Mail2FrontMatter.set_config([])
|
24
|
-
|
23
|
+
end.to raise_error
|
25
24
|
end
|
26
25
|
|
27
|
-
it
|
28
|
-
expect
|
26
|
+
it 'should fail loading malformed configs' do
|
27
|
+
expect do
|
29
28
|
Mail2FrontMatter.set_config(malformed_config)
|
30
|
-
|
29
|
+
end.to raise_error
|
31
30
|
end
|
32
31
|
|
33
|
-
it
|
32
|
+
it 'should attempt to load the default configuration if nothing is passed' do
|
34
33
|
# this should attempt and fail because there is no ./data/mail2frontmatter.yml
|
35
|
-
expect
|
34
|
+
expect do
|
36
35
|
Mail2FrontMatter.set_config do |config|
|
37
36
|
config[:foo] = 'bar'
|
38
37
|
end
|
39
|
-
|
38
|
+
end.to raise_error(LoadError)
|
40
39
|
end
|
41
|
-
|
42
|
-
end
|
40
|
+
end
|
File without changes
|
File without changes
|
data/spec/parser_spec.rb
CHANGED
@@ -1,43 +1,41 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Mail2FrontMatter::Parser,
|
4
|
-
|
3
|
+
describe Mail2FrontMatter::Parser, 'parsing' do
|
5
4
|
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
6
5
|
|
7
|
-
it
|
8
|
-
expect
|
6
|
+
it 'should parse HTML email' do
|
7
|
+
expect do
|
9
8
|
Mail2FrontMatter::Parser.new(message_one)
|
10
|
-
|
9
|
+
end.to_not raise_error
|
11
10
|
end
|
12
11
|
|
13
|
-
it
|
12
|
+
it 'should return an html body as a string' do
|
14
13
|
body = Mail2FrontMatter::Parser.new(message_one).body
|
15
14
|
expect(body).to match(/Charlie<br>/)
|
16
15
|
end
|
17
16
|
|
18
|
-
it
|
17
|
+
it 'should return have an email metadata hash with a from key' do
|
19
18
|
from = Mail2FrontMatter::Parser.new(message_one).metadata[:from]
|
20
|
-
expect(from).to eq(
|
19
|
+
expect(from).to eq('Kunal Shah <kunalashokshah@gmail.com>')
|
21
20
|
end
|
22
21
|
|
23
|
-
it
|
22
|
+
it 'should return have an email metadata hash with a to key' do
|
24
23
|
to = Mail2FrontMatter::Parser.new(message_one).metadata[:to]
|
25
|
-
expect(to).to eq(
|
24
|
+
expect(to).to eq('stream@kunalashah.com')
|
26
25
|
end
|
27
26
|
|
28
|
-
it
|
27
|
+
it 'should return have an email metadata hash with a received key' do
|
29
28
|
received = Mail2FrontMatter::Parser.new(message_one).metadata[:received]
|
30
29
|
expect(received.class).to eq(DateTime)
|
31
30
|
end
|
32
31
|
|
33
|
-
it
|
32
|
+
it 'should return have an email metadata hash with a subject key' do
|
34
33
|
subject = Mail2FrontMatter::Parser.new(message_one).metadata[:subject]
|
35
|
-
expect(subject).to eq(
|
34
|
+
expect(subject).to eq('295 Abandoned Elevator Shaft')
|
36
35
|
end
|
37
36
|
|
38
|
-
it
|
37
|
+
it 'should save attachments to disk' do
|
39
38
|
attachment_path = Mail2FrontMatter::Parser.new(message_one).metadata[:attachments].first[1][:filepath]
|
40
39
|
expect(File.exist?(attachment_path)).to eq(true)
|
41
40
|
end
|
42
|
-
|
43
|
-
end
|
41
|
+
end
|
data/spec/preprocessor_spec.rb
CHANGED
@@ -7,56 +7,55 @@ describe Mail2FrontMatter::PreProcessor do
|
|
7
7
|
|
8
8
|
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
9
9
|
|
10
|
-
let(:invalidly_defined_preprocessor)
|
10
|
+
let(:invalidly_defined_preprocessor) do
|
11
11
|
class MyInvalidProcessor < Mail2FrontMatter::PreProcessor
|
12
12
|
# note, instanced not class
|
13
13
|
def run(metadata, body)
|
14
14
|
# some modification
|
15
|
-
|
15
|
+
[metadata, body]
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
return MyInvalidProcessor
|
20
|
-
|
20
|
+
end
|
21
21
|
|
22
|
-
let(:validly_defined_preprocessor)
|
22
|
+
let(:validly_defined_preprocessor) do
|
23
23
|
class MyValidProcessor < Mail2FrontMatter::PreProcessor
|
24
24
|
def self.run(metadata, body)
|
25
25
|
# some modification
|
26
|
-
|
26
|
+
[metadata, body]
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
30
30
|
return MyValidProcessor
|
31
|
-
|
32
|
-
|
33
|
-
context "registration" do
|
31
|
+
end
|
34
32
|
|
35
|
-
|
36
|
-
|
33
|
+
context 'registration' do
|
34
|
+
it 'should raise errors for invalid processors' do
|
35
|
+
expect do
|
37
36
|
invalidly_defined_preprocessor.register({})
|
38
|
-
|
37
|
+
end.to raise_error
|
39
38
|
end
|
40
39
|
|
41
|
-
it
|
42
|
-
expect
|
40
|
+
it 'should not raise errors for valid processors' do
|
41
|
+
expect do
|
43
42
|
validly_defined_preprocessor.register({})
|
44
|
-
|
43
|
+
end.to_not raise_error
|
45
44
|
end
|
46
45
|
|
47
|
-
it
|
48
|
-
expect
|
46
|
+
it 'should raise an error when registered without a hash' do
|
47
|
+
expect do
|
49
48
|
validly_defined_preprocessor.register(nil)
|
50
|
-
|
49
|
+
end.to raise_error(ArgumentError)
|
51
50
|
end
|
52
51
|
|
53
|
-
it
|
54
|
-
expect
|
55
|
-
validly_defined_preprocessor.register(
|
56
|
-
|
52
|
+
it 'should not raise an error when registered with a hash' do
|
53
|
+
expect do
|
54
|
+
validly_defined_preprocessor.register(foo: 'bar')
|
55
|
+
end.to_not raise_error
|
57
56
|
end
|
58
57
|
|
59
|
-
it
|
58
|
+
it 'should load preprocessors' do
|
60
59
|
Mail2FrontMatter.set_config(complex_config)
|
61
60
|
processors = Mail2FrontMatter::PreProcessor.processors
|
62
61
|
|
@@ -64,23 +63,23 @@ describe Mail2FrontMatter::PreProcessor do
|
|
64
63
|
expect(processors).to include(Mail2FrontMatter::FakeProcessorWithOptions)
|
65
64
|
end
|
66
65
|
|
67
|
-
it
|
66
|
+
it 'should provide preprocessors with passed options' do
|
68
67
|
Mail2FrontMatter.set_config(complex_config)
|
69
68
|
options = Mail2FrontMatter::FakeProcessorWithOptions.instance_variable_get(:@options)
|
70
69
|
|
71
70
|
expect(options.class).to eq(Hash)
|
72
|
-
expect(options[:foo]).to eq(
|
71
|
+
expect(options[:foo]).to eq('bar')
|
73
72
|
end
|
74
73
|
end
|
75
74
|
|
76
|
-
context
|
77
|
-
it
|
75
|
+
context 'operation' do
|
76
|
+
it 'should continue processing if an individual processor fails' do
|
78
77
|
Mail2FrontMatter.set_config(broken_config)
|
79
78
|
parser = Mail2FrontMatter::Parser.new(message_one)
|
80
79
|
|
81
|
-
expect
|
82
|
-
|
83
|
-
|
80
|
+
expect do
|
81
|
+
Mail2FrontMatter::PreProcessor.process(parser.metadata, parser.body)
|
82
|
+
end.to_not raise_error
|
84
83
|
end
|
85
84
|
end
|
86
85
|
end
|
File without changes
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,67 @@
|
|
1
1
|
|
2
2
|
M2FM_GEM_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
-
|
3
|
+
$LOAD_PATH << File.join(M2FM_GEM_PATH, 'fixtures')
|
4
4
|
|
5
5
|
require 'yaml'
|
6
|
+
require 'fileutils'
|
6
7
|
require File.join(M2FM_GEM_PATH, 'lib', 'mail2frontmatter')
|
8
|
+
|
9
|
+
module RSpec
|
10
|
+
# remove any data hanging around from spec runs...
|
11
|
+
def self.clean_testbed
|
12
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'remote', '*')])
|
13
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'installation', 'data', '*')])
|
14
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'installation', 'media', '*')])
|
15
|
+
FileUtils.rm_rf(Dir[File.join(M2FM_GEM_PATH, 'spec', 'installation', '.git')])
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
config.before(:suite) do
|
21
|
+
RSpec.clean_testbed
|
22
|
+
|
23
|
+
# setup a repo in spec/installation
|
24
|
+
repo = Rugged::Repository.init_at(File.join(M2FM_GEM_PATH, 'spec', 'installation', '.git'))
|
25
|
+
|
26
|
+
# setup another repo in spec/remote
|
27
|
+
Rugged::Repository.init_at(File.join(M2FM_GEM_PATH, 'spec', 'remote'), :bare)
|
28
|
+
|
29
|
+
# add the second repo as the origin of the first
|
30
|
+
repo.remotes.create('origin', File.join(M2FM_GEM_PATH, 'spec', 'remote'))
|
31
|
+
|
32
|
+
index = repo.index
|
33
|
+
|
34
|
+
# stage the blank folders
|
35
|
+
index.add(path: 'data/.gitkeep',
|
36
|
+
oid: (Rugged::Blob.from_workdir repo, 'data/.gitkeep'),
|
37
|
+
mode: 0100644)
|
38
|
+
|
39
|
+
index.add(path: 'media/.gitkeep',
|
40
|
+
oid: (Rugged::Blob.from_workdir repo, 'media/.gitkeep'),
|
41
|
+
mode: 0100644)
|
42
|
+
|
43
|
+
# commit them
|
44
|
+
tree = index.write_tree(repo)
|
45
|
+
index.write
|
46
|
+
|
47
|
+
author = {
|
48
|
+
email: 'sender@example.com',
|
49
|
+
name: 'The Sender',
|
50
|
+
time: Time.now
|
51
|
+
}
|
52
|
+
|
53
|
+
Rugged::Commit.create(repo, author: author,
|
54
|
+
committer: author,
|
55
|
+
message: 'checking in data/media empties',
|
56
|
+
parents: [],
|
57
|
+
tree: tree,
|
58
|
+
update_ref: 'HEAD')
|
59
|
+
|
60
|
+
# push
|
61
|
+
repo.push 'origin', ['refs/heads/master']
|
62
|
+
end
|
63
|
+
|
64
|
+
config.after(:suite) do
|
65
|
+
RSpec.clean_testbed
|
66
|
+
end
|
67
|
+
end
|
data/spec/writer_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mail2FrontMatter::Writer, 'writing' do
|
4
|
+
let(:config) { File.join(M2FM_GEM_PATH, 'fixtures', 'mail2frontmatter.simple.yml') }
|
5
|
+
let(:message_one) { Mail::Message.new(File.read(File.join(M2FM_GEM_PATH, 'fixtures', 'attachments.eml'))) }
|
6
|
+
|
7
|
+
it 'should write a parse and processed email' do
|
8
|
+
Mail2FrontMatter.set_config(config) do |config|
|
9
|
+
config[:data_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'data')
|
10
|
+
config[:media_directory] = File.join(M2FM_GEM_PATH, 'spec', 'installation', 'media')
|
11
|
+
end
|
12
|
+
|
13
|
+
parser = Mail2FrontMatter::Parser.new(message_one)
|
14
|
+
metadata, body = Mail2FrontMatter::PreProcessor.process(parser.metadata, parser.body)
|
15
|
+
|
16
|
+
Mail2FrontMatter::Writer.write(metadata, body)
|
17
|
+
|
18
|
+
expect(File.exist?(File.join(Mail2FrontMatter.config[:data_directory], '2009-11-25-295-abandoned-elevator-shaft.html.erb'))).to be(true)
|
19
|
+
expect(File.exist?(File.join(Mail2FrontMatter.config[:media_directory], 'images', 'IMG_0141.JPG'))).to be(true)
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mail2frontmatter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kunal Shah
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mailman
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 0.7.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 0.7.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: nokogiri
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rugged
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.21'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.21'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,8 +122,7 @@ dependencies:
|
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: '10.0'
|
111
|
-
description: '
|
112
|
-
poll an account. '
|
125
|
+
description: 'email-in for static blogs like Middleman. Uses Mailman to poll an account. '
|
113
126
|
email:
|
114
127
|
- me@kunalashah.com
|
115
128
|
executables:
|
@@ -135,6 +148,7 @@ files:
|
|
135
148
|
- fixtures/mail2frontmatter/fake-processor.rb
|
136
149
|
- fixtures/no_attachments.eml
|
137
150
|
- lib/mail2frontmatter.rb
|
151
|
+
- lib/mail2frontmatter/committer.rb
|
138
152
|
- lib/mail2frontmatter/configuration.rb
|
139
153
|
- lib/mail2frontmatter/parser.rb
|
140
154
|
- lib/mail2frontmatter/preprocessor.rb
|
@@ -142,10 +156,15 @@ files:
|
|
142
156
|
- lib/mail2frontmatter/watcher.rb
|
143
157
|
- lib/mail2frontmatter/writer.rb
|
144
158
|
- mail2frontmatter.gemspec
|
159
|
+
- spec/committer_spec.rb
|
145
160
|
- spec/configuration_spec.rb
|
161
|
+
- spec/installation/data/.gitkeep
|
162
|
+
- spec/installation/media/.gitkeep
|
146
163
|
- spec/parser_spec.rb
|
147
164
|
- spec/preprocessor_spec.rb
|
165
|
+
- spec/remote/.gitkeep
|
148
166
|
- spec/spec_helper.rb
|
167
|
+
- spec/writer_spec.rb
|
149
168
|
homepage: https://github.com/whistlerbrk/Mail2FrontMatter
|
150
169
|
licenses:
|
151
170
|
- MIT
|
@@ -166,12 +185,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
166
185
|
version: '0'
|
167
186
|
requirements: []
|
168
187
|
rubyforge_project:
|
169
|
-
rubygems_version: 2.
|
188
|
+
rubygems_version: 2.5.1
|
170
189
|
signing_key:
|
171
190
|
specification_version: 4
|
172
|
-
summary:
|
191
|
+
summary: email-in for static blogs like Middleman
|
173
192
|
test_files:
|
193
|
+
- spec/committer_spec.rb
|
174
194
|
- spec/configuration_spec.rb
|
195
|
+
- spec/installation/data/.gitkeep
|
196
|
+
- spec/installation/media/.gitkeep
|
175
197
|
- spec/parser_spec.rb
|
176
198
|
- spec/preprocessor_spec.rb
|
199
|
+
- spec/remote/.gitkeep
|
177
200
|
- spec/spec_helper.rb
|
201
|
+
- spec/writer_spec.rb
|