hcl 0.3.2 → 0.4.1
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.
- checksums.yaml +7 -0
- data/CHANGELOG +10 -0
- data/README.markdown +22 -20
- data/Rakefile +5 -4
- data/VERSION +1 -1
- data/hcl.gemspec +19 -22
- data/lib/hcl/app.rb +56 -26
- data/lib/hcl/commands.rb +52 -22
- data/lib/hcl/day_entry.rb +4 -8
- data/lib/hcl/task.rb +9 -3
- data/lib/hcl/timesheet_resource.rb +4 -4
- data/test/day_entry_test.rb +2 -2
- data/test/test_helper.rb +1 -1
- metadata +86 -112
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 045ee48931cd77620aacf51495ce49a0e4621602
|
4
|
+
data.tar.gz: 61957cdfa90886797d896efabfcd5b7cb90db63b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ec4895148c586158a395ae08de8e225fe94cea6a2d2102e90ebd99003bd1776314d0ebf871dcbfadebb38ee22029b60b9b79b3961be1078c7dbbc676469a7b4e
|
7
|
+
data.tar.gz: 3411878c71f1f625f9b983a77041108826ea74c1f8723559ec6ccce09798a7436dfc89abac31fa765faed4f72090342f3bf1f69e9318affeb8d16a7e2008141d
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
= Recent Changes in HCl
|
2
2
|
|
3
|
+
== v0.4.1
|
4
|
+
|
5
|
+
* update dependencies
|
6
|
+
|
7
|
+
== v0.4.0
|
8
|
+
|
9
|
+
* start a timer or add a note without having to specify the sub-command
|
10
|
+
* aliases can be specified with "@" anywhere on the command line
|
11
|
+
* added alias and unalias to simplify setting task aliases
|
12
|
+
|
3
13
|
== v0.3.2
|
4
14
|
|
5
15
|
* fixed support for modern Rubies
|
data/README.markdown
CHANGED
@@ -40,51 +40,53 @@ or you can install from source using jeweler:
|
|
40
40
|
hcl stop [msg]
|
41
41
|
hcl resume
|
42
42
|
|
43
|
-
###
|
43
|
+
### Available Projects and Tasks
|
44
44
|
|
45
45
|
To start a new timer you need to identify the project and task. After you've
|
46
46
|
used the show command you can use the tasks command to view a cached list of
|
47
|
-
available tasks.
|
48
|
-
IDs. You need both values to start a timer:
|
47
|
+
available tasks.
|
49
48
|
|
50
|
-
$ hcl show
|
51
|
-
-------------
|
52
|
-
0:00 total
|
53
49
|
$ hcl tasks
|
54
|
-
1234 5678 ClientX Software Development
|
55
|
-
1234 9876 ClientX Admin
|
56
|
-
$ hcl start 1234 5678 adding a new feature
|
57
50
|
|
58
|
-
###
|
51
|
+
### Starting a Timer
|
59
52
|
|
60
53
|
Since it's not practical to enter two long numbers every time you want to
|
61
54
|
identify a task, HCl supports task aliases:
|
62
55
|
|
63
|
-
$ hcl
|
64
|
-
$ hcl
|
56
|
+
$ hcl alias xdev 1234 5678
|
57
|
+
$ hcl @xdev Adding a new feature!
|
65
58
|
|
66
59
|
### Starting a Timer with Initial Time
|
67
60
|
|
68
61
|
You can also provide an initial time when starting a new timer.
|
69
62
|
This can be expressed in floating-point or HH:MM. The following two
|
70
|
-
commands are
|
63
|
+
commands are equivalent:
|
71
64
|
|
72
|
-
$ hcl
|
73
|
-
$ hcl
|
65
|
+
$ hcl @xdev +0:15 Adding a new feature!
|
66
|
+
$ hcl +.25 @xdev Adding a new feature!
|
74
67
|
|
75
68
|
### Adding Notes to a Running Task
|
76
69
|
|
77
|
-
While a task is running you can append
|
70
|
+
While a task is running you can append lines to the task notes.
|
71
|
+
Providing the note command is optional, just the bare message will work.
|
72
|
+
These two commands are equivalent:
|
78
73
|
|
79
|
-
$ hcl
|
80
|
-
$ hcl note
|
74
|
+
$ hcl Found a good time!
|
75
|
+
$ hcl note Found a good time!
|
81
76
|
|
82
77
|
### Stopping a Timer
|
83
78
|
|
84
79
|
The following command will stop a running timer (currently only one timer at
|
85
|
-
a time is supported)
|
80
|
+
a time is supported). You can provide a message when stopping a timer as
|
81
|
+
well:
|
82
|
+
|
83
|
+
$ hcl stop All done!
|
84
|
+
|
85
|
+
### Resuming a Timer
|
86
|
+
|
87
|
+
You can easily resume the last stopped timer:
|
86
88
|
|
87
|
-
$ hcl
|
89
|
+
$ hcl resume
|
88
90
|
|
89
91
|
### Date Formats
|
90
92
|
|
data/Rakefile
CHANGED
@@ -11,12 +11,13 @@ begin
|
|
11
11
|
gem.name = "hcl"
|
12
12
|
gem.summary = "Harvest timesheets from the command-line"
|
13
13
|
gem.description = "HCl is a command-line client for manipulating Harvest time sheets."
|
14
|
-
gem.email = "zack@
|
14
|
+
gem.email = "zack@zackhobson.com"
|
15
15
|
gem.homepage = "http://github.com/zenhob/hcl"
|
16
16
|
gem.authors = ["Zack Hobson"]
|
17
|
-
gem.
|
18
|
-
gem.add_dependency "
|
19
|
-
gem.add_dependency "
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.add_dependency "trollop"
|
19
|
+
gem.add_dependency "chronic"
|
20
|
+
gem.add_dependency "highline"
|
20
21
|
gem.add_development_dependency "shoulda"
|
21
22
|
gem.add_development_dependency "mocha"
|
22
23
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.1
|
data/hcl.gemspec
CHANGED
@@ -4,15 +4,14 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "0.
|
7
|
+
s.name = "hcl"
|
8
|
+
s.version = "0.4.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Zack Hobson"]
|
12
|
-
s.date =
|
13
|
-
s.
|
14
|
-
s.
|
15
|
-
s.email = %q{zack@opensourcery.com}
|
12
|
+
s.date = "2013-11-18"
|
13
|
+
s.description = "HCl is a command-line client for manipulating Harvest time sheets."
|
14
|
+
s.email = "zack@zackhobson.com"
|
16
15
|
s.executables = ["hcl"]
|
17
16
|
s.extra_rdoc_files = [
|
18
17
|
"LICENSE",
|
@@ -41,34 +40,32 @@ Gem::Specification.new do |s|
|
|
41
40
|
"test/test_helper.rb",
|
42
41
|
"test/utility_test.rb"
|
43
42
|
]
|
44
|
-
s.homepage =
|
43
|
+
s.homepage = "http://github.com/zenhob/hcl"
|
44
|
+
s.licenses = ["MIT"]
|
45
45
|
s.require_paths = ["lib"]
|
46
|
-
s.rubygems_version =
|
47
|
-
s.summary =
|
46
|
+
s.rubygems_version = "2.0.3"
|
47
|
+
s.summary = "Harvest timesheets from the command-line"
|
48
48
|
|
49
49
|
if s.respond_to? :specification_version then
|
50
|
-
s.specification_version =
|
50
|
+
s.specification_version = 4
|
51
51
|
|
52
52
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
53
|
-
s.add_runtime_dependency(%q<
|
54
|
-
s.add_runtime_dependency(%q<
|
55
|
-
s.add_runtime_dependency(%q<
|
56
|
-
s.add_runtime_dependency(%q<highline>, [">= 1.5.1"])
|
53
|
+
s.add_runtime_dependency(%q<trollop>, [">= 0"])
|
54
|
+
s.add_runtime_dependency(%q<chronic>, [">= 0"])
|
55
|
+
s.add_runtime_dependency(%q<highline>, [">= 0"])
|
57
56
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
58
57
|
s.add_development_dependency(%q<mocha>, [">= 0"])
|
59
58
|
else
|
60
|
-
s.add_dependency(%q<
|
61
|
-
s.add_dependency(%q<
|
62
|
-
s.add_dependency(%q<
|
63
|
-
s.add_dependency(%q<highline>, [">= 1.5.1"])
|
59
|
+
s.add_dependency(%q<trollop>, [">= 0"])
|
60
|
+
s.add_dependency(%q<chronic>, [">= 0"])
|
61
|
+
s.add_dependency(%q<highline>, [">= 0"])
|
64
62
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
65
63
|
s.add_dependency(%q<mocha>, [">= 0"])
|
66
64
|
end
|
67
65
|
else
|
68
|
-
s.add_dependency(%q<
|
69
|
-
s.add_dependency(%q<
|
70
|
-
s.add_dependency(%q<
|
71
|
-
s.add_dependency(%q<highline>, [">= 1.5.1"])
|
66
|
+
s.add_dependency(%q<trollop>, [">= 0"])
|
67
|
+
s.add_dependency(%q<chronic>, [">= 0"])
|
68
|
+
s.add_dependency(%q<highline>, [">= 0"])
|
72
69
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
73
70
|
s.add_dependency(%q<mocha>, [">= 0"])
|
74
71
|
end
|
data/lib/hcl/app.rb
CHANGED
@@ -3,6 +3,7 @@ require 'yaml'
|
|
3
3
|
require 'rexml/document'
|
4
4
|
require 'net/http'
|
5
5
|
require 'net/https'
|
6
|
+
require 'fileutils'
|
6
7
|
|
7
8
|
## gem dependencies
|
8
9
|
require 'chronic'
|
@@ -35,11 +36,14 @@ module HCl
|
|
35
36
|
class App
|
36
37
|
include HCl::Utility
|
37
38
|
include HCl::Commands
|
38
|
-
|
39
|
-
SETTINGS_FILE = "#{ENV['HOME']}/.
|
40
|
-
CONFIG_FILE = "#{ENV['HOME']}/.
|
41
|
-
|
39
|
+
|
40
|
+
SETTINGS_FILE = "#{ENV['HOME']}/.hcl/settings.yml"
|
41
|
+
CONFIG_FILE = "#{ENV['HOME']}/.hcl/config.yml"
|
42
|
+
OLD_SETTINGS_FILE = "#{ENV['HOME']}/.hcl_settings"
|
43
|
+
OLD_CONFIG_FILE = "#{ENV['HOME']}/.hcl_config"
|
44
|
+
|
42
45
|
def initialize
|
46
|
+
FileUtils.mkdir_p(File.join(ENV['HOME'], ".hcl"))
|
43
47
|
read_config
|
44
48
|
read_settings
|
45
49
|
end
|
@@ -56,7 +60,15 @@ module HCl
|
|
56
60
|
def command? command
|
57
61
|
Commands.method_defined? command
|
58
62
|
end
|
59
|
-
|
63
|
+
|
64
|
+
def start_or_note *args
|
65
|
+
if DayEntry.with_timer
|
66
|
+
note *args
|
67
|
+
else
|
68
|
+
start *args
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
60
72
|
# Start the application.
|
61
73
|
def run
|
62
74
|
begin
|
@@ -71,8 +83,7 @@ module HCl
|
|
71
83
|
end
|
72
84
|
end
|
73
85
|
else
|
74
|
-
|
75
|
-
exit 1
|
86
|
+
start_or_note @command, *@args
|
76
87
|
end
|
77
88
|
else
|
78
89
|
show
|
@@ -88,7 +99,7 @@ module HCl
|
|
88
99
|
exit 1
|
89
100
|
end
|
90
101
|
end
|
91
|
-
|
102
|
+
|
92
103
|
def process_args *args
|
93
104
|
Trollop::options(args) do
|
94
105
|
stop_on Commands.instance_methods
|
@@ -97,23 +108,38 @@ module HCl
|
|
97
108
|
HCl is a command-line client for manipulating Harvest time sheets.
|
98
109
|
|
99
110
|
Commands:
|
100
|
-
|
111
|
+
# show all available tasks
|
101
112
|
hcl tasks
|
113
|
+
|
114
|
+
# set a task alias
|
115
|
+
hcl alias <task> <project_id> <task_id>
|
116
|
+
|
117
|
+
# list task aliases
|
102
118
|
hcl aliases
|
103
|
-
|
104
|
-
|
105
|
-
hcl
|
106
|
-
|
119
|
+
|
120
|
+
# start a task using an alias
|
121
|
+
hcl @<task> [+time] [message]
|
122
|
+
|
123
|
+
# display the daily timesheet
|
124
|
+
hcl show [date]
|
125
|
+
|
126
|
+
# stop a running timer
|
127
|
+
hcl stop [message]
|
128
|
+
|
129
|
+
# resume the last stopped timer
|
107
130
|
hcl resume
|
108
|
-
|
131
|
+
|
132
|
+
# add a line to your running timer
|
133
|
+
hcl note <message>
|
109
134
|
|
110
135
|
Examples:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
136
|
+
hcl alias mytask 1234 4567
|
137
|
+
hcl @mytask +:15 Doing a thing that I started 15 minutes ago.
|
138
|
+
hcl Adding a note to my running task.
|
139
|
+
hcl stop That's enough for now.
|
140
|
+
hcl resume
|
141
|
+
hcl show yesterday
|
142
|
+
hcl show last tuesday
|
117
143
|
|
118
144
|
Options:
|
119
145
|
EOM
|
@@ -124,13 +150,13 @@ EOM
|
|
124
150
|
end
|
125
151
|
|
126
152
|
protected
|
127
|
-
|
153
|
+
|
128
154
|
def read_config
|
129
155
|
if File.exists? CONFIG_FILE
|
130
156
|
config = YAML::load File.read(CONFIG_FILE)
|
131
157
|
TimesheetResource.configure config
|
132
|
-
elsif File.exists?
|
133
|
-
config = YAML::load File.read(
|
158
|
+
elsif File.exists? OLD_CONFIG_FILE
|
159
|
+
config = YAML::load File.read(OLD_CONFIG_FILE)
|
134
160
|
TimesheetResource.configure config
|
135
161
|
write_config config
|
136
162
|
else
|
@@ -144,22 +170,26 @@ EOM
|
|
144
170
|
write_config config
|
145
171
|
end
|
146
172
|
end
|
147
|
-
|
173
|
+
|
148
174
|
def write_config config
|
149
175
|
puts "Writing configuration to #{CONFIG_FILE}."
|
150
176
|
File.open(CONFIG_FILE, 'w') do |f|
|
151
177
|
f.write config.to_yaml
|
152
178
|
end
|
179
|
+
FileUtils.chmod 0400, CONFIG_FILE
|
153
180
|
end
|
154
|
-
|
181
|
+
|
155
182
|
def read_settings
|
156
183
|
if File.exists? SETTINGS_FILE
|
157
184
|
@settings = YAML.load(File.read(SETTINGS_FILE))
|
185
|
+
elsif File.exists? OLD_SETTINGS_FILE
|
186
|
+
@settings = YAML.load(File.read(OLD_SETTINGS_FILE))
|
187
|
+
write_settings
|
158
188
|
else
|
159
189
|
@settings = {}
|
160
190
|
end
|
161
191
|
end
|
162
|
-
|
192
|
+
|
163
193
|
def write_settings
|
164
194
|
File.open(SETTINGS_FILE, 'w') do |f|
|
165
195
|
f.write @settings.to_yaml
|
data/lib/hcl/commands.rb
CHANGED
@@ -9,7 +9,7 @@ module HCl
|
|
9
9
|
end
|
10
10
|
nil
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def set key = nil, *args
|
14
14
|
if key.nil?
|
15
15
|
@settings.each do |k, v|
|
@@ -23,37 +23,66 @@ module HCl
|
|
23
23
|
end
|
24
24
|
nil
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
def unset key
|
28
28
|
@settings.delete key
|
29
29
|
write_settings
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
|
+
def unalias task
|
33
|
+
unset "task.#{task}"
|
34
|
+
puts "Removed task alias @#{task}."
|
35
|
+
end
|
36
|
+
|
37
|
+
def alias task_name, *value
|
38
|
+
task = Task.find *value
|
39
|
+
if task
|
40
|
+
set "task.#{task_name}", *value
|
41
|
+
puts "Added alias @#{task_name} for #{task}."
|
42
|
+
else
|
43
|
+
puts "Unrecognized project and task ID: #{value.inspect}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
32
47
|
def aliases
|
33
|
-
@settings.keys.select { |s| s =~ /^task\./ }.map { |s| s.slice(5..-1) }
|
48
|
+
@settings.keys.select { |s| s =~ /^task\./ }.map { |s| "@"+s.slice(5..-1) }
|
34
49
|
end
|
35
|
-
|
50
|
+
|
36
51
|
def start *args
|
37
52
|
starting_time = args.detect {|x| x =~ /^\+\d*(\.|:)?\d+$/ }
|
38
53
|
if starting_time
|
39
54
|
args.delete(starting_time)
|
40
55
|
starting_time = time2float starting_time
|
41
56
|
end
|
42
|
-
ident = args.
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
57
|
+
ident = args.detect {|a| a[0] == '@' }
|
58
|
+
if ident
|
59
|
+
args.delete(ident)
|
60
|
+
ident = ident.slice(1..-1)
|
61
|
+
else
|
62
|
+
ident = args.shift
|
63
|
+
end
|
64
|
+
if ident
|
65
|
+
task_ids = if @settings.key? "task.#{ident}"
|
66
|
+
@settings["task.#{ident}"].split(/\s+/)
|
67
|
+
else
|
68
|
+
[ident, args.shift]
|
69
|
+
end
|
70
|
+
task = Task.find *task_ids
|
71
|
+
if task.nil?
|
72
|
+
puts "Unknown task alias, try one of the following: ", aliases.join(', ')
|
73
|
+
exit 1
|
47
74
|
end
|
48
|
-
|
49
|
-
|
50
|
-
|
75
|
+
timer = task.start(
|
76
|
+
:starting_time => starting_time,
|
77
|
+
:note => args.join(' ')
|
78
|
+
)
|
79
|
+
puts "Started timer for #{timer} (at #{current_time})"
|
80
|
+
else
|
81
|
+
puts "You must provide a task alias to start a timer:", aliases.join(', ')
|
51
82
|
exit 1
|
52
83
|
end
|
53
|
-
timer = task.start(:starting_time => starting_time, :note => args.join(' '))
|
54
|
-
puts "Started timer for #{timer} (at #{current_time})"
|
55
84
|
end
|
56
|
-
|
85
|
+
|
57
86
|
def stop *args
|
58
87
|
entry = DayEntry.with_timer
|
59
88
|
if entry
|
@@ -64,30 +93,31 @@ module HCl
|
|
64
93
|
puts "No running timers found."
|
65
94
|
end
|
66
95
|
end
|
67
|
-
|
96
|
+
|
68
97
|
def note *args
|
69
98
|
message = args.join ' '
|
70
99
|
entry = DayEntry.with_timer
|
71
100
|
if entry
|
72
101
|
entry.append_note message
|
73
|
-
puts "Added note
|
102
|
+
puts "Added note to #{entry}."
|
74
103
|
else
|
75
104
|
puts "No running timers found."
|
76
105
|
end
|
77
106
|
end
|
78
|
-
|
107
|
+
|
79
108
|
def show *args
|
80
109
|
date = args.empty? ? nil : Chronic.parse(args.join(' '))
|
81
110
|
total_hours = 0.0
|
82
111
|
DayEntry.all(date).each do |day|
|
83
112
|
running = day.running? ? '(running) ' : ''
|
84
|
-
|
113
|
+
columns = HighLine::SystemExtensions.terminal_size[0]
|
114
|
+
puts "\t#{day.formatted_hours}\t#{running}#{day.project}: #{day.notes.lines.last}"[0..columns-1]
|
85
115
|
total_hours = total_hours + day.hours.to_f
|
86
116
|
end
|
87
117
|
puts "\t" + '-' * 13
|
88
118
|
puts "\t#{as_hours total_hours}\ttotal (as of #{current_time})"
|
89
119
|
end
|
90
|
-
|
120
|
+
|
91
121
|
def resume
|
92
122
|
entry = DayEntry.last
|
93
123
|
if entry
|
@@ -97,7 +127,7 @@ module HCl
|
|
97
127
|
puts "No timers found"
|
98
128
|
end
|
99
129
|
end
|
100
|
-
|
130
|
+
|
101
131
|
private
|
102
132
|
def current_time
|
103
133
|
Time.now.strftime('%I:%M %p').downcase
|
data/lib/hcl/day_entry.rb
CHANGED
@@ -31,18 +31,15 @@ module HCl
|
|
31
31
|
def append_note new_notes
|
32
32
|
# If I don't include hours it gets reset.
|
33
33
|
# This doens't appear to be the case for task and project.
|
34
|
-
|
35
|
-
|
36
|
-
<notes>#{notes
|
37
|
-
<hours>#{hours}</hours>
|
38
|
-
</request>
|
39
|
-
EOD
|
34
|
+
(self.notes << "\n#{new_notes}").lstrip!
|
35
|
+
DayEntry.post "daily/update/#{id}",
|
36
|
+
%{<request><notes>#{notes}</notes><hours>#{hours}</hours></request>}
|
40
37
|
end
|
41
38
|
|
42
39
|
def self.with_timer
|
43
40
|
all.detect {|t| t.running? }
|
44
41
|
end
|
45
|
-
|
42
|
+
|
46
43
|
def self.last
|
47
44
|
all.sort {|a,b| a.updated_at<=>b.updated_at}[-1]
|
48
45
|
end
|
@@ -65,6 +62,5 @@ module HCl
|
|
65
62
|
def formatted_hours
|
66
63
|
as_hours hours
|
67
64
|
end
|
68
|
-
|
69
65
|
end
|
70
66
|
end
|
data/lib/hcl/task.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
1
3
|
module HCl
|
2
4
|
class Task < TimesheetResource
|
3
5
|
def self.cache_tasks doc
|
@@ -9,14 +11,19 @@ module HCl
|
|
9
11
|
end)
|
10
12
|
end
|
11
13
|
unless tasks.empty?
|
14
|
+
FileUtils.mkdir_p(cache_dir)
|
12
15
|
File.open(cache_file, 'w') do |f|
|
13
16
|
f.write tasks.uniq.to_yaml
|
14
17
|
end
|
15
18
|
end
|
16
19
|
end
|
17
|
-
|
20
|
+
|
18
21
|
def self.cache_file
|
19
|
-
File.join(
|
22
|
+
File.join(cache_dir, 'tasks.yml')
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.cache_dir
|
26
|
+
File.join(ENV['HOME'],'.hcl/cache')
|
20
27
|
end
|
21
28
|
|
22
29
|
def self.all
|
@@ -63,7 +70,6 @@ module HCl
|
|
63
70
|
DayEntry.from_xml(Task.get("daily/timer/#{day.id}")).first
|
64
71
|
end
|
65
72
|
end
|
66
|
-
|
67
73
|
end
|
68
74
|
end
|
69
75
|
|
@@ -12,7 +12,7 @@ module HCl
|
|
12
12
|
yield self
|
13
13
|
end
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
# configuration accessors
|
17
17
|
%w[ login password subdomain ssl ].each do |config_var|
|
18
18
|
class_eval <<-EOC
|
@@ -24,11 +24,11 @@ module HCl
|
|
24
24
|
end
|
25
25
|
EOC
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def initialize params
|
29
29
|
@data = params
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def self.get action
|
33
33
|
http_do Net::HTTP::Get, action
|
34
34
|
end
|
@@ -53,7 +53,7 @@ module HCl
|
|
53
53
|
raise Failure, "Unexpected response from the upstream API"
|
54
54
|
end
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
def id
|
58
58
|
@data[:id]
|
59
59
|
end
|
data/test/day_entry_test.rb
CHANGED
@@ -37,13 +37,13 @@ class DayEntryTest < Test::Unit::TestCase
|
|
37
37
|
entry = HCl::DayEntry.new(:id => '1', :notes => 'yourmom.', :hours => '1.0')
|
38
38
|
HCl::DayEntry.stubs(:post)
|
39
39
|
entry.append_note('hi world')
|
40
|
-
assert_equal
|
40
|
+
assert_equal "yourmom.\nhi world", entry.notes
|
41
41
|
end
|
42
42
|
|
43
43
|
should "append to an undefined note" do
|
44
44
|
entry = HCl::DayEntry.new(:id => '1', :notes => nil, :hours => '1.0')
|
45
45
|
HCl::DayEntry.stubs(:post)
|
46
46
|
entry.append_note('hi world')
|
47
|
-
assert_equal '
|
47
|
+
assert_equal 'hi world', entry.notes
|
48
48
|
end
|
49
49
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,109 +1,94 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: hcl
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 3
|
9
|
-
- 2
|
10
|
-
version: 0.3.2
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.1
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Zack Hobson
|
14
8
|
autorequire:
|
15
9
|
bindir: bin
|
16
10
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
11
|
+
date: 2013-11-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
22
14
|
name: trollop
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
hash: 59
|
30
|
-
segments:
|
31
|
-
- 1
|
32
|
-
- 10
|
33
|
-
- 2
|
34
|
-
version: 1.10.2
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
35
20
|
type: :runtime
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: chronic
|
39
21
|
prerelease: false
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: chronic
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
51
34
|
type: :runtime
|
52
|
-
version_requirements: *id002
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: highline
|
55
35
|
prerelease: false
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: highline
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
67
48
|
type: :runtime
|
68
|
-
version_requirements: *id003
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: shoulda
|
71
49
|
prerelease: false
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: shoulda
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
81
62
|
type: :development
|
82
|
-
version_requirements: *id004
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: mocha
|
85
63
|
prerelease: false
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mocha
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
95
76
|
type: :development
|
96
|
-
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
97
83
|
description: HCl is a command-line client for manipulating Harvest time sheets.
|
98
|
-
email: zack@
|
99
|
-
executables:
|
84
|
+
email: zack@zackhobson.com
|
85
|
+
executables:
|
100
86
|
- hcl
|
101
87
|
extensions: []
|
102
|
-
|
103
|
-
extra_rdoc_files:
|
88
|
+
extra_rdoc_files:
|
104
89
|
- LICENSE
|
105
90
|
- README.markdown
|
106
|
-
files:
|
91
|
+
files:
|
107
92
|
- .document
|
108
93
|
- CHANGELOG
|
109
94
|
- HACKING.markdown
|
@@ -125,39 +110,28 @@ files:
|
|
125
110
|
- test/day_entry_test.rb
|
126
111
|
- test/test_helper.rb
|
127
112
|
- test/utility_test.rb
|
128
|
-
has_rdoc: true
|
129
113
|
homepage: http://github.com/zenhob/hcl
|
130
|
-
licenses:
|
131
|
-
|
114
|
+
licenses:
|
115
|
+
- MIT
|
116
|
+
metadata: {}
|
132
117
|
post_install_message:
|
133
118
|
rdoc_options: []
|
134
|
-
|
135
|
-
require_paths:
|
119
|
+
require_paths:
|
136
120
|
- lib
|
137
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
none: false
|
148
|
-
requirements:
|
149
|
-
- - ">="
|
150
|
-
- !ruby/object:Gem::Version
|
151
|
-
hash: 3
|
152
|
-
segments:
|
153
|
-
- 0
|
154
|
-
version: "0"
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
155
131
|
requirements: []
|
156
|
-
|
157
132
|
rubyforge_project:
|
158
|
-
rubygems_version:
|
133
|
+
rubygems_version: 2.0.3
|
159
134
|
signing_key:
|
160
|
-
specification_version:
|
135
|
+
specification_version: 4
|
161
136
|
summary: Harvest timesheets from the command-line
|
162
137
|
test_files: []
|
163
|
-
|