ppl 1.5.2 → 1.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,15 @@ require "vpim/vcard"
3
3
 
4
4
  class Ppl::Adapter::Vcard::Vpim
5
5
 
6
+ @@postal_address_property_map = {
7
+ :street => :street,
8
+ :postalcode => :postal_code,
9
+ :pobox => :po_box,
10
+ :country => :country,
11
+ :region => :region,
12
+ :locality => :locality,
13
+ }
14
+
6
15
  def encode(contact)
7
16
  vcard = Vpim::Vcard::Maker.make2 do |maker|
8
17
  encode_birthday(contact, maker)
@@ -65,23 +74,11 @@ class Ppl::Adapter::Vcard::Vpim
65
74
  def encode_postal_address(contact, vcard_maker)
66
75
  if !contact.postal_address.nil?
67
76
  vcard_maker.add_addr do |address|
68
- if !contact.postal_address.street.nil?
69
- address.street = contact.postal_address.street
70
- end
71
- if !contact.postal_address.postal_code.nil?
72
- address.postalcode = contact.postal_address.postal_code
73
- end
74
- if !contact.postal_address.po_box.nil?
75
- address.pobox = contact.postal_address.po_box
76
- end
77
- if !contact.postal_address.country.nil?
78
- address.country = contact.postal_address.country
79
- end
80
- if !contact.postal_address.region.nil?
81
- address.region = contact.postal_address.region
82
- end
83
- if !contact.postal_address.locality.nil?
84
- address.locality = contact.postal_address.locality
77
+ @@postal_address_property_map.each_pair do |vpim_name, ppl_name|
78
+ value = contact.postal_address.send(ppl_name)
79
+ if !value.nil?
80
+ address.send("#{vpim_name.to_s}=", value)
81
+ end
85
82
  end
86
83
  end
87
84
  end
@@ -112,12 +109,11 @@ class Ppl::Adapter::Vcard::Vpim
112
109
  def decode_postal_address(vcard, contact)
113
110
  if !vcard.address.nil?
114
111
  contact.postal_address = Ppl::Entity::PostalAddress.new
115
- contact.postal_address.street = vcard.address.street
116
- contact.postal_address.postal_code = vcard.address.postalcode
117
- contact.postal_address.po_box = vcard.address.pobox
118
- contact.postal_address.locality = vcard.address.locality
119
- contact.postal_address.region = vcard.address.region
120
- contact.postal_address.country = vcard.address.country
112
+ @@postal_address_property_map.each_pair do |vpim_name, ppl_name|
113
+ value = vcard.address.send(vpim_name)
114
+ method = "#{ppl_name.to_s}="
115
+ contact.postal_address.send(method, value)
116
+ end
121
117
  end
122
118
  end
123
119
 
@@ -1,8 +1,8 @@
1
1
 
2
2
  class Ppl::Application::Command
3
3
 
4
- attr_accessor :name
5
- attr_accessor :description
4
+ @@property_values = {}
5
+
6
6
  attr_accessor :storage
7
7
 
8
8
  def execute(input, output)
@@ -12,5 +12,47 @@ class Ppl::Application::Command
12
12
  def options(parser, options)
13
13
  end
14
14
 
15
+ def self.add_property(name)
16
+ @@property_values[name] = {}
17
+ self.add_static_property_setter(name)
18
+ self.add_instance_property_getter(name)
19
+ self.add_instance_property_setter(name)
20
+ end
21
+
22
+
23
+ private
24
+
25
+ def self.add_static_property_setter(property_name)
26
+ define_singleton_method(property_name) do |value = nil|
27
+ if value.nil?
28
+ @@property_values[property_name][self]
29
+ else
30
+ @@property_values[property_name][self] = value
31
+ end
32
+ end
33
+ end
34
+
35
+ def self.add_instance_property_getter(property_name)
36
+ define_method(property_name) do
37
+ instance_variable = instance_variable_get("@#{property_name}")
38
+ class_variable = @@property_values[property_name][self.class]
39
+ if !instance_variable.nil?
40
+ instance_variable
41
+ elsif !class_variable.nil?
42
+ class_variable
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.add_instance_property_setter(property_name)
48
+ define_method("#{property_name}=") do |value|
49
+ instance_variable_set("@#{property_name}", value)
50
+ end
51
+ end
52
+
53
+ add_property :name
54
+ add_property :description
55
+
56
+
15
57
  end
16
58
 
@@ -11,13 +11,9 @@ class Ppl::Application::Shell
11
11
  command = select_command(input)
12
12
  prepare_command(command, input)
13
13
  outcome = execute_command(command, input, output)
14
- rescue OptionParser::InvalidOption
15
- output.error($!)
16
- output.error(@optparse.to_s)
17
- rescue OptionParser::MissingArgument
18
- output.error($!)
19
- output.error(@optparse.to_s)
20
- rescue Ppl::Error::IncorrectUsage
14
+ rescue Ppl::Error::ContactNotFound
15
+ output.error("ppl: Contact '#{$!}' not found")
16
+ rescue OptionParser::InvalidOption, OptionParser::MissingArgument, Ppl::Error::IncorrectUsage
21
17
  output.error($!)
22
18
  output.error(@optparse.to_s)
23
19
  rescue
@@ -1,10 +1,8 @@
1
1
 
2
2
  class Ppl::Command::Add < Ppl::Application::Command
3
3
 
4
- def initialize
5
- @name = "add"
6
- @description = "Add a new contact"
7
- end
4
+ name "add"
5
+ description "Add a new contact"
8
6
 
9
7
  def options(parser, options)
10
8
  parser.banner = "usage: ppl add <contact> <name>"
@@ -1,12 +1,13 @@
1
1
 
2
2
  class Ppl::Command::Bday < Ppl::Application::Command
3
3
 
4
+ name "bday"
5
+ description "List, show or change birthdays"
6
+
4
7
  attr_writer :list_format
5
8
  attr_writer :show_format
6
9
 
7
10
  def initialize
8
- @name = "bday"
9
- @description = "List, show or change birthdays"
10
11
  @list_format = Ppl::Format::AddressBook::Birthdays.new
11
12
  @show_format = Ppl::Format::Contact::Birthday.new
12
13
  end
@@ -1,12 +1,13 @@
1
1
 
2
2
  class Ppl::Command::Email < Ppl::Application::Command
3
3
 
4
+ name "email"
5
+ description "Show or change a contact's email address"
6
+
4
7
  attr_writer :show_format
5
8
  attr_writer :list_format
6
9
 
7
10
  def initialize
8
- @name = "email"
9
- @description = "Show or change a contact's email address"
10
11
  @show_format = Ppl::Format::Contact::EmailAddresses.new
11
12
  @list_format = Ppl::Format::AddressBook::EmailAddresses.new
12
13
  end
@@ -1,12 +1,10 @@
1
1
 
2
2
  class Ppl::Command::Help < Ppl::Application::Command
3
3
 
4
- attr_accessor :command_suite
4
+ name "help"
5
+ description "Show a list of commands"
5
6
 
6
- def initialize
7
- @name = "help"
8
- @description = "Show a list of commands"
9
- end
7
+ attr_accessor :command_suite
10
8
 
11
9
  def execute(input, output)
12
10
  @command_suite.sort_by_name
@@ -26,7 +24,7 @@ class Ppl::Command::Help < Ppl::Application::Command
26
24
  name = command.name
27
25
  description = command.description
28
26
 
29
- if @name == name
27
+ if self.name == name
30
28
  next
31
29
  end
32
30
 
@@ -1,10 +1,8 @@
1
1
 
2
2
  class Ppl::Command::Init < Ppl::Application::Command
3
3
 
4
- def initialize
5
- @name = "init"
6
- @description = "Create an empty address book"
7
- end
4
+ name "init"
5
+ description "Create an empty address book"
8
6
 
9
7
  def options(parser, options)
10
8
  parser.banner = "usage: ppl init [directory]"
@@ -1,12 +1,12 @@
1
1
 
2
2
  class Ppl::Command::Ls < Ppl::Application::Command
3
3
 
4
+ name "ls"
5
+ description "List all contacts"
6
+
4
7
  attr_writer :format
5
8
 
6
9
  def initialize
7
- @name = "ls"
8
- @description = "List all contacts"
9
-
10
10
  @format = Ppl::Format::AddressBook::OneLine.new
11
11
  end
12
12
 
@@ -1,12 +1,12 @@
1
1
 
2
2
  class Ppl::Command::Mutt < Ppl::Application::Command
3
3
 
4
+ name "mutt"
5
+ description "Integration with mutt's query_command"
6
+
4
7
  attr_writer :format
5
8
 
6
9
  def initialize
7
- @name = "mutt"
8
- @description = "Integration with mutt's query_command"
9
-
10
10
  @format = Ppl::Format::AddressBook::MuttQuery.new
11
11
  end
12
12
 
@@ -15,43 +15,27 @@ class Ppl::Command::Mutt < Ppl::Application::Command
15
15
  end
16
16
 
17
17
  def execute(input, output)
18
- query = input.arguments.shift
19
- if query.nil?
20
- raise Ppl::Error::IncorrectUsage, "You must provide a query"
21
- end
22
-
23
- address_book = @storage.load_address_book
24
-
25
- matches = mutt_search(address_book, query)
26
-
27
- if matches.count > 0
28
-
29
- line = sprintf(
30
- "Searching database... %d entries... %d matching:",
31
- address_book.count,
32
- matches.count
33
- )
18
+ query = require_query(input)
19
+ matches = mutt_search(query)
20
+ output.line(describe_result(matches))
21
+ matches.count > 0
22
+ end
34
23
 
35
- results = @format.process(matches)
36
24
 
37
- output.line(line)
38
- output.line(results) unless results == ""
39
- true
25
+ private
40
26
 
41
- else
42
- output.line("No matches")
43
- false
27
+ def require_query(input)
28
+ if input.arguments.first.nil?
29
+ raise Ppl::Error::IncorrectUsage, "You must provide a query"
44
30
  end
45
-
31
+ input.arguments.first
46
32
  end
47
33
 
48
-
49
- private
50
-
51
- def mutt_search(address_book, query)
34
+ def mutt_search(query)
35
+ @address_book = @storage.load_address_book
52
36
  matches = Ppl::Entity::AddressBook.new
53
37
 
54
- address_book.each do |contact|
38
+ @address_book.each do |contact|
55
39
  next if contact.email_addresses.empty?
56
40
 
57
41
  matching_emails = contact.email_addresses.select do |email_address|
@@ -68,5 +52,23 @@ class Ppl::Command::Mutt < Ppl::Application::Command
68
52
  matches
69
53
  end
70
54
 
55
+ def describe_result(matches)
56
+ if matches.count > 0
57
+ describe_matches(matches)
58
+ else
59
+ "No matches"
60
+ end
61
+ end
62
+
63
+ def describe_matches(matches)
64
+ summary = sprintf(
65
+ "Searching address book... %d entries... %d matching:",
66
+ @address_book.count,
67
+ matches.count
68
+ )
69
+ results = @format.process(matches)
70
+ [summary, results].join("\n").strip
71
+ end
72
+
71
73
  end
72
74
 
@@ -1,10 +1,8 @@
1
1
 
2
2
  class Ppl::Command::Mv < Ppl::Application::Command
3
3
 
4
- def initialize
5
- @name = "mv"
6
- @description = "Rename a contact"
7
- end
4
+ name "mv"
5
+ description "Rename a contact"
8
6
 
9
7
  def options(parser, options)
10
8
  parser.banner = "usage: ppl mv <contact> <new ID>"
@@ -1,12 +1,13 @@
1
1
 
2
2
  class Ppl::Command::Name < Ppl::Application::Command
3
3
 
4
+ name "name"
5
+ description "List, show or change names"
6
+
4
7
  attr_writer :show_format
5
8
  attr_writer :list_format
6
9
 
7
10
  def initialize
8
- @name = "name"
9
- @description = "List, show or change names"
10
11
  @show_format = Ppl::Format::Contact::Name.new
11
12
  @list_format = Ppl::Format::AddressBook::Names.new
12
13
  end
@@ -1,12 +1,13 @@
1
1
 
2
2
  class Ppl::Command::Org < Ppl::Application::Command
3
3
 
4
+ name "org"
5
+ description "List, show or change organizations"
6
+
4
7
  attr_writer :show_format
5
8
  attr_writer :list_format
6
9
 
7
10
  def initialize
8
- @name = "org"
9
- @description = "List, show or change organizations"
10
11
  @show_format = Ppl::Format::Contact::Organization.new
11
12
  @list_format = Ppl::Format::AddressBook::Organizations.new
12
13
  end
@@ -1,12 +1,13 @@
1
1
 
2
2
  class Ppl::Command::Phone < Ppl::Application::Command
3
3
 
4
+ name "phone"
5
+ description "List, show or change phone numbers"
6
+
4
7
  attr_writer :show_format
5
8
  attr_writer :list_format
6
9
 
7
10
  def initialize
8
- @name = "phone"
9
- @description = "List, show or change phone numbers"
10
11
  @show_format = Ppl::Format::Contact::PhoneNumber.new
11
12
  @list_format = Ppl::Format::AddressBook::PhoneNumbers.new
12
13
  end
@@ -1,12 +1,13 @@
1
1
 
2
2
  class Ppl::Command::Post < Ppl::Application::Command
3
3
 
4
+ name "post"
5
+ description "List, show or change postal addresses"
6
+
4
7
  attr_writer :show_format
5
8
  attr_writer :list_format
6
9
 
7
10
  def initialize
8
- @name = "post"
9
- @description = "List, show or change postal addresses"
10
11
  @show_format = Ppl::Format::Contact::PostalAddress.new
11
12
  @list_format = Ppl::Format::AddressBook::PostalAddresses.new
12
13
  end
@@ -1,10 +1,8 @@
1
1
 
2
2
  class Ppl::Command::Rm < Ppl::Application::Command
3
3
 
4
- def initialize
5
- @name = "rm"
6
- @description = "Delete a contact"
7
- end
4
+ name "rm"
5
+ description "Delete a contact"
8
6
 
9
7
  def options(parser, options)
10
8
  parser.banner = "usage: ppl rm <contact>"
@@ -3,12 +3,10 @@ require "readline"
3
3
 
4
4
  class Ppl::Command::Shell < Ppl::Application::Command
5
5
 
6
- attr_writer :format
6
+ name "shell"
7
+ description "Interactive mode"
7
8
 
8
- def initialize
9
- @name = "shell"
10
- @description = "Interactive mode"
11
- end
9
+ attr_writer :format
12
10
 
13
11
  def options(parser, options)
14
12
  parser.banner = "usage: ppl shell"
@@ -1,12 +1,12 @@
1
1
 
2
2
  class Ppl::Command::Show < Ppl::Application::Command
3
3
 
4
+ name "show"
5
+ description "Display the full details of a contact"
6
+
4
7
  attr_writer :format
5
8
 
6
9
  def initialize
7
- @name = "show"
8
- @description = "Display the full details of a contact"
9
-
10
10
  @format = Ppl::Format::Contact::Full.new
11
11
  end
12
12
 
data/lib/ppl.rb CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  module Ppl
3
3
 
4
- Version = "1.5.2"
4
+ Version = "1.5.3"
5
5
 
6
6
  module Adapter
7
7
  end
data/ppl.gemspec CHANGED
@@ -2,8 +2,8 @@
2
2
  Gem::Specification.new do |spec|
3
3
 
4
4
  spec.name = "ppl"
5
- spec.version = "1.5.2"
6
- spec.date = "2012-12-23"
5
+ spec.version = "1.5.3"
6
+ spec.date = "2012-12-26"
7
7
 
8
8
  spec.required_ruby_version = ">= 1.9.3"
9
9
 
@@ -1,18 +1,91 @@
1
1
 
2
- describe Ppl::Application::Command, "#execute" do
2
+ describe Ppl::Application::Command do
3
3
 
4
4
  before(:each) do
5
5
  @command = Ppl::Application::Command.new
6
6
  end
7
7
 
8
- it "should raise not implemented error" do
9
- expect{@command.execute(nil, nil)}.to raise_error(NotImplementedError)
8
+ describe "#execute" do
9
+ it "should raise not implemented error" do
10
+ expect{@command.execute(nil, nil)}.to raise_error(NotImplementedError)
11
+ end
10
12
  end
11
13
 
12
- it "should accept a storage adapter" do
13
- storage = double(Ppl::Adapter::Storage)
14
- @command.storage = storage
15
- @command.storage.should be storage
14
+ describe "#storage=" do
15
+ it "should accept a storage adapter" do
16
+ storage = double(Ppl::Adapter::Storage)
17
+ @command.storage = storage
18
+ @command.storage.should be storage
19
+ end
20
+ end
21
+
22
+ describe "#add_property" do
23
+ it "should allow new properties to be defined" do
24
+ class TestCommand123 < Ppl::Application::Command
25
+ add_property :some_property
26
+ end
27
+ end
28
+
29
+ it "should allow properties to have values assigned to them" do
30
+ class TestCommand456 < Ppl::Application::Command
31
+ add_property :some_property
32
+ some_property "a value"
33
+ end
34
+ TestCommand456.some_property.should eq "a value"
35
+ end
36
+
37
+ it "should expose properties as instance variables too" do
38
+ class TestCommand789 < Ppl::Application::Command
39
+ add_property :some_property
40
+ some_property "a value"
41
+ end
42
+ instance = TestCommand789.new
43
+ instance.some_property.should eq "a value"
44
+ end
45
+
46
+ it "should allow properties to be overwritten by instance variables" do
47
+ class TestCommand901 < Ppl::Application::Command
48
+ add_property :some_property
49
+ some_property "a value"
50
+ end
51
+ instance = TestCommand901.new
52
+ instance.some_property = "different"
53
+ instance.some_property.should eq "different"
54
+ end
55
+ end
56
+
57
+ describe "#name=" do
58
+ it "should allow the name to be set as an instance variable" do
59
+ @command.name = "testing"
60
+ @command.name.should eq "testing"
61
+ end
62
+ end
63
+
64
+ describe "#description=" do
65
+ it "should allow the description to be set as an instance variable" do
66
+ @command.description = "testing"
67
+ @command.description.should eq "testing"
68
+ end
69
+ end
70
+
71
+ describe "#name" do
72
+ it "should allow the name to be set as a class variable" do
73
+ class TestCommand123 < Ppl::Application::Command
74
+ name "new_for_test"
75
+ end
76
+ command = TestCommand123.new
77
+ command.name.should eq "new_for_test"
78
+ end
79
+ end
80
+
81
+ describe "#desecription" do
82
+ it "should allow the description to be set as a class variable" do
83
+ class TestCommand123 < Ppl::Application::Command
84
+ description "desc_for_test"
85
+ end
86
+ command = TestCommand123.new
87
+ command.description.should eq "desc_for_test"
88
+ end
16
89
  end
17
90
 
18
91
  end
@@ -71,9 +71,15 @@ describe Ppl::Application::Shell do
71
71
  @command.should_receive(:options)
72
72
  @command.should_receive(:execute) { raise "Pool's Closed" }
73
73
  @router.should_receive(:route).and_return(@command)
74
-
75
74
  @output.should_receive(:error).with("ppl: Pool's Closed")
75
+ @shell.run(@input, @output)
76
+ end
76
77
 
78
+ it "should handle ContactNotFound errors nicely" do
79
+ @command.stub(:options)
80
+ @command.should_receive(:execute) { raise Ppl::Error::ContactNotFound, "example" }
81
+ @router.should_receive(:route).and_return(@command)
82
+ @output.should_receive(:error).with("ppl: Contact 'example' not found")
77
83
  @shell.run(@input, @output)
78
84
  end
79
85
 
@@ -26,9 +26,8 @@ describe Ppl::Command::Mutt do
26
26
  end
27
27
 
28
28
  it "should search the address book for the query" do
29
- @storage.should_receive(:load_address_book).and_return(@address_book)
30
29
  @input.arguments.push "query"
31
- @command.stub(:mutt_search) { |ab| [] }
30
+ @command.should_receive(:mutt_search).and_return([])
32
31
  @output.should_receive(:line).with("No matches")
33
32
  @command.execute(@input, @output).should eq false
34
33
  end
@@ -42,8 +41,10 @@ describe Ppl::Command::Mutt do
42
41
  @input.arguments.push "example"
43
42
 
44
43
  @storage.should_receive(:load_address_book).and_return(@address_book)
45
- @output.should_receive(:line).with("Searching database... 1 entries... 1 matching:")
46
- @output.should_receive(:line).with("test@example.org\tTest User")
44
+ @output.should_receive(:line) do |line|
45
+ line.should include "Searching address book... 1 entries... 1 matching:"
46
+ line.should include "test@example.org\tTest User"
47
+ end
47
48
  @command.execute(@input, @output).should eq true
48
49
  end
49
50
 
@@ -56,8 +57,10 @@ describe Ppl::Command::Mutt do
56
57
  @input.arguments.push "User"
57
58
 
58
59
  @storage.should_receive(:load_address_book).and_return(@address_book)
59
- @output.should_receive(:line).with("Searching database... 1 entries... 1 matching:")
60
- @output.should_receive(:line).with("test@example.org\tTest User")
60
+ @output.should_receive(:line) do |line|
61
+ line.should include "Searching address book... 1 entries... 1 matching:"
62
+ line.should include "test@example.org\tTest User"
63
+ end
61
64
  @command.execute(@input, @output).should eq true
62
65
  end
63
66
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ppl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.5.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-23 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: inifile
16
- requirement: &16217320 !ruby/object:Gem::Requirement
16
+ requirement: &19907800 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - =
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.0.2
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *16217320
24
+ version_requirements: *19907800
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rugged
27
- requirement: &16216640 !ruby/object:Gem::Requirement
27
+ requirement: &19907120 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - =
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 0.17.0.b6
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *16216640
35
+ version_requirements: *19907120
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: vpim
38
- requirement: &16215860 !ruby/object:Gem::Requirement
38
+ requirement: &19906320 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - =
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: '0.695'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *16215860
46
+ version_requirements: *19906320
47
47
  description: CLI Address Book
48
48
  email: henry@henrysmith.org
49
49
  executables: