signore 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/signore'
4
+ Signore::Executable.new.run
@@ -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