paradeiser 0.2.0 → 0.4.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/.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
|