haora 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,11 @@
1
+ require 'fileutils'
2
+
3
+ class File
4
+
5
+ def self.ensure_exist(path)
6
+ dir = File.dirname path
7
+ FileUtils.makedirs dir unless Dir.exist? dir
8
+ FileUtils.touch path unless File.exist? path
9
+ end
10
+
11
+ end
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: []