pomo 2.0.2 → 2.1.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/.travis.yml +7 -0
- data/{HISTORY.md → CHANGELOG.md} +25 -0
- data/{LICENSE.txt → LICENSE.md} +0 -0
- data/README.md +57 -30
- data/Rakefile +12 -5
- data/bin/pomo +166 -97
- data/features/configuration.feature +35 -0
- data/features/manage_list.feature +34 -0
- data/features/manage_tasks.feature +73 -0
- data/features/step_definitions/pomo_steps.rb +8 -0
- data/features/support/env.rb +12 -0
- data/lib/pomo.rb +0 -9
- data/lib/pomo/configuration.rb +57 -15
- data/lib/pomo/github_task.rb +51 -13
- data/lib/pomo/list.rb +59 -21
- data/lib/pomo/notifier.rb +5 -0
- data/lib/pomo/notifier/growl_notifier.rb +1 -0
- data/lib/pomo/notifier/libnotify_notifier.rb +1 -0
- data/lib/pomo/notifier/notification_center_notifier.rb +1 -0
- data/lib/pomo/os.rb +2 -0
- data/lib/pomo/task.rb +16 -4
- data/lib/pomo/version.rb +1 -1
- data/pomo.gemspec +7 -3
- data/spec/pomo/configuration_spec.rb +108 -0
- data/spec/pomo/list_spec.rb +63 -0
- data/spec/pomo/task_spec.rb +15 -0
- data/spec/spec_helper.rb +40 -2
- metadata +71 -8
- data/spec/pomo_spec.rb +0 -8
@@ -0,0 +1,35 @@
|
|
1
|
+
Feature: Configure pomo
|
2
|
+
In order to use pomo
|
3
|
+
As a user
|
4
|
+
I want a sane default configuration for my system
|
5
|
+
and a data file to store my tasks
|
6
|
+
|
7
|
+
Scenario: Execute pomo without configuration
|
8
|
+
When I run `pomo`
|
9
|
+
Then the following files should exist:
|
10
|
+
| /tmp/home/.pomorc |
|
11
|
+
| /tmp/home/.pomo |
|
12
|
+
And the output should contain "Initialized default config file in /tmp/home/.pomorc. See 'pomo help initconfig' for options."
|
13
|
+
|
14
|
+
Scenario: Initialize configuration
|
15
|
+
When I run `pomo initconfig`
|
16
|
+
Then the following files should exist:
|
17
|
+
| /tmp/home/.pomorc |
|
18
|
+
| /tmp/home/.pomo |
|
19
|
+
And the output should contain "Initialized config file"
|
20
|
+
|
21
|
+
Scenario: Initialize configuration (no clobber)
|
22
|
+
Given a file named "/tmp/home/.pomorc" with:
|
23
|
+
"""
|
24
|
+
hello world
|
25
|
+
"""
|
26
|
+
When I run `pomo initconfig`
|
27
|
+
Then the output should contain "Not overwriting existing config file"
|
28
|
+
|
29
|
+
Scenario: Force initialize configuration (clobber)
|
30
|
+
Given a file named "/tmp/home/.pomorc" with:
|
31
|
+
"""
|
32
|
+
hello world
|
33
|
+
"""
|
34
|
+
When I run `pomo initconfig --force`
|
35
|
+
Then the file "/tmp/home/.pomorc" should not contain "hello world"
|
@@ -0,0 +1,34 @@
|
|
1
|
+
Feature: Manage Pomodoro list
|
2
|
+
In order to complete tasks
|
3
|
+
As a user
|
4
|
+
I want to manage the order and content of my task list
|
5
|
+
|
6
|
+
Scenario: Add tasks
|
7
|
+
When I run `pomo add 'Remember the milk'`
|
8
|
+
And I run `pomo list`
|
9
|
+
Then the output from "pomo list" should contain "Remember the milk"
|
10
|
+
|
11
|
+
Scenario: Remove tasks
|
12
|
+
Given the following tasks:
|
13
|
+
| Remember the milk |
|
14
|
+
| Walk the dog |
|
15
|
+
| Shave the yak |
|
16
|
+
When I run `pomo rm first`
|
17
|
+
And I run `pomo list`
|
18
|
+
Then the output from "pomo list" should not contain "Remember the milk"
|
19
|
+
|
20
|
+
Scenario: Move tasks
|
21
|
+
Given the following tasks:
|
22
|
+
| Remember the milk |
|
23
|
+
| Walk the dog |
|
24
|
+
| Shave the yak |
|
25
|
+
When I run `pomo mv first last`
|
26
|
+
And I run `pomo list`
|
27
|
+
Then the output from "pomo list" should contain exactly:
|
28
|
+
"""
|
29
|
+
0. Walk the dog : 25 minutes
|
30
|
+
1. Shave the yak : 25 minutes
|
31
|
+
2. Remember the milk : 25 minutes
|
32
|
+
75 minutes
|
33
|
+
|
34
|
+
"""
|
@@ -0,0 +1,73 @@
|
|
1
|
+
Feature: Manage Pomodoro task
|
2
|
+
In order to track tasks
|
3
|
+
As a user
|
4
|
+
I want to manage the metadata and status of my tasks
|
5
|
+
|
6
|
+
Scenario: Edit tasks
|
7
|
+
When I run `pomo add 'Remember the milk' -d '1 qt Almond milk' -l 60`
|
8
|
+
And I run `pomo edit first -n 'Remember the Almond milk' -d '1 qt' -l 30`
|
9
|
+
And I run `pomo show first`
|
10
|
+
Then the output from "pomo show first" should contain exactly:
|
11
|
+
"""
|
12
|
+
|
13
|
+
name : Remember the Almond milk
|
14
|
+
length : 30 minutes
|
15
|
+
description : 1 qt
|
16
|
+
complete : [ ]
|
17
|
+
|
18
|
+
|
19
|
+
"""
|
20
|
+
|
21
|
+
Scenario: Copy tasks
|
22
|
+
When I run `pomo add 'Remember the milk'`
|
23
|
+
And I run `pomo complete first`
|
24
|
+
And I run `pomo show first`
|
25
|
+
Then the output from "pomo show first" should contain exactly:
|
26
|
+
"""
|
27
|
+
|
28
|
+
name : Remember the milk
|
29
|
+
length : 25 minutes
|
30
|
+
complete : [✓]
|
31
|
+
|
32
|
+
|
33
|
+
"""
|
34
|
+
When I run `pomo copy first`
|
35
|
+
And I run `pomo show last`
|
36
|
+
Then the output from "pomo show last" should contain exactly:
|
37
|
+
"""
|
38
|
+
|
39
|
+
name : Remember the milk
|
40
|
+
length : 25 minutes
|
41
|
+
complete : [ ]
|
42
|
+
|
43
|
+
|
44
|
+
"""
|
45
|
+
|
46
|
+
Scenario: Complete tasks
|
47
|
+
When I run `pomo add 'Remember the milk'`
|
48
|
+
And I run `pomo complete first`
|
49
|
+
And I run `pomo show first`
|
50
|
+
Then the output from "pomo show first" should contain exactly:
|
51
|
+
"""
|
52
|
+
|
53
|
+
name : Remember the milk
|
54
|
+
length : 25 minutes
|
55
|
+
complete : [✓]
|
56
|
+
|
57
|
+
|
58
|
+
"""
|
59
|
+
|
60
|
+
Scenario: Incomplete tasks
|
61
|
+
When I run `pomo add 'Remember the milk'`
|
62
|
+
And I run `pomo complete first`
|
63
|
+
And I run `pomo incomplete first`
|
64
|
+
And I run `pomo show first`
|
65
|
+
Then the output from "pomo show first" should contain exactly:
|
66
|
+
"""
|
67
|
+
|
68
|
+
name : Remember the milk
|
69
|
+
length : 25 minutes
|
70
|
+
complete : [ ]
|
71
|
+
|
72
|
+
|
73
|
+
"""
|
data/lib/pomo.rb
CHANGED
@@ -1,15 +1,6 @@
|
|
1
|
-
require 'rbconfig'
|
2
1
|
require 'pomo/os'
|
3
|
-
require 'terminal-notifier' if Pomo::OS.mac?
|
4
|
-
require 'growl' if Pomo::OS.mac? || Pomo::OS.windows?
|
5
|
-
require 'libnotify' if Pomo::OS.linux?
|
6
|
-
require 'yaml'
|
7
|
-
require 'octokit'
|
8
2
|
require 'pomo/configuration'
|
9
3
|
require 'pomo/notifier'
|
10
|
-
require 'pomo/notifier/notification_center_notifier'
|
11
|
-
require 'pomo/notifier/growl_notifier'
|
12
|
-
require 'pomo/notifier/libnotify_notifier'
|
13
4
|
require 'pomo/list'
|
14
5
|
require 'pomo/task'
|
15
6
|
require 'pomo/github_task'
|
data/lib/pomo/configuration.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'commander'
|
3
|
+
include Commander::UI
|
4
|
+
|
1
5
|
module Pomo
|
2
6
|
class Configuration
|
3
7
|
##
|
@@ -7,6 +11,13 @@ module Pomo
|
|
7
11
|
|
8
12
|
attr_reader :notifier
|
9
13
|
|
14
|
+
##
|
15
|
+
# Run with progress bar.
|
16
|
+
#
|
17
|
+
# values: true | false
|
18
|
+
|
19
|
+
attr_accessor :progress
|
20
|
+
|
10
21
|
##
|
11
22
|
# Refresh tmux status bar.
|
12
23
|
#
|
@@ -16,29 +27,60 @@ module Pomo
|
|
16
27
|
|
17
28
|
##
|
18
29
|
# Initialize configuration.
|
19
|
-
def initialize
|
20
|
-
options = {
|
21
|
-
:notifier => default_notifier,
|
22
|
-
:tmux => false
|
23
|
-
}
|
24
30
|
|
25
|
-
|
31
|
+
def initialize(options = {})
|
32
|
+
@notifier = options[:notifier]
|
33
|
+
@progress = options[:progress]
|
34
|
+
@tmux = options[:tmux]
|
35
|
+
end
|
26
36
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
37
|
+
##
|
38
|
+
# Load configuration file or default_options. Passed options take precedence.
|
39
|
+
|
40
|
+
def self.load(options = {})
|
41
|
+
options.reject!{|k,v| ![:notifier, :progress, :tmux].include? k}
|
42
|
+
|
43
|
+
if !(File.exists? config_file)
|
44
|
+
File.open(config_file, 'w') { |file| YAML::dump(default_options, file) }
|
45
|
+
say "Initialized default config file in #{config_file}. See 'pomo help initconfig' for options."
|
46
|
+
end
|
47
|
+
|
48
|
+
config_file_options = YAML.load_file(config_file)
|
49
|
+
new(config_file_options.merge(options))
|
50
|
+
end
|
51
|
+
|
52
|
+
##
|
53
|
+
# Save configuration. Passed options take precendence over default_options.
|
54
|
+
|
55
|
+
def self.save(options = {})
|
56
|
+
force_save = options.delete :force
|
57
|
+
options.reject!{|k,v| ![:notifier, :progress, :tmux].include? k}
|
58
|
+
|
59
|
+
options = default_options.merge(options)
|
60
|
+
|
61
|
+
if !(File.exists? config_file) || force_save
|
31
62
|
File.open(config_file, 'w') { |file| YAML::dump(options, file) }
|
32
|
-
|
63
|
+
say "Initialized config file in #{config_file}"
|
64
|
+
else
|
65
|
+
say_error "Not overwriting existing config file #{config_file}, use --force to override. See 'pomo help initconfig'."
|
33
66
|
end
|
67
|
+
end
|
34
68
|
|
35
|
-
|
36
|
-
|
69
|
+
# Helpers
|
70
|
+
|
71
|
+
def self.config_file
|
72
|
+
File.join(ENV['HOME'],'.pomorc')
|
37
73
|
end
|
38
74
|
|
39
|
-
|
75
|
+
def self.default_options
|
76
|
+
{
|
77
|
+
:notifier => default_notifier,
|
78
|
+
:progress => false,
|
79
|
+
:tmux => false
|
80
|
+
}
|
81
|
+
end
|
40
82
|
|
41
|
-
def default_notifier
|
83
|
+
def self.default_notifier
|
42
84
|
if Pomo::OS.has_notification_center?
|
43
85
|
return 'notification_center'
|
44
86
|
elsif Pomo::OS.linux?
|
data/lib/pomo/github_task.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# This is to make sure Faraday doesn't warn the user about the `system_timer` gem missing in Ruby 1.8
|
2
|
+
old_warn, $-w = $-w, nil
|
3
|
+
begin
|
4
|
+
require 'faraday'
|
5
|
+
ensure
|
6
|
+
$-w = old_warn
|
7
|
+
end
|
8
|
+
require 'octokit'
|
1
9
|
|
2
10
|
module Pomo
|
3
|
-
class Task
|
4
|
-
def github?
|
5
|
-
false
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
11
|
class GithubTask < Task
|
10
12
|
|
11
13
|
##
|
@@ -28,27 +30,63 @@ module Pomo
|
|
28
30
|
|
29
31
|
attr_accessor :number
|
30
32
|
|
33
|
+
##
|
34
|
+
# Absolute URI.
|
35
|
+
|
36
|
+
attr_accessor :url
|
37
|
+
|
31
38
|
##
|
32
39
|
# Initialize with _name_ and _options_.
|
33
40
|
|
34
|
-
def initialize
|
41
|
+
def initialize(name = nil, options = {})
|
35
42
|
super
|
36
43
|
options.each { |k,v| send :"#{k}=", v }
|
37
44
|
end
|
38
45
|
|
39
46
|
##
|
40
|
-
#
|
47
|
+
# Quoted github issue name and number.
|
41
48
|
|
42
|
-
def
|
43
|
-
|
49
|
+
def to_s
|
50
|
+
"#%-3s %s" % [ number, name]
|
44
51
|
end
|
45
52
|
|
46
53
|
##
|
47
|
-
#
|
54
|
+
# Output verbose task information.
|
48
55
|
|
49
|
-
def
|
50
|
-
|
56
|
+
def verbose_output(format)
|
57
|
+
super(format)
|
58
|
+
say format % ['labels', labels.join(', ')] if labels and not labels.empty?
|
59
|
+
say format % ['project', [username, project].join('/')]
|
60
|
+
say format % ['url', url ]
|
51
61
|
end
|
52
62
|
|
63
|
+
##
|
64
|
+
# Import Github issue(s) with _user_, _project_, _number_ as GithubTask(s).
|
65
|
+
|
66
|
+
def self.import(user, project, number)
|
67
|
+
tasks = []
|
68
|
+
if number
|
69
|
+
issues = [Octokit.issue({:username => user, :repo => project}, number)]
|
70
|
+
else
|
71
|
+
issues = Octokit.list_issues({:username => user, :repo => project}, :state => 'open', :sort => 'created')
|
72
|
+
end
|
73
|
+
|
74
|
+
issues.each do |issue|
|
75
|
+
tasks << new(issue.title,
|
76
|
+
:username => user,
|
77
|
+
:project => project,
|
78
|
+
:description => issue.body,
|
79
|
+
:labels => issue.labels.map(&:name),
|
80
|
+
:number => issue.number,
|
81
|
+
:url => issue.html_url
|
82
|
+
)
|
83
|
+
end
|
84
|
+
return tasks
|
85
|
+
rescue Octokit::NotFound => e
|
86
|
+
say "\n"
|
87
|
+
say_error '404: This is not the repo you are looking for.'
|
88
|
+
say_error e.message
|
89
|
+
abort
|
90
|
+
end
|
53
91
|
end
|
54
92
|
end
|
data/lib/pomo/list.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'yaml'
|
1
2
|
|
2
3
|
module Pomo
|
3
4
|
class List
|
@@ -15,11 +16,11 @@ module Pomo
|
|
15
16
|
##
|
16
17
|
# Initialize with _path_.
|
17
18
|
|
18
|
-
def initialize
|
19
|
+
def initialize(opts = {})
|
19
20
|
if opts[:init]
|
20
21
|
path = '.pomo'
|
21
22
|
else
|
22
|
-
path = File.exists?('.pomo') ? '.pomo' : File.join(ENV['HOME'],'.pomo')
|
23
|
+
path = (File.exists?('.pomo') && ENV['POMO_ENV']!='test') ? '.pomo' : File.join(ENV['HOME'],'.pomo')
|
23
24
|
end
|
24
25
|
@path = File.expand_path path
|
25
26
|
@tasks = []
|
@@ -35,35 +36,51 @@ module Pomo
|
|
35
36
|
# * n n n
|
36
37
|
# * n..n
|
37
38
|
# * n..-n
|
39
|
+
# * n..n n..n n..n
|
38
40
|
# * first
|
39
41
|
# * last
|
42
|
+
# * first last
|
40
43
|
# * incomplete
|
41
44
|
# * complete[d]
|
42
45
|
# * all
|
43
46
|
#
|
44
47
|
|
45
|
-
def find
|
48
|
+
def find(*args, &block)
|
46
49
|
found = []
|
47
50
|
found << tasks.first if args.empty?
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
51
|
+
|
52
|
+
args.each do |arg|
|
53
|
+
case arg
|
54
|
+
when 'all'
|
55
|
+
found = tasks
|
56
|
+
break
|
57
|
+
when 'first'
|
58
|
+
found << tasks.first
|
59
|
+
when 'last'
|
60
|
+
found << tasks.last
|
61
|
+
when 'complete'
|
62
|
+
found.concat tasks.select { |task| task.complete? }
|
63
|
+
when 'completed'
|
64
|
+
found.concat tasks.select { |task| task.complete? }
|
65
|
+
when 'incomplete'
|
66
|
+
found.concat tasks.select { |task| not task.complete? }
|
67
|
+
when /^(\d+)$/
|
68
|
+
found << tasks[$1.to_i]
|
69
|
+
when /^(\d+)\.\.(-?\d+)$/
|
70
|
+
found.concat tasks[$1.to_i..$2.to_i]
|
63
71
|
end
|
64
72
|
end
|
65
|
-
|
66
|
-
|
73
|
+
|
74
|
+
found.compact!
|
75
|
+
|
76
|
+
if block.arity == 2
|
77
|
+
found.each_with_index do |task, i|
|
78
|
+
yield task, i
|
79
|
+
end
|
80
|
+
else
|
81
|
+
found.each do |task|
|
82
|
+
yield task
|
83
|
+
end
|
67
84
|
end
|
68
85
|
end
|
69
86
|
|
@@ -77,11 +94,18 @@ module Pomo
|
|
77
94
|
##
|
78
95
|
# Add _task_ to the list in memory (requires saving).
|
79
96
|
|
80
|
-
def add
|
97
|
+
def add(task)
|
81
98
|
@tasks << task
|
82
99
|
end
|
83
100
|
alias :<< :add
|
84
101
|
|
102
|
+
##
|
103
|
+
# Move task at _from_ index to _to_ index (requres saving).
|
104
|
+
|
105
|
+
def move(from, to)
|
106
|
+
@tasks.insert(index(to), @tasks.delete_at(index(from)))
|
107
|
+
end
|
108
|
+
|
85
109
|
##
|
86
110
|
# Save the list.
|
87
111
|
|
@@ -100,5 +124,19 @@ module Pomo
|
|
100
124
|
self
|
101
125
|
end
|
102
126
|
|
127
|
+
private
|
128
|
+
|
129
|
+
def index(arg)
|
130
|
+
case arg
|
131
|
+
when 'first'
|
132
|
+
0
|
133
|
+
when 'last'
|
134
|
+
@tasks.size - 1
|
135
|
+
when /^(\d+)$/
|
136
|
+
$1.to_i
|
137
|
+
else
|
138
|
+
abort "Invalid argument: #{arg}. See 'pomo help move'"
|
139
|
+
end
|
140
|
+
end
|
103
141
|
end
|
104
142
|
end
|