doing 2.0.6.pre → 2.0.10
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 +7 -7
- data/Gemfile.lock +30 -10
- data/README.md +1 -1
- data/Rakefile +8 -1
- data/bin/doing +367 -21
- 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 +5 -1
- data/doing.rdoc +354 -6
- data/example_plugin.rb +6 -6
- data/lib/doing/array.rb +1 -1
- data/lib/doing/configuration.rb +14 -12
- data/lib/doing/errors.rb +1 -1
- data/lib/doing/hash.rb +1 -1
- data/lib/doing/item.rb +113 -23
- data/lib/doing/log_adapter.rb +123 -113
- 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 +8 -2
- data/lib/doing/plugins/import/doing_import.rb +10 -10
- data/lib/doing/plugins/import/timing_import.rb +12 -4
- data/lib/doing/string.rb +94 -19
- 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 +455 -335
- data/lib/doing/wwidfile.rb +5 -5
- data/lib/doing.rb +2 -1
- data/lib/examples/plugins/say_export.rb +6 -6
- data/lib/examples/plugins/{templates → wiki_export/templates}/wiki.css +0 -0
- data/lib/examples/plugins/{templates → wiki_export/templates}/wiki.haml +0 -0
- data/lib/examples/plugins/{templates → wiki_export/templates}/wiki_index.haml +0 -0
- data/lib/examples/plugins/{wiki_export.rb → wiki_export/wiki_export.rb} +0 -0
- data/rdocfixer.rb +1 -1
- data/scripts/generate_zsh_completions.rb +3 -2
- data/yard_templates/default/method_details/setup.rb +3 -0
- metadata +121 -8
data/example_plugin.rb
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
|
|
27
27
|
module Doing
|
|
28
28
|
##
|
|
29
|
-
##
|
|
29
|
+
## Plugin class
|
|
30
30
|
##
|
|
31
31
|
class SayExport
|
|
32
32
|
include Doing::Util
|
|
@@ -65,7 +65,7 @@ module Doing
|
|
|
65
65
|
##
|
|
66
66
|
## wwid.config['plugins'][PLUGIN_NAME][KEY]
|
|
67
67
|
##
|
|
68
|
-
##
|
|
68
|
+
## Method to return plugin settings (required)
|
|
69
69
|
##
|
|
70
70
|
## @return Hash of settings for this plugin
|
|
71
71
|
##
|
|
@@ -87,7 +87,7 @@ module Doing
|
|
|
87
87
|
## included in settings. The method should return a
|
|
88
88
|
## string (not output it to the STDOUT).
|
|
89
89
|
##
|
|
90
|
-
##
|
|
90
|
+
## Method to return template (optional)
|
|
91
91
|
##
|
|
92
92
|
## @param trigger The trigger passed to the
|
|
93
93
|
## template function. When this
|
|
@@ -96,7 +96,7 @@ module Doing
|
|
|
96
96
|
## used to determine which one is
|
|
97
97
|
## output.
|
|
98
98
|
##
|
|
99
|
-
## @return
|
|
99
|
+
## @return [String] template contents
|
|
100
100
|
##
|
|
101
101
|
def self.template(trigger)
|
|
102
102
|
return unless trigger =~ /^say(it)?$/
|
|
@@ -106,7 +106,7 @@ module Doing
|
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
##
|
|
109
|
-
##
|
|
109
|
+
## Render data received from an output
|
|
110
110
|
## command
|
|
111
111
|
##
|
|
112
112
|
## @param wwid The wwid object with config
|
|
@@ -118,7 +118,7 @@ module Doing
|
|
|
118
118
|
## flags passed to command
|
|
119
119
|
## (variables[:options])
|
|
120
120
|
##
|
|
121
|
-
## @return
|
|
121
|
+
## @return [String] Rendered output
|
|
122
122
|
##
|
|
123
123
|
def self.render(wwid, items, variables: {})
|
|
124
124
|
return if items.nil? || items.empty?
|
data/lib/doing/array.rb
CHANGED
data/lib/doing/configuration.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Doing
|
|
4
4
|
##
|
|
5
|
-
##
|
|
5
|
+
## Configuration object
|
|
6
6
|
##
|
|
7
7
|
class Configuration
|
|
8
8
|
attr_reader :settings
|
|
@@ -106,14 +106,15 @@ module Doing
|
|
|
106
106
|
|
|
107
107
|
def value_for_key(keypath = '')
|
|
108
108
|
cfg = @settings
|
|
109
|
+
real_path = []
|
|
109
110
|
unless keypath =~ /^[.*]?$/
|
|
110
111
|
paths = keypath.split(/[:.]/)
|
|
111
112
|
while paths.length.positive? && !cfg.nil?
|
|
112
113
|
path = paths.shift
|
|
113
114
|
new_cfg = nil
|
|
114
115
|
cfg.each do |key, val|
|
|
115
|
-
next unless key =~
|
|
116
|
-
|
|
116
|
+
next unless key =~ path.to_rx(distance: 2)
|
|
117
|
+
real_path << key
|
|
117
118
|
new_cfg = val
|
|
118
119
|
break
|
|
119
120
|
end
|
|
@@ -122,12 +123,13 @@ module Doing
|
|
|
122
123
|
Doing.logger.error("Key match not found: #{path}")
|
|
123
124
|
break
|
|
124
125
|
end
|
|
125
|
-
|
|
126
126
|
cfg = new_cfg
|
|
127
127
|
end
|
|
128
128
|
end
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
Doing.logger.debug('Config:', "translated key path #{keypath} to #{real_path.join('.')}")
|
|
130
|
+
result = {}
|
|
131
|
+
result[real_path[-1]] = cfg
|
|
132
|
+
result
|
|
131
133
|
end
|
|
132
134
|
|
|
133
135
|
# It takes the input, fills in the defaults where values do not exist.
|
|
@@ -148,9 +150,9 @@ module Doing
|
|
|
148
150
|
end
|
|
149
151
|
|
|
150
152
|
##
|
|
151
|
-
##
|
|
153
|
+
## Read user configuration and merge with defaults
|
|
152
154
|
##
|
|
153
|
-
## @param opt
|
|
155
|
+
## @param opt [Hash] Additional Options
|
|
154
156
|
##
|
|
155
157
|
def configure(opt = {})
|
|
156
158
|
@ignore_local = opt[:ignore_local] if opt[:ignore_local]
|
|
@@ -219,7 +221,7 @@ module Doing
|
|
|
219
221
|
end
|
|
220
222
|
|
|
221
223
|
##
|
|
222
|
-
##
|
|
224
|
+
## Read local configurations
|
|
223
225
|
##
|
|
224
226
|
## @return Hash of config options
|
|
225
227
|
##
|
|
@@ -251,7 +253,7 @@ module Doing
|
|
|
251
253
|
end
|
|
252
254
|
|
|
253
255
|
##
|
|
254
|
-
##
|
|
256
|
+
## Reads a configuration.
|
|
255
257
|
##
|
|
256
258
|
def read_config
|
|
257
259
|
unless File.exist?(config_file)
|
|
@@ -279,9 +281,9 @@ module Doing
|
|
|
279
281
|
end
|
|
280
282
|
|
|
281
283
|
##
|
|
282
|
-
##
|
|
284
|
+
## Finds a project-specific configuration file
|
|
283
285
|
##
|
|
284
|
-
## @return
|
|
286
|
+
## @return [String] A file path
|
|
285
287
|
##
|
|
286
288
|
def find_local_config
|
|
287
289
|
dir = Dir.pwd
|
data/lib/doing/errors.rb
CHANGED
data/lib/doing/hash.rb
CHANGED
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,43 +102,83 @@ 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
|
|
|
63
|
-
|
|
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
|
+
##
|
|
136
|
+
def tags?(tags, bool = :and, negate: false)
|
|
64
137
|
tags = split_tags(tags)
|
|
65
138
|
bool = bool.normalize_bool
|
|
66
139
|
|
|
67
|
-
case bool
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
140
|
+
matches = case bool
|
|
141
|
+
when :and
|
|
142
|
+
all_tags?(tags)
|
|
143
|
+
when :not
|
|
144
|
+
no_tags?(tags)
|
|
145
|
+
else
|
|
146
|
+
any_tags?(tags)
|
|
147
|
+
end
|
|
148
|
+
negate ? !matches : matches
|
|
149
|
+
end
|
|
150
|
+
|
|
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)
|
|
78
163
|
text = @title + @note.to_s
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
164
|
+
|
|
165
|
+
if search.is_rx? || !fuzzy
|
|
166
|
+
matches = text =~ search.to_rx(distance: distance, case_type: case_type)
|
|
167
|
+
else
|
|
168
|
+
distance = 0.25 if distance > 1
|
|
169
|
+
score = if (case_type == :smart && search !~ /[A-Z]/) || case_type == :ignore
|
|
170
|
+
text.downcase.pair_distance_similar(search.downcase)
|
|
85
171
|
else
|
|
86
|
-
|
|
87
|
-
search.split('').join('.{0,3}')
|
|
172
|
+
score = text.pair_distance_similar(search)
|
|
88
173
|
end
|
|
89
|
-
rx = Regexp.new(pattern, !case_sensitive)
|
|
90
174
|
|
|
91
|
-
|
|
175
|
+
if score >= distance
|
|
176
|
+
matches = true
|
|
177
|
+
Doing.logger.debug('Fuzzy Match:', %(#{@title}, "#{search}" #{score}))
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
negate ? !matches : matches
|
|
92
182
|
end
|
|
93
183
|
|
|
94
184
|
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
|
|
@@ -32,7 +32,7 @@ module Doing
|
|
|
32
32
|
].freeze
|
|
33
33
|
|
|
34
34
|
#
|
|
35
|
-
#
|
|
35
|
+
# Create a new instance of a log writer
|
|
36
36
|
#
|
|
37
37
|
# @param level (optional, symbol) the log level
|
|
38
38
|
#
|
|
@@ -47,29 +47,25 @@ module Doing
|
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
#
|
|
50
|
-
#
|
|
50
|
+
# Set the log level on the writer
|
|
51
51
|
#
|
|
52
52
|
# @param level (symbol) the log level
|
|
53
53
|
#
|
|
54
54
|
# @return nothing
|
|
55
55
|
#
|
|
56
|
-
def log_level=(level)
|
|
57
|
-
level ||= 'info'
|
|
56
|
+
def log_level=(level = 'info')
|
|
58
57
|
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
|
|
58
|
+
|
|
59
|
+
level = case level
|
|
60
|
+
when /^[e0]/i
|
|
61
|
+
:error
|
|
62
|
+
when /^[w1]/i
|
|
63
|
+
:warn
|
|
64
|
+
when /^[d3]/i
|
|
65
|
+
:debug
|
|
66
|
+
else
|
|
67
|
+
:info
|
|
68
|
+
end
|
|
73
69
|
|
|
74
70
|
@level = level
|
|
75
71
|
end
|
|
@@ -84,46 +80,6 @@ module Doing
|
|
|
84
80
|
# log_now :debug, 'Doing Version:', Doing::VERSION
|
|
85
81
|
end
|
|
86
82
|
|
|
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
83
|
def count(key, level: :info, count: 1, tag: nil, message: nil)
|
|
128
84
|
raise ArgumentError, 'invalid counter key' unless COUNT_KEYS.include?(key)
|
|
129
85
|
|
|
@@ -134,7 +90,7 @@ module Doing
|
|
|
134
90
|
end
|
|
135
91
|
|
|
136
92
|
#
|
|
137
|
-
#
|
|
93
|
+
# Print a debug message
|
|
138
94
|
#
|
|
139
95
|
# @param topic the topic of the message
|
|
140
96
|
# @param message the message detail
|
|
@@ -146,7 +102,7 @@ module Doing
|
|
|
146
102
|
end
|
|
147
103
|
|
|
148
104
|
#
|
|
149
|
-
#
|
|
105
|
+
# Print a message
|
|
150
106
|
#
|
|
151
107
|
# @param topic the topic of the message, e.g.
|
|
152
108
|
# "Configuration file",
|
|
@@ -160,7 +116,7 @@ module Doing
|
|
|
160
116
|
end
|
|
161
117
|
|
|
162
118
|
#
|
|
163
|
-
#
|
|
119
|
+
# Print a message
|
|
164
120
|
#
|
|
165
121
|
# @param topic the topic of the message, e.g.
|
|
166
122
|
# "Configuration file",
|
|
@@ -174,7 +130,7 @@ module Doing
|
|
|
174
130
|
end
|
|
175
131
|
|
|
176
132
|
#
|
|
177
|
-
#
|
|
133
|
+
# Print an error message
|
|
178
134
|
#
|
|
179
135
|
# @param topic the topic of the message, e.g.
|
|
180
136
|
# "Configuration file",
|
|
@@ -188,7 +144,7 @@ module Doing
|
|
|
188
144
|
end
|
|
189
145
|
|
|
190
146
|
#
|
|
191
|
-
#
|
|
147
|
+
# Print an error message and immediately
|
|
192
148
|
# abort the process
|
|
193
149
|
#
|
|
194
150
|
# @param topic the topic of the message, e.g.
|
|
@@ -204,33 +160,8 @@ module Doing
|
|
|
204
160
|
abort
|
|
205
161
|
end
|
|
206
162
|
|
|
207
|
-
# Internal: Build a topic method
|
|
208
163
|
#
|
|
209
|
-
#
|
|
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
|
-
#
|
|
233
|
-
# @brief Format the topic
|
|
164
|
+
# Format the topic
|
|
234
165
|
#
|
|
235
166
|
# @param topic the topic of the message, e.g.
|
|
236
167
|
# "Configuration file",
|
|
@@ -250,39 +181,34 @@ module Doing
|
|
|
250
181
|
end
|
|
251
182
|
|
|
252
183
|
#
|
|
253
|
-
#
|
|
254
|
-
# given the log level.
|
|
255
|
-
#
|
|
256
|
-
# @param level_of_message the Symbol level of
|
|
257
|
-
# message, one of :debug,
|
|
258
|
-
# :info, :warn, :error
|
|
259
|
-
#
|
|
260
|
-
# @return whether the message should be written.
|
|
261
|
-
#
|
|
262
|
-
def write_message?(level_of_message)
|
|
263
|
-
LOG_LEVELS.fetch(@level) <= LOG_LEVELS.fetch(level_of_message)
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
#
|
|
267
|
-
# @brief Log a message.
|
|
184
|
+
# Log a message.
|
|
268
185
|
#
|
|
269
|
-
# @param level_of_message the Symbol
|
|
270
|
-
# message, one of
|
|
271
|
-
# :info, :warn,
|
|
272
|
-
#
|
|
273
|
-
#
|
|
274
|
-
#
|
|
275
|
-
#
|
|
186
|
+
# @param level_of_message [Symbol] the Symbol
|
|
187
|
+
# level of message, one of
|
|
188
|
+
# :debug, :info, :warn,
|
|
189
|
+
# :error
|
|
190
|
+
# @param topic [String] the String
|
|
191
|
+
# topic or full message
|
|
192
|
+
# @param message [String] the String
|
|
193
|
+
# message (optional)
|
|
276
194
|
# @param block a block containing the
|
|
277
195
|
# message (optional)
|
|
278
196
|
#
|
|
279
|
-
# @return false if the message was not written
|
|
197
|
+
# @return [Boolean] false if the message was not written
|
|
280
198
|
#
|
|
281
199
|
def write(level_of_message, topic, message = nil, &block)
|
|
282
200
|
@results << { level: level_of_message, message: message(topic, message, &block) }
|
|
283
201
|
true
|
|
284
202
|
end
|
|
285
203
|
|
|
204
|
+
##
|
|
205
|
+
## Log to console immediately instead of writing messages on exit
|
|
206
|
+
##
|
|
207
|
+
## @param level [Symbol] The level
|
|
208
|
+
## @param topic [String] The topic or full message
|
|
209
|
+
## @param message [String] The message (optional)
|
|
210
|
+
## @param block a block containing the message (optional)
|
|
211
|
+
##
|
|
286
212
|
def log_now(level, topic, message = nil, &block)
|
|
287
213
|
return false unless write_message?(level)
|
|
288
214
|
|
|
@@ -293,6 +219,11 @@ module Doing
|
|
|
293
219
|
end
|
|
294
220
|
end
|
|
295
221
|
|
|
222
|
+
##
|
|
223
|
+
## Output registers based on log level
|
|
224
|
+
##
|
|
225
|
+
## @return nothing
|
|
226
|
+
##
|
|
296
227
|
def output_results
|
|
297
228
|
total_counters
|
|
298
229
|
|
|
@@ -309,6 +240,85 @@ module Doing
|
|
|
309
240
|
|
|
310
241
|
private
|
|
311
242
|
|
|
243
|
+
def format_counter(key, data)
|
|
244
|
+
case key
|
|
245
|
+
when :added_tags
|
|
246
|
+
['Tagged:', data[:message] || 'added %tags to %count %items']
|
|
247
|
+
when :removed_tags
|
|
248
|
+
['Untagged:', data[:message] || 'removed %tags from %count %items']
|
|
249
|
+
when :added
|
|
250
|
+
['Added:', data[:message] || 'added %count new %items']
|
|
251
|
+
when :updated
|
|
252
|
+
['Updated:', data[:message] || 'updated %count %items']
|
|
253
|
+
when :deleted
|
|
254
|
+
['Deleted:', data[:message] || 'deleted %count %items']
|
|
255
|
+
when :moved
|
|
256
|
+
['Moved:', data[:message] || 'moved %count %items']
|
|
257
|
+
when :completed
|
|
258
|
+
['Completed:', data[:message] || 'completed %count %items']
|
|
259
|
+
when :archived
|
|
260
|
+
['Archived:', data[:message] || 'archived %count %items']
|
|
261
|
+
when :completed_archived
|
|
262
|
+
['Archived:', data[:message] || 'completed and archived %count %items']
|
|
263
|
+
when :skipped
|
|
264
|
+
['Skipped:', data[:message] || '%count %items were unchanged']
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def total_counters
|
|
269
|
+
@counters.each do |key, data|
|
|
270
|
+
next if data[:count].zero?
|
|
271
|
+
|
|
272
|
+
count = data[:count]
|
|
273
|
+
tags = data[:tag] ? data[:tag].uniq.map { |t| "@#{t}".cyan }.join(', ') : 'tags'
|
|
274
|
+
topic, m = format_counter(key, data)
|
|
275
|
+
message = m.dup
|
|
276
|
+
message.sub!(/%count/, count.to_s)
|
|
277
|
+
message.sub!(/%items/, count == 1 ? 'item' : 'items')
|
|
278
|
+
message.sub!(/%tags/, tags)
|
|
279
|
+
write(data[:level], topic, message)
|
|
280
|
+
end
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
#
|
|
284
|
+
# Check if the message should be written
|
|
285
|
+
# given the log level.
|
|
286
|
+
#
|
|
287
|
+
# @param level_of_message the Symbol level of
|
|
288
|
+
# message, one of :debug,
|
|
289
|
+
# :info, :warn, :error
|
|
290
|
+
#
|
|
291
|
+
# @return whether the message should be written.
|
|
292
|
+
#
|
|
293
|
+
def write_message?(level_of_message)
|
|
294
|
+
LOG_LEVELS.fetch(@level) <= LOG_LEVELS.fetch(level_of_message)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Internal: Build a topic method
|
|
298
|
+
#
|
|
299
|
+
# @param topic the topic of the message, e.g.
|
|
300
|
+
# "Configuration file",
|
|
301
|
+
# "Deprecation", etc.
|
|
302
|
+
# @param message the message detail
|
|
303
|
+
#
|
|
304
|
+
# @return the formatted message
|
|
305
|
+
#
|
|
306
|
+
def message(topic, message = nil)
|
|
307
|
+
raise ArgumentError, 'block or message, not both' if block_given? && message
|
|
308
|
+
|
|
309
|
+
message = yield if block_given?
|
|
310
|
+
message = message.to_s.gsub(/\s+/, ' ')
|
|
311
|
+
|
|
312
|
+
return topic.ljust(TOPIC_WIDTH) if topic && message.strip.empty?
|
|
313
|
+
|
|
314
|
+
topic = formatted_topic(topic, colon: block_given?)
|
|
315
|
+
message.truncmiddle!(@max_length - TOPIC_WIDTH - 5)
|
|
316
|
+
out = topic + message
|
|
317
|
+
out.truncate!(@max_length) if @max_length.positive?
|
|
318
|
+
messages << out
|
|
319
|
+
out
|
|
320
|
+
end
|
|
321
|
+
|
|
312
322
|
def color_message(level, topic, message = nil, &block)
|
|
313
323
|
colors = Doing::Color
|
|
314
324
|
message = message(topic, message, &block)
|