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 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 :rubygems
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
- lovely-rufus (>= 0.0.2)
6
- trollop
5
+ lovely_rufus (~> 0.1.0)
7
6
 
8
7
  GEM
9
- remote: http://rubygems.org/
8
+ remote: https://rubygems.org/
10
9
  specs:
11
- lovely-rufus (0.0.2)
12
- minitest (2.11.4)
13
- rake (0.9.2.2)
14
- trollop (1.16.2)
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 (>= 2.11.1)
21
- rake
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-MMXII Piotr Szotkowski <chastell@chastell.net>, licensed under AGPL 3 (see LICENCE)
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
- 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
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
- task default: :spec
18
+ Rubocop::RakeTask.new
data/config/reek.yml ADDED
@@ -0,0 +1,14 @@
1
+ DuplicateMethodCall:
2
+ exclude:
3
+ - Signore::Database#find
4
+
5
+ IrresponsibleModule:
6
+ enabled: false
7
+
8
+ NestedIterators:
9
+ exclude:
10
+ - Signore::Database#find
11
+ max_allowed_nesting: 2
12
+
13
+ UnusedParameters:
14
+ enabled: false
@@ -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
- @store.transaction do
11
- @store['signatures'] ||= []
12
- @store['signatures'] << sig
7
+ store.transaction do
8
+ store['signatures'] ||= []
9
+ store['signatures'] << sig
13
10
  end
14
11
  end
15
12
 
16
- def find opts = {}
17
- opts = { tags: [], no_tags: [] }.merge opts
18
-
19
- @store.transaction true do
20
- @store['signatures']
21
- .select { |sig| opts[:tags].all? { |tag| sig.tagged_with? tag } }
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
@@ -1,34 +1,23 @@
1
- # encoding: UTF-8
2
-
3
1
  module Signore class Executable
4
-
5
- def initialize args = ARGV, db_class = Database
6
- opts = Trollop.options args do
7
- opt :database, 'Location of the signature database', default: ENV.fetch('XDG_DATA_HOME') { File.expand_path '~/.local/share' } + '/signore/signatures.yml'
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 input = $stdin
20
- case @action
21
- when 'prego'
22
- sig = @db.find tags: @tags, no_tags: @no_tags
23
- when 'pronto'
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 get_params input
42
- Hash[[:text, :author, :subject, :source].map do |param|
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
@@ -1,34 +1,39 @@
1
- module Signore class Signature < Struct.new :text, :author, :source, :subject, :tags
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 = LovelyRufus::Wrapper.new(text.gsub("\n", "\n\n")).wrapped(80).gsub("\n\n", "\n")
9
- wrapped + meta_for(wrapped)
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 meta
15
- case
16
- when author && subject && source then "#{author} #{subject}, #{source}"
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 meta_for wrapped
26
- return '' unless meta
27
-
28
- indent = wrapped.split("\n").map(&:size).max - meta.size - 2
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
- "\n#{spaces}[#{meta}]"
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
@@ -1,6 +1,7 @@
1
1
  require 'fileutils'
2
- require 'lovely-rufus'
3
- require 'trollop'
2
+ require 'lovely_rufus'
3
+ require 'optparse'
4
+ require 'ostruct'
4
5
  require 'psych'
5
6
  require 'yaml/store'
6
7
 
data/signore.gemspec CHANGED
@@ -1,17 +1,18 @@
1
1
  Gem::Specification.new do |gem|
2
2
  gem.name = 'signore'
3
- gem.version = '0.1.2'
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 = Dir['bin/*'].map { |d| d.split '/' }.map &:last
11
- gem.test_files = Dir['spec/**/*.rb']
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 'lovely-rufus', '>= 0.0.2'
14
- gem.add_dependency 'trollop'
15
- gem.add_development_dependency 'minitest', '>= 2.11.1'
16
- gem.add_development_dependency 'rake'
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
@@ -1,35 +1,42 @@
1
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.
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
- - :text: I have a fever and it’s not disco related.
7
- :meta: opi
8
- :wrapped: |-
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
- - :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: |-
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
- - :text: No, no, it’s spelled Raymond Luxury Yacht, but it’s pronounced Throatwobbler Mangrove.
20
- :meta: Monty Python
21
- :wrapped: |-
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
- - :text: |-
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
- :meta: M. Edward (Ed) Borasky, Matt Lawrence, Gregory Brown, ruby-talk
32
- :wrapped: |-
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
- - :text: |-
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
- :meta: Spehro Pefhany, CyberCypher, Jess Askin, don groves, alt.usage.english
46
- :wrapped: |-
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
- - :text: I’ve been trying for some time to develop a lifestyle that doesn’t require my presence.
59
- :meta: Gary Trudeau
60
- :wrapped: |-
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
- - :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, thats a good enough outcome for me.
72
- [Steve VanDevender]
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 cant 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
- - :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: |-
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
- before do
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
- srand 1981
16
- @db.find.text.must_equal 'Amateur fighter pilot ignores orders, listens to the voices in his head and slaughters thousands.'
17
- srand 1979
18
- @db.find.text.must_equal 'stay-at-home executives vs. wallstreet dads'
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
- srand 2009
23
- @db.find(tags: []).text.must_equal '// sometimes I believe compiler ignores all my comments'
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
- @db.find(tags: ['programming']).text.must_equal '// sometimes I believe compiler ignores all my comments'
28
- @db.find(tags: ['work']).text.must_equal 'You do have to be mad to work here, but it doesn’t help.'
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
- @db.find(tags: ['tech'], no_tags: ['programming', 'security']).text.must_equal 'You do have to be mad to work here, but it doesn’t help.'
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 '#save' do
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
- sig = Signature.new 'Normaliser Unix c’est comme pasteuriser le camembert.'
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
- stderr = capture_io { -> { Executable.new [] }.must_raise SystemExit }.last
11
- stderr.must_include 'usage: signore prego|pronto [label, …]'
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
- stderr = capture_io { -> { Executable.new ['bogus'] }.must_raise SystemExit }.last
16
- stderr.must_include 'usage: signore prego|pronto [label, …]'
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
- db_class = MiniTest::Mock.new
21
- db_class.expect :new, nil, ['signatures.yml']
22
- Executable.new ['-d', 'signatures.yml', 'prego'], db_class
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 'loads the signature database from ~/.local/share/signore/signatures.yml if no location specified' do
27
- pending if ENV['XDG_DATA_HOME']
28
- db_class = MiniTest::Mock.new
29
- db_class.expect :new, nil, [File.expand_path('~/.local/share/signore/signatures.yml')]
30
- Executable.new ['prego'], db_class
31
- db_class.verify
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 'loads the signature database from $XDG_DATA_HOME/signore/signatures.yml if $XDG_DATA_HOME is set' do
36
+ it 'defaults to $XDG_DATA_HOME/signore/signatures.yml' do
35
37
  begin
36
- orig_data_home = ENV.delete 'XDG_DATA_HOME'
38
+ orig = ENV.delete 'XDG_DATA_HOME'
37
39
  ENV['XDG_DATA_HOME'] = Dir.tmpdir
38
- db_class = MiniTest::Mock.new
39
- db_class.expect :new, nil, ["#{ENV['XDG_DATA_HOME']}/signore/signatures.yml"]
40
- Executable.new ['prego'], db_class
41
- db_class.verify
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
- orig_data_home ? ENV['XDG_DATA_HOME'] = orig_data_home : ENV.delete('XDG_DATA_HOME')
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
- stdout = capture_io { Executable.new(['-d', 'spec/fixtures/signatures.yml', 'prego', 'tech', 'programming']).run }.first
55
- stdout.must_equal <<-end.dedent
56
- // sometimes I believe compiler ignores all my comments
57
- end
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
- stdout = capture_io { Executable.new(['-d', 'spec/fixtures/signatures.yml', 'prego', '~programming', 'tech', '~security']).run }.first
62
- stdout.must_equal <<-end.dedent
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 given signature with provided labels' do
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.\n
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
- stdout = capture_io { Executable.new(['-d', @file.path, 'pronto', 'Wikipedia', 'ADHD']).run input }.first
83
- stdout.must_equal <<-end.dedent
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
- stdout = capture_io { Executable.new(['-d', @file.path, 'prego', 'Wikipedia', 'ADHD']).run }.first
93
- stdout.must_equal <<-end.dedent
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
- I’ve gone through over-stressed to physical exhaustion – whats next?’
102
- Tuesday.’\n
103
- Simon Burr, Kyle Hearn\n\n\n
105
+ You’ve got an interesting accent. Subtle. I cant 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
- stdout = capture_io { Executable.new(['-d', @file.path, 'pronto']).run input }.first
107
- stdout.must_equal <<-end.dedent
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
- I’ve gone through over-stressed to physical exhaustion – whats next?’
113
- Tuesday.’
114
- [Simon Burr, Kyle Hearn]
118
+ You’ve got an interesting accent. Subtle. I cant 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
- before do
8
- @confusion, @mad, @compiler, @bruce, @dads, @starwars = YAML.load_file('spec/fixtures/signatures.yml')['signatures']
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
- refute @compiler.tagged_with? 'fnord'
15
- assert @compiler.tagged_with? 'programming'
16
- assert @compiler.tagged_with? 'tech'
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 @dads.tagged_with? 'fnord'
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 'returns a signature formatted with meta information (if available)' do
28
- @compiler.to_s.must_equal <<-end.dedent.strip
29
- // sometimes I believe compiler ignores all my comments
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
- @mad.to_s.must_equal <<-end.dedent.strip
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
- @bruce.to_s.must_equal <<-end.dedent.strip
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
- @confusion.to_s.must_equal <<-end.dedent.strip
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
- @starwars.to_s.must_equal <<-end.dedent.strip
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
- class SignatureWithMeta < Signature
62
- attr_accessor :meta
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
- gem 'minitest'
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
- require_relative '../lib/signore'
8
+ require 'signore'
9
9
 
10
10
  class String
11
11
  def dedent
12
- gsub /^#{self[/\A\s*/]}/, ''
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.1.2
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: 2012-03-30 00:00:00.000000000 Z
11
+ date: 2014-02-18 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
- name: lovely-rufus
16
- requirement: &13739880 !ruby/object:Gem::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.2
19
+ version: 0.1.0
22
20
  type: :runtime
23
21
  prerelease: false
24
- version_requirements: *13739880
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: trollop
27
- requirement: &13739160 !ruby/object:Gem::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: :runtime
33
+ version: '5.0'
34
+ type: :development
34
35
  prerelease: false
35
- version_requirements: *13739160
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: minitest
38
- requirement: &13804800 !ruby/object:Gem::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: 2.11.1
47
+ version: '1.3'
44
48
  type: :development
45
49
  prerelease: false
46
- version_requirements: *13804800
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: rake
49
- requirement: &13804260 !ruby/object:Gem::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: '0'
61
+ version: 0.18.0
55
62
  type: :development
56
63
  prerelease: false
57
- version_requirements: *13804260
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
- - .rvmrc
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: 1.8.17
115
+ rubygems_version: 2.2.0
104
116
  signing_key:
105
- specification_version: 3
106
- summary: ! 'signore: an email signature manager/randomiser'
117
+ specification_version: 4
118
+ summary: 'signore: an email signature manager/randomiser'
107
119
  test_files:
108
- - spec/spec_helper.rb
120
+ - spec/signore/database_spec.rb
109
121
  - spec/signore/executable_spec.rb
110
122
  - spec/signore/signature_spec.rb
111
- - spec/signore/database_spec.rb
112
- has_rdoc:
123
+ - spec/spec_helper.rb
data/.rvmrc DELETED
@@ -1,2 +0,0 @@
1
- rvm gemset use signore
2
- bundle