prb 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +14 -3
- data/README.md +32 -16
- data/exe/prb +20 -9
- data/lib/prb.rb +6 -0
- data/lib/prb/command_runner.rb +22 -28
- data/lib/prb/opts.rb +16 -0
- data/lib/prb/server.rb +24 -60
- data/lib/prb/timer.rb +35 -19
- data/lib/prb/timer_control.rb +15 -24
- data/lib/prb/version.rb +1 -1
- data/prb.gemspec +2 -1
- metadata +21 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d09ffeecc26a41b306564b20a9e9acc62d5cbbfd9b03a16684ae0204f289717e
|
4
|
+
data.tar.gz: 0d6615043f85ff16ab3f4da9c5e2c5fa17525d16c6425b32d210898084683680
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d5c9433e04646ea3467add2f8915cdb2ccd6c2ecb8a1dfcd6118a46f42593b0db22ab0a210316b90de478a38939a401b9e80fabbe602c9dd20c49e2036fd58cd
|
7
|
+
data.tar.gz: 8836c99454be9f1cbaf3a1f63c1104c3437ed350b5db9abe656fc417ff2976be188052e1b4194f349851588b9e17e479f5396350a77da42c2f925d28d627a21b
|
data/Gemfile.lock
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
prb (0.
|
5
|
-
optimist
|
4
|
+
prb (0.2.0)
|
5
|
+
optimist (~> 3.0)
|
6
|
+
sinatra (~> 2.0)
|
6
7
|
|
7
8
|
GEM
|
8
9
|
remote: https://rubygems.org/
|
9
10
|
specs:
|
10
11
|
diff-lcs (1.3)
|
12
|
+
mustermann (1.0.3)
|
11
13
|
optimist (3.0.0)
|
14
|
+
rack (2.0.7)
|
15
|
+
rack-protection (2.0.7)
|
16
|
+
rack
|
12
17
|
rake (10.5.0)
|
13
18
|
rspec (3.8.0)
|
14
19
|
rspec-core (~> 3.8.0)
|
@@ -23,6 +28,12 @@ GEM
|
|
23
28
|
diff-lcs (>= 1.2.0, < 2.0)
|
24
29
|
rspec-support (~> 3.8.0)
|
25
30
|
rspec-support (3.8.0)
|
31
|
+
sinatra (2.0.7)
|
32
|
+
mustermann (~> 1.0)
|
33
|
+
rack (~> 2.0)
|
34
|
+
rack-protection (= 2.0.7)
|
35
|
+
tilt (~> 2.0)
|
36
|
+
tilt (2.0.10)
|
26
37
|
|
27
38
|
PLATFORMS
|
28
39
|
ruby
|
@@ -34,4 +45,4 @@ DEPENDENCIES
|
|
34
45
|
rspec (~> 3.0)
|
35
46
|
|
36
47
|
BUNDLED WITH
|
37
|
-
2.0.
|
48
|
+
2.0.2
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Prb
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
Prb is a light-weight HTTP service written in Ruby for controlling a pomodoro
|
4
|
+
timer.
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
@@ -11,24 +11,40 @@ Install the gem
|
|
11
11
|
|
12
12
|
## Usage
|
13
13
|
|
14
|
+
The promodoro timer can be started using `prb start -d` where `-d` will
|
15
|
+
run the process in the background.
|
16
|
+
|
17
|
+
```
|
18
|
+
prb start -d
|
19
|
+
```
|
20
|
+
|
21
|
+
Options can be passed to configure the timer. By default, there are 4 pomodoro's
|
22
|
+
each taking 25 minutes to complete. You can override this behaviour using the
|
23
|
+
following command:
|
24
|
+
|
25
|
+
```
|
26
|
+
prb start -d --pomodoros=4 --timer=25
|
14
27
|
```
|
15
|
-
prb v0.1.0 - Pomodoro timer service
|
16
28
|
|
17
|
-
|
18
|
-
|
29
|
+
After starting the service you can query the timers status over HTTP using
|
30
|
+
`curl`:
|
19
31
|
|
20
|
-
|
21
|
-
|
32
|
+
```
|
33
|
+
curl http://localhost:3838/status
|
34
|
+
|
35
|
+
{
|
36
|
+
"running" true,
|
37
|
+
"completed": 0, # completed pomodoros
|
38
|
+
"remaining": 4, # remaining pomodoros
|
39
|
+
"time_remaining": 440
|
40
|
+
}
|
41
|
+
```
|
22
42
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
reset Reset the current timer
|
29
|
-
pause Pause the current timer
|
30
|
-
-v, --version Print version and exit
|
31
|
-
-h, --help Show this message
|
43
|
+
After each pomodoro the timer will stop. The timer can be resumed
|
44
|
+
and the next pomodoro started by using `prb resume` or by `curl` request:
|
45
|
+
|
46
|
+
```
|
47
|
+
curl http://localhost:3838/resume
|
32
48
|
```
|
33
49
|
|
34
50
|
## Development
|
data/exe/prb
CHANGED
@@ -1,31 +1,42 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require "optimist"
|
4
|
+
require "webrick"
|
4
5
|
require "bundler/setup"
|
5
6
|
require "prb"
|
6
7
|
|
7
8
|
COMMAND_MAP = {
|
8
9
|
'start' => 'Start pomodoro service',
|
9
|
-
'
|
10
|
-
'
|
11
|
-
'skip' => 'Skip the current timer',
|
12
|
-
'reset' => 'Reset the current timer',
|
13
|
-
'pause' => 'Pause the current timer'
|
10
|
+
'resume' => 'Resume pomodoro timer',
|
11
|
+
'stop' => 'Stop pomodoro service'
|
14
12
|
}
|
15
13
|
|
16
|
-
|
14
|
+
global_opts = Optimist::options do
|
17
15
|
version "prb v#{Prb::VERSION}"
|
18
16
|
banner "prb v#{Prb::VERSION} - Pomodoro timer service\n \n"
|
19
17
|
banner "Usage:"
|
20
|
-
banner " prb [COMMAND] [SUB_COMMAND]\n
|
21
|
-
banner "Options:"
|
22
|
-
opt :daemonize, 'Start the service in the background', short: '-d'
|
18
|
+
banner " prb [COMMAND] [SUB_COMMAND]\n"
|
23
19
|
banner "\nCommands:"
|
24
20
|
COMMAND_MAP.each { |cmd, desc| banner format(" %-10s %s", cmd, desc) }
|
21
|
+
|
22
|
+
stop_on COMMAND_MAP.keys
|
25
23
|
end
|
26
24
|
|
27
25
|
commands = COMMAND_MAP.keys & ARGV
|
28
26
|
cmd = commands.first
|
27
|
+
opts = {}
|
28
|
+
|
29
|
+
case cmd
|
30
|
+
when "start"
|
31
|
+
opts = Optimist::options do
|
32
|
+
opt :pomodoros, "Number of pomodoros", default: 4
|
33
|
+
opt :timer, "The time in minutes for the timer", default: 25
|
34
|
+
opt :port, "The port to run the pomodoro HTTP server", default: 3838
|
35
|
+
opt :daemonize, 'Start the service in the background', short: '-d'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
opts = opts.merge(global_opts)
|
29
40
|
|
30
41
|
if COMMAND_MAP.keys.include?(cmd)
|
31
42
|
Prb::CommandRunner.new(opts).send(cmd)
|
data/lib/prb.rb
CHANGED
data/lib/prb/command_runner.rb
CHANGED
@@ -1,57 +1,51 @@
|
|
1
1
|
module Prb
|
2
2
|
class CommandRunner
|
3
3
|
def initialize(opts)
|
4
|
-
@opts = opts
|
4
|
+
@opts = Opts.new(opts)
|
5
5
|
end
|
6
6
|
|
7
7
|
def start
|
8
|
-
if
|
8
|
+
if running?(@opts.port)
|
9
9
|
puts "A prb server is already running."
|
10
10
|
exit(1)
|
11
11
|
end
|
12
12
|
|
13
|
-
Process.daemon() if @opts
|
13
|
+
Process.daemon() if @opts.daemonize?
|
14
14
|
|
15
|
-
Prb::Server.new
|
15
|
+
app = Prb::Server.new(@opts)
|
16
|
+
Rack::Server.start(
|
17
|
+
app: app,
|
18
|
+
Port: @opts.port
|
19
|
+
)
|
16
20
|
end
|
17
21
|
|
18
|
-
def
|
19
|
-
|
20
|
-
puts response
|
21
|
-
end
|
22
|
-
|
23
|
-
def skip
|
24
|
-
send_command('SKIP')
|
25
|
-
end
|
26
|
-
|
27
|
-
def pause
|
28
|
-
send_command('PAUSE')
|
29
|
-
end
|
30
|
-
|
31
|
-
def reset
|
32
|
-
send_command('RESET')
|
22
|
+
def resume
|
23
|
+
send_request('resume')
|
33
24
|
end
|
34
25
|
|
35
26
|
def stop
|
36
|
-
|
27
|
+
send_request('stop')
|
37
28
|
end
|
38
29
|
|
39
30
|
private
|
40
31
|
|
41
|
-
def
|
32
|
+
def send_request(endpoint)
|
33
|
+
uri = URI.parse("http://0.0.0.0:#{@opts.port}/#{endpoint}")
|
34
|
+
Net::HTTP.get_response(uri)
|
35
|
+
rescue
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def running?(port)
|
42
40
|
Timeout::timeout(1) do
|
43
41
|
begin
|
44
|
-
s = TCPSocket.new('
|
45
|
-
s.puts(cmd)
|
46
|
-
response = s.gets.chomp
|
42
|
+
s = TCPSocket.new('0.0.0.0', port)
|
47
43
|
s.close
|
48
|
-
return
|
44
|
+
return true
|
49
45
|
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
50
|
-
|
51
|
-
exit(1)
|
46
|
+
return false
|
52
47
|
end
|
53
48
|
end
|
54
49
|
end
|
55
50
|
end
|
56
|
-
|
57
51
|
end
|
data/lib/prb/opts.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Prb
|
2
|
+
class Opts
|
3
|
+
attr_reader :pomodoros, :timer, :port
|
4
|
+
|
5
|
+
def initialize(opts)
|
6
|
+
@pomodoros = opts[:pomodoros].to_i
|
7
|
+
@timer = opts[:timer].to_i
|
8
|
+
@daemonize = opts[:daemonize]
|
9
|
+
@port = (opts[:port] || 3838).to_i
|
10
|
+
end
|
11
|
+
|
12
|
+
def daemonize?
|
13
|
+
!!@daemonize
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/prb/server.rb
CHANGED
@@ -1,76 +1,40 @@
|
|
1
|
-
require 'socket'
|
2
1
|
require 'timeout'
|
2
|
+
require 'sinatra/base'
|
3
3
|
|
4
4
|
module Prb
|
5
|
-
|
5
|
+
class Server < Sinatra::Base
|
6
|
+
def initialize(opts)
|
7
|
+
puts <<~MSG
|
8
|
+
Starting pomodoro service...
|
6
9
|
|
7
|
-
|
8
|
-
|
9
|
-
@controller = TimerControl.new
|
10
|
-
end
|
11
|
-
|
12
|
-
def start
|
13
|
-
@controller.start
|
14
|
-
|
15
|
-
server = TCPServer.open('127.0.0.1', PRB_PORT)
|
16
|
-
puts "Server listening on #{PRB_PORT}"
|
10
|
+
Number of pomodoros: #{opts.pomodoros} pomodoro(s)
|
11
|
+
Pomodoro timer: #{opts.timer} minute(s)
|
17
12
|
|
18
|
-
|
19
|
-
Thread.start(server.accept) do |socket|
|
20
|
-
while cmd = socket.gets.chomp
|
21
|
-
puts "RECV: #{cmd}"
|
13
|
+
MSG
|
22
14
|
|
23
|
-
|
24
|
-
|
25
|
-
when 'STATUS'
|
26
|
-
output = status_line
|
27
|
-
when 'SKIP'
|
28
|
-
@controller.toggle
|
29
|
-
when 'RESET'
|
30
|
-
@controller.reset
|
31
|
-
when 'PAUSE'
|
32
|
-
@controller.pause
|
33
|
-
when 'QUIT'
|
34
|
-
socket.puts "OK"
|
35
|
-
exit(0)
|
36
|
-
else
|
37
|
-
puts "ERR: #{cmd} not a command"
|
38
|
-
output = "ERR: #{cmd} not a command"
|
39
|
-
end
|
40
|
-
|
41
|
-
socket.puts output
|
42
|
-
end
|
15
|
+
@controller = TimerControl.new(opts)
|
16
|
+
@controller.start
|
43
17
|
|
44
|
-
|
45
|
-
|
46
|
-
end
|
18
|
+
super
|
19
|
+
end
|
47
20
|
|
48
|
-
|
21
|
+
get '/status' do
|
22
|
+
content_type :json
|
23
|
+
@controller.render_status
|
49
24
|
end
|
50
25
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
s = TCPSocket.new('127.0.0.1', PRB_PORT)
|
55
|
-
s.close
|
56
|
-
return true
|
57
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
58
|
-
return false
|
59
|
-
end
|
60
|
-
end
|
26
|
+
get '/reset' do
|
27
|
+
@controller.reset
|
28
|
+
status 200
|
61
29
|
end
|
62
30
|
|
63
|
-
|
31
|
+
get '/resume' do
|
32
|
+
@controller.resume
|
33
|
+
status 200
|
34
|
+
end
|
64
35
|
|
65
|
-
|
66
|
-
|
67
|
-
status << @controller.timer.render
|
68
|
-
status << ","
|
69
|
-
status << "WORKING" if @controller.is_working?
|
70
|
-
status << "BREAK" if !@controller.is_working?
|
71
|
-
status << ",PAUSED" if @controller.paused?
|
72
|
-
status << ",RUNNING" if !@controller.paused?
|
73
|
-
status
|
36
|
+
get '/stop' do
|
37
|
+
Process.kill("INT", Process.pid)
|
74
38
|
end
|
75
39
|
end
|
76
40
|
end
|
data/lib/prb/timer.rb
CHANGED
@@ -1,41 +1,57 @@
|
|
1
1
|
module Prb
|
2
2
|
class Timer
|
3
|
-
|
3
|
+
attr_reader :pomodoros, :seconds, :paused, :completed
|
4
|
+
|
5
|
+
WORKING = 1
|
6
|
+
PAUSED = 2
|
7
|
+
|
8
|
+
def initialize(opts)
|
9
|
+
@opts = opts
|
10
|
+
|
4
11
|
@paused = false
|
5
|
-
|
6
|
-
end
|
12
|
+
@pomodoros = opts.pomodoros
|
7
13
|
|
8
|
-
|
9
|
-
@
|
10
|
-
@seconds = @_seconds
|
14
|
+
# set pomodoro timer
|
15
|
+
set_timer(@opts.timer)
|
11
16
|
end
|
12
17
|
|
13
18
|
def tick
|
14
|
-
|
15
|
-
@seconds -= 1 unless @paused or finished?
|
16
|
-
end
|
19
|
+
return if completed? or paused?
|
17
20
|
|
18
|
-
|
19
|
-
|
21
|
+
if @seconds == 0
|
22
|
+
if @paused == false
|
23
|
+
@pomodoros -= 1
|
24
|
+
@paused = true
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@seconds -= 1
|
28
|
+
end
|
20
29
|
end
|
21
30
|
|
22
|
-
def
|
23
|
-
@
|
31
|
+
def resume
|
32
|
+
@paused = false
|
33
|
+
set_timer(@opts.timer)
|
24
34
|
end
|
25
35
|
|
26
|
-
def
|
27
|
-
@paused =
|
36
|
+
def reset
|
37
|
+
@paused = false
|
38
|
+
@pomodoros = @opts.pomodoros
|
39
|
+
set_timer(@opts.timer)
|
28
40
|
end
|
29
41
|
|
30
42
|
def paused?
|
31
43
|
@paused
|
32
44
|
end
|
33
45
|
|
34
|
-
|
35
|
-
|
36
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def set_timer(minutes)
|
49
|
+
@_seconds = minutes * 60
|
50
|
+
@seconds = @_seconds
|
51
|
+
end
|
37
52
|
|
38
|
-
|
53
|
+
def completed?
|
54
|
+
@pomodoros == 0
|
39
55
|
end
|
40
56
|
end
|
41
57
|
end
|
data/lib/prb/timer_control.rb
CHANGED
@@ -1,45 +1,36 @@
|
|
1
1
|
module Prb
|
2
2
|
class TimerControl
|
3
|
-
WORK_MINUTES = 25
|
4
|
-
BREAK_MINUTES = 5
|
5
|
-
|
6
3
|
attr_reader :timer
|
7
4
|
|
8
|
-
def initialize
|
9
|
-
@
|
10
|
-
@
|
5
|
+
def initialize(opts)
|
6
|
+
@opts = opts
|
7
|
+
@timer = Timer.new(@opts)
|
11
8
|
end
|
12
9
|
|
13
10
|
def start
|
14
11
|
Thread.new do
|
15
12
|
loop do
|
13
|
+
sleep 1
|
16
14
|
@timer.tick
|
17
|
-
toggle if @timer.finished?
|
18
15
|
end
|
19
16
|
end
|
20
17
|
end
|
21
18
|
|
22
|
-
def
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
def render_status
|
20
|
+
{
|
21
|
+
running: !@timer.paused?,
|
22
|
+
completed: @opts.pomodoros - @timer.pomodoros,
|
23
|
+
remaining: @timer.pomodoros,
|
24
|
+
time_remaining: @timer.seconds,
|
25
|
+
}.to_json
|
28
26
|
end
|
29
27
|
|
30
|
-
def
|
31
|
-
@timer.
|
32
|
-
end
|
33
|
-
|
34
|
-
def is_working?
|
35
|
-
@is_working
|
28
|
+
def reset
|
29
|
+
@timer.reset
|
36
30
|
end
|
37
31
|
|
38
|
-
def
|
39
|
-
@
|
40
|
-
@timer.set_timer(@is_working ?
|
41
|
-
WORK_MINUTES : BREAK_MINUTES)
|
42
|
-
@timer.pause unless @timer.paused?
|
32
|
+
def resume
|
33
|
+
@timer.resume
|
43
34
|
end
|
44
35
|
end
|
45
36
|
end
|
data/lib/prb/version.rb
CHANGED
data/prb.gemspec
CHANGED
@@ -36,7 +36,8 @@ Gem::Specification.new do |spec|
|
|
36
36
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
37
|
spec.require_paths = ["lib"]
|
38
38
|
|
39
|
-
spec.add_dependency "optimist"
|
39
|
+
spec.add_dependency "optimist", "~> 3.0"
|
40
|
+
spec.add_dependency "sinatra", "~> 2.0"
|
40
41
|
|
41
42
|
spec.add_development_dependency "bundler", "~> 2.0"
|
42
43
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,29 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Ramsden
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-11-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: optimist
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '3.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: sinatra
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
25
32
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,6 +100,7 @@ files:
|
|
86
100
|
- exe/prb
|
87
101
|
- lib/prb.rb
|
88
102
|
- lib/prb/command_runner.rb
|
103
|
+
- lib/prb/opts.rb
|
89
104
|
- lib/prb/server.rb
|
90
105
|
- lib/prb/timer.rb
|
91
106
|
- lib/prb/timer_control.rb
|