signore 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +2 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +20 -0
- data/LICENCE +661 -0
- data/README.md +108 -0
- data/Rakefile +16 -0
- data/bin/signore +4 -0
- data/lib/signore/database.rb +32 -0
- data/lib/signore/executable.rb +33 -0
- data/lib/signore/signature.rb +24 -0
- data/lib/signore/wrapper.rb +65 -0
- data/lib/signore.rb +10 -0
- data/signore.gemspec +16 -0
- data/spec/fixtures/min_yaml.yml +39 -0
- data/spec/fixtures/signatures.yml +22 -0
- data/spec/fixtures/wrapper.yml +80 -0
- data/spec/signore/database_spec.rb +93 -0
- data/spec/signore/executable_spec.rb +111 -0
- data/spec/signore/signature_spec.rb +38 -0
- data/spec/signore/wrapper_spec.rb +15 -0
- data/spec/spec_helper.rb +7 -0
- metadata +104 -0
data/README.md
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
signore
|
2
|
+
=======
|
3
|
+
|
4
|
+
Email signature manager/randomiser.
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
Usage
|
9
|
+
-----
|
10
|
+
|
11
|
+
signore has two subcommands – `prego` and `pronto`, allowing you to retrieve and store signatures (respectively).
|
12
|
+
|
13
|
+
Retrieving signatures is done with `signore prego` and picks a signature at random based on the provided tags:
|
14
|
+
|
15
|
+
$ signore prego tech
|
16
|
+
// sometimes I believe compiler ignores all my comments
|
17
|
+
$ signore prego tech
|
18
|
+
You do have to be mad to work here, but it doesn’t help.
|
19
|
+
[Gary Barnes, asr]
|
20
|
+
|
21
|
+
A tilde (`~`) before a tag means tag negation – i.e., it means that the returned signature cannot be tagged with the given tag:
|
22
|
+
|
23
|
+
$ signore prego tech ~work ~programming
|
24
|
+
Bruce Schneier knows Alice and Bob’s shared secret.
|
25
|
+
[Bruce Schneier Facts]
|
26
|
+
|
27
|
+
Storing signatures is also quite simple; the tags can be provided as the parameters to the `signore pronto` command, and signore asks you about the various parts of the signature you might want to store (the source in this example is omitted); the signature is then displayed (formatted the way it will be when fetched with `signore prego`):
|
28
|
+
|
29
|
+
$ signore pronto literature
|
30
|
+
text?
|
31
|
+
Transported to a surreal landscape, a young girl kills the first person she meets and then teams up with three strangers to kill again.
|
32
|
+
|
33
|
+
author?
|
34
|
+
Rick Polito
|
35
|
+
|
36
|
+
subject?
|
37
|
+
on The Wonderful Wizard of Oz
|
38
|
+
|
39
|
+
source?
|
40
|
+
|
41
|
+
Transported to a surreal landscape, a young girl kills the first
|
42
|
+
person she meets and then teams up with three strangers to kill again.
|
43
|
+
[Rick Polito on The Wonderful Wizard of Oz]
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
Application
|
48
|
+
-----------
|
49
|
+
|
50
|
+
One of the ways to use signore is teaching your old email editor new tricks. If you happen to be a [Vim](http://www.vim.org/) user, the following will delete the current signature and replace it with a random one on every `,ss` sequence:
|
51
|
+
|
52
|
+
map ,ss G?^-- $<CR><Down>dG:r! signore prego<CR>Go<CR><CR><Esc>
|
53
|
+
|
54
|
+
Of course you can pass any tags to the command – so if you’re often writing emails to a technical mailing list, you might want to be able to use, say, `,stt` to get a signature tagged with ‘tech’:
|
55
|
+
|
56
|
+
map ,stt G?^-- $<CR><Down>dG:r! signore prego tech<CR>Go<CR><CR><Esc>
|
57
|
+
|
58
|
+
This can be helpful if you happen to send emails in different languages and want the signature to be actually readable by the recipient. If you tag all your signatures with the right language, the following will allow you to press `,sp` to get a signature in Polish and `,se` to get a signature in English:
|
59
|
+
|
60
|
+
map ,sp G?^-- $<CR><Down>dG:r! signore prego pl<CR>Go<CR><CR><Esc>
|
61
|
+
map ,se G?^-- $<CR><Down>dG:r! signore prego en<CR>Go<CR><CR><Esc>
|
62
|
+
|
63
|
+
Finally, remember that tags can be combined and negated – and so if you often write to non-technical people who prefer Polish, the following will make sure that `,slp` will generate a proper signature (assuming all your Polish signatures are tagged with ‘pl’ and all your technical ones are tagged with ‘tech’):
|
64
|
+
|
65
|
+
map ,slp G?^-- $<CR><Down>dG:r! signore prego pl ~tech<CR>Go<CR><CR><Esc>
|
66
|
+
|
67
|
+
Another aproach would be to create a named pipe that your email program reads from, and run `signore prego` on every read.
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
Options
|
72
|
+
-------
|
73
|
+
|
74
|
+
signore supports a single option, `--database` (or `-d` for short), which can be used to use a non-default signature database location:
|
75
|
+
|
76
|
+
$ signore prego -d spec/fixtures/signatures.yml
|
77
|
+
Amateur fighter pilot ignores orders, listens to
|
78
|
+
the voices in his head and slaughters thousands.
|
79
|
+
[Star Wars ending explained]
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
Properties
|
84
|
+
----------
|
85
|
+
|
86
|
+
Most `Signature`s have `text` and `tags`, some also have `author`, `source` and `subject`. Currently `tags` are used to query the sig database, while `author`, `source` and `subject` are combined into meta information displayed below the actual signature (right aligned and and in square brackets).
|
87
|
+
|
88
|
+
The `text` of the `Signature`s is wrapped to 80 characters or fewer upon display (separately for every line). Additionally, if the result is two lines, signore attempts to make them roughly the same length. The wrapping engine also attempts to avoid one-letter words at ends of lines (moving them to the next line if possible).
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
Storage
|
93
|
+
-------
|
94
|
+
|
95
|
+
signore stores the signatures in a YAML file (for ease of editing, if such a need arises) in `$XDG_DATA_HOME/signore/signatures.yml` (where `$XDG_DATA_HOME` is usually `~/.local/share`).
|
96
|
+
|
97
|
+
|
98
|
+
|
99
|
+
Requirements
|
100
|
+
------------
|
101
|
+
|
102
|
+
signore requires Ruby 1.9 and works best with Ruby 1.9.2 compiled with Psych (for sanity when hand-editing the YAML file, if it happens to sport non-US-ASCII characters).
|
103
|
+
|
104
|
+
|
105
|
+
|
106
|
+
---
|
107
|
+
|
108
|
+
© MMIX-MMXI Piotr Szotkowski <chastell@chastell.net>, licensed under AGPL 3 (see LICENCE)
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
|
3
|
+
Rake::TestTask.new :spec do |task|
|
4
|
+
task.test_files = FileList['spec/**/*_spec.rb']
|
5
|
+
end
|
6
|
+
|
7
|
+
desc 'Run signore console'
|
8
|
+
task :console do
|
9
|
+
require 'irb'
|
10
|
+
require_relative 'lib/signore'
|
11
|
+
include Signore
|
12
|
+
ARGV.clear
|
13
|
+
IRB.start
|
14
|
+
end
|
15
|
+
|
16
|
+
task default: :spec
|
data/bin/signore
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Signore class Database
|
4
|
+
|
5
|
+
def self.db
|
6
|
+
@db
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.find opts = {}
|
10
|
+
opts = {tags: [], no_tags: []}.merge opts
|
11
|
+
@db
|
12
|
+
.select { |sig| opts[:tags].all? { |tag| sig.tagged_with? tag } }
|
13
|
+
.reject { |sig| opts[:no_tags].any? { |tag| sig.tagged_with? tag } }
|
14
|
+
.shuffle.first
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load path
|
18
|
+
@path = path
|
19
|
+
@db = File.exists?(@path) ? YAML.load_file(@path) : []
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.min_yaml
|
23
|
+
@db.to_yaml.gsub /^ (author|source|subject|tags): !!null \n/, ''
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.save sig
|
27
|
+
@db << sig
|
28
|
+
FileUtils.mkpath File.dirname @path
|
29
|
+
File.open(@path, 'w') { |file| file << self.min_yaml }
|
30
|
+
end
|
31
|
+
|
32
|
+
end end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Signore class Executable
|
4
|
+
|
5
|
+
def initialize args = ARGV, db = Database
|
6
|
+
opts = Trollop.options args do
|
7
|
+
opt :database, 'Location of the signature database', default: (ENV['XDG_DATA_HOME'] or File.expand_path '~/.local/share') + '/signore/signatures.yml'
|
8
|
+
end
|
9
|
+
Trollop.die 'usage: signore prego|pronto [label, …]' unless ['prego', 'pronto'].include? args.first
|
10
|
+
db.load opts[:database]
|
11
|
+
@action = args.shift
|
12
|
+
@no_tags, @tags = args.partition { |tag| tag[0] == '~' }
|
13
|
+
@no_tags.map! { |tag| tag[1..-1] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def run output = STDOUT, input = STDIN
|
17
|
+
case @action
|
18
|
+
when 'prego'
|
19
|
+
output.puts Database.find(tags: @tags, no_tags: @no_tags).display
|
20
|
+
when 'pronto'
|
21
|
+
params = Hash[[:text, :author, :subject, :source].map do |elem|
|
22
|
+
output.puts "#{elem}?"
|
23
|
+
value = ''
|
24
|
+
value << input.gets until value.lines.to_a.last == "\n"
|
25
|
+
[elem, value.rstrip]
|
26
|
+
end].delete_if { |elem, value| value.empty? }
|
27
|
+
sig = Signature.new params[:text], params[:author], params[:source], params[:subject], @tags
|
28
|
+
Database.save sig
|
29
|
+
output.puts sig.display
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Signore class Signature < Struct.new :text, :author, :source, :subject, :tags
|
2
|
+
|
3
|
+
def display
|
4
|
+
Wrapper.new(text, meta).display
|
5
|
+
end
|
6
|
+
|
7
|
+
def tagged_with? tag
|
8
|
+
tags and tags.include? tag
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def meta
|
14
|
+
case
|
15
|
+
when author && subject && source then "#{author} #{subject}, #{source}"
|
16
|
+
when author && subject then "#{author} #{subject}"
|
17
|
+
when author && source then "#{author}, #{source}"
|
18
|
+
when author then "#{author}"
|
19
|
+
when source then "#{source}"
|
20
|
+
when subject then "#{subject}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Signore class Wrapper
|
4
|
+
|
5
|
+
NBSP = ' '
|
6
|
+
|
7
|
+
def initialize text, meta
|
8
|
+
@lines = text.split "\n"
|
9
|
+
@meta = meta
|
10
|
+
end
|
11
|
+
|
12
|
+
def display
|
13
|
+
wrap
|
14
|
+
add_meta if @meta
|
15
|
+
@lines.join "\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def add_meta
|
21
|
+
@lines << "[#{@meta}]"
|
22
|
+
@lines.last.insert 0, ' ' * (width - @meta.size - 2)
|
23
|
+
end
|
24
|
+
|
25
|
+
def find_hangout wrapped
|
26
|
+
lines = wrapped.split "\n"
|
27
|
+
lines.each_with_index do |line, nr|
|
28
|
+
space = line.rindex /[ #{NBSP}]/
|
29
|
+
next unless space and nr < lines.size - 1
|
30
|
+
return nr if nr > 0 and space >= lines[nr - 1].size
|
31
|
+
return nr if nr < lines.size - 2 and space >= lines[nr + 1].size
|
32
|
+
return nr if nr < lines.size - 1 and space >= lines[nr + 1].size and lines.size == 2
|
33
|
+
end
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def width
|
38
|
+
@lines.map { |line| line.split "\n" }.flatten.map(&:size).max
|
39
|
+
end
|
40
|
+
|
41
|
+
def wrap
|
42
|
+
@lines.map! do |line|
|
43
|
+
best_wrap = wrap_line_to line, 80
|
44
|
+
79.downto 1 do |size|
|
45
|
+
new_wrap = wrap_line_to line, size
|
46
|
+
break if new_wrap.count("\n") > best_wrap.count("\n")
|
47
|
+
best_wrap = new_wrap
|
48
|
+
end
|
49
|
+
best_wrap.chomp
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def wrap_line_to line, size
|
54
|
+
line = line.gsub(/ ([^ ]) /, " \\1#{NBSP}")
|
55
|
+
line = line.gsub(/(.{1,#{size}})( |$\n?)/, "\\1\n")
|
56
|
+
if hangout = find_hangout(line)
|
57
|
+
lines = line.split "\n"
|
58
|
+
lines[hangout] << NBSP
|
59
|
+
line = lines.join(' ').gsub("#{NBSP} ", NBSP)
|
60
|
+
line = wrap_line_to line, size
|
61
|
+
end
|
62
|
+
line.tr NBSP, ' '
|
63
|
+
end
|
64
|
+
|
65
|
+
end end
|
data/lib/signore.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'trollop'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
YAML::ENGINE.yamler = 'psych' if defined? Psych
|
6
|
+
|
7
|
+
require_relative 'signore/database'
|
8
|
+
require_relative 'signore/executable'
|
9
|
+
require_relative 'signore/signature'
|
10
|
+
require_relative 'signore/wrapper'
|
data/signore.gemspec
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
Gem::Specification.new do |gem|
|
2
|
+
gem.name = 'signore'
|
3
|
+
gem.version = '0.0.0'
|
4
|
+
gem.summary = 'signore: an email signature manager/randomiser'
|
5
|
+
gem.homepage = 'http://github.com/chastell/signore'
|
6
|
+
gem.author = 'Piotr Szotkowski'
|
7
|
+
gem.email = 'chastell@chastell.net'
|
8
|
+
|
9
|
+
gem.files = `git ls-files -z`.split "\0"
|
10
|
+
gem.executables = Dir['bin/*'].map { |d| d.split '/' }.map &:last
|
11
|
+
gem.test_files = Dir['spec/**/*.rb']
|
12
|
+
|
13
|
+
gem.add_dependency 'trollop'
|
14
|
+
gem.add_development_dependency 'minitest', '>= 2.3'
|
15
|
+
gem.add_development_dependency 'rake'
|
16
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
---
|
2
|
+
- !ruby/struct:Signore::Signature
|
3
|
+
text: Patches are like Free Software love letters.
|
4
|
+
- !ruby/struct:Signore::Signature
|
5
|
+
text: It’s 8:21 AM, do you know where your process is? Call 0-800-GREP to find out
|
6
|
+
more how YOU can prevent zombification.
|
7
|
+
author: opi
|
8
|
+
tags:
|
9
|
+
- programming
|
10
|
+
- Unix
|
11
|
+
- !ruby/struct:Signore::Signature
|
12
|
+
text: ! '‘Humor. It is a difficult concept: It is not logical.’
|
13
|
+
|
14
|
+
‘We learn by doing.’'
|
15
|
+
source: ! 'Star Trek: The Wrath of Khan'
|
16
|
+
- !ruby/struct:Signore::Signature
|
17
|
+
text: In 1940 he summarized his work in an influential book, ‘Punched Card Methods
|
18
|
+
in Scientific Computation’.
|
19
|
+
author: Paul E. Ceruzzi
|
20
|
+
source: A History of Modern Computing
|
21
|
+
subject: on Wallace Eckert
|
22
|
+
- !ruby/struct:Signore::Signature
|
23
|
+
text: ! 'Idea: A James Cameron-directed prequel entitled ''T\0: The Null Terminator''.'
|
24
|
+
author: Matthew Baldwin
|
25
|
+
- !ruby/struct:Signore::Signature
|
26
|
+
text: ! 'The #1 lesson I learned on my one and only trip to the Caribbean is that
|
27
|
+
society will not actually collapse if you walk down a public street with a beer
|
28
|
+
in your hand. Who woulda thunk?'
|
29
|
+
author: J.D. Baldwin
|
30
|
+
- !ruby/struct:Signore::Signature
|
31
|
+
text: '3:10'
|
32
|
+
author: Elmore Leonard
|
33
|
+
- !ruby/struct:Signore::Signature
|
34
|
+
text: ! ' ← space, the final frontier'
|
35
|
+
- !ruby/struct:Signore::Signature
|
36
|
+
text: Just got another wonderful request from the client… you’re going to lie this
|
37
|
+
one.
|
38
|
+
author: Chris Ivens
|
39
|
+
source: ! '#civicrm'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
- !ruby/struct:Signore::Signature
|
2
|
+
text: She was good at playing abstract confusion in the same way a midget is good at being short.
|
3
|
+
author: Clive James
|
4
|
+
subject: on Marilyn Monroe
|
5
|
+
- !ruby/struct:Signore::Signature
|
6
|
+
text: You do have to be mad to work here, but it doesn’t help.
|
7
|
+
author: Gary Barnes
|
8
|
+
source: asr
|
9
|
+
tags: [tech, work]
|
10
|
+
- !ruby/struct:Signore::Signature
|
11
|
+
text: // sometimes I believe compiler ignores all my comments
|
12
|
+
tags: [programming, tech]
|
13
|
+
- !ruby/struct:Signore::Signature
|
14
|
+
text: Bruce Schneier knows Alice and Bob’s shared secret.
|
15
|
+
source: Bruce Schneier Facts
|
16
|
+
tags: [security, tech]
|
17
|
+
- !ruby/struct:Signore::Signature
|
18
|
+
text: stay-at-home executives vs. wallstreet dads
|
19
|
+
author: kodz
|
20
|
+
- !ruby/struct:Signore::Signature
|
21
|
+
text: Amateur fighter pilot ignores orders, listens to the voices in his head and slaughters thousands.
|
22
|
+
subject: Star Wars ending explained
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# wrapping doesn’t affect one-liners
|
2
|
+
- :text: Patches are like Free Software love letters.
|
3
|
+
:wrapped: Patches are like Free Software love letters.
|
4
|
+
|
5
|
+
# meta info is right-aligned on its own line
|
6
|
+
- :text: I have a fever and it’s not disco related.
|
7
|
+
:meta: opi
|
8
|
+
:wrapped: |-
|
9
|
+
I have a fever and it’s not disco related.
|
10
|
+
[opi]
|
11
|
+
|
12
|
+
# more-than-80-column signatures are be wrapped, with the result being as short as possible
|
13
|
+
- :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.
|
14
|
+
:wrapped: |-
|
15
|
+
It may look like I’m just sitting here doing nothing. But
|
16
|
+
I’m really actively waiting for all my problems to go away.
|
17
|
+
|
18
|
+
# meta info is right-aligned to the longest line
|
19
|
+
- :text: No, no, it’s spelled Raymond Luxury Yacht, but it’s pronounced Throatwobbler Mangrove.
|
20
|
+
:meta: Monty Python
|
21
|
+
:wrapped: |-
|
22
|
+
No, no, it’s spelled Raymond Luxury Yacht,
|
23
|
+
but it’s pronounced Throatwobbler Mangrove.
|
24
|
+
[Monty Python]
|
25
|
+
|
26
|
+
# multi-line signatures are wrapped on a line-by-line basis
|
27
|
+
- :text: |-
|
28
|
+
‘The Ruby community should proceed with all deliberate speed towards ISO standardization of the language.’
|
29
|
+
‘Yeah, look what it did to Forth.’
|
30
|
+
‘Don’t just say it, show it. <http://vividpicture.com/aleks/atari/forth.jpg>’
|
31
|
+
:meta: M. Edward (Ed) Borasky, Matt Lawrence, Gregory Brown, ruby-talk
|
32
|
+
:wrapped: |-
|
33
|
+
‘The Ruby community should proceed with all deliberate
|
34
|
+
speed towards ISO standardization of the language.’
|
35
|
+
‘Yeah, look what it did to Forth.’
|
36
|
+
‘Don’t just say it, show it. <http://vividpicture.com/aleks/atari/forth.jpg>’
|
37
|
+
[M. Edward (Ed) Borasky, Matt Lawrence, Gregory Brown, ruby-talk]
|
38
|
+
|
39
|
+
# long meta info is flushed left
|
40
|
+
- :text: |-
|
41
|
+
‘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
|
+
‘They should have. Hinckley missed the vital spot, so who needs him?’
|
43
|
+
‘As everybody knows, Reagan was killed in that attack and a lookalike was substituted.’
|
44
|
+
‘You mean we were governed all those years by an ACTOR!’
|
45
|
+
:meta: Spehro Pefhany, CyberCypher, Jess Askin, don groves, alt.usage.english
|
46
|
+
:wrapped: |-
|
47
|
+
‘The Guardian also had a pre-election column, in which an allegedly
|
48
|
+
“ironic joke” was open to other interpretations: “John Wilkes Booth,
|
49
|
+
Lee Harvey Oswald, John Hinckley Jr., where are you now that we need
|
50
|
+
you?” They removed the column from on-line access and apologized.’
|
51
|
+
‘They should have. Hinckley missed the vital spot, so who needs him?’
|
52
|
+
‘As everybody knows, Reagan was killed in
|
53
|
+
that attack and a lookalike was substituted.’
|
54
|
+
‘You mean we were governed all those years by an ACTOR!’
|
55
|
+
[Spehro Pefhany, CyberCypher, Jess Askin, don groves, alt.usage.english]
|
56
|
+
|
57
|
+
# wrapping doesn’t left one-letter words at the end of lines
|
58
|
+
- :text: I’ve been trying for some time to develop a lifestyle that doesn’t require my presence.
|
59
|
+
:meta: Gary Trudeau
|
60
|
+
:wrapped: |-
|
61
|
+
I’ve been trying for some time to develop
|
62
|
+
a lifestyle that doesn’t require my presence.
|
63
|
+
[Gary Trudeau]
|
64
|
+
|
65
|
+
# there are no hangouts
|
66
|
+
- :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.
|
67
|
+
:meta: Steve VanDevender
|
68
|
+
:wrapped: |-
|
69
|
+
Better to teach a man to fish than to give him a fish.
|
70
|
+
And if he can’t be bothered to learn to fish and starves
|
71
|
+
to death, that’s a good enough outcome for me.
|
72
|
+
[Steve VanDevender]
|
73
|
+
|
74
|
+
# for two-line signatures, first line is considered for hangouts
|
75
|
+
- :text: Well, the old ones go mmmmmbbbbzzzzttteeeeeep as they start up and the new ones go whupwhupwhupwhooopwhooooopwhooooooommmmmmmmmm.
|
76
|
+
:meta: Graham Reed on subway engines, asr
|
77
|
+
:wrapped: |-
|
78
|
+
Well, the old ones go mmmmmbbbbzzzzttteeeeeep as they start up
|
79
|
+
and the new ones go whupwhupwhupwhooopwhooooopwhooooooommmmmmmmmm.
|
80
|
+
[Graham Reed on subway engines, asr]
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
module Signore describe Database do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@path = "#{Dir.tmpdir}/#{rand}/signatures.yml"
|
9
|
+
end
|
10
|
+
|
11
|
+
after do
|
12
|
+
FileUtils.rmtree File.dirname @path
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '.db' do
|
16
|
+
|
17
|
+
it 'returns the signature database loaded by .load' do
|
18
|
+
Database.load @path
|
19
|
+
Database.db.must_equal []
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '.find' do
|
25
|
+
|
26
|
+
before do
|
27
|
+
srand
|
28
|
+
Database.load 'spec/fixtures/signatures.yml'
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'returns a random signature by default' do
|
32
|
+
srand 1981
|
33
|
+
Database.find.text.must_equal 'Amateur fighter pilot ignores orders, listens to the voices in his head and slaughters thousands.'
|
34
|
+
srand 1979
|
35
|
+
Database.find.text.must_equal 'stay-at-home executives vs. wallstreet dads'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'returns a random signature if the tags are empty' do
|
39
|
+
srand 2009
|
40
|
+
Database.find(tags: []).text.must_equal '// sometimes I believe compiler ignores all my comments'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns a random signature based on provided tags' do
|
44
|
+
Database.find(tags: ['programming']).text.must_equal '// sometimes I believe compiler ignores all my comments'
|
45
|
+
Database.find(tags: ['work']).text.must_equal 'You do have to be mad to work here, but it doesn’t help.'
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns a random signature based on required and forbidden tags' do
|
49
|
+
Database.find(tags: ['tech'], no_tags: ['programming', 'security']).text.must_equal 'You do have to be mad to work here, but it doesn’t help.'
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '.load' do
|
55
|
+
|
56
|
+
it 'creates an empty signature database if it does not exist, but does not save it' do
|
57
|
+
refute Pathname(@path).exist?
|
58
|
+
Database.load @path
|
59
|
+
Database.db.must_equal []
|
60
|
+
refute Pathname(@path).exist?
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '.save' do
|
66
|
+
|
67
|
+
it 'saves the provided signature to disk' do
|
68
|
+
Database.load @path
|
69
|
+
sig = Signature.new 'Normaliser Unix c’est comme pasteuriser le camembert.'
|
70
|
+
Database.save sig
|
71
|
+
File.read(@path).must_equal "---\n- !ruby/struct:Signore::Signature\n text: Normaliser Unix c’est comme pasteuriser le camembert.\n"
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '.min_yaml' do
|
77
|
+
|
78
|
+
it 'returns the minimal YAML representation of the signature database' do
|
79
|
+
Database.load 'spec/fixtures/min_yaml.yml'
|
80
|
+
Database.min_yaml.must_equal File.read('spec/fixtures/min_yaml.yml')
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'escapes initial spaces in multi-line signatures' do
|
84
|
+
tng = " ← space\nthe final\nfrontier"
|
85
|
+
Database.load @path
|
86
|
+
Database.save Signature.new tng
|
87
|
+
Database.load @path
|
88
|
+
Database.find.display.must_equal tng
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
module Signore describe Executable do
|
6
|
+
|
7
|
+
describe '#initialize' do
|
8
|
+
|
9
|
+
before do
|
10
|
+
$stderr = StringIO.new
|
11
|
+
end
|
12
|
+
|
13
|
+
after do
|
14
|
+
$stderr = STDERR
|
15
|
+
end
|
16
|
+
|
17
|
+
def stderr
|
18
|
+
$stderr.rewind
|
19
|
+
$stderr.read
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'prints usage if no command is given' do
|
23
|
+
lambda { Executable.new([]) }.must_raise SystemExit
|
24
|
+
stderr.must_match /usage: signore prego\|pronto \[label, …\]/
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'prints usage if a bogus command is given' do
|
28
|
+
lambda { Executable.new(['bogus']) }.must_raise SystemExit
|
29
|
+
stderr.must_match /usage: signore prego\|pronto \[label, …\]/
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'loads the signature database from the specified location' do
|
33
|
+
db = MiniTest::Mock.new
|
34
|
+
db.expect :load, nil, ['signatures.yml']
|
35
|
+
Executable.new ['-d', 'signatures.yml', 'prego'], db
|
36
|
+
db.verify
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'loads the signature database from ~/.local/share/signore/signatures.yml if no location specified' do
|
40
|
+
pending if ENV['XDG_DATA_HOME']
|
41
|
+
db = MiniTest::Mock.new
|
42
|
+
db.expect :load, nil, [File.expand_path('~/.local/share/signore/signatures.yml')]
|
43
|
+
Executable.new ['prego'], db
|
44
|
+
db.verify
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'loads the signature database from $XDG_DATA_HOME/signore/signatures.yml if $XDG_DATA_HOME is set' do
|
48
|
+
begin
|
49
|
+
orig_data_home = ENV.delete 'XDG_DATA_HOME'
|
50
|
+
ENV['XDG_DATA_HOME'] = Dir.tmpdir
|
51
|
+
db = MiniTest::Mock.new
|
52
|
+
db.expect :load, nil, ["#{ENV['XDG_DATA_HOME']}/signore/signatures.yml"]
|
53
|
+
Executable.new ['prego'], db
|
54
|
+
db.verify
|
55
|
+
ensure
|
56
|
+
orig_data_home ? ENV['XDG_DATA_HOME'] = orig_data_home : ENV.delete('XDG_DATA_HOME')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#run' do
|
63
|
+
|
64
|
+
describe 'prego' do
|
65
|
+
|
66
|
+
it 'prints a signature tagged with the provided tags' do
|
67
|
+
Executable.new(['-d', 'spec/fixtures/signatures.yml', 'prego', 'tech', 'programming']).run output = StringIO.new
|
68
|
+
output.rewind
|
69
|
+
output.read.must_equal "// sometimes I believe compiler ignores all my comments\n"
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'prints a signature based on allowed and forbidden tags' do
|
73
|
+
Executable.new(['-d', 'spec/fixtures/signatures.yml', 'prego', '~programming', 'tech', '~security']).run output = StringIO.new
|
74
|
+
output.rewind
|
75
|
+
output.read.must_equal "You do have to be mad to work here, but it doesn’t help.\n [Gary Barnes, asr]\n"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
describe 'pronto' do
|
81
|
+
|
82
|
+
before do
|
83
|
+
@path = "#{Dir.tmpdir}/#{rand}/signatures.yml"
|
84
|
+
end
|
85
|
+
|
86
|
+
after do
|
87
|
+
FileUtils.rmtree File.dirname @path
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'asks about signature parts and saves given signature with provided labels' do
|
91
|
+
input = StringIO.new "The Wikipedia page on ADHD is like 20 pages long. That’s just cruel.\n\nMark Pilgrim\n\n\n\n"
|
92
|
+
Executable.new(['-d', @path, 'pronto', 'Wikipedia', 'ADHD']).run output = StringIO.new, input
|
93
|
+
output.rewind
|
94
|
+
output.read.must_equal "text?\nauthor?\nsubject?\nsource?\nThe Wikipedia page on ADHD is like 20 pages long. That’s just cruel.\n [Mark Pilgrim]\n"
|
95
|
+
Executable.new(['-d', @path, 'prego', 'Wikipedia', 'ADHD']).run output = StringIO.new
|
96
|
+
output.rewind
|
97
|
+
output.read.must_equal "The Wikipedia page on ADHD is like 20 pages long. That’s just cruel.\n [Mark Pilgrim]\n"
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'handles multi-line signatures' do
|
101
|
+
input = StringIO.new "‘I’ve gone through over-stressed to physical exhaustion – what’s next?’\n‘Tuesday.’\n\nSimon Burr, Kyle Hearn\n\n\n\n"
|
102
|
+
Executable.new(['-d', @path, 'pronto']).run output = StringIO.new, input
|
103
|
+
output.rewind
|
104
|
+
output.read.must_equal "text?\nauthor?\nsubject?\nsource?\n‘I’ve gone through over-stressed to physical exhaustion – what’s next?’\n‘Tuesday.’\n [Simon Burr, Kyle Hearn]\n"
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
end end
|