doing 2.1.39 → 2.1.40
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/bin/commands/config.rb +43 -34
- data/bin/commands/done.rb +1 -18
- data/bin/commands/finish.rb +30 -25
- data/bin/commands/grep.rb +3 -14
- data/bin/commands/last.rb +2 -8
- data/bin/commands/meanwhile.rb +13 -6
- data/bin/commands/on.rb +3 -16
- data/bin/commands/recent.rb +2 -8
- data/bin/commands/reset.rb +24 -1
- data/bin/commands/select.rb +1 -1
- data/bin/commands/show.rb +6 -17
- data/bin/commands/since.rb +1 -12
- data/bin/commands/today.rb +2 -13
- data/bin/commands/view.rb +1 -1
- data/bin/commands/yesterday.rb +2 -13
- data/bin/doing +15 -8
- data/docs/doc/Array.html +1 -1
- data/docs/doc/BooleanTermParser/Clause.html +1 -1
- data/docs/doc/BooleanTermParser/Operator.html +1 -1
- data/docs/doc/BooleanTermParser/Query.html +1 -1
- data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
- data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +166 -20
- data/docs/doc/Doing/Completion.html +1 -1
- data/docs/doc/Doing/Configuration.html +1 -1
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +7 -3
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +7 -3
- data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
- data/docs/doc/Doing/Errors/EmptyInput.html +10 -2
- data/docs/doc/Doing/Errors/HistoryLimitError.html +194 -0
- data/docs/doc/Doing/Errors/InvalidPlugin.html +194 -0
- data/docs/doc/Doing/Errors/MissingBackupFile.html +194 -0
- data/docs/doc/Doing/Errors/NoResults.html +10 -2
- data/docs/doc/Doing/Errors/PluginException.html +1 -1
- data/docs/doc/Doing/Errors/UserCancelled.html +10 -2
- data/docs/doc/Doing/Errors/WrongCommand.html +10 -2
- data/docs/doc/Doing/Errors.html +9 -9
- data/docs/doc/Doing/Hooks.html +1 -1
- data/docs/doc/Doing/Item.html +90 -1615
- data/docs/doc/Doing/Items.html +121 -5
- data/docs/doc/Doing/Logger.html +1 -1
- data/docs/doc/Doing/Note.html +1 -1
- data/docs/doc/Doing/Pager.html +1 -1
- data/docs/doc/Doing/Plugins.html +1 -1
- data/docs/doc/Doing/Prompt.html +2 -2
- data/docs/doc/Doing/Section.html +1 -1
- data/docs/doc/Doing/TemplateString.html +2 -2
- data/docs/doc/Doing/Types.html +1 -1
- data/docs/doc/Doing/Util/Backup.html +5 -5
- data/docs/doc/Doing/Util.html +1 -1
- data/docs/doc/Doing/WWID.html +197 -4033
- data/docs/doc/Doing.html +2 -2
- data/docs/doc/FalseClass.html +1 -1
- data/docs/doc/GLI/Commands/Help.html +1 -1
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
- data/docs/doc/GLI/Commands.html +1 -1
- data/docs/doc/GLI.html +1 -1
- data/docs/doc/Hash.html +1 -1
- data/docs/doc/Object.html +1 -1
- data/docs/doc/PhraseParser/Operator.html +1 -1
- data/docs/doc/PhraseParser/PhraseClause.html +1 -1
- data/docs/doc/PhraseParser/Query.html +1 -1
- data/docs/doc/PhraseParser/QueryParser.html +1 -1
- data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
- data/docs/doc/PhraseParser/TermClause.html +1 -1
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +1 -1
- data/docs/doc/String.html +1 -1
- data/docs/doc/Symbol.html +1 -1
- data/docs/doc/Time.html +1 -1
- data/docs/doc/TrueClass.html +1 -1
- data/docs/doc/_index.html +26 -5
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +2 -2
- data/docs/doc/index.html +2 -2
- data/docs/doc/method_list.html +293 -773
- data/docs/doc/top-level-namespace.html +3 -3
- data/docs/index.md +1 -1
- data/doing.rdoc +49 -7
- data/lib/completion/_doing.zsh +5 -5
- data/lib/completion/doing.bash +8 -8
- data/lib/completion/doing.fish +7 -2
- data/lib/doing/add_options.rb +31 -1
- data/lib/doing/chronify/array.rb +64 -22
- data/lib/doing/colors.rb +77 -30
- data/lib/doing/completion.rb +4 -5
- data/lib/doing/errors.rb +51 -35
- data/lib/doing/hooks.rb +3 -3
- data/lib/doing/item/dates.rb +112 -0
- data/lib/doing/item/query.rb +433 -0
- data/lib/doing/item/state.rb +59 -0
- data/lib/doing/item/tags.rb +87 -0
- data/lib/doing/item.rb +6 -667
- data/lib/doing/items.rb +38 -13
- data/lib/doing/plugin_manager.rb +3 -3
- data/lib/doing/plugins/export/template_export.rb +4 -4
- data/lib/doing/plugins/import/cal_to_json.scpt +0 -0
- data/lib/doing/util_backup.rb +6 -8
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid/display.rb +399 -0
- data/lib/doing/wwid/editor.rb +214 -0
- data/lib/doing/wwid/filetools.rb +186 -0
- data/lib/doing/wwid/filter.rb +218 -0
- data/lib/doing/wwid/guess.rb +87 -0
- data/lib/doing/wwid/interactive.rb +385 -0
- data/lib/doing/wwid/modify.rb +618 -0
- data/lib/doing/wwid/tags.rb +54 -0
- data/lib/doing/wwid/timers.rb +345 -0
- data/lib/doing/wwid/wwidutil.rb +104 -0
- data/lib/doing/wwid.rb +31 -2317
- metadata +19 -2
data/lib/doing/colors.rb
CHANGED
@@ -2,9 +2,18 @@
|
|
2
2
|
|
3
3
|
# Cribbed from <https://github.com/flori/term-ansicolor>
|
4
4
|
module Doing
|
5
|
-
# Terminal color functions
|
5
|
+
# Terminal output color functions.
|
6
6
|
module Color
|
7
|
-
#
|
7
|
+
# All available color names. Available as methods and string extensions.
|
8
|
+
#
|
9
|
+
# @example Use a color as a method. Color reset will be added to end of string.
|
10
|
+
# Color.yellow('This text is yellow') => "\e[33mThis text is yellow\e[0m"
|
11
|
+
#
|
12
|
+
# @example Use a color as a string extension. Color reset added automatically.
|
13
|
+
# 'This text is green'.green => "\e[1;32mThis text is green\e[0m"
|
14
|
+
#
|
15
|
+
# @example Send a text string as a color
|
16
|
+
# Color.send('red') => "\e[31m"
|
8
17
|
ATTRIBUTES = [
|
9
18
|
[:clear, 0], # String#clear is already used to empty string in Ruby 1.9
|
10
19
|
[:reset, 0], # synonym for :clear
|
@@ -66,7 +75,7 @@ module Doing
|
|
66
75
|
[:redacted, '0;30;40'],
|
67
76
|
[:alert, '1;31;43'],
|
68
77
|
[:error, '1;37;41'],
|
69
|
-
[:default,
|
78
|
+
[:default, '0;39']
|
70
79
|
].map(&:freeze).freeze
|
71
80
|
|
72
81
|
ATTRIBUTE_NAMES = ATTRIBUTES.transpose.first
|
@@ -119,24 +128,60 @@ module Doing
|
|
119
128
|
end
|
120
129
|
|
121
130
|
class << self
|
122
|
-
# Returns true
|
131
|
+
# Returns true if the coloring function of this module
|
123
132
|
# is switched on, false otherwise.
|
124
133
|
def coloring?
|
125
134
|
@coloring
|
126
135
|
end
|
127
136
|
|
128
|
-
# Turns the coloring on or off globally, so you can easily do
|
129
|
-
# this for example:
|
130
|
-
# Doing::Color::coloring = STDOUT.isatty
|
131
137
|
attr_writer :coloring
|
132
138
|
|
139
|
+
##
|
140
|
+
## Enables colored output
|
141
|
+
##
|
142
|
+
## @example Turn color on or off based on TTY
|
143
|
+
## Doing::Color.coloring = STDOUT.isatty
|
133
144
|
def coloring
|
134
145
|
@coloring ||= true
|
135
146
|
end
|
147
|
+
|
148
|
+
##
|
149
|
+
## Convert a template string to a colored string.
|
150
|
+
## Colors are specified with single letters inside
|
151
|
+
## curly braces. Uppercase changes background color.
|
152
|
+
##
|
153
|
+
## w: white, k: black, g: green, l: blue, y: yellow, c: cyan,
|
154
|
+
## m: magenta, r: red, b: bold, u: underline, i: italic,
|
155
|
+
## x: reset (remove background, color, emphasis)
|
156
|
+
##
|
157
|
+
## @example Convert a templated string
|
158
|
+
## Color.template('{Rwb}Warning:{x} {w}you look a little {g}ill{x}')
|
159
|
+
##
|
160
|
+
## @param input [String, Array] The template
|
161
|
+
## string. If this is an array, the
|
162
|
+
## elements will be joined with a
|
163
|
+
## space.
|
164
|
+
##
|
165
|
+
## @return [String] Colorized string
|
166
|
+
##
|
167
|
+
def template(input)
|
168
|
+
input = input.join(' ') if input.is_a? Array
|
169
|
+
fmt = input.gsub(/\{(\w+)\}/) do
|
170
|
+
Regexp.last_match(1).split('').map { |c| "%<#{c}>s" }.join('')
|
171
|
+
end
|
172
|
+
|
173
|
+
colors = { w: white, k: black, g: green, l: blue,
|
174
|
+
y: yellow, c: cyan, m: magenta, r: red,
|
175
|
+
W: bgwhite, K: bgblack, G: bggreen, L: bgblue,
|
176
|
+
Y: bgyellow, C: bgcyan, M: bgmagenta, R: bgred,
|
177
|
+
b: bold, u: underline, i: italic, x: reset }
|
178
|
+
|
179
|
+
format(fmt, colors)
|
180
|
+
end
|
136
181
|
end
|
137
182
|
|
138
183
|
ATTRIBUTES.each do |c, v|
|
139
|
-
|
184
|
+
new_method = <<-EOSCRIPT
|
140
185
|
def #{c}(string = nil)
|
141
186
|
result = ''
|
142
187
|
result << "\e[#{v}m" if Doing::Color.coloring?
|
@@ -152,33 +197,37 @@ module Doing
|
|
152
197
|
result << "\e[0m" if Doing::Color.coloring?
|
153
198
|
result
|
154
199
|
end
|
155
|
-
|
200
|
+
EOSCRIPT
|
201
|
+
|
202
|
+
module_eval(new_method)
|
203
|
+
|
204
|
+
next unless c =~ /bold/
|
156
205
|
|
157
206
|
# Accept brightwhite in addition to boldwhite
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
return result #only switch on
|
171
|
-
end
|
172
|
-
result << "\e[0m" if Doing::Color.coloring?
|
173
|
-
result
|
207
|
+
new_method = <<-EOSCRIPT
|
208
|
+
def #{c.to_s.sub(/bold/, 'bright')}(string = nil)
|
209
|
+
result = ''
|
210
|
+
result << "\e[#{v}m" if Doing::Color.coloring?
|
211
|
+
if block_given?
|
212
|
+
result << yield
|
213
|
+
elsif string.respond_to?(:to_str)
|
214
|
+
result << string.to_str
|
215
|
+
elsif respond_to?(:to_str)
|
216
|
+
result << to_str
|
217
|
+
else
|
218
|
+
return result #only switch on
|
174
219
|
end
|
175
|
-
|
176
|
-
|
220
|
+
result << "\e[0m" if Doing::Color.coloring?
|
221
|
+
result
|
222
|
+
end
|
223
|
+
EOSCRIPT
|
224
|
+
|
225
|
+
module_eval(new_method)
|
177
226
|
end
|
178
227
|
|
179
228
|
# Regular expression that is used to scan for ANSI-sequences while
|
180
229
|
# uncoloring strings.
|
181
|
-
COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m
|
230
|
+
COLORED_REGEXP = /\e\[(?:(?:[349]|10)[0-7]|[0-9])?m/.freeze
|
182
231
|
|
183
232
|
# Returns an uncolored version of the string, that is all
|
184
233
|
# ANSI-sequences are stripped from the string.
|
@@ -194,8 +243,6 @@ module Doing
|
|
194
243
|
end
|
195
244
|
end
|
196
245
|
|
197
|
-
module_function
|
198
|
-
|
199
246
|
# Returns an array of all Doing::Color attributes as symbols.
|
200
247
|
def attributes
|
201
248
|
ATTRIBUTE_NAMES
|
data/lib/doing/completion.rb
CHANGED
@@ -2,11 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'tty-progressbar'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
require 'bash_completion'
|
5
|
+
require_relative 'completion/string'
|
6
|
+
require_relative 'completion/fish_completion'
|
7
|
+
require_relative 'completion/zsh_completion'
|
8
|
+
require_relative 'completion/bash_completion'
|
10
9
|
|
11
10
|
module Doing
|
12
11
|
# Completion script generator
|
data/lib/doing/errors.rb
CHANGED
@@ -2,19 +2,27 @@
|
|
2
2
|
|
3
3
|
module Doing
|
4
4
|
module Errors
|
5
|
-
class
|
6
|
-
def initialize(msg =
|
5
|
+
class DoingNoTraceError < ::StandardError
|
6
|
+
def initialize(msg = nil, level: nil, topic: 'Error:', exit_code: 1)
|
7
|
+
level ||= :error
|
7
8
|
Doing.logger.output_results
|
8
|
-
|
9
|
-
|
9
|
+
if msg
|
10
|
+
Doing.logger.log_now(level, topic, msg)
|
11
|
+
end
|
12
|
+
|
13
|
+
Process.exit exit_code
|
10
14
|
end
|
11
15
|
end
|
12
16
|
|
13
|
-
class
|
17
|
+
class UserCancelled < DoingNoTraceError
|
18
|
+
def initialize(msg = 'Cancelled', topic = 'Exited:')
|
19
|
+
super(msg, level: :warn, topic: topic, exit_code: 1)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class EmptyInput < DoingNoTraceError
|
14
24
|
def initialize(msg = 'No input', topic = 'Exited:')
|
15
|
-
|
16
|
-
Doing.logger.log_now(:warn, topic, msg)
|
17
|
-
Process.exit 1
|
25
|
+
super(msg, level: :warn, topic: topic, exit_code: 6)
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
@@ -22,44 +30,47 @@ module Doing
|
|
22
30
|
def initialize(msg = '')
|
23
31
|
Doing.logger.output_results
|
24
32
|
|
25
|
-
super
|
33
|
+
super(msg)
|
26
34
|
end
|
27
35
|
end
|
28
36
|
|
29
|
-
class WrongCommand <
|
37
|
+
class WrongCommand < DoingNoTraceError
|
30
38
|
def initialize(msg = 'wrong command', topic: 'Error:')
|
31
|
-
|
32
|
-
|
33
|
-
super(msg)
|
39
|
+
super(msg, level: :warn, topic: topic, exit_code: 2)
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
37
43
|
class DoingRuntimeError < ::RuntimeError
|
38
|
-
def initialize(msg = 'Runtime Error', topic: 'Error:')
|
44
|
+
def initialize(msg = 'Runtime Error', exit_code = nil, topic: 'Error:')
|
39
45
|
Doing.logger.output_results
|
40
46
|
Doing.logger.log_now(:error, topic, msg)
|
41
|
-
|
47
|
+
|
48
|
+
Process.exit exit_code if exit_code
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
45
|
-
class NoResults <
|
52
|
+
class NoResults < DoingNoTraceError
|
46
53
|
def initialize(msg = 'No results', topic = 'Exited:')
|
47
|
-
|
48
|
-
Doing.logger.log_now(:warn, topic, msg)
|
49
|
-
Process.exit 0
|
54
|
+
super(msg, level: :warn, topic: topic, exit_code: 0)
|
50
55
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
class
|
55
|
-
def initialize(msg
|
56
|
-
level
|
57
|
-
|
58
|
-
|
59
|
-
Doing.logger.log_now(level, topic, msg)
|
60
|
-
end
|
59
|
+
class HistoryLimitError < DoingNoTraceError
|
60
|
+
def initialize(msg, exit_code = 24)
|
61
|
+
super(msg, level: :error, topic: 'History:', exit_code: exit_code)
|
62
|
+
end
|
63
|
+
end
|
61
64
|
|
62
|
-
|
65
|
+
class MissingBackupFile < DoingNoTraceError
|
66
|
+
def initialize(msg, exit_code = 26)
|
67
|
+
super(msg, level: :error, topic: 'History:', exit_code: exit_code)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class InvalidPlugin < DoingRuntimeError
|
72
|
+
def initialize(kind = 'output', msg = nil)
|
73
|
+
super(%(Invalid #{kind} type (#{msg})), 128, topic: 'Invalid:')
|
63
74
|
end
|
64
75
|
end
|
65
76
|
|
@@ -75,6 +86,10 @@ module Doing
|
|
75
86
|
'Import plugin'
|
76
87
|
when /^e/
|
77
88
|
'Export plugin'
|
89
|
+
when /^h/
|
90
|
+
'Hook'
|
91
|
+
when /^u/
|
92
|
+
'Unrecognized'
|
78
93
|
else
|
79
94
|
type.to_s
|
80
95
|
end
|
@@ -82,7 +97,8 @@ module Doing
|
|
82
97
|
msg = "(#{@type}: #{@plugin}) #{msg}"
|
83
98
|
|
84
99
|
Doing.logger.log_now(:error, 'Plugin:', msg)
|
85
|
-
|
100
|
+
|
101
|
+
super(msg)
|
86
102
|
end
|
87
103
|
end
|
88
104
|
|
@@ -90,17 +106,17 @@ module Doing
|
|
90
106
|
InvalidPluginType = Class.new(PluginException)
|
91
107
|
PluginUncallable = Class.new(PluginException)
|
92
108
|
|
93
|
-
InvalidArgument = Class.new(
|
94
|
-
MissingArgument = Class.new(
|
95
|
-
MissingFile = Class.new(
|
96
|
-
MissingEditor = Class.new(
|
109
|
+
InvalidArgument = Class.new(DoingNoTraceError)
|
110
|
+
MissingArgument = Class.new(DoingNoTraceError)
|
111
|
+
MissingFile = Class.new(DoingNoTraceError)
|
112
|
+
MissingEditor = Class.new(DoingNoTraceError)
|
97
113
|
NonInteractive = Class.new(StandardError)
|
98
114
|
|
99
|
-
NoEntryError = Class.new(
|
115
|
+
NoEntryError = Class.new(DoingNoTraceError)
|
100
116
|
|
101
117
|
InvalidTimeExpression = Class.new(DoingRuntimeError)
|
102
|
-
InvalidSection = Class.new(
|
103
|
-
InvalidView = Class.new(
|
118
|
+
InvalidSection = Class.new(DoingNoTraceError)
|
119
|
+
InvalidView = Class.new(DoingNoTraceError)
|
104
120
|
|
105
121
|
ItemNotFound = Class.new(DoingRuntimeError)
|
106
122
|
# FatalException = Class.new(::RuntimeError)
|
data/lib/doing/hooks.rb
CHANGED
@@ -15,7 +15,7 @@ module Doing
|
|
15
15
|
post_entry_removed: [], # wwid, entry.dup
|
16
16
|
pre_export: [], # wwid, format, entries
|
17
17
|
pre_write: [], # wwid, file
|
18
|
-
post_write: [] #
|
18
|
+
post_write: [] # file
|
19
19
|
}
|
20
20
|
|
21
21
|
# map of all hooks and their priorities
|
@@ -40,10 +40,10 @@ module Doing
|
|
40
40
|
# register a single hook to be called later, internal API
|
41
41
|
def self.register_one(event, priority, &block)
|
42
42
|
unless @registry[event]
|
43
|
-
raise Doing::Errors::HookUnavailable
|
43
|
+
raise Doing::Errors::HookUnavailable.new("Invalid hook. Doing only supports #{@registry.keys.inspect}", 'hook', event)
|
44
44
|
end
|
45
45
|
|
46
|
-
raise Doing::Errors::PluginUncallable
|
46
|
+
raise Doing::Errors::PluginUncallable.new('Hooks must respond to :call', 'hook', event) unless block.respond_to? :call
|
47
47
|
|
48
48
|
Doing.logger.debug('Hook Manager:', "Registered #{event} hook") if ENV['DOING_PLUGIN_DEBUG']
|
49
49
|
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Doing
|
2
|
+
class Item
|
3
|
+
# def date=(new_date)
|
4
|
+
# @date = new_date.is_a?(Time) ? new_date : Time.parse(new_date)
|
5
|
+
# end
|
6
|
+
|
7
|
+
## If the entry doesn't have a @done date, return the elapsed time
|
8
|
+
def duration
|
9
|
+
return nil unless should_time? && should_finish?
|
10
|
+
|
11
|
+
return nil if @title =~ /(?<=^| )@done\b/
|
12
|
+
|
13
|
+
return Time.now - @date
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
## Get the difference between the item's start date and
|
18
|
+
## the value of its @done tag (if present)
|
19
|
+
##
|
20
|
+
## @return Interval in seconds
|
21
|
+
##
|
22
|
+
def interval
|
23
|
+
@interval ||= calc_interval
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
## Get the value of the item's @done tag
|
28
|
+
##
|
29
|
+
## @return [Time] @done value
|
30
|
+
##
|
31
|
+
def end_date
|
32
|
+
@end_date ||= Time.parse(Regexp.last_match(1)) if @title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
|
33
|
+
end
|
34
|
+
|
35
|
+
def calculate_end_date(opt)
|
36
|
+
if opt[:took]
|
37
|
+
if @date + opt[:took] > Time.now
|
38
|
+
@date = Time.now - opt[:took]
|
39
|
+
Time.now
|
40
|
+
else
|
41
|
+
@date + opt[:took]
|
42
|
+
end
|
43
|
+
elsif opt[:back]
|
44
|
+
if opt[:back].is_a? Integer
|
45
|
+
@date + opt[:back]
|
46
|
+
else
|
47
|
+
@date + (opt[:back] - @date)
|
48
|
+
end
|
49
|
+
else
|
50
|
+
Time.now
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
## Test if two items occur at the same time (same start date and equal duration)
|
56
|
+
##
|
57
|
+
## @param item_b [Item] The item to compare
|
58
|
+
##
|
59
|
+
## @return [Boolean] is equal?
|
60
|
+
##
|
61
|
+
def same_time?(item_b)
|
62
|
+
date == item_b.date ? interval == item_b.interval : false
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
## Test if the interval between start date and @done
|
67
|
+
## value overlaps with another item's
|
68
|
+
##
|
69
|
+
## @param item_b [Item] The item to compare
|
70
|
+
##
|
71
|
+
## @return [Boolean] overlaps?
|
72
|
+
##
|
73
|
+
def overlapping_time?(item_b)
|
74
|
+
return true if same_time?(item_b)
|
75
|
+
|
76
|
+
start_a = date
|
77
|
+
a_interval = interval
|
78
|
+
end_a = a_interval ? start_a + a_interval.to_i : start_a
|
79
|
+
start_b = item_b.date
|
80
|
+
b_interval = item_b.interval
|
81
|
+
end_b = b_interval ? start_b + b_interval.to_i : start_b
|
82
|
+
(start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
## Updates the title of the Item by expanding natural
|
87
|
+
## language dates within configured date tags (tags
|
88
|
+
## whose value is expected to be a date)
|
89
|
+
##
|
90
|
+
## @param additional_tags An array of additional
|
91
|
+
## tag names to consider
|
92
|
+
## dates
|
93
|
+
##
|
94
|
+
def expand_date_tags(additional_tags = nil)
|
95
|
+
@title.expand_date_tags(additional_tags)
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def calc_interval
|
101
|
+
return nil unless should_time? && should_finish?
|
102
|
+
|
103
|
+
done = end_date
|
104
|
+
return nil if done.nil?
|
105
|
+
|
106
|
+
start = @date
|
107
|
+
|
108
|
+
t = (done - start).to_i
|
109
|
+
t.positive? ? t : nil
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|