ppl 0.3.0 → 0.9.0
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.
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +4 -0
- data/README.md +1 -3
- data/lib/ppl/adapter/storage/disk.rb +27 -7
- data/lib/ppl/adapter/storage/factory.rb +26 -0
- data/lib/ppl/adapter/storage/git.rb +101 -0
- data/lib/ppl/adapter/storage.rb +4 -0
- data/lib/ppl/adapter/vcard/vpim.rb +16 -0
- data/lib/ppl/application/bootstrap.rb +23 -10
- data/lib/ppl/application/command.rb +3 -0
- data/lib/ppl/application/command_suite.rb +8 -0
- data/lib/ppl/application/configuration.rb +50 -0
- data/lib/ppl/application/output.rb +1 -0
- data/lib/ppl/application/shell.rb +21 -0
- data/lib/ppl/command/add.rb +34 -0
- data/lib/ppl/command/bday.rb +72 -0
- data/lib/ppl/command/email.rb +55 -0
- data/lib/ppl/command/help.rb +43 -0
- data/lib/ppl/command/init.rb +26 -0
- data/lib/ppl/command/ls.rb +26 -0
- data/lib/ppl/command/mv.rb +42 -0
- data/lib/ppl/command/name.rb +54 -0
- data/lib/ppl/command/org.rb +55 -0
- data/lib/ppl/command/phone.rb +55 -0
- data/lib/ppl/command/rm.rb +26 -0
- data/lib/ppl/command/show.rb +31 -0
- data/lib/ppl/entity/contact.rb +2 -0
- data/lib/ppl/format/address_book/birthdays.rb +34 -0
- data/lib/ppl/format/address_book/email_addresses.rb +34 -0
- data/lib/ppl/format/address_book/names.rb +34 -0
- data/lib/ppl/format/address_book/one_line.rb +34 -0
- data/lib/ppl/format/address_book/organizations.rb +34 -0
- data/lib/ppl/format/address_book/phone_numbers.rb +34 -0
- data/lib/ppl/format/address_book.rb +9 -0
- data/lib/ppl/format/contact/birthday.rb +13 -0
- data/lib/ppl/format/contact/email_address.rb +13 -0
- data/lib/ppl/format/contact/full.rb +55 -0
- data/lib/ppl/format/contact/name.rb +15 -0
- data/lib/ppl/format/contact/organization.rb +13 -0
- data/lib/ppl/format/contact/phone_number.rb +13 -0
- data/lib/ppl/format/contact.rb +9 -0
- data/lib/ppl/format/table.rb +48 -0
- data/lib/ppl.rb +33 -11
- data/ppl.gemspec +1 -1
- data/spec/ppl/adapter/storage/disk_spec.rb +57 -10
- data/spec/ppl/adapter/storage/factory_spec.rb +34 -0
- data/spec/ppl/adapter/storage/git_spec.rb +114 -0
- data/spec/ppl/adapter/storage_spec.rb +6 -0
- data/spec/ppl/adapter/vcard/vpim_spec.rb +34 -0
- data/spec/ppl/application/bootstrap_spec.rb +42 -4
- data/spec/ppl/application/command_suite_spec.rb +8 -0
- data/spec/ppl/application/configuration_spec.rb +32 -0
- data/spec/ppl/application/shell_spec.rb +4 -0
- data/spec/ppl/command/{contact_add_spec.rb → add_spec.rb} +2 -2
- data/spec/ppl/command/bday_spec.rb +56 -0
- data/spec/ppl/command/email_spec.rb +56 -0
- data/spec/ppl/command/help_spec.rb +79 -0
- data/spec/ppl/command/init_spec.rb +40 -0
- data/spec/ppl/command/ls_spec.rb +32 -0
- data/spec/ppl/command/mv_spec.rb +62 -0
- data/spec/ppl/command/name_spec.rb +59 -0
- data/spec/ppl/command/org_spec.rb +57 -0
- data/spec/ppl/command/phone_spec.rb +55 -0
- data/spec/ppl/command/{contact_delete_spec.rb → rm_spec.rb} +8 -2
- data/spec/ppl/command/{contact_show_spec.rb → show_spec.rb} +12 -6
- data/spec/ppl/format/address_book/birthdays_spec.rb +38 -0
- data/spec/ppl/format/address_book/email_addresses_spec.rb +38 -0
- data/spec/ppl/format/address_book/names_spec.rb +38 -0
- data/spec/ppl/format/address_book/one_line_spec.rb +41 -0
- data/spec/ppl/format/address_book/organizations_spec.rb +38 -0
- data/spec/ppl/format/address_book/phone_numbers_spec.rb +38 -0
- data/spec/ppl/format/address_book_spec.rb +18 -0
- data/spec/ppl/format/contact/birthday_spec.rb +23 -0
- data/spec/ppl/format/contact/email_address_spec.rb +23 -0
- data/spec/ppl/format/contact/full_spec.rb +44 -0
- data/spec/ppl/format/contact/name_spec.rb +23 -0
- data/spec/ppl/format/contact/organization_spec.rb +23 -0
- data/spec/ppl/format/contact/phone_number_spec.rb +23 -0
- data/spec/ppl/format/contact_spec.rb +17 -0
- data/spec/ppl/format/table_spec.rb +72 -0
- metadata +61 -19
- data/lib/ppl/command/command_list.rb +0 -21
- data/lib/ppl/command/contact_add.rb +0 -26
- data/lib/ppl/command/contact_delete.rb +0 -16
- data/lib/ppl/command/contact_list.rb +0 -24
- data/lib/ppl/command/contact_rename.rb +0 -23
- data/lib/ppl/command/contact_show.rb +0 -20
- data/lib/ppl/command/set_birthday.rb +0 -30
- data/lib/ppl/command/set_email.rb +0 -23
- data/lib/ppl/command/set_name.rb +0 -28
- data/spec/ppl/command/command_list_spec.rb +0 -37
- data/spec/ppl/command/contact_list_spec.rb +0 -15
- data/spec/ppl/command/contact_rename_spec.rb +0 -42
- data/spec/ppl/command/set_birthday_spec.rb +0 -50
- data/spec/ppl/command/set_email_spec.rb +0 -38
- data/spec/ppl/command/set_name_spec.rb +0 -45
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -9,6 +9,7 @@ GEM
|
|
|
9
9
|
specs:
|
|
10
10
|
diff-lcs (1.1.3)
|
|
11
11
|
fakefs (0.4.1)
|
|
12
|
+
inifile (2.0.2)
|
|
12
13
|
rake (10.0.1)
|
|
13
14
|
rspec (2.12.0)
|
|
14
15
|
rspec-core (~> 2.12.0)
|
|
@@ -18,12 +19,15 @@ GEM
|
|
|
18
19
|
rspec-expectations (2.12.0)
|
|
19
20
|
diff-lcs (~> 1.1.3)
|
|
20
21
|
rspec-mocks (2.12.0)
|
|
22
|
+
rugged (0.17.0.b6)
|
|
21
23
|
|
|
22
24
|
PLATFORMS
|
|
23
25
|
ruby
|
|
24
26
|
|
|
25
27
|
DEPENDENCIES
|
|
26
28
|
fakefs
|
|
29
|
+
inifile (= 2.0.2)
|
|
27
30
|
rake
|
|
28
31
|
rspec
|
|
32
|
+
rugged (= 0.17.0.b6)
|
|
29
33
|
vpim (= 12.1.12)!
|
data/README.md
CHANGED
|
@@ -127,9 +127,7 @@ Bug reports, fixes, and additional features are encouraged. The project uses
|
|
|
127
127
|
[Github issues](https://github.com/h2s/ppl/issues) to track bug reports.
|
|
128
128
|
|
|
129
129
|
If you'd like to contribute code, please just bear in mind that ppl development
|
|
130
|
-
is test-driven
|
|
131
|
-
as described in the book [Clean
|
|
132
|
-
Code](http://books.google.co.uk/books?id=_i6bDeoCQzsC).
|
|
130
|
+
is test-driven.
|
|
133
131
|
|
|
134
132
|
License
|
|
135
133
|
-------
|
|
@@ -1,17 +1,26 @@
|
|
|
1
1
|
|
|
2
|
+
require "fileutils"
|
|
3
|
+
|
|
2
4
|
class Ppl::Adapter::Storage::Disk < Ppl::Adapter::Storage
|
|
3
5
|
|
|
4
|
-
attr_accessor :
|
|
6
|
+
attr_accessor :directory
|
|
5
7
|
attr_accessor :vcard_adapter
|
|
6
8
|
|
|
7
|
-
def
|
|
8
|
-
|
|
9
|
+
def self.create_address_book(path)
|
|
10
|
+
if !Dir.exists? path
|
|
11
|
+
FileUtils.mkdir_p(path)
|
|
12
|
+
end
|
|
13
|
+
storage = self.new(path)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(directory)
|
|
17
|
+
@directory = directory
|
|
9
18
|
end
|
|
10
19
|
|
|
11
20
|
def load_address_book
|
|
12
21
|
address_book = Ppl::Entity::AddressBook.new
|
|
13
22
|
|
|
14
|
-
pattern = File.join @path, "*.vcf"
|
|
23
|
+
pattern = File.join @directory.path, "*.vcf"
|
|
15
24
|
filenames = Dir.glob pattern
|
|
16
25
|
|
|
17
26
|
filenames.each do |filename|
|
|
@@ -24,7 +33,7 @@ class Ppl::Adapter::Storage::Disk < Ppl::Adapter::Storage
|
|
|
24
33
|
end
|
|
25
34
|
|
|
26
35
|
def load_contact(id)
|
|
27
|
-
filename =
|
|
36
|
+
filename = filename_for_contact_id(id)
|
|
28
37
|
contact = nil
|
|
29
38
|
if File.exists?(filename)
|
|
30
39
|
vcard = File.read filename
|
|
@@ -39,12 +48,23 @@ class Ppl::Adapter::Storage::Disk < Ppl::Adapter::Storage
|
|
|
39
48
|
def save_contact(contact)
|
|
40
49
|
vcard = @vcard_adapter.encode(contact)
|
|
41
50
|
|
|
42
|
-
|
|
43
|
-
filename = File.join @path, basename
|
|
51
|
+
filename = filename_for_contact(contact)
|
|
44
52
|
File.open(filename, "w") do |file|
|
|
45
53
|
file.write(vcard)
|
|
46
54
|
end
|
|
47
55
|
end
|
|
48
56
|
|
|
57
|
+
def delete_contact(contact)
|
|
58
|
+
File.unlink filename_for_contact(contact)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def filename_for_contact(contact)
|
|
62
|
+
filename_for_contact_id(contact.id)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def filename_for_contact_id(id)
|
|
66
|
+
File.join(@directory.path, id + ".vcf")
|
|
67
|
+
end
|
|
68
|
+
|
|
49
69
|
end
|
|
50
70
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
class Ppl::Adapter::Storage::Factory
|
|
3
|
+
|
|
4
|
+
def initialize(vcard_adapter)
|
|
5
|
+
@vcard_adapter = vcard_adapter
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def load_adapter(directory)
|
|
9
|
+
git_dir = File.join(directory.path, ".git")
|
|
10
|
+
|
|
11
|
+
disk_adapter = Ppl::Adapter::Storage::Disk.new(directory)
|
|
12
|
+
disk_adapter.vcard_adapter = @vcard_adapter
|
|
13
|
+
|
|
14
|
+
adapter = disk_adapter
|
|
15
|
+
|
|
16
|
+
if File.exists?(git_dir)
|
|
17
|
+
git_adapter = Ppl::Adapter::Storage::Git.new(disk_adapter)
|
|
18
|
+
git_adapter.vcard_adapter = @vcard_adapter
|
|
19
|
+
adapter = git_adapter
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
return adapter
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
|
|
2
|
+
require "rugged"
|
|
3
|
+
require "socket"
|
|
4
|
+
|
|
5
|
+
class Ppl::Adapter::Storage::Git < Ppl::Adapter::Storage
|
|
6
|
+
|
|
7
|
+
attr_accessor :disk
|
|
8
|
+
attr_accessor :repository
|
|
9
|
+
attr_accessor :vcard_adapter
|
|
10
|
+
|
|
11
|
+
def initialize(disk)
|
|
12
|
+
@disk = disk
|
|
13
|
+
@repository = Rugged::Repository.new(@disk.directory.path)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.create_address_book(path)
|
|
17
|
+
disk = Ppl::Adapter::Storage::Disk.create_address_book(path)
|
|
18
|
+
repo = Rugged::Repository.init_at(path, false)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def load_address_book
|
|
22
|
+
address_book = Ppl::Entity::AddressBook.new
|
|
23
|
+
|
|
24
|
+
head = @repository.lookup(@repository.head.target)
|
|
25
|
+
head.tree.each do |file|
|
|
26
|
+
extension = file[:name].slice(-4..-1)
|
|
27
|
+
if extension != ".vcf"
|
|
28
|
+
next
|
|
29
|
+
end
|
|
30
|
+
contact_id = file[:name].slice(0..-5)
|
|
31
|
+
contact = load_contact(contact_id)
|
|
32
|
+
address_book.add_contact(contact)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
return address_book
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def load_contact(id)
|
|
39
|
+
filename = id + ".vcf"
|
|
40
|
+
target = @repository.head.target
|
|
41
|
+
vcard = @repository.file_at(target, filename)
|
|
42
|
+
contact = nil
|
|
43
|
+
|
|
44
|
+
if !vcard.nil?
|
|
45
|
+
contact = @vcard_adapter.decode(vcard)
|
|
46
|
+
contact.id = id
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
return contact
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def save_contact(contact)
|
|
53
|
+
@disk.save_contact(contact)
|
|
54
|
+
|
|
55
|
+
add("#{contact.id}.vcf")
|
|
56
|
+
commit("save_contact(#{contact.id})")
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def delete_contact(contact)
|
|
60
|
+
@repository.index.remove("#{contact.id}.vcf")
|
|
61
|
+
@repository.index.write
|
|
62
|
+
commit("remove_contact(#{contact.id})")
|
|
63
|
+
@disk.delete_contact(contact)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def add(file)
|
|
69
|
+
@repository.index.add(file)
|
|
70
|
+
@repository.index.write
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def commit(message)
|
|
74
|
+
hash = @repository.index.write_tree
|
|
75
|
+
tree = @repository.lookup hash
|
|
76
|
+
parents = [ @repository.lookup( @repository.head.target ).oid ]
|
|
77
|
+
|
|
78
|
+
name = ENV['USER']
|
|
79
|
+
host = Socket.gethostname
|
|
80
|
+
|
|
81
|
+
author = {
|
|
82
|
+
:email => name + "@" + host,
|
|
83
|
+
:time => Time.now,
|
|
84
|
+
:name => name,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
data = {
|
|
88
|
+
:author => author,
|
|
89
|
+
:message => message,
|
|
90
|
+
:committer => author,
|
|
91
|
+
:tree => tree,
|
|
92
|
+
:parents => parents,
|
|
93
|
+
:update_ref => "HEAD",
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
Rugged::Commit.create(@repository, data)
|
|
97
|
+
true
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
|
data/lib/ppl/adapter/storage.rb
CHANGED
|
@@ -19,6 +19,14 @@ class Ppl::Adapter::Vcard::Vpim
|
|
|
19
19
|
maker.add_email(contact.email_address)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
if !contact.phone_number.nil?
|
|
23
|
+
maker.add_tel(contact.phone_number)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if !contact.organization.nil?
|
|
27
|
+
maker.org=(contact.organization)
|
|
28
|
+
end
|
|
29
|
+
|
|
22
30
|
end
|
|
23
31
|
|
|
24
32
|
return vcard.to_s
|
|
@@ -36,6 +44,14 @@ class Ppl::Adapter::Vcard::Vpim
|
|
|
36
44
|
contact.email_address = email.to_s
|
|
37
45
|
end
|
|
38
46
|
|
|
47
|
+
if !vcard.telephones.empty?
|
|
48
|
+
contact.phone_number = vcard.telephones.first
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if !vcard.org.nil?
|
|
52
|
+
contact.organization = vcard.org.first
|
|
53
|
+
end
|
|
54
|
+
|
|
39
55
|
name = nil
|
|
40
56
|
name = vcard.name
|
|
41
57
|
|
|
@@ -3,15 +3,18 @@ class Ppl::Application::Bootstrap
|
|
|
3
3
|
|
|
4
4
|
def commands
|
|
5
5
|
commands = [
|
|
6
|
-
Ppl::Command::
|
|
7
|
-
Ppl::Command::
|
|
8
|
-
Ppl::Command::
|
|
9
|
-
Ppl::Command::
|
|
10
|
-
Ppl::Command::
|
|
11
|
-
Ppl::Command::
|
|
12
|
-
Ppl::Command::
|
|
13
|
-
Ppl::Command::
|
|
14
|
-
Ppl::Command::
|
|
6
|
+
Ppl::Command::Init.new,
|
|
7
|
+
Ppl::Command::Bday.new,
|
|
8
|
+
Ppl::Command::Help.new,
|
|
9
|
+
Ppl::Command::Add.new,
|
|
10
|
+
Ppl::Command::Rm.new,
|
|
11
|
+
Ppl::Command::Ls.new,
|
|
12
|
+
Ppl::Command::Mv.new,
|
|
13
|
+
Ppl::Command::Show.new,
|
|
14
|
+
Ppl::Command::Name.new,
|
|
15
|
+
Ppl::Command::Email.new,
|
|
16
|
+
Ppl::Command::Org.new,
|
|
17
|
+
Ppl::Command::Phone.new,
|
|
15
18
|
]
|
|
16
19
|
commands.each do |command|
|
|
17
20
|
command.storage = storage_adapter
|
|
@@ -28,6 +31,11 @@ class Ppl::Application::Bootstrap
|
|
|
28
31
|
return suite
|
|
29
32
|
end
|
|
30
33
|
|
|
34
|
+
def configuration
|
|
35
|
+
config = Ppl::Application::Configuration.new
|
|
36
|
+
return config
|
|
37
|
+
end
|
|
38
|
+
|
|
31
39
|
def input
|
|
32
40
|
input = Ppl::Application::Input.new(ARGV.dup)
|
|
33
41
|
return input
|
|
@@ -51,7 +59,12 @@ class Ppl::Application::Bootstrap
|
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
def storage_adapter
|
|
54
|
-
|
|
62
|
+
config = configuration
|
|
63
|
+
|
|
64
|
+
directory = Dir.new(config.address_book_path)
|
|
65
|
+
factory = Ppl::Adapter::Storage::Factory.new(vcard_adapter)
|
|
66
|
+
storage = factory.load_adapter(directory)
|
|
67
|
+
|
|
55
68
|
storage.vcard_adapter = vcard_adapter
|
|
56
69
|
return storage
|
|
57
70
|
end
|
|
@@ -20,6 +20,14 @@ class Ppl::Application::CommandSuite
|
|
|
20
20
|
def find_command(name)
|
|
21
21
|
@commands.select { |command| command.name == name }.first
|
|
22
22
|
end
|
|
23
|
+
|
|
24
|
+
def sort_by_name
|
|
25
|
+
@commands.sort! { |a, b| a.name <=> b.name }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def [](index)
|
|
29
|
+
@commands[index]
|
|
30
|
+
end
|
|
23
31
|
|
|
24
32
|
end
|
|
25
33
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
|
|
2
|
+
require "inifile"
|
|
3
|
+
|
|
4
|
+
class Ppl::Application::Configuration
|
|
5
|
+
|
|
6
|
+
USER_CONFIG = "~/.pplconfig"
|
|
7
|
+
REPO_CONFIG = "./.ppl/config"
|
|
8
|
+
|
|
9
|
+
def address_book_path
|
|
10
|
+
default_config = default_configuration
|
|
11
|
+
user_config = user_configuration
|
|
12
|
+
|
|
13
|
+
path = default_config["address book"]["path"]
|
|
14
|
+
if !user_config["address book"].nil? && !user_config["address book"]["path"].nil?
|
|
15
|
+
path = File.expand_path(user_config["address book"]["path"])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
return path
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def aliases
|
|
22
|
+
aliases = {}
|
|
23
|
+
return aliases
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def default_configuration
|
|
29
|
+
{
|
|
30
|
+
"address book" => {
|
|
31
|
+
"path" => Dir.pwd
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def user_configuration
|
|
37
|
+
filename = File.expand_path(USER_CONFIG)
|
|
38
|
+
config = {}
|
|
39
|
+
if File.exists?(filename)
|
|
40
|
+
config = IniFile::load(filename).to_h
|
|
41
|
+
end
|
|
42
|
+
return config
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def repository_configuration
|
|
46
|
+
{}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
|
|
2
|
+
require "optparse"
|
|
3
|
+
|
|
2
4
|
class Ppl::Application::Shell
|
|
3
5
|
|
|
4
6
|
attr_writer :router
|
|
@@ -7,7 +9,17 @@ class Ppl::Application::Shell
|
|
|
7
9
|
outcome = false
|
|
8
10
|
begin
|
|
9
11
|
command = select_command(input)
|
|
12
|
+
prepare_command(command, input)
|
|
10
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
|
|
21
|
+
output.error($!)
|
|
22
|
+
output.error(@optparse.to_s)
|
|
11
23
|
rescue
|
|
12
24
|
output.error("ppl: " + $!.message)
|
|
13
25
|
outcome = false
|
|
@@ -22,6 +34,15 @@ class Ppl::Application::Shell
|
|
|
22
34
|
@router.route(input.arguments.shift)
|
|
23
35
|
end
|
|
24
36
|
|
|
37
|
+
def prepare_command(command, input)
|
|
38
|
+
if !command.nil?
|
|
39
|
+
@optparse = OptionParser.new do |parser|
|
|
40
|
+
command.options(parser, input.options)
|
|
41
|
+
end
|
|
42
|
+
@optparse.parse!(input.arguments)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
25
46
|
def execute_command(command, input, output)
|
|
26
47
|
outcome = false
|
|
27
48
|
if !command.nil?
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
class Ppl::Command::Add < Ppl::Application::Command
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@name = "add"
|
|
6
|
+
@description = "Add a new contact"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def options(parser, options)
|
|
10
|
+
parser.banner = "usage: ppl add <contact> <name>"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def execute(input, output)
|
|
14
|
+
contact_id = input.arguments.shift
|
|
15
|
+
contact_name = input.arguments.shift
|
|
16
|
+
|
|
17
|
+
if contact_id.nil?
|
|
18
|
+
raise Ppl::Error::IncorrectUsage, "No contact specified"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
if contact_name.nil?
|
|
22
|
+
raise Ppl::Error::IncorrectUsage, "No name specified"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
contact = Ppl::Entity::Contact.new
|
|
26
|
+
contact.id = contact_id.dup
|
|
27
|
+
contact.name = contact_name.dup
|
|
28
|
+
|
|
29
|
+
@storage.save_contact(contact)
|
|
30
|
+
return true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
class Ppl::Command::Bday < Ppl::Application::Command
|
|
3
|
+
|
|
4
|
+
attr_writer :list_format
|
|
5
|
+
attr_writer :show_format
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@name = "bday"
|
|
9
|
+
@description = "List, show or change birthdays"
|
|
10
|
+
@list_format = Ppl::Format::AddressBook::Birthdays.new
|
|
11
|
+
@show_format = Ppl::Format::Contact::Birthday.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def options(parser, options)
|
|
15
|
+
parser.banner = "usage: ppl birthday <contact> [<date>]"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def execute(input, output)
|
|
19
|
+
action = determine_action(input)
|
|
20
|
+
send(action, input, output)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def determine_action(input)
|
|
27
|
+
if input.arguments[0].nil?
|
|
28
|
+
:list_birthdays
|
|
29
|
+
elsif input.arguments[1].nil?
|
|
30
|
+
:show_birthday
|
|
31
|
+
else
|
|
32
|
+
:set_birthday
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def list_birthdays(input, output)
|
|
37
|
+
address_book = @storage.load_address_book
|
|
38
|
+
birthday_list = @list_format.process(address_book)
|
|
39
|
+
output.line(birthday_list)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def show_birthday(input, output)
|
|
43
|
+
contact_id = input.arguments.shift
|
|
44
|
+
if contact_id.nil?
|
|
45
|
+
raise Ppl::Error::IncorrectUsage, "No contact specified"
|
|
46
|
+
end
|
|
47
|
+
contact = @storage.require_contact(contact_id)
|
|
48
|
+
|
|
49
|
+
line = @show_format.process(contact)
|
|
50
|
+
output.line(line)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def set_birthday(input, output)
|
|
54
|
+
contact_id = input.arguments.shift
|
|
55
|
+
birthday = input.arguments.shift
|
|
56
|
+
|
|
57
|
+
if contact_id.nil?
|
|
58
|
+
raise Ppl::Error::IncorrectUsage, "No contact specified"
|
|
59
|
+
end
|
|
60
|
+
contact = @storage.require_contact(contact_id)
|
|
61
|
+
|
|
62
|
+
begin
|
|
63
|
+
date = Date.parse birthday
|
|
64
|
+
rescue ArgumentError
|
|
65
|
+
raise Ppl::Error::IncorrectUsage, "Invalid date '#{birthday}'"
|
|
66
|
+
end
|
|
67
|
+
contact.birthday = date
|
|
68
|
+
@storage.save_contact(contact)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
|
|
2
|
+
class Ppl::Command::Email < Ppl::Application::Command
|
|
3
|
+
|
|
4
|
+
attr_writer :show_format
|
|
5
|
+
attr_writer :list_format
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
@name = "email"
|
|
9
|
+
@description = "Show or change a contact's email address"
|
|
10
|
+
@show_format = Ppl::Format::Contact::EmailAddress.new
|
|
11
|
+
@list_format = Ppl::Format::AddressBook::EmailAddresses.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def options(parser, options)
|
|
15
|
+
parser.banner = "usage: ppl email <contact> [<email-address>]"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def execute(input, output)
|
|
19
|
+
action = determine_action(input)
|
|
20
|
+
send(action, input, output)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def determine_action(input)
|
|
27
|
+
if input.arguments[0].nil?
|
|
28
|
+
:list_email_addresses
|
|
29
|
+
elsif input.arguments[1].nil?
|
|
30
|
+
:show_email_address
|
|
31
|
+
else
|
|
32
|
+
:set_email_address
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def list_email_addresses(input, output)
|
|
37
|
+
address_book = @storage.load_address_book
|
|
38
|
+
email_list = @list_format.process(address_book)
|
|
39
|
+
output.line(email_list)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def show_email_address(input, output)
|
|
43
|
+
contact = @storage.require_contact(input.arguments[0])
|
|
44
|
+
email_address = @show_format.process(contact)
|
|
45
|
+
output.line(email_address)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def set_email_address(input, output)
|
|
49
|
+
contact = @storage.require_contact(input.arguments[0])
|
|
50
|
+
contact.email_address = input.arguments[1].dup
|
|
51
|
+
@storage.save_contact(contact)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
|
|
2
|
+
class Ppl::Command::Help < Ppl::Application::Command
|
|
3
|
+
|
|
4
|
+
attr_accessor :command_suite
|
|
5
|
+
|
|
6
|
+
def initialize
|
|
7
|
+
@name = "help"
|
|
8
|
+
@description = "Show a list of commands"
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def execute(input, output)
|
|
12
|
+
@command_suite.sort_by_name
|
|
13
|
+
max_name_length = 0
|
|
14
|
+
|
|
15
|
+
@command_suite.each do |command|
|
|
16
|
+
name_length = command.name.length
|
|
17
|
+
if name_length > max_name_length
|
|
18
|
+
max_name_length = name_length
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
output.line("usage: ppl <command>")
|
|
23
|
+
output.line(nil)
|
|
24
|
+
|
|
25
|
+
@command_suite.each do |command|
|
|
26
|
+
name = command.name
|
|
27
|
+
description = command.description
|
|
28
|
+
|
|
29
|
+
if @name == name
|
|
30
|
+
next
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
line = sprintf(" %-#{max_name_length}s %s", name, description)
|
|
34
|
+
|
|
35
|
+
output.line(line)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
output.line(nil)
|
|
39
|
+
return true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
class Ppl::Command::Init < Ppl::Application::Command
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@name = "init"
|
|
6
|
+
@description = "Create an empty address book"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def options(parser, options)
|
|
10
|
+
parser.banner = "usage: ppl init [directory]"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def execute(input, output)
|
|
14
|
+
|
|
15
|
+
path = input.arguments.shift
|
|
16
|
+
if path.nil?
|
|
17
|
+
path = Dir.pwd
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
storage = Ppl::Adapter::Storage::Git.create_address_book(path)
|
|
21
|
+
|
|
22
|
+
return true
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|