logbook-ruby 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 4bf9e794073c670236e9601796efb0ac9260d2825f409034b3f246dbe65cb4b6
4
- data.tar.gz: 88bd820e0f1d5a07fccb6a75161c9d1e751d3d582ed3574ebaa5bdba983da17f
2
+ SHA1:
3
+ metadata.gz: 33922c3808312335aa817342c0057f110fa07d4f
4
+ data.tar.gz: cbe8daaf3b9811df06e7846fbbc0f879f0c8e573
5
5
  SHA512:
6
- metadata.gz: 0f053d6ec96f78f6214449425e7e89d6f22f35095af529ea499d04ad261498cf52301b721b9a37812aba42e4c2071c49753232fbfc2eba0862508baa308d0e71
7
- data.tar.gz: 7a9a11bc868752d1f3e50f59f0b5b99ec9b510f729710c85600f99b810cb490062e0bd2782d7828e32e8ad3f3ad0747c41d916a4aae2df2768de419f3c5d3d30
6
+ metadata.gz: 7c0e74d9d25e2cf64b288b6485213fb3eccd236e6db5073ab39c6e8ef57eb9040616431e359c331366ef8518bd032a2c4bd60a17abbe41f5b5232dbcb2288429
7
+ data.tar.gz: 83dfb63517c4597bed2a636e4cc53179f9d15cc34272cf2abfaf9fcbc02619797113c8eebed2a91a09aff7a5358951914ad3bc94d330b076251df413d4a18438
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.5.0
1
+ ruby 2.4.1
data/lib/logbook.rb CHANGED
@@ -1,15 +1,19 @@
1
1
  module Logbook
2
- VERSION = "0.1.4"
2
+ VERSION = "0.1.5"
3
3
 
4
4
  require "logbook/builder"
5
+ require "logbook/clock"
6
+ require "logbook/log_entry"
5
7
  require "logbook/page"
6
8
  require "logbook/parser"
7
- require "logbook/log_entry"
9
+ require "logbook/property"
8
10
  require "logbook/task"
9
11
  require "logbook/task_definition"
10
12
  require "logbook/task_entry"
11
13
 
12
- Duration = Struct.new(:minutes)
13
- Property = Struct.new(:name, :value)
14
- Tag = Struct.new(:value)
14
+ Duration = Struct.new(:minutes) do
15
+ def +(other_duration)
16
+ Duration.new(self.minutes + other_duration.minutes)
17
+ end
18
+ end
15
19
  end
@@ -2,7 +2,7 @@ require "parslet"
2
2
 
3
3
  module Logbook
4
4
  class Builder < Parslet::Transform
5
- rule(tag: simple(:tag)) { Tag.new(tag.to_s) }
5
+ rule(tag: simple(:tag)) { Property.new(tag.to_s) }
6
6
 
7
7
  rule(property: {name: simple(:name), value: simple(:value)}) do
8
8
  Property.new(name.to_s, value.to_s)
@@ -16,21 +16,19 @@ module Logbook
16
16
  end
17
17
 
18
18
  rule(task_definition: subtree(:task)) do
19
- properties = task[:properties].select { |item| item.instance_of?(Property) }.map { |property| [property.name, property.value] }.to_h
20
- tags = task[:properties].select { |item| item.instance_of?(Tag) }
19
+ properties = task[:properties].map { |property| [property.name, property] }.to_h
21
20
  line_number, _ = task[:status].line_and_column
22
21
  note = task[:note].to_s.strip.chomp
23
22
 
24
- TaskDefinition.new(line_number, task[:title].to_s, task[:status].to_s, properties, tags, note)
23
+ TaskDefinition.new(line_number, task[:title].to_s, task[:status].to_s, properties, note)
25
24
  end
26
25
 
27
26
  rule(task_entry: subtree(:task)) do
28
- properties = task[:properties].select { |item| item.instance_of?(Property) }.map { |property| [property.name, property.value] }.to_h
29
- tags = task[:properties].select { |item| item.instance_of?(Tag) }
27
+ properties = task[:properties].map { |property| [property.name, property] }.to_h
30
28
  line_number, _ = task[:status].line_and_column
31
29
  note = task[:note].to_s.strip.chomp
32
30
 
33
- TaskEntry.new(line_number, task[:time].to_s, task[:title].to_s, task[:status].to_s, properties, tags, note)
31
+ TaskEntry.new(line_number, task[:time].to_s, task[:title].to_s, task[:status].to_s, properties, note)
34
32
  end
35
33
 
36
34
  def self.build(contents)
@@ -40,7 +38,7 @@ module Logbook
40
38
  logbook_page = entries_and_properties.inject(Page.new) do |page, entry_or_property|
41
39
  case entry_or_property
42
40
  when Property
43
- current_properties[entry_or_property.name] = entry_or_property.value
41
+ current_properties[entry_or_property.name] = entry_or_property
44
42
  page
45
43
  when TaskDefinition, TaskEntry
46
44
  entry_or_property.merge_page_properties(current_properties)
@@ -0,0 +1,43 @@
1
+ module Logbook
2
+ class Clock
3
+ def tick(entry)
4
+ case entry
5
+ when LogEntry
6
+ if running?
7
+ yield(tracked_entry, minutes_in_between(tracked_entry, entry))
8
+ reset
9
+ end
10
+ when TaskEntry
11
+ if running?
12
+ yield(tracked_entry, minutes_in_between(tracked_entry, entry))
13
+ reset
14
+ end
15
+
16
+ if entry.starts_clock?
17
+ track(entry)
18
+ end
19
+ else
20
+ # ignore
21
+ end
22
+ end
23
+
24
+ private
25
+ attr_accessor :tracked_entry
26
+
27
+ def reset
28
+ @tracked_entry = nil
29
+ end
30
+
31
+ def running?
32
+ !tracked_entry.nil?
33
+ end
34
+
35
+ def track(entry)
36
+ @tracked_entry = entry
37
+ end
38
+
39
+ def minutes_in_between(previous_entry, current_entry)
40
+ Duration.new((current_entry.recorded_at.to_time - previous_entry.recorded_at.to_time) / 60)
41
+ end
42
+ end
43
+ end
@@ -5,19 +5,11 @@ module Logbook
5
5
  attr_accessor :properties
6
6
 
7
7
  def recorded_at
8
- date = self.properties[DATE_PROPERTY_NAME]
8
+ date = self.properties[DATE_PROPERTY_NAME].value
9
9
  time = self.time
10
10
 
11
11
  DateTime.parse(date + " " + time)
12
12
  rescue ArgumentError
13
13
  end
14
-
15
- def starts_clock?
16
- false
17
- end
18
-
19
- def stops_clock?
20
- true
21
- end
22
14
  end
23
15
  end
data/lib/logbook/page.rb CHANGED
@@ -1,39 +1,44 @@
1
1
  module Logbook
2
2
  class Page
3
- attr_accessor :entries, :properties
3
+ attr_accessor :clock, :entries, :logged_work, :properties
4
4
 
5
5
  def initialize
6
+ @clock = Clock.new
6
7
  @entries = []
8
+ @logged_work = {}
7
9
  end
8
10
 
9
11
  def add(entry)
10
12
  entries << entry
13
+ clock.tick(entry) { |tracked_entry, duration| logged_work.store(tracked_entry, duration) }
11
14
  end
12
15
 
13
16
  def entry_at(line_number)
14
17
  entries.reverse.find { |entry| entry.line_number <= line_number }
15
18
  end
16
19
 
17
- def total_duration
18
- _, duration = entries.inject([nil, Duration.new(0)]) do |(previous_entry, duration), current_entry|
19
- if previous_entry && previous_entry.starts_clock?
20
- if current_entry.stops_clock?
21
- new_duration = Duration.new(duration.minutes + minutes_in_between(previous_entry, current_entry))
22
- [current_entry, new_duration]
23
- else
24
- [previous_entry, duration]
20
+ def logged_time
21
+ logged_work.map { |entry, duration| duration }.reduce(Duration.new(0), &:+)
22
+ end
23
+
24
+ def tasks
25
+ entries.reduce({}) do |tasks, entry|
26
+ case entry
27
+ when TaskEntry, TaskDefinition
28
+ if entry.belongs_to_task?
29
+ task = tasks[entry.task_id] ||= Task.new(entry.task_id)
30
+
31
+ if logged_work.has_key?(entry)
32
+ task.log_work(entry, logged_work[entry])
33
+ else
34
+ task.add_entry(entry)
35
+ end
25
36
  end
26
37
  else
27
- [current_entry, duration]
28
38
  end
29
- end
30
39
 
31
- duration
32
- end
33
-
34
- private
35
- def minutes_in_between(previous_entry, current_entry)
36
- (current_entry.recorded_at.to_time - previous_entry.recorded_at.to_time) / 60
40
+ tasks
41
+ end
37
42
  end
38
43
  end
39
44
  end
@@ -7,7 +7,8 @@ module Logbook
7
7
  rule(:newline) { match("\n") }
8
8
 
9
9
  rule(:text) { match("[^\n]") }
10
- rule(:text_line) { text.repeat(0) >> newline }
10
+ rule(:text_line) { text.repeat(1) }
11
+ rule(:text_line_with_newline) { text.repeat(0) >> newline }
11
12
  rule(:label) { match["a-zA-Z"] >> match["a-zA-Z0-9_-"].repeat }
12
13
 
13
14
  rule(:property_value) { match("[^\\n\\]\\[]").repeat(1) }
@@ -27,19 +28,19 @@ module Logbook
27
28
  rule(:status) { str("[") >> label.as(:status) >> str("]") }
28
29
  rule(:title) { text.repeat }
29
30
 
30
- rule(:note_line) { time.absent? >> status.absent? >> property.absent? >> text_line }
31
+ rule(:note_line) { time.absent? >> status.absent? >> property.absent? >> (text_line_with_newline | text_line)}
31
32
  rule(:note) { note_line.repeat }
32
33
 
33
34
  rule(:log_entry) { time >> whitespace >> newline.maybe >> note.as(:note) }
34
35
 
35
36
  rule(:task_definition) do
36
- status >> whitespace >> title.as(:title) >> str("\n") >>
37
+ status >> whitespace >> title.as(:title) >> newline >>
37
38
  newline.repeat >> property_or_tag_list.as(:properties) >>
38
39
  newline.repeat >> note.as(:note)
39
40
  end
40
41
 
41
42
  rule(:task_entry) do
42
- time >> whitespace >> status >> whitespace >> title.as(:title) >> str("\n") >>
43
+ time >> whitespace >> status >> whitespace >> title.as(:title) >> newline >>
43
44
  newline.repeat >> property_or_tag_list.as(:properties) >>
44
45
  newline.repeat >> note.as(:note)
45
46
  end
@@ -50,7 +51,7 @@ module Logbook
50
51
  task_entry.as(:task_entry) |
51
52
  log_entry.as(:log_entry) |
52
53
  property.as(:property) |
53
- text_line
54
+ (text_line_with_newline | text_line)
54
55
  ).repeat
55
56
  end
56
57
 
@@ -0,0 +1,20 @@
1
+ module Logbook
2
+ class Property
3
+ attr_accessor :name, :value
4
+
5
+ TAG_VALUE = nil
6
+
7
+ def initialize(name, value = TAG_VALUE)
8
+ @name = name
9
+ @value = value
10
+ end
11
+
12
+ def has_value?
13
+ !is_tag? && !value.strip.empty?
14
+ end
15
+
16
+ def is_tag?
17
+ self.value === TAG_VALUE
18
+ end
19
+ end
20
+ end
data/lib/logbook/task.rb CHANGED
@@ -1,9 +1,31 @@
1
1
  module Logbook
2
2
  class Task
3
+ attr_accessor :entries, :id, :properties, :status, :title, :time_logged
4
+
3
5
  DONE = "Done"
4
6
  PAUSE = "Pause"
5
7
  REOPEN = "Reopen"
6
8
  RESUME = "Resume"
7
9
  START = "Start"
10
+ TASK_ID_PROPERTY = "ID"
11
+
12
+ def initialize(id)
13
+ @entries = []
14
+ @id = id
15
+ @properties = {}
16
+ @time_logged = Duration.new(0)
17
+ end
18
+
19
+ def add_entry(entry)
20
+ self.properties.merge!(entry.properties)
21
+ self.status = entry.status
22
+ self.title = entry.title
23
+ end
24
+
25
+ def log_work(entry, duration)
26
+ add_entry(entry)
27
+
28
+ self.time_logged += duration
29
+ end
8
30
  end
9
31
  end
@@ -1,15 +1,16 @@
1
1
  module Logbook
2
- class TaskDefinition < Struct.new(:line_number, :title, :status, :properties, :tags, :note)
3
- def merge_page_properties(properties)
4
- self.properties = properties.merge(self.properties)
2
+ class TaskDefinition < Struct.new(:line_number, :title, :status, :properties, :note)
3
+ def belongs_to_task?
4
+ self.properties.has_key?(Task::TASK_ID_PROPERTY) &&
5
+ self.properties[Task::TASK_ID_PROPERTY].has_value?
5
6
  end
6
7
 
7
- def starts_clock?
8
- false
8
+ def merge_page_properties(properties)
9
+ self.properties = properties.merge(self.properties)
9
10
  end
10
11
 
11
- def stops_clock?
12
- false
12
+ def task_id
13
+ self.properties[Task::TASK_ID_PROPERTY].value
13
14
  end
14
15
  end
15
16
  end
@@ -1,15 +1,20 @@
1
1
  require "date"
2
2
 
3
3
  module Logbook
4
- class TaskEntry < Struct.new(:line_number, :time, :title, :status, :properties, :tags, :note)
4
+ class TaskEntry < Struct.new(:line_number, :time, :title, :status, :properties, :note)
5
5
  DATE_PROPERTY_NAME = "Date"
6
6
 
7
+ def belongs_to_task?
8
+ self.properties.has_key?(Task::TASK_ID_PROPERTY) &&
9
+ self.properties[Task::TASK_ID_PROPERTY].has_value?
10
+ end
11
+
7
12
  def merge_page_properties(properties)
8
13
  self.properties = properties.merge(self.properties)
9
14
  end
10
15
 
11
16
  def recorded_at
12
- date = self.properties[DATE_PROPERTY_NAME]
17
+ date = self.properties[DATE_PROPERTY_NAME].value
13
18
  time = self.time
14
19
 
15
20
  DateTime.parse(date + " " + time)
@@ -20,8 +25,8 @@ module Logbook
20
25
  [Task::START, Task::RESUME, Task::REOPEN].include?(self.status)
21
26
  end
22
27
 
23
- def stops_clock?
24
- true
28
+ def task_id
29
+ self.properties[Task::TASK_ID_PROPERTY].value
25
30
  end
26
31
  end
27
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logbook-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.1.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gabriel Malkas
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-24 00:00:00.000000000 Z
11
+ date: 2018-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -114,9 +114,11 @@ files:
114
114
  - bin/setup
115
115
  - lib/logbook.rb
116
116
  - lib/logbook/builder.rb
117
+ - lib/logbook/clock.rb
117
118
  - lib/logbook/log_entry.rb
118
119
  - lib/logbook/page.rb
119
120
  - lib/logbook/parser.rb
121
+ - lib/logbook/property.rb
120
122
  - lib/logbook/task.rb
121
123
  - lib/logbook/task_definition.rb
122
124
  - lib/logbook/task_entry.rb
@@ -140,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
140
142
  version: '0'
141
143
  requirements: []
142
144
  rubyforge_project:
143
- rubygems_version: 2.7.3
145
+ rubygems_version: 2.6.11
144
146
  signing_key:
145
147
  specification_version: 4
146
148
  summary: Ruby library for the Logbook file format