haora 0.0.1
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 +7 -0
- data/bin/haora +43 -0
- data/lib/haora/day.rb +42 -0
- data/lib/haora/file.rb +11 -0
- data/lib/haora/io.rb +56 -0
- data/lib/haora/project.rb +31 -0
- data/lib/haora/renderer.rb +42 -0
- data/lib/haora/task.rb +19 -0
- data/lib/haora/timestamp.rb +78 -0
- data/lib/haora/workbook.rb +35 -0
- data/lib/haora.rb +60 -0
- metadata +125 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dfa559ad454e9144340aa59e327854c6bd4dc187
|
4
|
+
data.tar.gz: ecfabc805841a3352dbef5923bd2bd4fbf0a16d4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 47689c4dadc88d8aaba74bc8a40afd287542b737e078f0f416ef850b890b5ce747b5a30b64438fdb96a425041025b7dd78bad1b06c12364df18a9b8fd19a383a
|
7
|
+
data.tar.gz: 6caba7632ef466873407ec2d299d3c84c8087268d3d44802c5e9085edfdcfbfb752422eedecaf6388481bee388849ea437e744506d4823b585b3160bbae0b85d
|
data/bin/haora
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'gli'
|
4
|
+
include GLI::App
|
5
|
+
|
6
|
+
require 'haora'
|
7
|
+
|
8
|
+
desc 'Path to file containing working times'
|
9
|
+
arg_name 'file_name'
|
10
|
+
default_value File.join(ENV['HOME'], '.haora', 'workbook')
|
11
|
+
flag :f, :file
|
12
|
+
|
13
|
+
desc 'Date to be used'
|
14
|
+
arg_name 'date'
|
15
|
+
default_value Date.today.strftime '%d.%m.%Y'
|
16
|
+
flag :d, :date
|
17
|
+
|
18
|
+
desc 'Adds a task to the current or another day'
|
19
|
+
command :add do |c|
|
20
|
+
c.flag :p, :project
|
21
|
+
c.flag :b, :begin
|
22
|
+
c.flag :e, :end
|
23
|
+
c.action do |global_actions, options, args|
|
24
|
+
file_name = global_actions[:file]
|
25
|
+
date = global_actions[:date]
|
26
|
+
start = options[:begin]
|
27
|
+
stop = options[:end]
|
28
|
+
project = options[:project]
|
29
|
+
text = args[0]
|
30
|
+
Haora::Service.for(file_name).add_task(date: date, start: start, stop: stop, project: project, text: text)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc 'Lists tasks of a day'
|
35
|
+
command :list do |c|
|
36
|
+
c.action do |global_actions, options, args|
|
37
|
+
file_name = global_actions[:file]
|
38
|
+
date = global_actions[:date]
|
39
|
+
puts Haora::Service.for(file_name).list(date)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
exit run(ARGV)
|
data/lib/haora/day.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Haora
|
4
|
+
|
5
|
+
class Day
|
6
|
+
attr_reader :date
|
7
|
+
|
8
|
+
def initialize(date = nil)
|
9
|
+
@date = date.nil? ? Date.today : date
|
10
|
+
end
|
11
|
+
|
12
|
+
def tasks
|
13
|
+
@tasks ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(task)
|
17
|
+
tasks << task
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
date == other.date
|
22
|
+
end
|
23
|
+
|
24
|
+
def <=>(other)
|
25
|
+
date <=> other.date
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
@date.strftime '%F'
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
class DateParser
|
35
|
+
|
36
|
+
def self.parse(date)
|
37
|
+
return Date.strptime(date, '%d.%m.%Y')
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/haora/file.rb
ADDED
data/lib/haora/io.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
module Haora
|
2
|
+
|
3
|
+
module TextIOExporter
|
4
|
+
|
5
|
+
def export(workbook, io)
|
6
|
+
io.puts(workbook.days.sort.map { |d| export_day(d) })
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def export_day(day)
|
12
|
+
d = 'DAY ' << day.date.strftime('%F') << $/
|
13
|
+
d << day.tasks
|
14
|
+
.map { |t| t.start.to_s << '-' << t.stop.to_s << '|' << t.project.name << '|' << t.text << $/ }
|
15
|
+
.join
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module TextIOImporter
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
DAY_RE = /DAY (\d\d\d\d-\d\d-\d\d)/
|
25
|
+
TASK_RE = /(\d?\d:\d\d)-(\d\d:\d\d)?\|(.*)\|(.*)?/
|
26
|
+
|
27
|
+
public
|
28
|
+
|
29
|
+
def import(io)
|
30
|
+
@workbook = Workbook.new
|
31
|
+
io.each_line { |line|
|
32
|
+
DAY_RE.match(line) { |date_match| new_day(date_match) }
|
33
|
+
TASK_RE.match(line) { |task_match| new_task(task_match) }
|
34
|
+
}
|
35
|
+
@workbook
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def new_task(task_match)
|
41
|
+
@day << Task.new(start: task_match[1], stop: task_match[2], project: task_match[3], text: task_match[4])
|
42
|
+
end
|
43
|
+
|
44
|
+
def new_day(date_match)
|
45
|
+
@day = Day.new(Date.parse(date_match[1]))
|
46
|
+
@workbook << @day
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
module TextIO
|
52
|
+
include TextIOExporter
|
53
|
+
include TextIOImporter
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Haora
|
2
|
+
|
3
|
+
class Project
|
4
|
+
attr_reader :name
|
5
|
+
|
6
|
+
@projects = Hash.new
|
7
|
+
@projects.default_proc = proc do |hash, name|
|
8
|
+
hash[name] = Project.new(name)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.by(params)
|
12
|
+
@projects[params[:name]]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.all
|
16
|
+
@projects
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.clear
|
20
|
+
@projects.clear
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def initialize(name)
|
26
|
+
@name = name
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Haora
|
2
|
+
|
3
|
+
class StandardDayRenderer
|
4
|
+
|
5
|
+
def render(day)
|
6
|
+
'Tasks of ' << rendered_date_of(day) << "\n" \
|
7
|
+
<< rendered(day.tasks)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def rendered_date_of(day)
|
13
|
+
if day.date == Date.today
|
14
|
+
'today'
|
15
|
+
else
|
16
|
+
day.date.strftime('%d.%m.%Y')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def rendered(tasks)
|
21
|
+
tasks.map { |task| rendered_task(task) }.join("\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def rendered_task(task)
|
25
|
+
timespan = rendered_timespan(task.start, task.stop)
|
26
|
+
duration = rendered_duration(task.start, task.stop)
|
27
|
+
'%s = %s on %s: %s' % [timespan, duration, task.project.name, task.text]
|
28
|
+
end
|
29
|
+
|
30
|
+
def rendered_timespan(start, stop)
|
31
|
+
timespan = start.to_s << ' - ' << stop.to_s
|
32
|
+
timespan.prepend(' ') if timespan.length < 13
|
33
|
+
timespan
|
34
|
+
end
|
35
|
+
|
36
|
+
def rendered_duration(start, stop)
|
37
|
+
'%5.2f' % (stop - start).hours
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
data/lib/haora/task.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Haora
|
2
|
+
|
3
|
+
class Task
|
4
|
+
attr_reader :start, :stop, :project, :text
|
5
|
+
|
6
|
+
def initialize(params)
|
7
|
+
@start = params[:start] ? Timestamp.new(params[:start]) : Timestamp.now
|
8
|
+
@stop = params[:stop] ? Timestamp.new(params[:stop]) : nil
|
9
|
+
@project = Project.by(name: params[:project])
|
10
|
+
@text = params[:text] || ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
'%s - %s : %s : %s' % [@start, @stop, @project.name, @text]
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Haora
|
2
|
+
|
3
|
+
class Timestamp
|
4
|
+
attr_reader :hour, :minute
|
5
|
+
|
6
|
+
def initialize(*params)
|
7
|
+
if params.size == 1 && params.first.is_a?(String)
|
8
|
+
@hour, @minute = parse_timestamp_literal(params.first)
|
9
|
+
elsif params.size == 2 && (params.all? { |p| p.is_a?(Integer) })
|
10
|
+
@hour, @minute = params.first(2)
|
11
|
+
end
|
12
|
+
raise ArgumentError if invalid?
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.now
|
16
|
+
now = Time.now
|
17
|
+
Timestamp.new(now.hour, now.min)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_timestamp_literal(timestamp)
|
23
|
+
/(\d?\d):(\d\d)/.match(timestamp) do |m|
|
24
|
+
return [m[1].to_i, m[2].to_i]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def invalid?
|
29
|
+
raise ArgumentError if !@hour.is_a?(Integer) || !@minute.is_a?(Integer)
|
30
|
+
raise ArgumentError if @hour < 0 || @minute < 0
|
31
|
+
raise ArgumentError if @hour > 23 || @minute > 59
|
32
|
+
end
|
33
|
+
|
34
|
+
public
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
'%d:%02d' % [hour, minute]
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_minutes
|
41
|
+
hour * 60 + minute
|
42
|
+
end
|
43
|
+
|
44
|
+
def -(other)
|
45
|
+
Duration.of_minutes(self.to_minutes - other.to_minutes)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
class Duration
|
51
|
+
attr_reader :minutes
|
52
|
+
|
53
|
+
def self.of_minutes(minutes)
|
54
|
+
Duration.new(minutes)
|
55
|
+
end
|
56
|
+
|
57
|
+
def parts
|
58
|
+
{:hours => @minutes / 60,
|
59
|
+
:minutes => @minutes % 60}
|
60
|
+
end
|
61
|
+
|
62
|
+
def hours
|
63
|
+
minutes / 60.0
|
64
|
+
end
|
65
|
+
|
66
|
+
def to_s
|
67
|
+
'%d h %d m' % [parts[:hours], parts[:minutes]]
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def initialize(minutes)
|
73
|
+
@minutes = minutes
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Haora
|
2
|
+
|
3
|
+
class Workbook
|
4
|
+
attr_accessor :path
|
5
|
+
|
6
|
+
def days
|
7
|
+
@days ||= []
|
8
|
+
end
|
9
|
+
|
10
|
+
def <<(day)
|
11
|
+
days << day
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](param)
|
15
|
+
date = parse_date_param(param)
|
16
|
+
day = days.select { |d| d.date == date }.first
|
17
|
+
days << (day = Day.new(date)) if day.nil?
|
18
|
+
day
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def parse_date_param(param)
|
24
|
+
date = Date.today
|
25
|
+
if param.is_a? String
|
26
|
+
date = DateParser.parse param
|
27
|
+
elsif param.is_a? Date
|
28
|
+
date = param
|
29
|
+
end
|
30
|
+
date
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
data/lib/haora.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'haora/timestamp'
|
2
|
+
require 'haora/task'
|
3
|
+
require 'haora/project'
|
4
|
+
require 'haora/day'
|
5
|
+
require 'haora/renderer'
|
6
|
+
require 'haora/workbook'
|
7
|
+
require 'haora/io'
|
8
|
+
require 'haora/file'
|
9
|
+
|
10
|
+
module Haora
|
11
|
+
|
12
|
+
class Service
|
13
|
+
attr_reader :workbook
|
14
|
+
|
15
|
+
def self.for(file_name)
|
16
|
+
Service.new(file_name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_task(params)
|
20
|
+
apply {
|
21
|
+
@workbook[params[:date]] << Task.new(start: params[:start], stop: params[:stop], project: params[:project], text: params[:text])
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
def list(date = nil)
|
26
|
+
day = @workbook[date]
|
27
|
+
StandardDayRenderer.new.render(day)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def apply
|
33
|
+
yield
|
34
|
+
close
|
35
|
+
end
|
36
|
+
|
37
|
+
include TextIO
|
38
|
+
|
39
|
+
def initialize(file_name)
|
40
|
+
@workbook = open_workbook(file_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def open_workbook(file_name)
|
44
|
+
File.ensure_exist file_name
|
45
|
+
File.open(file_name, 'r') do |file|
|
46
|
+
workbook = import(file)
|
47
|
+
workbook.path = file.path
|
48
|
+
workbook
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def close
|
53
|
+
File.open(@workbook.path, 'w') do |file|
|
54
|
+
export(@workbook, file)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: haora
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dirk Rademann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-16 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gli
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest-reporters
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: aruba
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.14'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.14'
|
83
|
+
description: Command line application to keep track of daily work hours.
|
84
|
+
email: dirk.rademann@icloud.com
|
85
|
+
executables:
|
86
|
+
- haora
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- bin/haora
|
91
|
+
- lib/haora.rb
|
92
|
+
- lib/haora/day.rb
|
93
|
+
- lib/haora/file.rb
|
94
|
+
- lib/haora/io.rb
|
95
|
+
- lib/haora/project.rb
|
96
|
+
- lib/haora/renderer.rb
|
97
|
+
- lib/haora/task.rb
|
98
|
+
- lib/haora/timestamp.rb
|
99
|
+
- lib/haora/workbook.rb
|
100
|
+
homepage: http://github.com/drademann/haora-cli
|
101
|
+
licenses:
|
102
|
+
- MIT
|
103
|
+
metadata: {}
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 2.6.10
|
122
|
+
signing_key:
|
123
|
+
specification_version: 4
|
124
|
+
summary: Work Hour Diary
|
125
|
+
test_files: []
|