paradeiser 0.2.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/Guardfile +1 -0
- data/README.md +98 -6
- data/TODO.md +22 -6
- data/VISION.md +171 -26
- data/bin/par +20 -4
- data/lib/paradeiser/controllers/breaks_controller.rb +0 -1
- data/lib/paradeiser/controllers/controller.rb +15 -1
- data/lib/paradeiser/controllers/paradeiser_controller.rb +23 -1
- data/lib/paradeiser/controllers/pomodori_controller.rb +23 -1
- data/lib/paradeiser/errors.rb +6 -0
- data/lib/paradeiser/executor.rb +1 -1
- data/lib/paradeiser/initializers/inflections.rb +3 -0
- data/lib/paradeiser/models/break.rb +1 -0
- data/lib/paradeiser/models/pomodoro.rb +13 -1
- data/lib/paradeiser/models/repository.rb +11 -1
- data/lib/paradeiser/models/scheduled.rb +7 -1
- data/lib/paradeiser/refinements/pluralize.rb +10 -0
- data/lib/paradeiser/router.rb +0 -2
- data/lib/paradeiser/version.rb +1 -1
- data/lib/paradeiser/view.rb +1 -1
- data/lib/paradeiser/views/breaks/finish.erb +1 -0
- data/lib/paradeiser/views/breaks/start.erb +1 -0
- data/lib/paradeiser/views/paradeiser/init.erb +1 -1
- data/lib/paradeiser/views/paradeiser/report.erb +10 -4
- data/lib/paradeiser/views/paradeiser/status.erb +2 -1
- data/lib/paradeiser/views/pomodori/annotate.erb +1 -0
- data/lib/paradeiser/views/pomodori/cancel.erb +1 -0
- data/lib/paradeiser/views/pomodori/interrupt.erb +1 -0
- data/lib/paradeiser/views/pomodori/log.erb +1 -0
- data/lib/paradeiser/views/pomodori/start.erb +1 -1
- data/paradeiser.gemspec +2 -0
- data/test/bin/notify-send +1 -0
- data/test/helper.rb +7 -24
- data/test/integration/test_annotate.rb +19 -0
- data/test/integration/test_finish.rb +9 -0
- data/test/integration/test_interrupt.rb +9 -0
- data/test/integration/test_log.rb +12 -0
- data/test/integration/test_no_args.rb +7 -0
- data/test/integration/test_start.rb +7 -0
- data/test/integration/test_status.rb +10 -0
- data/test/integration/test_unknown.rb +7 -0
- data/test/lib/at_mock.rb +1 -1
- data/test/lib/controller_test.rb +25 -0
- data/test/lib/integration_test.rb +45 -0
- data/test/lib/paradeiser_controller_test.rb +7 -0
- data/test/lib/view_test.rb +12 -0
- data/test/unit/test_break.rb +7 -44
- data/test/unit/test_break_view.rb +22 -0
- data/test/unit/test_breaks_controller.rb +66 -0
- data/test/unit/test_paradeiser_controller_export.rb +107 -0
- data/test/unit/test_paradeiser_controller_report.rb +73 -26
- data/test/unit/test_paradeiser_controller_status.rb +42 -24
- data/test/unit/test_paradeiser_view_init.rb +7 -0
- data/test/unit/test_paradeiser_view_report.rb +132 -0
- data/test/unit/test_paradeiser_view_status.rb +17 -0
- data/test/unit/test_pomodori_controller.rb +241 -33
- data/test/unit/test_pomodori_view.rb +26 -13
- data/test/unit/test_pomodoro.rb +23 -81
- data/test/unit/test_pomodoro_hooks.rb +12 -25
- data/test/unit/test_repository.rb +5 -21
- data/test/unit/test_scheduler.rb +1 -1
- metadata +61 -8
- data/test/integration/test_par.rb +0 -17
- data/test/unit/test_break_controller.rb +0 -56
- data/test/unit/test_paradeiser_view.rb +0 -66
data/bin/par
CHANGED
@@ -1,8 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'bundler'
|
4
|
-
Bundler.require
|
5
|
-
|
6
3
|
require 'commander/import'
|
7
4
|
require 'paradeiser'
|
8
5
|
include Paradeiser
|
@@ -52,6 +49,20 @@ begin
|
|
52
49
|
end
|
53
50
|
alias_command :interrupt, :'pomodoro interrupt'
|
54
51
|
|
52
|
+
command :'pomodoro annotate' do |c|
|
53
|
+
c.syntax = "#{program(:name)} #{c.name}"
|
54
|
+
c.summary = 'Annotates the active or most recent pomodoro'
|
55
|
+
c.action router.dispatch(c)
|
56
|
+
end
|
57
|
+
alias_command :annotate, :'pomodoro annotate'
|
58
|
+
|
59
|
+
command :'pomodoro log' do |c|
|
60
|
+
c.syntax = "#{program(:name)} #{c.name}"
|
61
|
+
c.summary = 'Logs an already finished pomodoro'
|
62
|
+
c.action router.dispatch(c)
|
63
|
+
end
|
64
|
+
alias_command :log, :'pomodoro log'
|
65
|
+
|
55
66
|
command :'break start' do |c|
|
56
67
|
c.syntax = "#{program(:name)} #{c.name}"
|
57
68
|
c.summary = 'Start a break'
|
@@ -71,10 +82,15 @@ begin
|
|
71
82
|
c.action router.dispatch(c)
|
72
83
|
end
|
73
84
|
|
85
|
+
command :export do |c|
|
86
|
+
c.syntax = "#{program(:name)} #{c.name}"
|
87
|
+
c.summary = 'Export all pomodori as JSON'
|
88
|
+
c.action router.dispatch(c)
|
89
|
+
end
|
90
|
+
|
74
91
|
command :status do |c|
|
75
92
|
c.syntax = "#{program(:name)} #{c.name}"
|
76
93
|
c.summary = 'Show status of active pomodoro or break'
|
77
|
-
c.option '--quiet', 'Be quiet - no output is printed. The exit code reflects the status.'
|
78
94
|
c.action router.dispatch(c)
|
79
95
|
end
|
80
96
|
rescue
|
@@ -4,7 +4,7 @@ module Paradeiser
|
|
4
4
|
|
5
5
|
def initialize(method)
|
6
6
|
@method = method
|
7
|
-
@exitstatus =
|
7
|
+
@exitstatus = 0
|
8
8
|
@has_output = false
|
9
9
|
end
|
10
10
|
|
@@ -12,6 +12,7 @@ module Paradeiser
|
|
12
12
|
@args = args
|
13
13
|
@options = options
|
14
14
|
send(@method)
|
15
|
+
render
|
15
16
|
end
|
16
17
|
|
17
18
|
def model
|
@@ -22,6 +23,19 @@ module Paradeiser
|
|
22
23
|
return binding
|
23
24
|
end
|
24
25
|
|
26
|
+
def render(options = {})
|
27
|
+
return if @already_rendered # render only once
|
28
|
+
return unless (@options && @options.verbose) || has_output
|
29
|
+
|
30
|
+
if options.has_key?(:text)
|
31
|
+
puts options[:text]
|
32
|
+
else
|
33
|
+
puts View.new(model, @method).render(binding)
|
34
|
+
end
|
35
|
+
|
36
|
+
@already_rendered = true
|
37
|
+
end
|
38
|
+
|
25
39
|
protected
|
26
40
|
|
27
41
|
attr_writer :exitstatus, :has_output
|
@@ -1,4 +1,8 @@
|
|
1
1
|
require 'fileutils'
|
2
|
+
#require 'action_view/helpers/text_helper'
|
3
|
+
require 'active_support/core_ext/enumerable'
|
4
|
+
require 'active_model'
|
5
|
+
require 'active_model/serializers/json'
|
2
6
|
|
3
7
|
module Paradeiser
|
4
8
|
class ParadeiserController < Controller
|
@@ -8,7 +12,19 @@ module Paradeiser
|
|
8
12
|
end
|
9
13
|
|
10
14
|
def report
|
11
|
-
|
15
|
+
pomodori = Repository.all_pomodori
|
16
|
+
|
17
|
+
@finished = pomodori.select{|p| p.finished?}.size
|
18
|
+
@canceled = pomodori.select{|p| p.canceled?}.size
|
19
|
+
@external_interrupts = pomodori.map{|p| p.interrupts}.flatten.select{|i| :external == i.type}.size
|
20
|
+
@internal_interrupts = pomodori.map{|p| p.interrupts}.flatten.select{|i| :internal == i.type}.size
|
21
|
+
|
22
|
+
breaks = Repository.all_breaks
|
23
|
+
@breaks = breaks.size
|
24
|
+
@break_minutes = breaks.sum{|b| b.duration}.to_i.minutes
|
25
|
+
|
26
|
+
@annotations = pomodori.collect{|p| p.annotations}.flatten
|
27
|
+
|
12
28
|
self.has_output = true
|
13
29
|
end
|
14
30
|
|
@@ -16,6 +32,12 @@ module Paradeiser
|
|
16
32
|
@pom = Repository.active || Repository.all.last
|
17
33
|
self.exitstatus = Status.of(@pom).to_i
|
18
34
|
self.has_output = true
|
35
|
+
render(:text => 'There are no pomodori or breaks.') unless @pom
|
36
|
+
end
|
37
|
+
|
38
|
+
def export
|
39
|
+
self.has_output = true
|
40
|
+
render(:text => Repository.all.to_json)
|
19
41
|
end
|
20
42
|
end
|
21
43
|
end
|
@@ -7,7 +7,6 @@ module Paradeiser
|
|
7
7
|
raise SingletonError.new(Pomodoro, Repository.active, :start) if Repository.active?
|
8
8
|
|
9
9
|
@pom = Pomodoro.new
|
10
|
-
@pom.start!
|
11
10
|
Repository.save(@pom)
|
12
11
|
end
|
13
12
|
|
@@ -15,6 +14,7 @@ module Paradeiser
|
|
15
14
|
@pom = Repository.active
|
16
15
|
raise NotActiveError unless @pom
|
17
16
|
raise SingletonError.new(Pomodoro, @pom, :finish) if Repository.active? && !@pom.kind_of?(Pomodoro)
|
17
|
+
@pom.annotate(@args.join(' ')) if @args.any?
|
18
18
|
@pom.cancel!
|
19
19
|
Repository.save(@pom)
|
20
20
|
end
|
@@ -23,6 +23,7 @@ module Paradeiser
|
|
23
23
|
@pom = Repository.active
|
24
24
|
raise NotActiveError unless @pom
|
25
25
|
raise SingletonError.new(Pomodoro, @pom, :finish) if Repository.active? && !@pom.kind_of?(Pomodoro)
|
26
|
+
@pom.annotate(@args.join(' ')) if @args.any?
|
26
27
|
@pom.finish!
|
27
28
|
Repository.save(@pom)
|
28
29
|
end
|
@@ -32,15 +33,36 @@ module Paradeiser
|
|
32
33
|
raise NotActiveError unless @pom
|
33
34
|
raise SingletonError.new(Pomodoro, @pom, :interrupt) if Repository.active? && !@pom.kind_of?(Pomodoro)
|
34
35
|
|
36
|
+
@pom.annotate(@args.join(' ')) if @args.any?
|
37
|
+
|
35
38
|
if @options.external
|
39
|
+
@interrupt_type = 'externally'
|
36
40
|
@pom.interrupt!(:external)
|
37
41
|
else
|
42
|
+
@interrupt_type = 'internally'
|
38
43
|
@pom.interrupt!
|
39
44
|
end
|
40
45
|
|
41
46
|
Repository.save(@pom)
|
42
47
|
end
|
43
48
|
|
49
|
+
def annotate
|
50
|
+
raise MissingAnnotationError unless @args && @args.any?
|
51
|
+
@pom = Repository.all.select{|p| p.kind_of?(Pomodoro)}.sort{|a,b| a.started_at <=> b.started_at}.last
|
52
|
+
@pom.annotate(@args.join(' '))
|
53
|
+
Repository.save(@pom)
|
54
|
+
end
|
55
|
+
|
56
|
+
def log
|
57
|
+
@pom = Pomodoro.new
|
58
|
+
@pom.id = Repository.next_id
|
59
|
+
@pom.annotate(@args.join(' ')) if @args.any?
|
60
|
+
@pom.status = :finished
|
61
|
+
@pom.finished_at = Time.now
|
62
|
+
@pom.started_at = @pom.finished_at - Pomodoro::MINUTES_25 * 60
|
63
|
+
Repository.save(@pom)
|
64
|
+
end
|
65
|
+
|
44
66
|
private
|
45
67
|
|
46
68
|
def end_break
|
data/lib/paradeiser/errors.rb
CHANGED
data/lib/paradeiser/executor.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
ActiveSupport::Inflector.inflections do |inflect|
|
2
|
+
inflect.irregular 'paradeiser', 'paradeiser'
|
2
3
|
inflect.irregular 'pomodoro', 'pomodori'
|
4
|
+
inflect.irregular 'interrupt', 'interrupts'
|
3
5
|
inflect.irregular 'break', 'breaks'
|
6
|
+
inflect.irregular 'minute', 'minutes'
|
4
7
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module Paradeiser
|
2
2
|
class Pomodoro < Scheduled
|
3
|
-
attr_reader :interrupts, :interrupt_type
|
3
|
+
attr_reader :interrupts, :interrupt_type, :annotations
|
4
4
|
attr_accessor :canceled_at
|
5
5
|
|
6
6
|
MINUTES_25 = 25
|
@@ -52,6 +52,8 @@ module Paradeiser
|
|
52
52
|
def initialize
|
53
53
|
super # required for state_machine
|
54
54
|
@interrupts = []
|
55
|
+
@annotations = []
|
56
|
+
start!
|
55
57
|
end
|
56
58
|
|
57
59
|
def length
|
@@ -62,5 +64,15 @@ module Paradeiser
|
|
62
64
|
@interrupt_type = type
|
63
65
|
super
|
64
66
|
end
|
67
|
+
|
68
|
+
def duration
|
69
|
+
start = started_at || Time.now
|
70
|
+
finish = finished_at || canceled_at || Time.now
|
71
|
+
(finish - start).to_i
|
72
|
+
end
|
73
|
+
|
74
|
+
def annotate(text)
|
75
|
+
@annotations << text
|
76
|
+
end
|
65
77
|
end
|
66
78
|
end
|
@@ -7,6 +7,14 @@ module Paradeiser
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
def all_pomodori
|
11
|
+
all.select{|p| p.kind_of?(Pomodoro)}
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_breaks
|
15
|
+
all.select{|b| b.kind_of?(Break)}
|
16
|
+
end
|
17
|
+
|
10
18
|
def any?(&blk)
|
11
19
|
all.any?(&blk)
|
12
20
|
end
|
@@ -40,7 +48,9 @@ module Paradeiser
|
|
40
48
|
|
41
49
|
def save(pom)
|
42
50
|
raise IllegalStatusError if pom.idle?
|
43
|
-
|
51
|
+
|
52
|
+
# Do not allow saving of a new active pomodoro while another pomodoro or break is active
|
53
|
+
raise SingletonError.new(pom.class, self.active, :save) if self.active? && pom.new?
|
44
54
|
|
45
55
|
pom.id = next_id if pom.new?
|
46
56
|
backend.transaction do
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'active_support/core_ext/enumerable'
|
2
|
+
|
1
3
|
module Paradeiser
|
2
4
|
class Scheduled
|
3
5
|
attr_accessor :id, :started_at, :finished_at
|
@@ -9,7 +11,7 @@ module Paradeiser
|
|
9
11
|
# from https://github.com/travis-ci/travis/blob/master/lib/travis/client/job.rb
|
10
12
|
def duration
|
11
13
|
start = started_at || Time.now
|
12
|
-
finish = finished_at ||
|
14
|
+
finish = finished_at || Time.now
|
13
15
|
(finish - start).to_i
|
14
16
|
end
|
15
17
|
|
@@ -21,5 +23,9 @@ module Paradeiser
|
|
21
23
|
def name
|
22
24
|
self.class.name.split("::").last.downcase
|
23
25
|
end
|
26
|
+
|
27
|
+
def as_json(*options)
|
28
|
+
{:type => name.titlecase, :length => length}.merge(super(*options))
|
29
|
+
end
|
24
30
|
end
|
25
31
|
end
|
data/lib/paradeiser/router.rb
CHANGED
@@ -25,8 +25,6 @@ module Paradeiser
|
|
25
25
|
controller = controller_class.new(verb)
|
26
26
|
controller.call(args, options)
|
27
27
|
|
28
|
-
View.new(controller.model, verb).render(controller.get_binding) if options.verbose || controller.has_output
|
29
|
-
|
30
28
|
@status = controller.exitstatus
|
31
29
|
end
|
32
30
|
end
|
data/lib/paradeiser/version.rb
CHANGED
data/lib/paradeiser/view.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
Finished break #<%= @break.id %> after <%= @break.duration.minutes %> minutes.
|
@@ -0,0 +1 @@
|
|
1
|
+
Started a new break (<%= @break.length.minutes %> minutes).
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
Successfully initialized <%= Paradeiser.par_dir %>.
|
@@ -1,5 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
# Pomodoro Report
|
2
|
+
- <%= pluralize(@finished, 'pomodoro') %> finished
|
3
|
+
- <%= pluralize(@canceled, 'pomodoro') %> canceled
|
4
|
+
- <%= pluralize(@internal_interrupts, 'internal interrupt') %>
|
5
|
+
- <%= pluralize(@external_interrupts, 'external interrupt') %>
|
6
|
+
- <%= pluralize(@breaks, 'break') %> (<%= pluralize(@break_minutes, 'minute') %> in total)
|
7
|
+
<% if @annotations.any? %>
|
8
|
+
|
9
|
+
## Annotations<% @annotations.each do |annotation| %>
|
10
|
+
* <%= annotation %><% end %>
|
5
11
|
<% end %>
|
@@ -1,4 +1,5 @@
|
|
1
|
-
<%
|
1
|
+
<%
|
2
|
+
case @pom.status_name
|
2
3
|
when :active
|
3
4
|
%><%= @pom.name.capitalize %> #<%= @pom.id %> is active for another <%= @pom.remaining.minutes %> minutes (started at <%= @pom.started_at.strftime('%R') %>).<% unless !@pom.respond_to?(:interrupts) || @pom.interrupts.empty? %> <%= @pom.interrupts.size %> interrupts on record.<% end %><%
|
4
5
|
when :break
|
@@ -0,0 +1 @@
|
|
1
|
+
Successfully annotated pomodoro #<%= @pom.id %>.
|
@@ -0,0 +1 @@
|
|
1
|
+
Canceled pomodoro #<%= @pom.id %> after <%= @pom.duration.minutes %> minutes.
|
@@ -0,0 +1 @@
|
|
1
|
+
Marked pomodoro #<%= @pom.id %> as <%= @interrupt_type %> interrupted.
|
@@ -0,0 +1 @@
|
|
1
|
+
Successfully logged pomodoro #<%= @pom.id %>.
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
Started pomodoro #<%= @pom.id %>.
|
data/paradeiser.gemspec
CHANGED
@@ -23,6 +23,8 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.add_runtime_dependency 'state_machine'
|
24
24
|
spec.add_runtime_dependency 'activesupport'
|
25
25
|
spec.add_runtime_dependency 'actionpack'
|
26
|
+
# spec.add_runtime_dependency 'actionview'
|
27
|
+
spec.add_runtime_dependency 'activemodel'
|
26
28
|
|
27
29
|
# Moved to the Gemfile so that Travis CI can load the test group
|
28
30
|
# spec.add_development_dependency 'rake'
|
@@ -0,0 +1 @@
|
|
1
|
+
true
|
data/test/helper.rb
CHANGED
@@ -10,9 +10,13 @@ class MiniTest::Test
|
|
10
10
|
|
11
11
|
protected
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
|
13
|
+
def produce(clazz)
|
14
|
+
@started = srand
|
15
|
+
|
16
|
+
Time.stub :now, Time.at(@started) do
|
17
|
+
Scheduler.stub(:add, nil) do
|
18
|
+
clazz.new
|
19
|
+
end
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
@@ -34,24 +38,3 @@ protected
|
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
37
|
-
|
38
|
-
class ControllerTest < MiniTest::Test
|
39
|
-
|
40
|
-
protected
|
41
|
-
|
42
|
-
def invoke(method, *attributes)
|
43
|
-
controller = ParadeiserController.new(method)
|
44
|
-
|
45
|
-
Repository.stub :backend, @backend do
|
46
|
-
Scheduler.stub(:add, nil) do
|
47
|
-
Scheduler.stub(:clear, nil) do
|
48
|
-
controller.call(nil, nil)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
attributes.map do |attribute|
|
54
|
-
controller.get_binding.eval(attribute)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|