paradeiser 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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