doing 2.0.7.pre → 2.0.11
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 +13 -9
- data/Gemfile.lock +30 -10
- data/README.md +1 -1
- data/Rakefile +8 -1
- data/bin/doing +368 -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 +15 -2
- 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 +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 +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 +96 -21
- 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 +510 -368
- 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/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
|
@@ -2,7 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
module Doing
|
|
4
4
|
##
|
|
5
|
-
##
|
|
5
|
+
## Array helpers
|
|
6
6
|
##
|
|
7
|
-
class ::Array
|
|
7
|
+
class ::Array
|
|
8
|
+
def to_tags
|
|
9
|
+
map { |t| t.sub(/^@?/, '@') }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def highlight_tags(color = 'cyan')
|
|
13
|
+
tag_color = Doing::Color.send(color)
|
|
14
|
+
to_tags.map { |t| "#{tag_color}#{t}" }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def log_tags
|
|
18
|
+
highlight_tags.join(', ')
|
|
19
|
+
end
|
|
20
|
+
end
|
|
8
21
|
end
|
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?
|