doing 2.0.9.pre → 2.0.15
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/.yardoc/checksums +20 -0
- data/.yardoc/complete +0 -0
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/.yardopts +1 -0
- data/CHANGELOG.md +21 -1
- data/Gemfile.lock +20 -10
- data/README.md +1 -1
- data/Rakefile +10 -1
- data/bin/doing +106 -38
- data/doc/Array.html +135 -0
- data/doc/Doing/Color.html +506 -0
- data/doc/Doing/Configuration.html +680 -0
- data/doc/Doing/Errors/DoingNoTraceError.html +186 -0
- data/doc/Doing/Errors/DoingRuntimeError.html +186 -0
- data/doc/Doing/Errors/DoingStandardError.html +186 -0
- data/doc/Doing/Errors/EmptyInput.html +186 -0
- data/doc/Doing/Errors/NoResults.html +186 -0
- data/doc/Doing/Errors/PluginException.html +248 -0
- data/doc/Doing/Errors/UserCancelled.html +186 -0
- data/doc/Doing/Errors/WrongCommand.html +186 -0
- data/doc/Doing/Errors.html +191 -0
- data/doc/Doing/Hooks.html +364 -0
- data/doc/Doing/Item.html +1385 -0
- data/doc/Doing/Items.html +393 -0
- data/doc/Doing/LogAdapter.html +1650 -0
- data/doc/Doing/Note.html +535 -0
- data/doc/Doing/Pager.html +268 -0
- data/doc/Doing/Plugins.html +849 -0
- data/doc/Doing/Util.html +870 -0
- data/doc/Doing/WWID.html +4827 -0
- data/doc/Doing.html +145 -0
- data/doc/GLI/Commands/MarkdownDocumentListener.html +763 -0
- data/doc/GLI/Commands.html +115 -0
- data/doc/GLI.html +115 -0
- data/doc/Hash.html +332 -0
- data/doc/Status.html +292 -0
- data/doc/String.html +1714 -0
- data/doc/Symbol.html +250 -0
- data/doc/Time.html +182 -0
- data/doc/_index.html +411 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +497 -0
- data/doc/file.README.html +123 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +123 -0
- data/doc/js/app.js +314 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1867 -0
- data/doc/top-level-namespace.html +112 -0
- data/doing.gemspec +6 -1
- data/doing.rdoc +16 -16
- data/example_plugin.rb +6 -6
- data/lib/completion/_doing.zsh +24 -20
- data/lib/completion/doing.bash +41 -30
- data/lib/completion/doing.fish +50 -1
- data/lib/doing/array.rb +15 -2
- data/lib/doing/configuration.rb +14 -12
- data/lib/doing/hash.rb +1 -1
- data/lib/doing/item.rb +104 -19
- data/lib/doing/log_adapter.rb +132 -119
- data/lib/doing/note.rb +1 -1
- data/lib/doing/plugin_manager.rb +5 -5
- data/lib/doing/plugins/export/csv_export.rb +1 -1
- data/lib/doing/plugins/export/template_export.rb +5 -7
- data/lib/doing/plugins/import/calendar_import.rb +1 -1
- data/lib/doing/plugins/import/doing_import.rb +4 -4
- data/lib/doing/plugins/import/timing_import.rb +5 -3
- data/lib/doing/string.rb +77 -24
- data/lib/doing/symbol.rb +9 -5
- data/lib/doing/time.rb +1 -1
- data/lib/doing/util.rb +18 -11
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +513 -372
- data/lib/doing/wwidfile.rb +5 -5
- data/lib/doing.rb +2 -1
- data/lib/examples/plugins/say_export.rb +6 -6
- data/rdocfixer.rb +1 -1
- data/yard_templates/default/method_details/setup.rb +3 -0
- metadata +111 -4
data/lib/doing/item.rb
CHANGED
|
@@ -2,11 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Doing
|
|
4
4
|
##
|
|
5
|
-
##
|
|
5
|
+
## This class describes a single WWID item
|
|
6
6
|
##
|
|
7
7
|
class Item
|
|
8
|
+
# include Amatch
|
|
9
|
+
|
|
8
10
|
attr_accessor :date, :title, :section, :note
|
|
9
11
|
|
|
12
|
+
##
|
|
13
|
+
## Initialize an item with date, title, section, and
|
|
14
|
+
## optional note
|
|
15
|
+
##
|
|
16
|
+
## @param date [Time] The item's start date
|
|
17
|
+
## @param title [String] The title
|
|
18
|
+
## @param section [String] The section to which
|
|
19
|
+
## the item belongs
|
|
20
|
+
## @param note [Array or String] The note
|
|
21
|
+
## (optional)
|
|
22
|
+
##
|
|
10
23
|
def initialize(date, title, section, note = nil)
|
|
11
24
|
@date = date.is_a?(Time) ? date : Time.parse(date)
|
|
12
25
|
@title = title
|
|
@@ -18,14 +31,36 @@ module Doing
|
|
|
18
31
|
# @date = new_date.is_a?(Time) ? new_date : Time.parse(new_date)
|
|
19
32
|
# end
|
|
20
33
|
|
|
34
|
+
##
|
|
35
|
+
## Get the difference between the item's start date and
|
|
36
|
+
## the value of its @done tag (if present)
|
|
37
|
+
##
|
|
38
|
+
## @return Interval in seconds
|
|
39
|
+
##
|
|
21
40
|
def interval
|
|
22
41
|
@interval ||= calc_interval
|
|
23
42
|
end
|
|
24
43
|
|
|
44
|
+
##
|
|
45
|
+
## Get the value of the item's @done tag
|
|
46
|
+
##
|
|
47
|
+
## @return [Time] @done value
|
|
48
|
+
##
|
|
25
49
|
def end_date
|
|
26
50
|
@end_date ||= Time.parse(Regexp.last_match(1)) if @title =~ /@done\((\d{4}-\d\d-\d\d \d\d:\d\d.*?)\)/
|
|
27
51
|
end
|
|
28
52
|
|
|
53
|
+
def hash_id
|
|
54
|
+
(@date.to_s + @title + @section + @note.join(' ')).hash
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
##
|
|
58
|
+
## Test for equality between items
|
|
59
|
+
##
|
|
60
|
+
## @param other [Item] The other item
|
|
61
|
+
##
|
|
62
|
+
## @return [Boolean] is equal?
|
|
63
|
+
##
|
|
29
64
|
def equal?(other)
|
|
30
65
|
return false if @title.strip != other.title.strip
|
|
31
66
|
|
|
@@ -36,10 +71,25 @@ module Doing
|
|
|
36
71
|
true
|
|
37
72
|
end
|
|
38
73
|
|
|
74
|
+
##
|
|
75
|
+
## Test if two items occur at the same time (same start date and equal duration)
|
|
76
|
+
##
|
|
77
|
+
## @param item_b [Item] The item to compare
|
|
78
|
+
##
|
|
79
|
+
## @return [Boolean] is equal?
|
|
80
|
+
##
|
|
39
81
|
def same_time?(item_b)
|
|
40
82
|
date == item_b.date ? interval == item_b.interval : false
|
|
41
83
|
end
|
|
42
84
|
|
|
85
|
+
##
|
|
86
|
+
## Test if the interval between start date and @done
|
|
87
|
+
## value overlaps with another item's
|
|
88
|
+
##
|
|
89
|
+
## @param item_b [Item] The item to compare
|
|
90
|
+
##
|
|
91
|
+
## @return [Boolean] overlaps?
|
|
92
|
+
##
|
|
43
93
|
def overlapping_time?(item_b)
|
|
44
94
|
return true if same_time?(item_b)
|
|
45
95
|
|
|
@@ -52,14 +102,37 @@ module Doing
|
|
|
52
102
|
(start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
|
|
53
103
|
end
|
|
54
104
|
|
|
105
|
+
##
|
|
106
|
+
## Add (or remove) tags from the title of the item
|
|
107
|
+
##
|
|
108
|
+
## @param tag [String] The tag to add
|
|
109
|
+
## @param value [String] A value to include as @tag(value)
|
|
110
|
+
## @param remove [Boolean] if true remove instead of adding
|
|
111
|
+
## @param rename_to [String] if not nil, rename target tag to this tag name
|
|
112
|
+
## @param regex [Boolean] treat target tag string as regex pattern
|
|
113
|
+
##
|
|
55
114
|
def tag(tag, value: nil, remove: false, rename_to: nil, regex: false)
|
|
56
115
|
@title.tag!(tag, value: value, remove: remove, rename_to: rename_to, regex: regex).strip!
|
|
57
116
|
end
|
|
58
117
|
|
|
118
|
+
##
|
|
119
|
+
## Get a list of tags on the item
|
|
120
|
+
##
|
|
121
|
+
## @return [Array] array of tags (no values)
|
|
122
|
+
##
|
|
59
123
|
def tags
|
|
60
124
|
@title.scan(/(?<= |\A)@([^\s(]+)/).map {|tag| tag[0]}.sort.uniq
|
|
61
125
|
end
|
|
62
126
|
|
|
127
|
+
##
|
|
128
|
+
## Test if item contains tag(s)
|
|
129
|
+
##
|
|
130
|
+
## @param tags (Array or String) The tags to test. Can be an array or a comma-separated string.
|
|
131
|
+
## @param bool (Symbol) The boolean to use for multiple tags (:and, :or, :not)
|
|
132
|
+
## @param negate [Boolean] negate the result?
|
|
133
|
+
##
|
|
134
|
+
## @return [Boolean] true if tag/bool combination passes
|
|
135
|
+
##
|
|
63
136
|
def tags?(tags, bool = :and, negate: false)
|
|
64
137
|
tags = split_tags(tags)
|
|
65
138
|
bool = bool.normalize_bool
|
|
@@ -75,26 +148,38 @@ module Doing
|
|
|
75
148
|
negate ? !matches : matches
|
|
76
149
|
end
|
|
77
150
|
|
|
78
|
-
|
|
151
|
+
##
|
|
152
|
+
## Test if item matches search string
|
|
153
|
+
##
|
|
154
|
+
## @param search [String] The search string
|
|
155
|
+
## @param negate [Boolean] negate results
|
|
156
|
+
## @param case_type (Symbol) The case-sensitivity
|
|
157
|
+
## type (:sensitive,
|
|
158
|
+
## :ignore, :smart)
|
|
159
|
+
##
|
|
160
|
+
## @return [Boolean] matches search criteria
|
|
161
|
+
##
|
|
162
|
+
def search(search, distance: 3, negate: false, case_type: :smart, fuzzy: false)
|
|
79
163
|
text = @title + @note.to_s
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
164
|
+
matches = text =~ search.to_rx(distance: distance, case_type: case_type)
|
|
165
|
+
|
|
166
|
+
# if search.is_rx? || !fuzzy
|
|
167
|
+
# matches = text =~ search.to_rx(distance: distance, case_type: case_type)
|
|
168
|
+
# else
|
|
169
|
+
# distance = 0.25 if distance > 1
|
|
170
|
+
# score = if (case_type == :smart && search !~ /[A-Z]/) || case_type == :ignore
|
|
171
|
+
# text.downcase.pair_distance_similar(search.downcase)
|
|
172
|
+
# else
|
|
173
|
+
# score = text.pair_distance_similar(search)
|
|
174
|
+
# end
|
|
175
|
+
|
|
176
|
+
# if score >= distance
|
|
177
|
+
# matches = true
|
|
178
|
+
# Doing.logger.debug('Fuzzy Match:', %(#{@title}, "#{search}" #{score}))
|
|
179
|
+
# end
|
|
180
|
+
# end
|
|
92
181
|
|
|
93
|
-
|
|
94
|
-
end
|
|
95
|
-
rx = Regexp.new(pattern, !case_sensitive)
|
|
96
|
-
|
|
97
|
-
negate ? text !~ rx : text =~ rx
|
|
182
|
+
negate ? !matches : matches
|
|
98
183
|
end
|
|
99
184
|
|
|
100
185
|
def should_finish?
|
data/lib/doing/log_adapter.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Doing
|
|
4
4
|
##
|
|
5
|
-
##
|
|
5
|
+
## Log adapter
|
|
6
6
|
##
|
|
7
7
|
class LogAdapter
|
|
8
8
|
attr_writer :logdev, :max_length
|
|
@@ -19,20 +19,21 @@ module Doing
|
|
|
19
19
|
}.freeze
|
|
20
20
|
|
|
21
21
|
COUNT_KEYS = %i[
|
|
22
|
-
added_tags
|
|
23
|
-
removed_tags
|
|
24
22
|
added
|
|
25
|
-
|
|
26
|
-
deleted
|
|
27
|
-
completed
|
|
23
|
+
added_tags
|
|
28
24
|
archived
|
|
29
|
-
|
|
25
|
+
autotag
|
|
26
|
+
completed
|
|
30
27
|
completed_archived
|
|
28
|
+
deleted
|
|
29
|
+
moved
|
|
30
|
+
removed_tags
|
|
31
31
|
skipped
|
|
32
|
+
updated
|
|
32
33
|
].freeze
|
|
33
34
|
|
|
34
35
|
#
|
|
35
|
-
#
|
|
36
|
+
# Create a new instance of a log writer
|
|
36
37
|
#
|
|
37
38
|
# @param level (optional, symbol) the log level
|
|
38
39
|
#
|
|
@@ -47,29 +48,25 @@ module Doing
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
#
|
|
50
|
-
#
|
|
51
|
+
# Set the log level on the writer
|
|
51
52
|
#
|
|
52
53
|
# @param level (symbol) the log level
|
|
53
54
|
#
|
|
54
55
|
# @return nothing
|
|
55
56
|
#
|
|
56
|
-
def log_level=(level)
|
|
57
|
-
level ||= 'info'
|
|
57
|
+
def log_level=(level = 'info')
|
|
58
58
|
level = level.to_s
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
else
|
|
71
|
-
level = level.downcase.to_sym
|
|
72
|
-
end
|
|
59
|
+
|
|
60
|
+
level = case level
|
|
61
|
+
when /^[e0]/i
|
|
62
|
+
:error
|
|
63
|
+
when /^[w1]/i
|
|
64
|
+
:warn
|
|
65
|
+
when /^[d3]/i
|
|
66
|
+
:debug
|
|
67
|
+
else
|
|
68
|
+
:info
|
|
69
|
+
end
|
|
73
70
|
|
|
74
71
|
@level = level
|
|
75
72
|
end
|
|
@@ -84,46 +81,6 @@ module Doing
|
|
|
84
81
|
# log_now :debug, 'Doing Version:', Doing::VERSION
|
|
85
82
|
end
|
|
86
83
|
|
|
87
|
-
def format_counter(key, data)
|
|
88
|
-
case key
|
|
89
|
-
when :added_tags
|
|
90
|
-
['Tagged:', data[:message] || 'added %tags to %count %items']
|
|
91
|
-
when :removed_tags
|
|
92
|
-
['Untagged:', data[:message] || 'removed %tags from %count %items']
|
|
93
|
-
when :added
|
|
94
|
-
['Added:', data[:message] || 'added %count new %items']
|
|
95
|
-
when :updated
|
|
96
|
-
['Updated:', data[:message] || 'updated %count %items']
|
|
97
|
-
when :deleted
|
|
98
|
-
['Deleted:', data[:message] || 'deleted %count %items']
|
|
99
|
-
when :moved
|
|
100
|
-
['Moved:', data[:message] || 'moved %count %items']
|
|
101
|
-
when :completed
|
|
102
|
-
['Completed:', data[:message] || 'completed %count %items']
|
|
103
|
-
when :archived
|
|
104
|
-
['Archived:', data[:message] || 'archived %count %items']
|
|
105
|
-
when :completed_archived
|
|
106
|
-
['Archived:', data[:message] || 'completed and archived %count %items']
|
|
107
|
-
when :skipped
|
|
108
|
-
['Skipped:', data[:message] || '%count %items were unchanged']
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def total_counters
|
|
113
|
-
@counters.each do |key, data|
|
|
114
|
-
next if data[:count].zero?
|
|
115
|
-
|
|
116
|
-
count = data[:count]
|
|
117
|
-
tags = data[:tag] ? data[:tag].uniq.map { |t| "@#{t}".cyan }.join(', ') : 'tags'
|
|
118
|
-
topic, m = format_counter(key, data)
|
|
119
|
-
message = m.dup
|
|
120
|
-
message.sub!(/%count/, count.to_s)
|
|
121
|
-
message.sub!(/%items/, count == 1 ? 'item' : 'items')
|
|
122
|
-
message.sub!(/%tags/, tags)
|
|
123
|
-
write(data[:level], topic, message)
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
84
|
def count(key, level: :info, count: 1, tag: nil, message: nil)
|
|
128
85
|
raise ArgumentError, 'invalid counter key' unless COUNT_KEYS.include?(key)
|
|
129
86
|
|
|
@@ -134,7 +91,7 @@ module Doing
|
|
|
134
91
|
end
|
|
135
92
|
|
|
136
93
|
#
|
|
137
|
-
#
|
|
94
|
+
# Print a debug message
|
|
138
95
|
#
|
|
139
96
|
# @param topic the topic of the message
|
|
140
97
|
# @param message the message detail
|
|
@@ -146,7 +103,7 @@ module Doing
|
|
|
146
103
|
end
|
|
147
104
|
|
|
148
105
|
#
|
|
149
|
-
#
|
|
106
|
+
# Print a message
|
|
150
107
|
#
|
|
151
108
|
# @param topic the topic of the message, e.g.
|
|
152
109
|
# "Configuration file",
|
|
@@ -160,7 +117,7 @@ module Doing
|
|
|
160
117
|
end
|
|
161
118
|
|
|
162
119
|
#
|
|
163
|
-
#
|
|
120
|
+
# Print a message
|
|
164
121
|
#
|
|
165
122
|
# @param topic the topic of the message, e.g.
|
|
166
123
|
# "Configuration file",
|
|
@@ -174,7 +131,7 @@ module Doing
|
|
|
174
131
|
end
|
|
175
132
|
|
|
176
133
|
#
|
|
177
|
-
#
|
|
134
|
+
# Print an error message
|
|
178
135
|
#
|
|
179
136
|
# @param topic the topic of the message, e.g.
|
|
180
137
|
# "Configuration file",
|
|
@@ -188,7 +145,7 @@ module Doing
|
|
|
188
145
|
end
|
|
189
146
|
|
|
190
147
|
#
|
|
191
|
-
#
|
|
148
|
+
# Print an error message and immediately
|
|
192
149
|
# abort the process
|
|
193
150
|
#
|
|
194
151
|
# @param topic the topic of the message, e.g.
|
|
@@ -204,33 +161,8 @@ module Doing
|
|
|
204
161
|
abort
|
|
205
162
|
end
|
|
206
163
|
|
|
207
|
-
# Internal: Build a topic method
|
|
208
|
-
#
|
|
209
|
-
# @param topic the topic of the message, e.g.
|
|
210
|
-
# "Configuration file",
|
|
211
|
-
# "Deprecation", etc.
|
|
212
|
-
# @param message the message detail
|
|
213
|
-
#
|
|
214
|
-
# @return the formatted message
|
|
215
|
-
#
|
|
216
|
-
def message(topic, message = nil)
|
|
217
|
-
raise ArgumentError, 'block or message, not both' if block_given? && message
|
|
218
|
-
|
|
219
|
-
message = yield if block_given?
|
|
220
|
-
message = message.to_s.gsub(/\s+/, ' ')
|
|
221
|
-
|
|
222
|
-
return topic.ljust(TOPIC_WIDTH) if topic && message.strip.empty?
|
|
223
|
-
|
|
224
|
-
topic = formatted_topic(topic, colon: block_given?)
|
|
225
|
-
message.truncmiddle!(@max_length - TOPIC_WIDTH - 5)
|
|
226
|
-
out = topic + message
|
|
227
|
-
out.truncate!(@max_length) if @max_length.positive?
|
|
228
|
-
messages << out
|
|
229
|
-
out
|
|
230
|
-
end
|
|
231
|
-
|
|
232
164
|
#
|
|
233
|
-
#
|
|
165
|
+
# Format the topic
|
|
234
166
|
#
|
|
235
167
|
# @param topic the topic of the message, e.g.
|
|
236
168
|
# "Configuration file",
|
|
@@ -250,39 +182,34 @@ module Doing
|
|
|
250
182
|
end
|
|
251
183
|
|
|
252
184
|
#
|
|
253
|
-
#
|
|
254
|
-
# given the log level.
|
|
185
|
+
# Log a message.
|
|
255
186
|
#
|
|
256
|
-
# @param level_of_message the Symbol
|
|
257
|
-
# message, one of
|
|
258
|
-
# :info, :warn,
|
|
259
|
-
#
|
|
260
|
-
# @
|
|
261
|
-
#
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
#
|
|
267
|
-
# @brief Log a message.
|
|
268
|
-
#
|
|
269
|
-
# @param level_of_message the Symbol level of
|
|
270
|
-
# message, one of :debug,
|
|
271
|
-
# :info, :warn, :error
|
|
272
|
-
# @param topic the String topic or full
|
|
273
|
-
# message
|
|
274
|
-
# @param message the String message
|
|
275
|
-
# (optional)
|
|
187
|
+
# @param level_of_message [Symbol] the Symbol
|
|
188
|
+
# level of message, one of
|
|
189
|
+
# :debug, :info, :warn,
|
|
190
|
+
# :error
|
|
191
|
+
# @param topic [String] the String
|
|
192
|
+
# topic or full message
|
|
193
|
+
# @param message [String] the String
|
|
194
|
+
# message (optional)
|
|
276
195
|
# @param block a block containing the
|
|
277
196
|
# message (optional)
|
|
278
197
|
#
|
|
279
|
-
# @return false if the message was not written
|
|
198
|
+
# @return [Boolean] false if the message was not written
|
|
280
199
|
#
|
|
281
200
|
def write(level_of_message, topic, message = nil, &block)
|
|
282
201
|
@results << { level: level_of_message, message: message(topic, message, &block) }
|
|
283
202
|
true
|
|
284
203
|
end
|
|
285
204
|
|
|
205
|
+
##
|
|
206
|
+
## Log to console immediately instead of writing messages on exit
|
|
207
|
+
##
|
|
208
|
+
## @param level [Symbol] The level
|
|
209
|
+
## @param topic [String] The topic or full message
|
|
210
|
+
## @param message [String] The message (optional)
|
|
211
|
+
## @param block a block containing the message (optional)
|
|
212
|
+
##
|
|
286
213
|
def log_now(level, topic, message = nil, &block)
|
|
287
214
|
return false unless write_message?(level)
|
|
288
215
|
|
|
@@ -293,6 +220,11 @@ module Doing
|
|
|
293
220
|
end
|
|
294
221
|
end
|
|
295
222
|
|
|
223
|
+
##
|
|
224
|
+
## Output registers based on log level
|
|
225
|
+
##
|
|
226
|
+
## @return nothing
|
|
227
|
+
##
|
|
296
228
|
def output_results
|
|
297
229
|
total_counters
|
|
298
230
|
|
|
@@ -309,6 +241,87 @@ module Doing
|
|
|
309
241
|
|
|
310
242
|
private
|
|
311
243
|
|
|
244
|
+
def format_counter(key, data)
|
|
245
|
+
case key
|
|
246
|
+
when :autotag
|
|
247
|
+
['Autotag:', data[:message] || 'autotagged %count %items']
|
|
248
|
+
when :added_tags
|
|
249
|
+
['Tagged:', data[:message] || 'added %tags to %count %items']
|
|
250
|
+
when :removed_tags
|
|
251
|
+
['Untagged:', data[:message] || 'removed %tags from %count %items']
|
|
252
|
+
when :added
|
|
253
|
+
['Added:', data[:message] || 'added %count new %items']
|
|
254
|
+
when :updated
|
|
255
|
+
['Updated:', data[:message] || 'updated %count %items']
|
|
256
|
+
when :deleted
|
|
257
|
+
['Deleted:', data[:message] || 'deleted %count %items']
|
|
258
|
+
when :moved
|
|
259
|
+
['Moved:', data[:message] || 'moved %count %items']
|
|
260
|
+
when :completed
|
|
261
|
+
['Completed:', data[:message] || 'completed %count %items']
|
|
262
|
+
when :archived
|
|
263
|
+
['Archived:', data[:message] || 'archived %count %items']
|
|
264
|
+
when :completed_archived
|
|
265
|
+
['Archived:', data[:message] || 'completed and archived %count %items']
|
|
266
|
+
when :skipped
|
|
267
|
+
['Skipped:', data[:message] || '%count %items were unchanged']
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def total_counters
|
|
272
|
+
@counters.each do |key, data|
|
|
273
|
+
next if data[:count].zero?
|
|
274
|
+
|
|
275
|
+
count = data[:count]
|
|
276
|
+
tags = data[:tag] ? data[:tag].uniq.map { |t| "@#{t}".cyan }.join(', ') : 'tags'
|
|
277
|
+
topic, m = format_counter(key, data)
|
|
278
|
+
message = m.dup
|
|
279
|
+
message.sub!(/%count/, count.to_s)
|
|
280
|
+
message.sub!(/%items/, count == 1 ? 'item' : 'items')
|
|
281
|
+
message.sub!(/%tags/, tags)
|
|
282
|
+
write(data[:level], topic, message)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
#
|
|
287
|
+
# Check if the message should be written
|
|
288
|
+
# given the log level.
|
|
289
|
+
#
|
|
290
|
+
# @param level_of_message the Symbol level of
|
|
291
|
+
# message, one of :debug,
|
|
292
|
+
# :info, :warn, :error
|
|
293
|
+
#
|
|
294
|
+
# @return whether the message should be written.
|
|
295
|
+
#
|
|
296
|
+
def write_message?(level_of_message)
|
|
297
|
+
LOG_LEVELS.fetch(@level) <= LOG_LEVELS.fetch(level_of_message)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# Internal: Build a topic method
|
|
301
|
+
#
|
|
302
|
+
# @param topic the topic of the message, e.g.
|
|
303
|
+
# "Configuration file",
|
|
304
|
+
# "Deprecation", etc.
|
|
305
|
+
# @param message the message detail
|
|
306
|
+
#
|
|
307
|
+
# @return the formatted message
|
|
308
|
+
#
|
|
309
|
+
def message(topic, message = nil)
|
|
310
|
+
raise ArgumentError, 'block or message, not both' if block_given? && message
|
|
311
|
+
|
|
312
|
+
message = yield if block_given?
|
|
313
|
+
message = message.to_s.gsub(/\s+/, ' ')
|
|
314
|
+
|
|
315
|
+
return topic.ljust(TOPIC_WIDTH) if topic && message.strip.empty?
|
|
316
|
+
|
|
317
|
+
topic = formatted_topic(topic, colon: block_given?)
|
|
318
|
+
message.truncmiddle!(@max_length - TOPIC_WIDTH - 5)
|
|
319
|
+
out = topic + message
|
|
320
|
+
out.truncate!(@max_length) if @max_length.positive?
|
|
321
|
+
messages << out
|
|
322
|
+
out
|
|
323
|
+
end
|
|
324
|
+
|
|
312
325
|
def color_message(level, topic, message = nil, &block)
|
|
313
326
|
colors = Doing::Color
|
|
314
327
|
message = message(topic, message, &block)
|
data/lib/doing/note.rb
CHANGED
data/lib/doing/plugin_manager.rb
CHANGED
|
@@ -107,7 +107,7 @@ module Doing
|
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
##
|
|
110
|
-
##
|
|
110
|
+
## List available plugins to stdout
|
|
111
111
|
##
|
|
112
112
|
## @param options { type, separator }
|
|
113
113
|
##
|
|
@@ -129,11 +129,11 @@ module Doing
|
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
##
|
|
132
|
-
##
|
|
132
|
+
## Return array of available plugin names
|
|
133
133
|
##
|
|
134
134
|
## @param type Plugin type (:import, :export)
|
|
135
135
|
##
|
|
136
|
-
## @
|
|
136
|
+
## @return [Array<String>] plugin names
|
|
137
137
|
##
|
|
138
138
|
def available_plugins(type: :export)
|
|
139
139
|
type = valid_type(type)
|
|
@@ -141,7 +141,7 @@ module Doing
|
|
|
141
141
|
end
|
|
142
142
|
|
|
143
143
|
##
|
|
144
|
-
##
|
|
144
|
+
## Return string version of plugin names
|
|
145
145
|
##
|
|
146
146
|
## @param type Plugin type (:import, :export)
|
|
147
147
|
## @param separator The separator to join names with
|
|
@@ -154,7 +154,7 @@ module Doing
|
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
##
|
|
157
|
-
##
|
|
157
|
+
## Return a regular expression of all
|
|
158
158
|
## plugin triggers for type
|
|
159
159
|
##
|
|
160
160
|
## @param type The type :import or :export
|
|
@@ -94,7 +94,7 @@ module Doing
|
|
|
94
94
|
end
|
|
95
95
|
|
|
96
96
|
if note.empty?
|
|
97
|
-
output.gsub!(/%([io]d|(\^.)?(([ _t]|[^a-z0-9])?\d+)?(.[ _t]?)?)?note/, '')
|
|
97
|
+
output.gsub!(/%(chomp|[io]d|(\^.)?(([ _t]|[^a-z0-9])?\d+)?(.[ _t]?)?)?note/, '')
|
|
98
98
|
else
|
|
99
99
|
output.sub!(/%note/, "\n#{note.map { |l| "\t#{l.strip} " }.join("\n")}")
|
|
100
100
|
output.sub!(/%idnote/, "\n#{note.map { |l| "\t\t#{l.strip} " }.join("\n")}")
|
|
@@ -111,15 +111,13 @@ module Doing
|
|
|
111
111
|
prefix = m['prefix'] || ''
|
|
112
112
|
"\n#{note.map { |l| "#{mark}#{indent}#{prefix}#{l.strip} " }.join("\n")}"
|
|
113
113
|
end
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
end
|
|
118
|
-
chomp_note.join(' ')
|
|
114
|
+
|
|
115
|
+
output.sub!(/%chompnote/) do
|
|
116
|
+
note.map { |l| l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ') }.join(' ')
|
|
119
117
|
end
|
|
120
118
|
end
|
|
121
119
|
|
|
122
|
-
output.gsub!(/%hr(_under)?/) do
|
|
120
|
+
output.gsub!(/%hr(_under)?/) do
|
|
123
121
|
o = ''
|
|
124
122
|
`tput cols`.to_i.times do
|
|
125
123
|
o += Regexp.last_match(1).nil? ? '-' : '_'
|
|
@@ -15,11 +15,11 @@ module Doing
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
##
|
|
18
|
-
##
|
|
18
|
+
## Imports a Doing file
|
|
19
19
|
##
|
|
20
|
-
## @param wwid WWID object
|
|
21
|
-
## @param path
|
|
22
|
-
## @param options
|
|
20
|
+
## @param wwid [WWID] WWID object
|
|
21
|
+
## @param path [String] Path to Doing file
|
|
22
|
+
## @param options [Hash] Additional Options
|
|
23
23
|
##
|
|
24
24
|
## @return Nothing
|
|
25
25
|
##
|
|
@@ -15,10 +15,12 @@ module Doing
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
##
|
|
18
|
-
##
|
|
18
|
+
## Imports a Timing report
|
|
19
19
|
##
|
|
20
|
-
## @param
|
|
21
|
-
## @param
|
|
20
|
+
## @param wwid [WWID] The wwid object
|
|
21
|
+
## @param path [String] Path to JSON report
|
|
22
|
+
## file
|
|
23
|
+
## @param options [Hash] Additional Options
|
|
22
24
|
##
|
|
23
25
|
def self.import(wwid, path, options: {})
|
|
24
26
|
exit_now! 'Path to JSON report required' if path.nil?
|