frecli 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa2a056d45476409699fa4a851d0cf52f70484bb
4
- data.tar.gz: 4322731614f81187010f2a5fe85c819278c2f3cf
3
+ metadata.gz: 16f3a566c8afc7aab09f9214e42ac57d5ab0e247
4
+ data.tar.gz: 6e49c3f9e9b561da01918ac677e1f5e36dffd7d2
5
5
  SHA512:
6
- metadata.gz: b954dcfcbee6b3f9f7c82f1f57230c974ca594cf889a30c6b058416ddce7c5d0b9bc2baf8c9a4d41a9460e7603d60c88291f827a1b6a543b26cd6f3451afe805
7
- data.tar.gz: 25822400a7b82abef2cb660251d68af0f53af1c4f73afd6d797b9383dd2f7c4397195bdd9c5b268c160d1969e6773b452be19387b8ec2b7d4722050283da5e86
6
+ metadata.gz: a14af37475312f06d8582ca8997616099ec3f2feb3c340140a3e88ec3ad61f920d46fb6400c0b6bc395bacd032d7583dc9ea955cb0955b7a46bda4f1eb40d91d
7
+ data.tar.gz: 5bd67c5fc7417e1ea33188eaf04007fa12962eab01529d84e98a850d7a438d880dd4b6d9e026222580c99488fcc0d253352fdbd58a11917d662ce9d302843c6a
data/README.md CHANGED
@@ -7,15 +7,49 @@ Freckle CLI client in Ruby.
7
7
  [![Code Climate](https://codeclimate.com/github/shkm/frecli/badges/gpa.svg)](https://codeclimate.com/github/shkm/frecli)
8
8
  [![Test Coverage](https://codeclimate.com/github/shkm/frecli/badges/coverage.svg)](https://codeclimate.com/github/shkm/frecli/coverage)
9
9
 
10
- ## What it does right now
10
+ ## What you can do with it right now
11
11
 
12
- This is still very basic and in development, but some functionality works. I'm working on both this and the API client behind it ([freckle-api](https://github.com/shkm/freckle-api)) consecutively.
12
+ - Basic time tracking (start, pause, log)
13
13
 
14
+ I'd eventually like FreCLI to be a real alternative UI for interacting with Freckle, but have had to scale it down in the short-term due to time constraints. Currently, I'd like to get basic time tracking and logging nailed, as that's the most interesting functionality to me and those around me.
14
15
 
15
- ### Projects
16
+ Having said that, I do intend to implement considerably more features. Also note that I'm working on the API client behind this, [freckle-api](https://github.com/shkm/freckle-api), as FreCLI is developed.
16
17
 
17
- - `projects` lists all projects available to you
18
- - `project ID` list the given project's attributes by its ID.
18
+
19
+ ## Commands
20
+
21
+ ### `frecli time`
22
+
23
+ Presents you with a list of projects. Simply enter the number of the project you'd like to time, and away you go.
24
+
25
+ ### `frecli status`
26
+
27
+ Displays the time on the running timer, if there is one.
28
+
29
+ ### `frecli pause`
30
+
31
+ Pauses the running timer.
32
+
33
+ ### `frecli log [description]`
34
+
35
+ Logs the current timer, adding a description if one is given.
36
+
37
+
38
+ ## TODO
39
+
40
+ - Daily report (time logged, unlogged, total)
41
+ - More specs
42
+ - Log timers of other projects
43
+ - Deal with exceptions / errors
44
+ - Project selection via settings
45
+ - Caching
46
+ - Expanded reports (e.g. weekly, monthly, with natural time parsing)
47
+ - Various report outputs (e.g. stdout, csv, html)
48
+ - Administrative features
49
+ - Project management
50
+ - Invoices
51
+ - Tags
52
+ - Reports for other users
19
53
 
20
54
  ## Configuration
21
55
 
@@ -80,5 +114,5 @@ fi
80
114
  ```
81
115
 
82
116
  ## Thanks
83
- - My work, [Lico Innovations](http://lico.nl/) for using Freckle :-)
117
+ - My work, [Lico Innovations](http://lico.nl/) for using Freckle and employing the coolest kids in town (I'm the exception).
84
118
  - The awesome Freckle developers — Thomas Cannon in particular — who shared interest in this project and even gave me a free account for testing!
data/bin/frecli CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'gli'
4
- require 'frecli/table'
5
4
  require 'frecli'
6
5
 
7
6
  include GLI::App
@@ -14,102 +13,37 @@ version Frecli::VERSION
14
13
  subcommand_option_handling :normal
15
14
  arguments :strict
16
15
 
17
- desc 'Manage projects'
18
- command [:project, :projects, :p] do |c|
19
- c.desc 'List all projects'
20
- c.command [:all, :a] do |all|
21
- all.action do
22
- puts Frecli::Table.vertical(
23
- Frecli.projects,
24
- [ 'ID', 'Name', 'Date created', 'Date updated' ],
25
- [ :id, :name, :created_at, :updated_at ]
26
- )
27
- end
16
+ desc 'Shows the current timing status'
17
+ command :status do |c|
18
+ c.action do
19
+ Frecli::Cli.status
28
20
  end
29
-
30
- c.desc 'Show a project'
31
- c.arg :id, :required
32
- c.command [:show, :s] do |show|
33
- show.action do |_, _, args|
34
- id = args[0]
35
-
36
- puts Frecli::Table.horizontal(
37
- Frecli.project(id),
38
- { ID: :id,
39
- Name: :name,
40
- Minutes: :minutes }
41
- )
42
- end
43
- end
44
-
45
- c.desc 'Show the currently timed project'
46
- c.command [:current, :c] do |current|
47
- current.action do
48
-
49
- # TODO: DRY
50
- puts Frecli::Table.horizontal(
51
- Frecli.project_current,
52
- { ID: :id,
53
- Name: :name,
54
- Minutes: :minutes }
55
- )
56
- end
57
- end
58
-
59
- c.default_command :current
60
21
  end
61
22
 
62
- desc 'Manage timers'
63
- command [:timer, :timers, :t] do |c|
64
- c.desc 'List all timers'
65
- c.command [:all, :a] do |all|
66
- all.action do
67
- puts Frecli::Table.vertical(
68
- Frecli.timers,
69
- [ 'Project ID', 'State', 'Time', 'Date' ],
70
- [ -> (timer) { timer.project.id }, :state, :formatted_time, :date ]
71
- )
72
- end
23
+ desc 'Times a project'
24
+ command :time do |c|
25
+ c.action do
26
+ Frecli::Cli.time
73
27
  end
28
+ end
74
29
 
75
- c.desc 'Show a timer'
76
- c.arg :id, :required
77
- c.command [:show, :s] do |show|
78
- show.action do |_, _, args|
79
- project_id = args[0]
80
-
81
-
82
- # TODO: DRY
83
- puts Frecli::Table.horizontal(
84
- Frecli.timer(project_id),
85
- { ID: :id,
86
- State: :state,
87
- Time: :formatted_time,
88
- Description: :description }
89
- )
90
- end
30
+ desc 'Pauses the running timer'
31
+ command :pause do |c|
32
+ c.action do
33
+ Frecli::Cli.pause
91
34
  end
35
+ end
92
36
 
93
- c.desc 'Show the current timer'
94
- c.command [:current, :c] do |current|
95
- current.action do
37
+ desc 'Logs the running timer'
38
+ arg_name 'description', :optional
39
+ command :log do |c|
40
+ c.action do |_, _, args|
41
+ description = args.shift.to_s
96
42
 
97
- # TODO: DRY
98
- puts Frecli::Table.horizontal(
99
- Frecli.timer_current,
100
- { ID: :id,
101
- State: :state,
102
- Time: :formatted_time,
103
- Description: :description }
104
- )
105
- end
43
+ Frecli::Cli.log(description)
106
44
  end
107
-
108
- c.default_command :current
109
45
  end
110
46
 
111
-
112
-
113
47
  pre do |global,command,options,args|
114
48
  # Pre logic here
115
49
  # Return true to proceed; false to abort and not call the
data/lib/frecli.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'frecli/version.rb'
2
2
  require 'frecli/settings.rb'
3
3
  require 'frecli/queries.rb'
4
+ require 'frecli/cli.rb'
5
+
4
6
  require 'freckle_api'
5
7
  require 'json'
6
8
 
data/lib/frecli/cli.rb ADDED
@@ -0,0 +1,69 @@
1
+ class Frecli
2
+ module Cli
3
+ def self.status
4
+ timer = Frecli.timer_current
5
+
6
+ if timer
7
+ puts "Timer running on #{timer.project.name} (#{timer.formatted_time})."
8
+ else
9
+ puts "No timer running."
10
+ end
11
+ end
12
+
13
+ def self.time
14
+ projects = Frecli.projects.sort { |x, y| x.name <=> y.name }
15
+
16
+ puts "Select a project to time:\n\n"
17
+
18
+ projects.each_with_index do |project, i|
19
+ puts "[#{i + 1}] #{project.name}"
20
+ end
21
+
22
+ print "\n\nProject: "
23
+
24
+ selection = STDIN.gets.chomp.to_i
25
+
26
+ unless (1..projects.count).include? selection
27
+ puts "Project invalid."
28
+
29
+ return
30
+ end
31
+
32
+ project = projects[selection - 1]
33
+ timer = Frecli.timer_start(project)
34
+
35
+ puts "Now timing #{project.name} (#{timer.formatted_time})."
36
+ end
37
+
38
+ def self.pause
39
+ timer = Frecli.timer_current
40
+
41
+ unless timer
42
+ puts 'No timer running.'
43
+ return
44
+ end
45
+
46
+ if Frecli.timer_pause(timer)
47
+ puts "Paused #{timer.project.name} (#{timer.formatted_time})."
48
+ else
49
+ puts 'Could not pause timer.'
50
+ end
51
+ end
52
+
53
+ def self.log(description = '')
54
+ timer = Frecli.timer_current
55
+
56
+ unless timer
57
+ puts 'No timer running.'
58
+ return
59
+ end
60
+
61
+ if Frecli.timer_log(timer, description)
62
+ puts "Logged #{timer.project.name} (#{timer.formatted_time})."
63
+ puts %Q("#{description}") unless description.empty?
64
+ else
65
+ puts 'Could not log timer.'
66
+ end
67
+ end
68
+ end
69
+ end
@@ -9,15 +9,6 @@ class Frecli
9
9
  @api = FreckleApi.new(Settings[:api_key])
10
10
  end
11
11
 
12
- # The project which is currently being timed.
13
- def project_current
14
- project_id = timer_current.project.id
15
-
16
- # TODO: use a reload method instead.
17
- sleep 0.5
18
- project(project_id)
19
- end
20
-
21
12
  def projects
22
13
  api.projects
23
14
  end
@@ -26,18 +17,31 @@ class Frecli
26
17
  api.project(id)
27
18
  end
28
19
 
20
+ def timers
21
+ api.timers
22
+ end
23
+
24
+ def timer_log(timer, description = nil)
25
+ timer.log!(api, description: description)
26
+ end
27
+
28
+ def timer(project_id = nil)
29
+ api.timer(project_id) || timer_current
30
+ end
31
+
29
32
  def timer_current
30
33
  timers.detect { |timer| timer.state == :running }
31
34
  end
32
35
 
33
- def timers
34
- api.timers
36
+ def timer_start(project)
37
+ FreckleApi::Timer.new(project: project).tap do |timer|
38
+ timer.start!(api)
39
+ end
35
40
  end
36
41
 
37
- def timer(project_id)
38
- api.timer(project_id)
42
+ def timer_pause(timer)
43
+ timer.pause!(api)
39
44
  end
40
-
41
45
  end
42
46
  end
43
47
  end
@@ -1,3 +1,3 @@
1
1
  class Frecli
2
- VERSION = '0.3.0'
2
+ VERSION = '0.4.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frecli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jamie Schembri
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-02 00:00:00.000000000 Z
11
+ date: 2016-01-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -122,34 +122,20 @@ dependencies:
122
122
  - - "~>"
123
123
  - !ruby/object:Gem::Version
124
124
  version: '2.13'
125
- - !ruby/object:Gem::Dependency
126
- name: terminal-table
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: '1.5'
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: '1.5'
139
125
  - !ruby/object:Gem::Dependency
140
126
  name: freckle-api
141
127
  requirement: !ruby/object:Gem::Requirement
142
128
  requirements:
143
129
  - - "~>"
144
130
  - !ruby/object:Gem::Version
145
- version: 0.1.4
131
+ version: 0.1.6
146
132
  type: :runtime
147
133
  prerelease: false
148
134
  version_requirements: !ruby/object:Gem::Requirement
149
135
  requirements:
150
136
  - - "~>"
151
137
  - !ruby/object:Gem::Version
152
- version: 0.1.4
138
+ version: 0.1.6
153
139
  description:
154
140
  email: jamie@schembri.me
155
141
  executables:
@@ -162,9 +148,9 @@ files:
162
148
  - bin/frecli
163
149
  - frecli.rdoc
164
150
  - lib/frecli.rb
151
+ - lib/frecli/cli.rb
165
152
  - lib/frecli/queries.rb
166
153
  - lib/frecli/settings.rb
167
- - lib/frecli/table.rb
168
154
  - lib/frecli/version.rb
169
155
  - spec/frecli/frecli_spec.rb
170
156
  - spec/frecli/settings_spec.rb
data/lib/frecli/table.rb DELETED
@@ -1,61 +0,0 @@
1
- require 'terminal-table'
2
-
3
- class Frecli
4
- module Table
5
- # Table where heading is in the first row,
6
- # and values are in the columns
7
- #
8
- # When records = [ { id: 1, name: 'Hello', body: 'Hello, world!' } ]
9
- # headings = 'ID', 'Name', 'Body']
10
- # values = [ :id, :name, :body]
11
- # +----------------------------+
12
- # | ID | Name | Body |
13
- # +----------------------------+
14
- # | 1 | Hello | Hello, world! |
15
- # +----------------------------+
16
- def self.vertical(records, headings, values)
17
- Terminal::Table.new do |table|
18
-
19
- table.headings = headings
20
- table.rows = records.map do |record|
21
- values.map { |value| table_item(record, value)}
22
- end
23
- end
24
- end
25
-
26
- # Table where heading is in the first column,
27
- # and value in the second.
28
- #
29
- # When records = [ { id: 1, name: 'Hello', body: 'Hello, world!' } ]
30
- # items = [ { ID: :id, Name: :name, Body: :body } ]
31
- # +----------------------+
32
- # | ID | 1 |
33
- # | Name | Hello |
34
- # | Body | Hello, world! |
35
- # +----------------------+
36
- def self.horizontal(record, items)
37
- Terminal::Table.new do |table|
38
- table.rows = items.map do |name, value|
39
- [name, table_item(record, value)]
40
- end
41
- end
42
- end
43
-
44
- # When record = { id: 1, name: 'Hello', body: 'Hello, world!' }
45
- #
46
- # value = :id
47
- # => 1
48
- #
49
- # value = -> (record) { record.name.upcase }
50
- # => 'HELLO'
51
- #
52
- # value = 'foo'
53
- # => 'foo'
54
- def self.table_item(record, value)
55
- return record[value] if value.is_a? Symbol
56
- return value[record] if value.respond_to? :call
57
-
58
- value
59
- end
60
- end
61
- end