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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97fa1172495612ccf5109e932970c74bdaf02690e9399f7da5a451f41598cfdf
4
- data.tar.gz: 1df513efca5f84ac516121e0f720c1522474eb97581a390777ad37786e6caf98
3
+ metadata.gz: d09ffeecc26a41b306564b20a9e9acc62d5cbbfd9b03a16684ae0204f289717e
4
+ data.tar.gz: 0d6615043f85ff16ab3f4da9c5e2c5fa17525d16c6425b32d210898084683680
5
5
  SHA512:
6
- metadata.gz: 4c3f24a6477fcca54805d9ed7a799a45f97e2afdf1007882131045f796b4ae9373b9af293fc0a8831bb2623e8398543150d6c7f32d9f03e837bd6787df19c96f
7
- data.tar.gz: a0995f9549574d236c49dfd5f99f0c927c61de46c0841d4e34dbd2c9b764dddc5311f18d391a50def038ebec010aefa596a0cbb312cd7b7883fb3ea1e29b5f2e
6
+ metadata.gz: d5c9433e04646ea3467add2f8915cdb2ccd6c2ecb8a1dfcd6118a46f42593b0db22ab0a210316b90de478a38939a401b9e80fabbe602c9dd20c49e2036fd58cd
7
+ data.tar.gz: 8836c99454be9f1cbaf3a1f63c1104c3437ed350b5db9abe656fc417ff2976be188052e1b4194f349851588b9e17e479f5396350a77da42c2f925d28d627a21b
@@ -1,14 +1,19 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- prb (0.1.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.1
48
+ 2.0.2
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # Prb
2
2
 
3
- `prb` is a light-weight timer service written in Ruby for the pomodoro
4
- technique.
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
- Usage:
18
- prb [COMMAND] [SUB_COMMAND]
29
+ After starting the service you can query the timers status over HTTP using
30
+ `curl`:
19
31
 
20
- Options:
21
- -d, --daemonize Start the service in the background
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
- Commands:
24
- start Start pomodoro service
25
- stop Stop pomodoro service
26
- status Print status of pomodoro service
27
- skip Skip the current timer
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
- 'stop' => 'Stop pomodoro service',
10
- 'status' => 'Print status of pomodoro service',
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
- opts = Optimist::options do
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 \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
@@ -1,4 +1,10 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'rack'
4
+ require 'rack/server'
5
+
1
6
  require_relative "prb/version"
7
+ require_relative "prb/opts"
2
8
  require_relative "prb/timer"
3
9
  require_relative "prb/timer_control"
4
10
  require_relative "prb/server"
@@ -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 Prb::Server.running?
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[:daemonize]
13
+ Process.daemon() if @opts.daemonize?
14
14
 
15
- Prb::Server.new.start
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 status
19
- response = send_command('STATUS')
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
- send_command('QUIT')
27
+ send_request('stop')
37
28
  end
38
29
 
39
30
  private
40
31
 
41
- def send_command(cmd)
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('127.0.0.1', PRB_PORT)
45
- s.puts(cmd)
46
- response = s.gets.chomp
42
+ s = TCPSocket.new('0.0.0.0', port)
47
43
  s.close
48
- return response
44
+ return true
49
45
  rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
50
- puts "A prb server is not running"
51
- exit(1)
46
+ return false
52
47
  end
53
48
  end
54
49
  end
55
50
  end
56
-
57
51
  end
@@ -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
@@ -1,76 +1,40 @@
1
- require 'socket'
2
1
  require 'timeout'
2
+ require 'sinatra/base'
3
3
 
4
4
  module Prb
5
- PRB_PORT = 3838
5
+ class Server < Sinatra::Base
6
+ def initialize(opts)
7
+ puts <<~MSG
8
+ Starting pomodoro service...
6
9
 
7
- class Server
8
- def initialize
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
- while true
19
- Thread.start(server.accept) do |socket|
20
- while cmd = socket.gets.chomp
21
- puts "RECV: #{cmd}"
13
+ MSG
22
14
 
23
- output = "OK"
24
- case cmd
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
- socket.close
45
- end
46
- end
18
+ super
19
+ end
47
20
 
48
- server.close
21
+ get '/status' do
22
+ content_type :json
23
+ @controller.render_status
49
24
  end
50
25
 
51
- def self.running?
52
- Timeout::timeout(1) do
53
- begin
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
- private
31
+ get '/resume' do
32
+ @controller.resume
33
+ status 200
34
+ end
64
35
 
65
- def status_line
66
- status = ""
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
@@ -1,41 +1,57 @@
1
1
  module Prb
2
2
  class Timer
3
- def initialize(minutes)
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
- set_timer(minutes)
6
- end
12
+ @pomodoros = opts.pomodoros
7
13
 
8
- def set_timer(minutes)
9
- @_seconds = minutes * 60
10
- @seconds = @_seconds
14
+ # set pomodoro timer
15
+ set_timer(@opts.timer)
11
16
  end
12
17
 
13
18
  def tick
14
- sleep 1
15
- @seconds -= 1 unless @paused or finished?
16
- end
19
+ return if completed? or paused?
17
20
 
18
- def finished?
19
- @seconds == 0
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 reset
23
- @seconds = @_seconds
31
+ def resume
32
+ @paused = false
33
+ set_timer(@opts.timer)
24
34
  end
25
35
 
26
- def pause
27
- @paused = !@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
- def render
35
- min = (@seconds / 60) % 60
36
- sec = (@seconds % 60)
46
+ private
47
+
48
+ def set_timer(minutes)
49
+ @_seconds = minutes * 60
50
+ @seconds = @_seconds
51
+ end
37
52
 
38
- format("%02d:%02d", min, sec)
53
+ def completed?
54
+ @pomodoros == 0
39
55
  end
40
56
  end
41
57
  end
@@ -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
- @timer = Timer.new(WORK_MINUTES)
10
- @is_working = true
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 reset
23
- @timer.reset
24
- end
25
-
26
- def pause
27
- @timer.pause
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 paused?
31
- @timer.paused?
32
- end
33
-
34
- def is_working?
35
- @is_working
28
+ def reset
29
+ @timer.reset
36
30
  end
37
31
 
38
- def toggle
39
- @is_working = !@is_working
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
@@ -1,3 +1,3 @@
1
1
  module Prb
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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.1.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-07-21 00:00:00.000000000 Z
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