signore 0.1.2 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +23 -0
- data/.ruby-version +1 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +30 -9
- data/README.md +1 -1
- data/Rakefile +10 -8
- data/config/reek.yml +14 -0
- data/lib/signore/database.rb +11 -14
- data/lib/signore/executable.rb +48 -26
- data/lib/signore/signature.rb +23 -18
- data/lib/signore.rb +3 -2
- data/signore.gemspec +8 -7
- data/spec/fixtures/wrapper.yml +43 -29
- data/spec/signore/database_spec.rb +19 -36
- data/spec/signore/executable_spec.rb +56 -53
- data/spec/signore/signature_spec.rb +51 -31
- data/spec/spec_helper.rb +4 -4
- metadata +50 -39
- data/.rvmrc +0 -2
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1ae3bd13eb44a22d1617a29fe32e78f4b3f9abe1
|
4
|
+
data.tar.gz: bc38ff309685c63d6c4cc37b687bf6f37f7af13a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8946f12a8af7ec349e419f688e95c9b98504b582bfbee04471aa33b8f3c61fd9336d17faeac680059556cf26c6f4bc844f5eb7df981d54a126842c5cadc4e6cf
|
7
|
+
data.tar.gz: ca59fe6dd1077779a688f8bbce6722d2c9ceb6fe71f5ae912b7f074cafc625d11a598474a2668f0d717ebe2f3608899e2e6b74a8a39de906bede9c630b6dfa4e
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
AccessModifierIndentation:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
AlignHash:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
AlignParameters:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
AndOr:
|
11
|
+
Enabled: false
|
12
|
+
|
13
|
+
Documentation:
|
14
|
+
Enabled: false
|
15
|
+
|
16
|
+
EndAlignment:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
IndentationWidth:
|
20
|
+
Enabled: false
|
21
|
+
|
22
|
+
MethodDefParentheses:
|
23
|
+
Enabled: false
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1
|
data/Gemfile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -2,21 +2,42 @@ PATH
|
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
4
|
signore (0.1.2)
|
5
|
-
|
6
|
-
trollop
|
5
|
+
lovely_rufus (~> 0.1.0)
|
7
6
|
|
8
7
|
GEM
|
9
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
10
9
|
specs:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
ast (1.1.0)
|
11
|
+
json (1.8.1)
|
12
|
+
lovely_rufus (0.1.0)
|
13
|
+
minitest (5.2.3)
|
14
|
+
parser (2.1.4)
|
15
|
+
ast (~> 1.1)
|
16
|
+
slop (~> 3.4, >= 3.4.5)
|
17
|
+
powerpack (0.0.9)
|
18
|
+
rainbow (2.0.0)
|
19
|
+
reek (1.3.6)
|
20
|
+
ruby2ruby (~> 2.0.7)
|
21
|
+
ruby_parser (~> 3.2)
|
22
|
+
sexp_processor
|
23
|
+
rubocop (0.18.1)
|
24
|
+
json (>= 1.7.7, < 2)
|
25
|
+
parser (~> 2.1.3)
|
26
|
+
powerpack (~> 0.0.6)
|
27
|
+
rainbow (>= 1.99.1, < 3.0)
|
28
|
+
ruby2ruby (2.0.7)
|
29
|
+
ruby_parser (~> 3.1)
|
30
|
+
sexp_processor (~> 4.0)
|
31
|
+
ruby_parser (3.4.1)
|
32
|
+
sexp_processor (~> 4.1)
|
33
|
+
sexp_processor (4.4.1)
|
34
|
+
slop (3.4.7)
|
15
35
|
|
16
36
|
PLATFORMS
|
17
37
|
ruby
|
18
38
|
|
19
39
|
DEPENDENCIES
|
20
|
-
minitest (
|
21
|
-
|
40
|
+
minitest (~> 5.0)
|
41
|
+
reek (~> 1.3)
|
42
|
+
rubocop (~> 0.18.0)
|
22
43
|
signore!
|
data/README.md
CHANGED
@@ -105,4 +105,4 @@ signore requires Ruby 1.9 and works best with Ruby 1.9.2 compiled with Psych (fo
|
|
105
105
|
|
106
106
|
---
|
107
107
|
|
108
|
-
© MMIX-
|
108
|
+
© MMIX-MMXIII Piotr Szotkowski <chastell@chastell.net>, licensed under AGPL 3 (see LICENCE)
|
data/Rakefile
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
require 'rake/testtask'
|
2
|
+
require 'reek/rake/task'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
|
5
|
+
task default: %i[spec rubocop reek]
|
2
6
|
|
3
7
|
Rake::TestTask.new :spec do |task|
|
4
8
|
task.test_files = FileList['spec/**/*_spec.rb']
|
9
|
+
task.warning = true
|
5
10
|
end
|
6
11
|
|
7
|
-
|
8
|
-
task
|
9
|
-
|
10
|
-
|
11
|
-
include Signore
|
12
|
-
ARGV.clear
|
13
|
-
IRB.start
|
12
|
+
Reek::Rake::Task.new do |task|
|
13
|
+
task.config_files = 'config/reek.yml'
|
14
|
+
task.fail_on_error = false
|
15
|
+
task.reek_opts = '--quiet'
|
14
16
|
end
|
15
17
|
|
16
|
-
|
18
|
+
Rubocop::RakeTask.new
|
data/config/reek.yml
ADDED
data/lib/signore/database.rb
CHANGED
@@ -1,27 +1,24 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
module Signore class Database
|
4
|
-
|
5
2
|
def initialize path
|
6
3
|
@store = YAML::Store.new path
|
7
4
|
end
|
8
5
|
|
9
6
|
def << sig
|
10
|
-
|
11
|
-
|
12
|
-
|
7
|
+
store.transaction do
|
8
|
+
store['signatures'] ||= []
|
9
|
+
store['signatures'] << sig
|
13
10
|
end
|
14
11
|
end
|
15
12
|
|
16
|
-
def find
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
.
|
22
|
-
.reject { |sig| opts[:no_tags].any? { |tag| sig.tagged_with? tag } }
|
23
|
-
.shuffle.first
|
13
|
+
def find(forbidden_tags: [], random: Random.new, required_tags: [])
|
14
|
+
store.transaction true do
|
15
|
+
store['signatures']
|
16
|
+
.select { |sig| required_tags.all? { |tag| sig.tagged_with? tag } }
|
17
|
+
.reject { |sig| forbidden_tags.any? { |tag| sig.tagged_with? tag } }
|
18
|
+
.sample random: random
|
24
19
|
end
|
25
20
|
end
|
26
21
|
|
22
|
+
attr_reader :store
|
23
|
+
private :store
|
27
24
|
end end
|
data/lib/signore/executable.rb
CHANGED
@@ -1,34 +1,23 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
module Signore class Executable
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
2
|
+
def initialize args = ARGV, db_factory: Database
|
3
|
+
@settings = settings_from args
|
4
|
+
@db = db_factory.new settings.db_path
|
5
|
+
unless %w[prego pronto].include? settings.action
|
6
|
+
abort 'usage: signore prego|pronto [tag, …]'
|
8
7
|
end
|
9
|
-
Trollop.die 'usage: signore prego|pronto [label, …]' unless ['prego', 'pronto'].include? args.first
|
10
|
-
|
11
|
-
@db = db_class.new opts[:database]
|
12
|
-
|
13
|
-
@action = args.shift
|
14
|
-
|
15
|
-
@no_tags, @tags = args.partition { |tag| tag.start_with? '~' }
|
16
|
-
@no_tags.map! { |tag| tag[1..-1] }
|
17
8
|
end
|
18
9
|
|
19
|
-
def run
|
20
|
-
case
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
params = get_params input
|
25
|
-
sig = Signature.new params[:text], params[:author], params[:source], params[:subject], @tags
|
26
|
-
@db << sig
|
27
|
-
end
|
28
|
-
|
10
|
+
def run(input: $stdin)
|
11
|
+
sig = case settings.action
|
12
|
+
when 'prego' then handle_prego settings
|
13
|
+
when 'pronto' then handle_pronto input
|
14
|
+
end
|
29
15
|
puts sig.to_s
|
30
16
|
end
|
31
17
|
|
18
|
+
attr_reader :db, :settings
|
19
|
+
private :db, :settings
|
20
|
+
|
32
21
|
private
|
33
22
|
|
34
23
|
def get_param param, input
|
@@ -38,10 +27,43 @@ module Signore class Executable
|
|
38
27
|
value.strip
|
39
28
|
end
|
40
29
|
|
41
|
-
def
|
42
|
-
|
30
|
+
def handle_prego settings
|
31
|
+
db.find required_tags: settings.required_tags,
|
32
|
+
forbidden_tags: settings.forbidden_tags
|
33
|
+
end
|
34
|
+
|
35
|
+
def handle_pronto input
|
36
|
+
params = params_from input
|
37
|
+
sig = Signature.new params.text, params.author, params.source,
|
38
|
+
params.subject, settings.required_tags
|
39
|
+
db << sig
|
40
|
+
sig
|
41
|
+
end
|
42
|
+
|
43
|
+
def settings_from args
|
44
|
+
OpenStruct.new.tap do |settings|
|
45
|
+
db_dir = ENV.fetch('XDG_DATA_HOME') { File.expand_path '~/.local/share' }
|
46
|
+
settings.db_path = "#{db_dir}/signore/signatures.yml"
|
47
|
+
parse_settings args, settings
|
48
|
+
settings.action = args.shift
|
49
|
+
settings.forbidden_tags, settings.required_tags = args.partition do |tag|
|
50
|
+
tag.start_with? '~'
|
51
|
+
end
|
52
|
+
settings.forbidden_tags.map! { |tag| tag[1..-1] }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def params_from input
|
57
|
+
OpenStruct.new Hash[[:text, :author, :subject, :source].map do |param|
|
43
58
|
[param, get_param(param, input)]
|
44
59
|
end].reject { |_, value| value.empty? }
|
45
60
|
end
|
46
61
|
|
62
|
+
def parse_settings args, settings
|
63
|
+
OptionParser.new do |opts|
|
64
|
+
opts.on '-d', '--database PATH', 'Database location' do |path|
|
65
|
+
settings.db_path = path
|
66
|
+
end
|
67
|
+
end.parse! args
|
68
|
+
end
|
47
69
|
end end
|
data/lib/signore/signature.rb
CHANGED
@@ -1,34 +1,39 @@
|
|
1
|
-
module Signore
|
1
|
+
module Signore Signature = Struct.new(*%i[text author source subject tags]) do
|
2
|
+
class << self
|
3
|
+
undef :[]
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.[](author: nil, source: nil, subject: nil, tags: nil, text: nil)
|
7
|
+
new text, author, source, subject, tags
|
8
|
+
end
|
2
9
|
|
3
10
|
def tagged_with? tag
|
4
11
|
tags and tags.include? tag
|
5
12
|
end
|
6
13
|
|
7
14
|
def to_s
|
8
|
-
wrapped
|
9
|
-
|
15
|
+
wrapped = LovelyRufus::TextWrapper.wrap text.gsub("\n", "\n\n"), width: 80
|
16
|
+
squeezed = wrapped.gsub("\n\n", "\n").chomp
|
17
|
+
squeezed + meta_for(squeezed)
|
10
18
|
end
|
11
19
|
|
12
20
|
private
|
13
21
|
|
14
|
-
def
|
15
|
-
|
16
|
-
|
17
|
-
when author && subject then "#{author} #{subject}"
|
18
|
-
when author && source then "#{author}, #{source}"
|
19
|
-
when author then "#{author}"
|
20
|
-
when source then "#{source}"
|
21
|
-
when subject then "#{subject}"
|
22
|
-
end
|
22
|
+
def indent_size_for text
|
23
|
+
indent = text_width(text) - meta.size - 2
|
24
|
+
indent < 0 ? 0 : indent
|
23
25
|
end
|
24
26
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
spaces = indent > 0 ? ' ' * indent : ''
|
27
|
+
def meta
|
28
|
+
stem = [author, subject].compact.join ' '
|
29
|
+
stem.empty? ? "#{source}" : [stem, source].compact.join(', ')
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
+
def meta_for text
|
33
|
+
meta.empty? ? '' : "\n#{' ' * indent_size_for(text)}[#{meta}]"
|
32
34
|
end
|
33
35
|
|
36
|
+
def text_width text
|
37
|
+
text.split("\n").map(&:size).max
|
38
|
+
end
|
34
39
|
end end
|
data/lib/signore.rb
CHANGED
data/signore.gemspec
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
Gem::Specification.new do |gem|
|
2
2
|
gem.name = 'signore'
|
3
|
-
gem.version = '0.
|
3
|
+
gem.version = '0.2.0'
|
4
4
|
gem.summary = 'signore: an email signature manager/randomiser'
|
5
5
|
gem.homepage = 'http://github.com/chastell/signore'
|
6
6
|
gem.author = 'Piotr Szotkowski'
|
7
7
|
gem.email = 'chastell@chastell.net'
|
8
8
|
|
9
9
|
gem.files = `git ls-files -z`.split "\0"
|
10
|
-
gem.executables =
|
11
|
-
gem.test_files =
|
10
|
+
gem.executables = gem.files.grep(%r{^bin/}).map { |path| File.basename path }
|
11
|
+
gem.test_files = gem.files.grep %r{^spec/.*\.rb$}
|
12
12
|
|
13
|
-
gem.add_dependency '
|
14
|
-
|
15
|
-
gem.add_development_dependency 'minitest', '
|
16
|
-
gem.add_development_dependency '
|
13
|
+
gem.add_dependency 'lovely_rufus', '~> 0.1.0'
|
14
|
+
|
15
|
+
gem.add_development_dependency 'minitest', '~> 5.0'
|
16
|
+
gem.add_development_dependency 'reek', '~> 1.3'
|
17
|
+
gem.add_development_dependency 'rubocop', '~> 0.18.0'
|
17
18
|
end
|
data/spec/fixtures/wrapper.yml
CHANGED
@@ -1,35 +1,42 @@
|
|
1
1
|
# wrapping doesn’t affect one-liners
|
2
|
-
- :
|
3
|
-
|
2
|
+
- - !ruby/struct:Signore::Signature
|
3
|
+
text: Patches are like Free Software love letters.
|
4
|
+
- |-
|
5
|
+
Patches are like Free Software love letters.
|
4
6
|
|
5
7
|
# meta info is right-aligned on its own line
|
6
|
-
- :
|
7
|
-
|
8
|
-
|
8
|
+
- - !ruby/struct:Signore::Signature
|
9
|
+
text: I have a fever and it’s not disco related.
|
10
|
+
author: opi
|
11
|
+
- |-
|
9
12
|
I have a fever and it’s not disco related.
|
10
13
|
[opi]
|
11
14
|
|
12
15
|
# more-than-80-column signatures are be wrapped, with the result being as short as possible
|
13
|
-
- :
|
14
|
-
|
16
|
+
- - !ruby/struct:Signore::Signature
|
17
|
+
text: It may look like I’m just sitting here doing nothing. But I’m really actively waiting for all my problems to go away.
|
18
|
+
- |-
|
15
19
|
It may look like I’m just sitting here doing nothing. But
|
16
20
|
I’m really actively waiting for all my problems to go away.
|
17
21
|
|
18
22
|
# meta info is right-aligned to the longest line
|
19
|
-
- :
|
20
|
-
|
21
|
-
|
23
|
+
- - !ruby/struct:Signore::Signature
|
24
|
+
text: No, no, it’s spelled Raymond Luxury Yacht, but it’s pronounced Throatwobbler Mangrove.
|
25
|
+
source: Monty Python
|
26
|
+
- |-
|
22
27
|
No, no, it’s spelled Raymond Luxury Yacht,
|
23
28
|
but it’s pronounced Throatwobbler Mangrove.
|
24
29
|
[Monty Python]
|
25
30
|
|
26
31
|
# multi-line signatures are wrapped on a line-by-line basis
|
27
|
-
- :
|
32
|
+
- - !ruby/struct:Signore::Signature
|
33
|
+
text: |-
|
28
34
|
‘The Ruby community should proceed with all deliberate speed towards ISO standardization of the language.’
|
29
35
|
‘Yeah, look what it did to Forth.’
|
30
36
|
‘Don’t just say it, show it. <http://vividpicture.com/aleks/atari/forth.jpg>’
|
31
|
-
|
32
|
-
|
37
|
+
author: M. Edward (Ed) Borasky, Matt Lawrence, Gregory Brown
|
38
|
+
source: ruby-talk
|
39
|
+
- |-
|
33
40
|
‘The Ruby community should proceed with all deliberate
|
34
41
|
speed towards ISO standardization of the language.’
|
35
42
|
‘Yeah, look what it did to Forth.’
|
@@ -37,13 +44,15 @@
|
|
37
44
|
[M. Edward (Ed) Borasky, Matt Lawrence, Gregory Brown, ruby-talk]
|
38
45
|
|
39
46
|
# long meta info is flushed left
|
40
|
-
- :
|
47
|
+
- - !ruby/struct:Signore::Signature
|
48
|
+
text: |-
|
41
49
|
‘The Guardian also had a pre-election column, in which an allegedly “ironic joke” was open to other interpretations: “John Wilkes Booth, Lee Harvey Oswald, John Hinckley Jr., where are you now that we need you?” They removed the column from on-line access and apologized.’
|
42
50
|
‘They should have. Hinckley missed the vital spot, so who needs him?’
|
43
51
|
‘As everybody knows, Reagan was killed in that attack and a lookalike was substituted.’
|
44
52
|
‘You mean we were governed all those years by an ACTOR!’
|
45
|
-
|
46
|
-
|
53
|
+
author: Spehro Pefhany, CyberCypher, Jess Askin, don groves
|
54
|
+
source: alt.usage.english
|
55
|
+
- |-
|
47
56
|
‘The Guardian also had a pre-election column, in which an allegedly
|
48
57
|
“ironic joke” was open to other interpretations: “John Wilkes Booth,
|
49
58
|
Lee Harvey Oswald, John Hinckley Jr., where are you now that we need
|
@@ -55,26 +64,31 @@
|
|
55
64
|
[Spehro Pefhany, CyberCypher, Jess Askin, don groves, alt.usage.english]
|
56
65
|
|
57
66
|
# wrapping doesn’t left one-letter words at the end of lines
|
58
|
-
- :
|
59
|
-
|
60
|
-
|
67
|
+
- - !ruby/struct:Signore::Signature
|
68
|
+
text: I’ve been trying for some time to develop a lifestyle that doesn’t require my presence.
|
69
|
+
author: Gary Trudeau
|
70
|
+
- |-
|
61
71
|
I’ve been trying for some time to develop
|
62
72
|
a lifestyle that doesn’t require my presence.
|
63
73
|
[Gary Trudeau]
|
64
74
|
|
65
75
|
# there are no hangouts
|
66
|
-
- :
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
76
|
+
- - !ruby/struct:Signore::Signature
|
77
|
+
text: Better to teach a man to fish than to give him a fish. And if he can’t be bothered to learn to fish and starves to death, that’s a good enough outcome for me.
|
78
|
+
author: Steve VanDevender
|
79
|
+
- |-
|
80
|
+
Better to teach a man to fish than to give him
|
81
|
+
a fish. And if he can’t be bothered to learn to
|
82
|
+
fish and starves to death, that’s a good enough outcome for me.
|
83
|
+
[Steve VanDevender]
|
73
84
|
|
74
85
|
# for two-line signatures, first line is considered for hangouts
|
75
|
-
- :
|
76
|
-
|
77
|
-
|
86
|
+
- - !ruby/struct:Signore::Signature
|
87
|
+
text: Well, the old ones go mmmmmbbbbzzzzttteeeeeep as they start up and the new ones go whupwhupwhupwhooopwhooooopwhooooooommmmmmmmmm.
|
88
|
+
author: Graham Reed
|
89
|
+
subject: on subway engines
|
90
|
+
source: asr
|
91
|
+
- |-
|
78
92
|
Well, the old ones go mmmmmbbbbzzzzttteeeeeep as they start up
|
79
93
|
and the new ones go whupwhupwhupwhooopwhooooopwhooooooommmmmmmmmm.
|
80
94
|
[Graham Reed on subway engines, asr]
|
@@ -1,60 +1,43 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require_relative '../spec_helper'
|
4
2
|
|
5
3
|
module Signore describe Database do
|
6
|
-
|
7
4
|
describe '#find' do
|
8
|
-
|
9
|
-
|
10
|
-
srand
|
11
|
-
@db = Database.new 'spec/fixtures/signatures.yml'
|
12
|
-
end
|
5
|
+
let(:db) { Database.new path }
|
6
|
+
let(:path) { 'spec/fixtures/signatures.yml' }
|
13
7
|
|
14
8
|
it 'returns a random signature by default' do
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
9
|
+
Database.new(path).find(random: Random.new(1981)).text
|
10
|
+
.must_include 'Amateur fighter pilot ignores orders'
|
11
|
+
Database.new(path).find(random: Random.new(2009)).text
|
12
|
+
.must_include '// sometimes I believe compiler ignores all my comments'
|
19
13
|
end
|
20
14
|
|
21
15
|
it 'returns a random signature if the tags are empty' do
|
22
|
-
|
23
|
-
|
16
|
+
Database.new(path).find(required_tags: [], random: Random.new(2013)).text
|
17
|
+
.must_equal '// sometimes I believe compiler ignores all my comments'
|
24
18
|
end
|
25
19
|
|
26
20
|
it 'returns a random signature based on provided tags' do
|
27
|
-
|
28
|
-
|
21
|
+
db.find(required_tags: ['programming']).text
|
22
|
+
.must_equal '// sometimes I believe compiler ignores all my comments'
|
23
|
+
db.find(required_tags: ['work']).text
|
24
|
+
.must_equal 'You do have to be mad to work here, but it doesn’t help.'
|
29
25
|
end
|
30
26
|
|
31
27
|
it 'returns a random signature based on required and forbidden tags' do
|
32
|
-
|
28
|
+
forbidden_tags = %w[programming security]
|
29
|
+
db.find(required_tags: ['tech'], forbidden_tags: forbidden_tags).text
|
30
|
+
.must_equal 'You do have to be mad to work here, but it doesn’t help.'
|
33
31
|
end
|
34
|
-
|
35
32
|
end
|
36
33
|
|
37
|
-
describe '
|
38
|
-
|
34
|
+
describe '#<<' do
|
39
35
|
it 'saves the provided signature to disk' do
|
36
|
+
text = 'Normaliser Unix c’est comme pasteuriser le camembert.'
|
40
37
|
file = Tempfile.new ''
|
41
38
|
db = Database.new file.path
|
42
|
-
|
43
|
-
|
44
|
-
db << sig
|
45
|
-
|
46
|
-
file.read.must_equal <<-end.dedent
|
47
|
-
---
|
48
|
-
signatures:
|
49
|
-
- !ruby/struct:Signore::Signature
|
50
|
-
text: Normaliser Unix c’est comme pasteuriser le camembert.
|
51
|
-
author:
|
52
|
-
source:
|
53
|
-
subject:
|
54
|
-
tags:
|
55
|
-
end
|
39
|
+
db << Signature.new(text)
|
40
|
+
file.read.must_include text
|
56
41
|
end
|
57
|
-
|
58
42
|
end
|
59
|
-
|
60
43
|
end end
|
@@ -1,86 +1,89 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require_relative '../spec_helper'
|
4
2
|
|
5
3
|
module Signore describe Executable do
|
6
|
-
|
7
4
|
describe '#initialize' do
|
8
|
-
|
9
5
|
it 'prints usage if no command is given' do
|
10
|
-
|
11
|
-
|
6
|
+
capture_io do
|
7
|
+
-> { Executable.new [] }.must_raise SystemExit
|
8
|
+
end.last.must_include 'usage: signore prego|pronto [tag, …]'
|
12
9
|
end
|
13
10
|
|
14
11
|
it 'prints usage if a bogus command is given' do
|
15
|
-
|
16
|
-
|
12
|
+
capture_io do
|
13
|
+
-> { Executable.new ['bogus'] }.must_raise SystemExit
|
14
|
+
end.last.must_include 'usage: signore prego|pronto [tag, …]'
|
17
15
|
end
|
18
16
|
|
19
17
|
it 'loads the signature database from the specified location' do
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
db_class.verify
|
18
|
+
db_factory = MiniTest::Mock.new.expect :new, nil, ['signatures.yml']
|
19
|
+
Executable.new %w[-d signatures.yml prego], db_factory: db_factory
|
20
|
+
db_factory.verify
|
24
21
|
end
|
25
22
|
|
26
|
-
it '
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
23
|
+
it 'defaults to ~/.local/share/signore/signatures.yml' do
|
24
|
+
begin
|
25
|
+
orig = ENV.delete 'XDG_DATA_HOME'
|
26
|
+
default_path = File.expand_path '~/.local/share/signore/signatures.yml'
|
27
|
+
db_factory = MiniTest::Mock.new
|
28
|
+
db_factory.expect :new, nil, [default_path]
|
29
|
+
Executable.new ['prego'], db_factory: db_factory
|
30
|
+
db_factory.verify
|
31
|
+
ensure
|
32
|
+
ENV['XDG_DATA_HOME'] = orig if orig
|
33
|
+
end
|
32
34
|
end
|
33
35
|
|
34
|
-
it '
|
36
|
+
it 'defaults to $XDG_DATA_HOME/signore/signatures.yml' do
|
35
37
|
begin
|
36
|
-
|
38
|
+
orig = ENV.delete 'XDG_DATA_HOME'
|
37
39
|
ENV['XDG_DATA_HOME'] = Dir.tmpdir
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
40
|
+
default_path = "#{ENV['XDG_DATA_HOME']}/signore/signatures.yml"
|
41
|
+
db_factory = MiniTest::Mock.new
|
42
|
+
db_factory.expect :new, nil, [default_path]
|
43
|
+
Executable.new ['prego'], db_factory: db_factory
|
44
|
+
db_factory.verify
|
42
45
|
ensure
|
43
|
-
|
46
|
+
orig ? ENV['XDG_DATA_HOME'] = orig : ENV.delete('XDG_DATA_HOME')
|
44
47
|
end
|
45
48
|
end
|
46
|
-
|
47
49
|
end
|
48
50
|
|
49
51
|
describe '#run' do
|
50
|
-
|
51
52
|
describe 'prego' do
|
52
|
-
|
53
53
|
it 'prints a signature tagged with the provided tags' do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
54
|
+
args = %w[-d spec/fixtures/signatures.yml prego tech programming]
|
55
|
+
output = "// sometimes I believe compiler ignores all my comments\n"
|
56
|
+
stdout = capture_io { Executable.new(args).run }.first
|
57
|
+
stdout.must_equal output
|
58
58
|
end
|
59
59
|
|
60
60
|
it 'prints a signature based on allowed and forbidden tags' do
|
61
|
-
|
62
|
-
|
61
|
+
path = 'spec/fixtures/signatures.yml'
|
62
|
+
args = %W[-d #{path} prego ~programming tech ~security]
|
63
|
+
out = capture_io { Executable.new(args).run }.first
|
64
|
+
out.must_equal <<-end.dedent
|
63
65
|
You do have to be mad to work here, but it doesn’t help.
|
64
66
|
[Gary Barnes, asr]
|
65
67
|
end
|
66
68
|
end
|
67
|
-
|
68
69
|
end
|
69
70
|
|
70
71
|
describe 'pronto' do
|
71
|
-
|
72
72
|
before do
|
73
73
|
@file = Tempfile.new ''
|
74
74
|
end
|
75
75
|
|
76
|
-
it 'asks about signature parts and saves
|
76
|
+
it 'asks about signature parts and saves resulting signature' do
|
77
77
|
input = StringIO.new <<-end.dedent
|
78
|
-
The Wikipedia page on ADHD is like 20 pages long. That’s just cruel
|
78
|
+
The Wikipedia page on ADHD is like 20 pages long. That’s just cruel.
|
79
|
+
|
79
80
|
Mark Pilgrim\n\n\n
|
80
81
|
end
|
81
82
|
|
82
|
-
|
83
|
-
|
83
|
+
capture_io do
|
84
|
+
args = %W[-d #{@file.path} pronto Wikipedia ADHD]
|
85
|
+
Executable.new(args).run input: input
|
86
|
+
end.first.must_equal <<-end.dedent
|
84
87
|
text?
|
85
88
|
author?
|
86
89
|
subject?
|
@@ -89,8 +92,9 @@ module Signore describe Executable do
|
|
89
92
|
[Mark Pilgrim]
|
90
93
|
end
|
91
94
|
|
92
|
-
|
93
|
-
|
95
|
+
capture_io do
|
96
|
+
Executable.new(%W[-d #{@file.path} prego Wikipedia ADHD]).run
|
97
|
+
end.first.must_equal <<-end.dedent
|
94
98
|
The Wikipedia page on ADHD is like 20 pages long. That’s just cruel.
|
95
99
|
[Mark Pilgrim]
|
96
100
|
end
|
@@ -98,25 +102,24 @@ module Signore describe Executable do
|
|
98
102
|
|
99
103
|
it 'handles multi-line signatures' do
|
100
104
|
input = StringIO.new <<-end.dedent
|
101
|
-
‘
|
102
|
-
‘
|
103
|
-
|
105
|
+
‘You’ve got an interesting accent. Subtle. I can’t place it.’
|
106
|
+
‘It’s text-to-speech… I was raised by smartphones.’
|
107
|
+
|
108
|
+
Patrick Ewing\n\n\n
|
104
109
|
end
|
105
110
|
|
106
|
-
|
107
|
-
|
111
|
+
capture_io do
|
112
|
+
Executable.new(['-d', @file.path, 'pronto']).run input: input
|
113
|
+
end.first.must_equal <<-end.dedent
|
108
114
|
text?
|
109
115
|
author?
|
110
116
|
subject?
|
111
117
|
source?
|
112
|
-
‘
|
113
|
-
‘
|
114
|
-
|
118
|
+
‘You’ve got an interesting accent. Subtle. I can’t place it.’
|
119
|
+
‘It’s text-to-speech… I was raised by smartphones.’
|
120
|
+
[Patrick Ewing]
|
115
121
|
end
|
116
122
|
end
|
117
|
-
|
118
123
|
end
|
119
|
-
|
120
124
|
end
|
121
|
-
|
122
125
|
end end
|
@@ -1,56 +1,84 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
|
3
1
|
require_relative '../spec_helper'
|
4
2
|
|
5
3
|
module Signore describe Signature do
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
describe '.[]' do
|
5
|
+
it 'instantiates Signatures via parameters' do
|
6
|
+
source = 'A History of Modern Computing'
|
7
|
+
text = 'In 1940 he summarized his work in an influential book, ' \
|
8
|
+
'‘Punched Card Methods in Scientific Computation’.'
|
9
|
+
sig = Signature[author: 'Paul E. Ceruzzi', source: source,
|
10
|
+
subject: 'on Wallace Eckert', tags: ['punched cards'], text: text]
|
11
|
+
sig.author.must_equal 'Paul E. Ceruzzi'
|
12
|
+
sig.source.must_equal source
|
13
|
+
sig.subject.must_equal 'on Wallace Eckert'
|
14
|
+
sig.tags.must_equal ['punched cards']
|
15
|
+
sig.text.must_equal text
|
16
|
+
end
|
9
17
|
end
|
10
18
|
|
11
19
|
describe '#tagged_with?' do
|
12
|
-
|
13
20
|
it 'says whether a tagged signature is tagged with a given tag' do
|
14
|
-
|
15
|
-
|
16
|
-
assert
|
21
|
+
sig = Signature[tags: %w[programming tech]]
|
22
|
+
refute sig.tagged_with? 'fnord'
|
23
|
+
assert sig.tagged_with? 'programming'
|
24
|
+
assert sig.tagged_with? 'tech'
|
17
25
|
end
|
18
26
|
|
19
27
|
it 'says that an untagged signature is not tagged with any tag' do
|
20
|
-
refute
|
28
|
+
refute Signature.new.tagged_with? 'fnord'
|
21
29
|
end
|
22
|
-
|
23
30
|
end
|
24
31
|
|
25
32
|
describe '#to_s' do
|
33
|
+
it 'does not show meta if there’s nothing to show' do
|
34
|
+
text = '// sometimes I believe compiler ignores all my comments'
|
35
|
+
sig = Signature.new text
|
36
|
+
sig.to_s.must_equal text
|
37
|
+
end
|
26
38
|
|
27
|
-
it '
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
@dads.to_s.must_equal <<-end.dedent.strip
|
39
|
+
it 'shows author on its own' do
|
40
|
+
sig = Signature.new 'stay-at-home executives vs. wallstreet dads', 'kodz'
|
41
|
+
sig.to_s.must_equal <<-end.dedent.strip
|
33
42
|
stay-at-home executives vs. wallstreet dads
|
34
43
|
[kodz]
|
35
44
|
end
|
45
|
+
end
|
36
46
|
|
37
|
-
|
47
|
+
it 'shows author and source, comma-separated' do
|
48
|
+
text = 'You do have to be mad to work here, but it doesn’t help.'
|
49
|
+
sig = Signature.new text, 'Gary Barnes', 'asr'
|
50
|
+
sig.to_s.must_equal <<-end.dedent.strip
|
38
51
|
You do have to be mad to work here, but it doesn’t help.
|
39
52
|
[Gary Barnes, asr]
|
40
53
|
end
|
54
|
+
end
|
41
55
|
|
42
|
-
|
56
|
+
it 'shows source on its own' do
|
57
|
+
text = 'Bruce Schneier knows Alice and Bob’s shared secret.'
|
58
|
+
sig = Signature[text: text, source: 'Bruce Schneier Facts']
|
59
|
+
sig.to_s.must_equal <<-end.dedent.strip
|
43
60
|
Bruce Schneier knows Alice and Bob’s shared secret.
|
44
61
|
[Bruce Schneier Facts]
|
45
62
|
end
|
63
|
+
end
|
46
64
|
|
47
|
-
|
65
|
+
it 'shows author and subject, space separated' do
|
66
|
+
text = 'She was good at playing abstract confusion ' \
|
67
|
+
'in the same way a midget is good at being short.'
|
68
|
+
sig = Signature[text: text, author: 'Clive James',
|
69
|
+
subject: 'on Marilyn Monroe']
|
70
|
+
sig.to_s.must_equal <<-end.dedent.strip
|
48
71
|
She was good at playing abstract confusion in
|
49
72
|
the same way a midget is good at being short.
|
50
73
|
[Clive James on Marilyn Monroe]
|
51
74
|
end
|
75
|
+
end
|
52
76
|
|
53
|
-
|
77
|
+
it 'shows subject on its own' do
|
78
|
+
text = 'Amateur fighter pilot ignores orders, listens ' \
|
79
|
+
'to the voices in his head and slaughters thousands.'
|
80
|
+
sig = Signature[text: text, subject: 'Star Wars ending explained']
|
81
|
+
sig.to_s.must_equal <<-end.dedent.strip
|
54
82
|
Amateur fighter pilot ignores orders, listens to
|
55
83
|
the voices in his head and slaughters thousands.
|
56
84
|
[Star Wars ending explained]
|
@@ -58,17 +86,9 @@ module Signore describe Signature do
|
|
58
86
|
end
|
59
87
|
|
60
88
|
it 'handles edge cases properly' do
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
YAML.load_file('spec/fixtures/wrapper.yml').each do |sample|
|
66
|
-
sig = SignatureWithMeta.new sample[:text]
|
67
|
-
sig.meta = sample[:meta]
|
68
|
-
sig.to_s.must_equal sample[:wrapped]
|
89
|
+
YAML.load_file('spec/fixtures/wrapper.yml').each do |sig, wrapped|
|
90
|
+
sig.to_s.must_equal wrapped
|
69
91
|
end
|
70
92
|
end
|
71
|
-
|
72
93
|
end
|
73
|
-
|
74
94
|
end end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
|
1
|
+
require 'bundler/setup'
|
2
2
|
require 'minitest/autorun'
|
3
|
-
|
3
|
+
require 'minitest/pride'
|
4
4
|
require 'pathname'
|
5
5
|
require 'tempfile'
|
6
6
|
require 'tmpdir'
|
7
7
|
|
8
|
-
|
8
|
+
require 'signore'
|
9
9
|
|
10
10
|
class String
|
11
11
|
def dedent
|
12
|
-
gsub
|
12
|
+
gsub(/^#{self[/\A\s*/]}/, '')
|
13
13
|
end
|
14
14
|
end
|
metadata
CHANGED
@@ -1,60 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: signore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.2.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Piotr Szotkowski
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-02-18 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
17
|
-
none: false
|
14
|
+
name: lovely_rufus
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - "~>"
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.0
|
19
|
+
version: 0.1.0
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.1.0
|
25
27
|
- !ruby/object:Gem::Dependency
|
26
|
-
name:
|
27
|
-
requirement:
|
28
|
-
none: false
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- -
|
31
|
+
- - "~>"
|
31
32
|
- !ruby/object:Gem::Version
|
32
|
-
version: '0'
|
33
|
-
type: :
|
33
|
+
version: '5.0'
|
34
|
+
type: :development
|
34
35
|
prerelease: false
|
35
|
-
version_requirements:
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.0'
|
36
41
|
- !ruby/object:Gem::Dependency
|
37
|
-
name:
|
38
|
-
requirement:
|
39
|
-
none: false
|
42
|
+
name: reek
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
40
44
|
requirements:
|
41
|
-
- -
|
45
|
+
- - "~>"
|
42
46
|
- !ruby/object:Gem::Version
|
43
|
-
version:
|
47
|
+
version: '1.3'
|
44
48
|
type: :development
|
45
49
|
prerelease: false
|
46
|
-
version_requirements:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
47
55
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
49
|
-
requirement:
|
50
|
-
none: false
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
51
58
|
requirements:
|
52
|
-
- -
|
59
|
+
- - "~>"
|
53
60
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
61
|
+
version: 0.18.0
|
55
62
|
type: :development
|
56
63
|
prerelease: false
|
57
|
-
version_requirements:
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.18.0
|
58
69
|
description:
|
59
70
|
email: chastell@chastell.net
|
60
71
|
executables:
|
@@ -62,13 +73,15 @@ executables:
|
|
62
73
|
extensions: []
|
63
74
|
extra_rdoc_files: []
|
64
75
|
files:
|
65
|
-
- .
|
76
|
+
- ".rubocop.yml"
|
77
|
+
- ".ruby-version"
|
66
78
|
- Gemfile
|
67
79
|
- Gemfile.lock
|
68
80
|
- LICENCE
|
69
81
|
- README.md
|
70
82
|
- Rakefile
|
71
83
|
- bin/signore
|
84
|
+
- config/reek.yml
|
72
85
|
- lib/signore.rb
|
73
86
|
- lib/signore/database.rb
|
74
87
|
- lib/signore/executable.rb
|
@@ -82,31 +95,29 @@ files:
|
|
82
95
|
- spec/spec_helper.rb
|
83
96
|
homepage: http://github.com/chastell/signore
|
84
97
|
licenses: []
|
98
|
+
metadata: {}
|
85
99
|
post_install_message:
|
86
100
|
rdoc_options: []
|
87
101
|
require_paths:
|
88
102
|
- lib
|
89
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
104
|
requirements:
|
92
|
-
- -
|
105
|
+
- - ">="
|
93
106
|
- !ruby/object:Gem::Version
|
94
107
|
version: '0'
|
95
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
96
|
-
none: false
|
97
109
|
requirements:
|
98
|
-
- -
|
110
|
+
- - ">="
|
99
111
|
- !ruby/object:Gem::Version
|
100
112
|
version: '0'
|
101
113
|
requirements: []
|
102
114
|
rubyforge_project:
|
103
|
-
rubygems_version:
|
115
|
+
rubygems_version: 2.2.0
|
104
116
|
signing_key:
|
105
|
-
specification_version:
|
106
|
-
summary:
|
117
|
+
specification_version: 4
|
118
|
+
summary: 'signore: an email signature manager/randomiser'
|
107
119
|
test_files:
|
108
|
-
- spec/
|
120
|
+
- spec/signore/database_spec.rb
|
109
121
|
- spec/signore/executable_spec.rb
|
110
122
|
- spec/signore/signature_spec.rb
|
111
|
-
- spec/
|
112
|
-
has_rdoc:
|
123
|
+
- spec/spec_helper.rb
|
data/.rvmrc
DELETED