paradeiser 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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/README.md +96 -35
  4. data/TODO.md +14 -15
  5. data/VISION.md +92 -84
  6. data/bin/{pom → par} +32 -2
  7. data/doc/Paradeiser::Break_status.svg +50 -0
  8. data/doc/Paradeiser::Pomodoro_status.svg +40 -22
  9. data/lib/paradeiser.rb +3 -3
  10. data/lib/paradeiser/controllers/breaks_controller.rb +19 -0
  11. data/lib/paradeiser/controllers/controller.rb +3 -3
  12. data/lib/paradeiser/controllers/paradeiser_controller.rb +13 -2
  13. data/lib/paradeiser/controllers/pomodori_controller.rb +36 -17
  14. data/lib/paradeiser/errors.rb +12 -6
  15. data/lib/paradeiser/executor.rb +2 -0
  16. data/lib/paradeiser/initializers/inflections.rb +4 -0
  17. data/lib/paradeiser/models/break.rb +40 -0
  18. data/lib/paradeiser/models/hook.rb +4 -4
  19. data/lib/paradeiser/models/interrupt.rb +18 -0
  20. data/lib/paradeiser/models/job.rb +1 -1
  21. data/lib/paradeiser/models/pomodoro.rb +30 -22
  22. data/lib/paradeiser/models/repository.rb +26 -13
  23. data/lib/paradeiser/models/scheduled.rb +25 -0
  24. data/lib/paradeiser/models/scheduler.rb +1 -1
  25. data/lib/paradeiser/models/status.rb +21 -0
  26. data/lib/paradeiser/{refinements.rb → refinements/numeric.rb} +4 -0
  27. data/lib/paradeiser/router.rb +12 -7
  28. data/lib/paradeiser/version.rb +1 -1
  29. data/lib/paradeiser/views/paradeiser/init.erb +1 -1
  30. data/lib/paradeiser/views/paradeiser/report.erb +5 -0
  31. data/lib/paradeiser/views/paradeiser/status.erb +13 -0
  32. data/paradeiser.gemspec +2 -0
  33. data/templates/linux/hooks/after-finish-break +10 -0
  34. data/templates/linux/hooks/after-finish-pomodoro +10 -0
  35. data/templates/linux/hooks/after-start-break +7 -0
  36. data/templates/linux/hooks/after-start-pomodoro +7 -0
  37. data/templates/mac/hooks/after-finish-break +10 -0
  38. data/templates/mac/hooks/after-finish-pomodoro +10 -0
  39. data/templates/mac/hooks/after-start-break +7 -0
  40. data/templates/mac/hooks/after-start-pomodoro +7 -0
  41. data/test/helper.rb +37 -4
  42. data/test/integration/{test_pom.rb → test_par.rb} +4 -4
  43. data/test/lib/{pomodoro_mock.rb → schedulable_mock.rb} +9 -1
  44. data/test/unit/test_break.rb +99 -0
  45. data/test/unit/test_break_controller.rb +56 -0
  46. data/test/unit/test_interrupt.rb +36 -0
  47. data/test/unit/test_paradeiser_controller_init.rb +92 -0
  48. data/test/unit/test_paradeiser_controller_report.rb +44 -0
  49. data/test/unit/test_paradeiser_controller_status.rb +70 -0
  50. data/test/unit/test_paradeiser_view.rb +66 -0
  51. data/test/unit/test_pomodori_controller.rb +87 -31
  52. data/test/unit/test_pomodori_view.rb +0 -50
  53. data/test/unit/test_pomodoro.rb +131 -9
  54. data/test/unit/test_pomodoro_hooks.rb +165 -17
  55. data/test/unit/test_repository.rb +38 -15
  56. data/test/unit/test_router.rb +4 -4
  57. data/test/unit/test_status.rb +26 -0
  58. metadata +70 -17
  59. data/lib/paradeiser/views/pomodori/report.erb +0 -5
  60. data/lib/paradeiser/views/pomodori/status.erb +0 -9
  61. data/templates/linux/hooks/after-finish +0 -10
  62. data/templates/linux/hooks/after-start +0 -7
  63. data/templates/mac/hooks/after-finish +0 -10
  64. data/templates/mac/hooks/after-start +0 -7
  65. data/test/unit/test_paradeiser_controller.rb +0 -88
@@ -23,17 +23,47 @@ begin
23
23
  c.action router.dispatch(c)
24
24
  end
25
25
 
26
- command :start do |c|
26
+ command :'pomodoro start' do |c|
27
27
  c.syntax = "#{program(:name)} #{c.name}"
28
28
  c.summary = 'Start a new pomodoro'
29
29
  c.action router.dispatch(c)
30
30
  end
31
+ alias_command :start, :'pomodoro start'
31
32
 
32
- command :finish do |c|
33
+ command :'pomodoro cancel' do |c|
34
+ c.syntax = "#{program(:name)} #{c.name}"
35
+ c.summary = 'Cancel the active pomodoro'
36
+ c.action router.dispatch(c)
37
+ end
38
+ alias_command :cancel, :'pomodoro cancel'
39
+
40
+ command :'pomodoro finish' do |c|
33
41
  c.syntax = "#{program(:name)} #{c.name}"
34
42
  c.summary = 'Finish the active pomodoro'
35
43
  c.action router.dispatch(c)
36
44
  end
45
+ alias_command :finish, :'pomodoro finish'
46
+
47
+ command :'pomodoro interrupt' do |c|
48
+ c.syntax = "#{program(:name)} #{c.name}"
49
+ c.option '--external', 'Record the interruption as external (default is internal)'
50
+ c.summary = 'Records the interruption of the active pomodoro'
51
+ c.action router.dispatch(c)
52
+ end
53
+ alias_command :interrupt, :'pomodoro interrupt'
54
+
55
+ command :'break start' do |c|
56
+ c.syntax = "#{program(:name)} #{c.name}"
57
+ c.summary = 'Start a break'
58
+ c.action router.dispatch(c)
59
+ end
60
+ alias_command :break, :'break start'
61
+
62
+ command :'break finish' do |c|
63
+ c.syntax = "#{program(:name)} #{c.name}"
64
+ c.summary = 'Finish a break'
65
+ c.action router.dispatch(c)
66
+ end
37
67
 
38
68
  command :report do |c|
39
69
  c.syntax = "#{program(:name)} #{c.name}"
@@ -0,0 +1,50 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <!-- Generated by graphviz version 2.30.1 (20130609.1303)
5
+ -->
6
+ <!-- Title: G Pages: 1 -->
7
+ <svg width="408pt" height="88pt"
8
+ viewBox="0.00 0.00 408.00 88.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9
+ <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 84)">
10
+ <title>G</title>
11
+ <polygon fill="white" stroke="white" points="-4,5 -4,-84 405,-84 405,5 -4,5"/>
12
+ <!-- idle -->
13
+ <g id="node1" class="node"><title>idle</title>
14
+ <ellipse fill="none" stroke="black" cx="78" cy="-40" rx="36" ry="36"/>
15
+ <text text-anchor="middle" x="78" y="-34.0493" font-family="Arial" font-size="14.00">idle</text>
16
+ </g>
17
+ <!-- active -->
18
+ <g id="node3" class="node"><title>active</title>
19
+ <ellipse fill="none" stroke="black" cx="214" cy="-40" rx="36" ry="36"/>
20
+ <text text-anchor="middle" x="214" y="-34.0493" font-family="Arial" font-size="14.00">active</text>
21
+ </g>
22
+ <!-- idle&#45;&gt;active -->
23
+ <g id="edge2" class="edge"><title>idle&#45;&gt;active</title>
24
+ <path fill="none" stroke="black" d="M114.207,-40C130.389,-40 149.793,-40 167.103,-40"/>
25
+ <polygon fill="black" stroke="black" points="167.563,-43.5001 177.563,-40 167.563,-36.5001 167.563,-43.5001"/>
26
+ <text text-anchor="middle" x="146" y="-42.0986" font-family="Arial" font-size="14.00">start</text>
27
+ </g>
28
+ <!-- starting_state -->
29
+ <g id="node2" class="node"><title>starting_state</title>
30
+ <ellipse fill="black" stroke="black" cx="2" cy="-40" rx="1.8" ry="1.8"/>
31
+ </g>
32
+ <!-- starting_state&#45;&gt;idle -->
33
+ <g id="edge1" class="edge"><title>starting_state&#45;&gt;idle</title>
34
+ <path fill="none" stroke="black" d="M3.83105,-40C6.96908,-40 18.5857,-40 31.6682,-40"/>
35
+ <polygon fill="black" stroke="black" points="31.8421,-43.5001 41.8421,-40 31.8421,-36.5001 31.8421,-43.5001"/>
36
+ </g>
37
+ <!-- finished -->
38
+ <g id="node4" class="node"><title>finished</title>
39
+ <ellipse fill="none" stroke="black" cx="360" cy="-40" rx="36" ry="36"/>
40
+ <ellipse fill="none" stroke="black" cx="360" cy="-40" rx="40" ry="40"/>
41
+ <text text-anchor="middle" x="360" y="-34.0493" font-family="Arial" font-size="14.00">finished</text>
42
+ </g>
43
+ <!-- active&#45;&gt;finished -->
44
+ <g id="edge3" class="edge"><title>active&#45;&gt;finished</title>
45
+ <path fill="none" stroke="black" d="M250.226,-40C268.083,-40 290.064,-40 309.582,-40"/>
46
+ <polygon fill="black" stroke="black" points="309.829,-43.5001 319.829,-40 309.829,-36.5001 309.829,-43.5001"/>
47
+ <text text-anchor="middle" x="285" y="-42.0986" font-family="Arial" font-size="14.00">finish</text>
48
+ </g>
49
+ </g>
50
+ </svg>
@@ -4,47 +4,65 @@
4
4
  <!-- Generated by graphviz version 2.30.1 (20130609.1303)
5
5
  -->
6
6
  <!-- Title: G Pages: 1 -->
7
- <svg width="408pt" height="88pt"
8
- viewBox="0.00 0.00 408.00 88.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9
- <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 84)">
7
+ <svg width="418pt" height="190pt"
8
+ viewBox="0.00 0.00 418.00 190.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9
+ <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 186)">
10
10
  <title>G</title>
11
- <polygon fill="white" stroke="white" points="-4,5 -4,-84 405,-84 405,5 -4,5"/>
11
+ <polygon fill="white" stroke="white" points="-4,5 -4,-186 415,-186 415,5 -4,5"/>
12
12
  <!-- idle -->
13
13
  <g id="node1" class="node"><title>idle</title>
14
- <ellipse fill="none" stroke="black" cx="78" cy="-40" rx="36" ry="36"/>
15
- <text text-anchor="middle" x="78" y="-34.0493" font-family="Arial" font-size="14.00">idle</text>
14
+ <ellipse fill="none" stroke="black" cx="78" cy="-90" rx="36" ry="36"/>
15
+ <text text-anchor="middle" x="78" y="-84.0493" font-family="Arial" font-size="14.00">idle</text>
16
16
  </g>
17
17
  <!-- active -->
18
18
  <g id="node3" class="node"><title>active</title>
19
- <ellipse fill="none" stroke="black" cx="214" cy="-40" rx="36" ry="36"/>
20
- <text text-anchor="middle" x="214" y="-34.0493" font-family="Arial" font-size="14.00">active</text>
19
+ <ellipse fill="none" stroke="black" cx="214" cy="-90" rx="36" ry="36"/>
20
+ <text text-anchor="middle" x="214" y="-84.0493" font-family="Arial" font-size="14.00">active</text>
21
21
  </g>
22
22
  <!-- idle&#45;&gt;active -->
23
23
  <g id="edge2" class="edge"><title>idle&#45;&gt;active</title>
24
- <path fill="none" stroke="black" d="M114.207,-40C130.389,-40 149.793,-40 167.103,-40"/>
25
- <polygon fill="black" stroke="black" points="167.563,-43.5001 177.563,-40 167.563,-36.5001 167.563,-43.5001"/>
26
- <text text-anchor="middle" x="146" y="-42.0986" font-family="Arial" font-size="14.00">start</text>
24
+ <path fill="none" stroke="black" d="M114.207,-90C130.389,-90 149.793,-90 167.103,-90"/>
25
+ <polygon fill="black" stroke="black" points="167.563,-93.5001 177.563,-90 167.563,-86.5001 167.563,-93.5001"/>
26
+ <text text-anchor="middle" x="146" y="-92.0986" font-family="Arial" font-size="14.00">start</text>
27
27
  </g>
28
28
  <!-- starting_state -->
29
29
  <g id="node2" class="node"><title>starting_state</title>
30
- <ellipse fill="black" stroke="black" cx="2" cy="-40" rx="1.8" ry="1.8"/>
30
+ <ellipse fill="black" stroke="black" cx="2" cy="-90" rx="1.8" ry="1.8"/>
31
31
  </g>
32
32
  <!-- starting_state&#45;&gt;idle -->
33
33
  <g id="edge1" class="edge"><title>starting_state&#45;&gt;idle</title>
34
- <path fill="none" stroke="black" d="M3.83105,-40C6.96908,-40 18.5857,-40 31.6682,-40"/>
35
- <polygon fill="black" stroke="black" points="31.8421,-43.5001 41.8421,-40 31.8421,-36.5001 31.8421,-43.5001"/>
34
+ <path fill="none" stroke="black" d="M3.83105,-90C6.96908,-90 18.5857,-90 31.6682,-90"/>
35
+ <polygon fill="black" stroke="black" points="31.8421,-93.5001 41.8421,-90 31.8421,-86.5001 31.8421,-93.5001"/>
36
+ </g>
37
+ <!-- active&#45;&gt;active -->
38
+ <g id="edge3" class="edge"><title>active&#45;&gt;active</title>
39
+ <path fill="none" stroke="black" d="M201.25,-123.75C201.25,-135 205.5,-144 214,-144 219.711,-144 223.503,-139.937 225.377,-133.859"/>
40
+ <polygon fill="black" stroke="black" points="228.872,-134.13 226.75,-123.75 221.936,-133.188 228.872,-134.13"/>
41
+ <text text-anchor="middle" x="214" y="-146.099" font-family="Arial" font-size="14.00">interrupt</text>
42
+ </g>
43
+ <!-- canceled -->
44
+ <g id="node4" class="node"><title>canceled</title>
45
+ <ellipse fill="none" stroke="black" cx="368" cy="-140" rx="38.4302" ry="38.4302"/>
46
+ <ellipse fill="none" stroke="black" cx="368" cy="-140" rx="42.4516" ry="42.4516"/>
47
+ <text text-anchor="middle" x="368" y="-134.049" font-family="Arial" font-size="14.00">canceled</text>
48
+ </g>
49
+ <!-- active&#45;&gt;canceled -->
50
+ <g id="edge4" class="edge"><title>active&#45;&gt;canceled</title>
51
+ <path fill="none" stroke="black" d="M248.357,-100.973C268.774,-107.689 295.26,-116.401 318.027,-123.89"/>
52
+ <polygon fill="black" stroke="black" points="316.935,-127.216 327.528,-127.016 319.122,-120.566 316.935,-127.216"/>
53
+ <text text-anchor="middle" x="288" y="-121.099" font-family="Arial" font-size="14.00">cancel</text>
36
54
  </g>
37
55
  <!-- finished -->
38
- <g id="node4" class="node"><title>finished</title>
39
- <ellipse fill="none" stroke="black" cx="360" cy="-40" rx="36" ry="36"/>
40
- <ellipse fill="none" stroke="black" cx="360" cy="-40" rx="40" ry="40"/>
41
- <text text-anchor="middle" x="360" y="-34.0493" font-family="Arial" font-size="14.00">finished</text>
56
+ <g id="node5" class="node"><title>finished</title>
57
+ <ellipse fill="none" stroke="black" cx="368" cy="-40" rx="36" ry="36"/>
58
+ <ellipse fill="none" stroke="black" cx="368" cy="-40" rx="40" ry="40"/>
59
+ <text text-anchor="middle" x="368" y="-34.0493" font-family="Arial" font-size="14.00">finished</text>
42
60
  </g>
43
61
  <!-- active&#45;&gt;finished -->
44
- <g id="edge3" class="edge"><title>active&#45;&gt;finished</title>
45
- <path fill="none" stroke="black" d="M250.226,-40C268.083,-40 290.064,-40 309.582,-40"/>
46
- <polygon fill="black" stroke="black" points="309.829,-43.5001 319.829,-40 309.829,-36.5001 309.829,-43.5001"/>
47
- <text text-anchor="middle" x="285" y="-42.0986" font-family="Arial" font-size="14.00">finish</text>
62
+ <g id="edge5" class="edge"><title>active&#45;&gt;finished</title>
63
+ <path fill="none" stroke="black" d="M248.357,-79.0273C269.385,-72.1101 296.853,-63.0746 320.063,-55.4397"/>
64
+ <polygon fill="black" stroke="black" points="321.313,-58.7132 329.719,-52.2636 319.126,-52.0637 321.313,-58.7132"/>
65
+ <text text-anchor="middle" x="288" y="-75.0986" font-family="Arial" font-size="14.00">finish</text>
48
66
  </g>
49
67
  </g>
50
68
  </svg>
@@ -6,12 +6,12 @@ require 'require_all'
6
6
  require_rel "paradeiser"
7
7
 
8
8
  module Paradeiser
9
- def self.pom_dir
10
- ENV['POM_DIR'] || File.expand_path('~/.paradeiser/')
9
+ def self.par_dir
10
+ ENV['PAR_DIR'] || File.expand_path('~/.paradeiser/')
11
11
  end
12
12
 
13
13
  def self.hooks_dir
14
- File.join(Paradeiser.pom_dir, 'hooks')
14
+ File.join(Paradeiser.par_dir, 'hooks')
15
15
  end
16
16
 
17
17
  def self.templates_dir
@@ -0,0 +1,19 @@
1
+ module Paradeiser
2
+ class BreaksController < Controller
3
+ def start
4
+ raise SingletonError.new(Break, Repository.active, :start) if Repository.active?
5
+
6
+ @break = Break.new
7
+ @break.start!
8
+ Repository.save(@break)
9
+ end
10
+
11
+ def finish
12
+ @break = Repository.active
13
+ raise NotActiveError unless @break
14
+ raise SingletonError.new(Break, @break, :finish) if Repository.active? && !@break.kind_of?(Break)
15
+ @break.finish!
16
+ Repository.save(@break)
17
+ end
18
+ end
19
+ end
@@ -4,7 +4,7 @@ module Paradeiser
4
4
 
5
5
  def initialize(method)
6
6
  @method = method
7
- @exitstatus = 0
7
+ @exitstatus = -1
8
8
  @has_output = false
9
9
  end
10
10
 
@@ -24,7 +24,7 @@ module Paradeiser
24
24
 
25
25
  protected
26
26
 
27
- attr_writer :exitstatus, :has_output
28
- attr_reader :options, :args
27
+ attr_writer :exitstatus, :has_output
28
+ attr_reader :options, :args
29
29
  end
30
30
  end
@@ -3,8 +3,19 @@ require 'fileutils'
3
3
  module Paradeiser
4
4
  class ParadeiserController < Controller
5
5
  def init
6
- FileUtils.mkdir_p(Paradeiser.pom_dir)
7
- FileUtils.cp_r(File.join(Paradeiser.templates_dir, Paradeiser.os.to_s, 'hooks'), Paradeiser.pom_dir)
6
+ FileUtils.mkdir_p(Paradeiser.par_dir)
7
+ FileUtils.cp_r(File.join(Paradeiser.templates_dir, Paradeiser.os.to_s, 'hooks'), Paradeiser.par_dir)
8
+ end
9
+
10
+ def report
11
+ @pom = Repository.all
12
+ self.has_output = true
13
+ end
14
+
15
+ def status
16
+ @pom = Repository.active || Repository.all.last
17
+ self.exitstatus = Status.of(@pom).to_i
18
+ self.has_output = true
8
19
  end
9
20
  end
10
21
  end
@@ -1,38 +1,57 @@
1
+ require 'active_support/core_ext/object/blank'
2
+
1
3
  module Paradeiser
2
4
  class PomodoriController < Controller
3
5
  def start
4
- # The repository will protect itself, but we don't want to create
5
- # a new pomodoro if saving it will fail anyway.
6
- raise SingletonError.new(Repository.active) if Repository.active?
6
+ end_break
7
+ raise SingletonError.new(Pomodoro, Repository.active, :start) if Repository.active?
7
8
 
8
9
  @pom = Pomodoro.new
9
10
  @pom.start!
10
11
  Repository.save(@pom)
11
12
  end
12
13
 
14
+ def cancel
15
+ @pom = Repository.active
16
+ raise NotActiveError unless @pom
17
+ raise SingletonError.new(Pomodoro, @pom, :finish) if Repository.active? && !@pom.kind_of?(Pomodoro)
18
+ @pom.cancel!
19
+ Repository.save(@pom)
20
+ end
21
+
13
22
  def finish
14
23
  @pom = Repository.active
15
- raise NoActivePomodoroError unless @pom
24
+ raise NotActiveError unless @pom
25
+ raise SingletonError.new(Pomodoro, @pom, :finish) if Repository.active? && !@pom.kind_of?(Pomodoro)
16
26
  @pom.finish!
17
27
  Repository.save(@pom)
18
28
  end
19
29
 
20
- def report
21
- @pom = Repository.all
22
- self.has_output = true
23
- end
30
+ def interrupt
31
+ @pom = Repository.active
32
+ raise NotActiveError unless @pom
33
+ raise SingletonError.new(Pomodoro, @pom, :interrupt) if Repository.active? && !@pom.kind_of?(Pomodoro)
24
34
 
25
- def status
26
- if @pom = Repository.active
27
- self.exitstatus = 0
28
- elsif @pom = Repository.find{|pom| pom.finished?}.last
29
- self.exitstatus = 1
30
- # elsif Repository.find(:status => 'cancelled').last
31
- # self.exitstatus = 2
35
+ if @options.external
36
+ @pom.interrupt!(:external)
32
37
  else
33
- @pom = Pomodoro.new # nothing found, we are idle
38
+ @pom.interrupt!
39
+ end
40
+
41
+ Repository.save(@pom)
42
+ end
43
+
44
+ private
45
+
46
+ def end_break
47
+ if Repository.active?
48
+ active = Repository.active
49
+
50
+ if active.kind_of?(Break)
51
+ active.finish!
52
+ Repository.save(active)
53
+ end
34
54
  end
35
- self.has_output = true
36
55
  end
37
56
  end
38
57
  end
@@ -1,25 +1,25 @@
1
1
  module Paradeiser
2
2
  class SingletonError < StandardError
3
- def initialize(pom)
4
- super("Pomodoro #{pom.id} is already active.")
3
+ def initialize(new_resource, existing_resource, verb)
4
+ super("Cannot #{verb} the #{new_resource.name.split("::").last.downcase} because #{existing_resource.name} ##{existing_resource.id} is active")
5
5
  end
6
6
  end
7
7
 
8
- class NoActivePomodoroError < StandardError
8
+ class NotActiveError < StandardError
9
9
  def initialize
10
- super('There is no active pomodoro.')
10
+ super('There is no active pomodoro or break')
11
11
  end
12
12
  end
13
13
 
14
14
  class NotInitializedError < StandardError
15
15
  def initialize(msg)
16
- super("Paradeiser was not properly initialized; #{msg}.")
16
+ super("Paradeiser was not properly initialized; #{msg}")
17
17
  end
18
18
  end
19
19
 
20
20
  class IllegalStatusError < StandardError
21
21
  def initialize
22
- super('Idle pomodori cannot be saved.')
22
+ super('Idle pomodori cannot be saved')
23
23
  end
24
24
  end
25
25
 
@@ -28,4 +28,10 @@ module Paradeiser
28
28
  super("The hook #{hook} failed with status #{status.exitstatus}. STDERR contained: #{err}")
29
29
  end
30
30
  end
31
+
32
+ class InvalidTypeError < StandardError
33
+ def initialize(type, choices)
34
+ super("'#{type}' is not a valid type. Valid are only #{choices}.")
35
+ end
36
+ end
31
37
  end
@@ -1,4 +1,6 @@
1
1
  module Executor
2
+ BIN_PAR = 'par'
3
+
2
4
  def exec(cmd)
3
5
  out, err, status = Open3.capture3(cmd)
4
6
  raise err if 0 < status.exitstatus
@@ -0,0 +1,4 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ inflect.irregular 'pomodoro', 'pomodori'
3
+ inflect.irregular 'break', 'breaks'
4
+ end
@@ -0,0 +1,40 @@
1
+ module Paradeiser
2
+ class Break < Scheduled
3
+
4
+ state_machine :status, :initial => :idle do
5
+ event :start do
6
+ transition :idle => :active
7
+ end
8
+
9
+ event :finish do
10
+ transition :active => :finished
11
+ end
12
+
13
+ after_transition :on => :start do |br3ak, transition|
14
+ br3ak.started_at = Time.now
15
+ Scheduler.clear # There must be no other jobs scheduled because of Rule #1
16
+ Scheduler.add(:"#{br3ak.name} finish", br3ak.length.minutes)
17
+ end
18
+
19
+ around_transition do |br3ak, transition, block|
20
+ Hook.new(:before).execute(br3ak, transition.event)
21
+ block.call
22
+ Hook.new(:after).execute(br3ak, transition.event)
23
+ end
24
+
25
+ after_transition :on => :finish do |br3ak, transition|
26
+ br3ak.finished_at = Time.now
27
+ Scheduler.clear # There must be no other jobs scheduled because of Rule #1
28
+ end
29
+ end
30
+
31
+ def initialize(length = 300.seconds)
32
+ super() # required for state_machine
33
+ @length = length
34
+ end
35
+
36
+ def length
37
+ @length
38
+ end
39
+ end
40
+ end
@@ -4,13 +4,13 @@ module Paradeiser
4
4
  @phase = phase
5
5
  end
6
6
 
7
- def execute(pom, transition)
8
- name = "#{@phase}-#{transition.event}"
7
+ def execute(pom, event)
8
+ name = "#{@phase}-#{event}-#{pom.name}"
9
9
  hook = hook(name)
10
10
 
11
11
  if File.exist?(hook) && File.executable?(hook)
12
- ENV['POM_ID'] = pom.id.to_s
13
- ENV['POM_STARTED_AT'] = pom.started_at.strftime('%H:%M') if pom.started_at
12
+ ENV["PAR_#{pom.name.upcase}_ID"] = pom.id ? pom.id.to_s : Repository.next_id.to_s
13
+ ENV["PAR_#{pom.name.upcase}_STARTED_AT"] = pom.started_at.strftime('%H:%M') if pom.started_at
14
14
 
15
15
  out, err, status = Open3.capture3(hook)
16
16
  raise HookFailedError.new(hook, out, err, status) if 0 != status.exitstatus