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.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +20 -0
  3. data/.yardoc/complete +0 -0
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/.yardoc/proxy_types +0 -0
  7. data/.yardopts +1 -0
  8. data/CHANGELOG.md +7 -7
  9. data/Gemfile.lock +30 -10
  10. data/README.md +1 -1
  11. data/Rakefile +8 -1
  12. data/bin/doing +367 -21
  13. data/doc/Array.html +135 -0
  14. data/doc/Doing/Color.html +506 -0
  15. data/doc/Doing/Configuration.html +680 -0
  16. data/doc/Doing/Errors/DoingNoTraceError.html +186 -0
  17. data/doc/Doing/Errors/DoingRuntimeError.html +186 -0
  18. data/doc/Doing/Errors/DoingStandardError.html +186 -0
  19. data/doc/Doing/Errors/EmptyInput.html +186 -0
  20. data/doc/Doing/Errors/NoResults.html +186 -0
  21. data/doc/Doing/Errors/PluginException.html +248 -0
  22. data/doc/Doing/Errors/UserCancelled.html +186 -0
  23. data/doc/Doing/Errors/WrongCommand.html +186 -0
  24. data/doc/Doing/Errors.html +191 -0
  25. data/doc/Doing/Hooks.html +364 -0
  26. data/doc/Doing/Item.html +1385 -0
  27. data/doc/Doing/Items.html +393 -0
  28. data/doc/Doing/LogAdapter.html +1650 -0
  29. data/doc/Doing/Note.html +535 -0
  30. data/doc/Doing/Pager.html +268 -0
  31. data/doc/Doing/Plugins.html +849 -0
  32. data/doc/Doing/Util.html +870 -0
  33. data/doc/Doing/WWID.html +4827 -0
  34. data/doc/Doing.html +145 -0
  35. data/doc/GLI/Commands/MarkdownDocumentListener.html +763 -0
  36. data/doc/GLI/Commands.html +115 -0
  37. data/doc/GLI.html +115 -0
  38. data/doc/Hash.html +332 -0
  39. data/doc/Status.html +292 -0
  40. data/doc/String.html +1714 -0
  41. data/doc/Symbol.html +250 -0
  42. data/doc/Time.html +182 -0
  43. data/doc/_index.html +411 -0
  44. data/doc/class_list.html +51 -0
  45. data/doc/css/common.css +1 -0
  46. data/doc/css/full_list.css +58 -0
  47. data/doc/css/style.css +497 -0
  48. data/doc/file.README.html +123 -0
  49. data/doc/file_list.html +56 -0
  50. data/doc/frames.html +17 -0
  51. data/doc/index.html +123 -0
  52. data/doc/js/app.js +314 -0
  53. data/doc/js/full_list.js +216 -0
  54. data/doc/js/jquery.js +4 -0
  55. data/doc/method_list.html +1867 -0
  56. data/doc/top-level-namespace.html +112 -0
  57. data/doing.gemspec +5 -1
  58. data/doing.rdoc +354 -6
  59. data/example_plugin.rb +6 -6
  60. data/lib/doing/array.rb +1 -1
  61. data/lib/doing/configuration.rb +14 -12
  62. data/lib/doing/errors.rb +1 -1
  63. data/lib/doing/hash.rb +1 -1
  64. data/lib/doing/item.rb +113 -23
  65. data/lib/doing/log_adapter.rb +123 -113
  66. data/lib/doing/note.rb +1 -1
  67. data/lib/doing/plugin_manager.rb +5 -5
  68. data/lib/doing/plugins/export/csv_export.rb +1 -1
  69. data/lib/doing/plugins/export/template_export.rb +5 -7
  70. data/lib/doing/plugins/import/calendar_import.rb +8 -2
  71. data/lib/doing/plugins/import/doing_import.rb +10 -10
  72. data/lib/doing/plugins/import/timing_import.rb +12 -4
  73. data/lib/doing/string.rb +94 -19
  74. data/lib/doing/symbol.rb +9 -5
  75. data/lib/doing/time.rb +1 -1
  76. data/lib/doing/util.rb +18 -11
  77. data/lib/doing/version.rb +1 -1
  78. data/lib/doing/wwid.rb +455 -335
  79. data/lib/doing/wwidfile.rb +5 -5
  80. data/lib/doing.rb +2 -1
  81. data/lib/examples/plugins/say_export.rb +6 -6
  82. data/lib/examples/plugins/{templates → wiki_export/templates}/wiki.css +0 -0
  83. data/lib/examples/plugins/{templates → wiki_export/templates}/wiki.haml +0 -0
  84. data/lib/examples/plugins/{templates → wiki_export/templates}/wiki_index.haml +0 -0
  85. data/lib/examples/plugins/{wiki_export.rb → wiki_export/wiki_export.rb} +0 -0
  86. data/rdocfixer.rb +1 -1
  87. data/scripts/generate_zsh_completions.rb +3 -2
  88. data/yard_templates/default/method_details/setup.rb +3 -0
  89. metadata +121 -8
data/lib/doing/note.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Doing
4
4
  ##
5
- ## @brief This class describes an item note.
5
+ ## This class describes an item note.
6
6
  ##
7
7
  class Note < Array
8
8
  def initialize(note = [])
@@ -107,7 +107,7 @@ module Doing
107
107
  end
108
108
 
109
109
  ##
110
- ## @brief List available plugins to stdout
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
- ## @brief Return array of available plugin names
132
+ ## Return array of available plugin names
133
133
  ##
134
134
  ## @param type Plugin type (:import, :export)
135
135
  ##
136
- ## @returns [Array<String>] plugin names
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
- ## @brief Return string version of plugin names
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
- ## @brief Return a regular expression of all
157
+ ## Return a regular expression of all
158
158
  ## plugin triggers for type
159
159
  ##
160
160
  ## @param type The type :import or :export
@@ -6,7 +6,7 @@
6
6
  # url: https://brettterpstra.com
7
7
  module Doing
8
8
  ##
9
- ## @brief CSV Export
9
+ ## CSV Export
10
10
  ##
11
11
  class CSVExport
12
12
  include Doing::Util
@@ -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
- output.sub!(/%chompnote/) do |_m|
115
- chomp_note = note.map do |l|
116
- l.gsub(/\n+/, ' ').gsub(/(^\s*|\s*$)/, '').gsub(/\s+/, ' ')
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 |_m|
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? ? '-' : '_'
@@ -8,7 +8,7 @@ require 'json'
8
8
 
9
9
  module Doing
10
10
  ##
11
- ## @brief Plugin for importing from Calendar.app on macOS
11
+ ## Plugin for importing from Calendar.app on macOS
12
12
  ##
13
13
  class CalendarImport
14
14
  include Doing::Util
@@ -64,9 +64,15 @@ module Doing
64
64
  new_items.push(new_entry)
65
65
  end
66
66
  total = new_items.count
67
+
68
+ new_items = wwid.filter_items(new_items, opt: options)
69
+ filtered = total - new_items.count
70
+ Doing.logger.debug('Skipped:' , %(#{filtered} items that didn't match filter criteria)) if filtered.positive?
71
+
67
72
  new_items = wwid.dedup(new_items, options[:no_overlap])
68
- dups = total - new_items.count
73
+ dups = filtered - new_items.count
69
74
  Doing.logger.info(%(Skipped #{dups} items with overlapping times)) if dups.positive?
75
+
70
76
  wwid.content[section][:items].concat(new_items)
71
77
  Doing.logger.info(%(Imported #{new_items.count} items to #{section}))
72
78
  end
@@ -15,11 +15,11 @@ module Doing
15
15
  end
16
16
 
17
17
  ##
18
- ## @brief Imports a Doing file
18
+ ## Imports a Doing file
19
19
  ##
20
- ## @param wwid WWID object
21
- ## @param path (String) Path to Doing file
22
- ## @param options (Hash) Additional 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
  ##
@@ -40,13 +40,13 @@ module Doing
40
40
 
41
41
  new_items = read_doing_file(path)
42
42
 
43
- if options[:date_filter]
44
- new_items = wwid.filter_items(new_items, opt: { count: 0, date_filter: options[:date_filter] })
45
- end
43
+ total = new_items.count
46
44
 
47
- if options[:before] || options[:after]
48
- new_items = wwid.filter_items(new_items, opt: { count: 0, before: options[:before], after: options[:after] })
49
- end
45
+ options[:count] = 0
46
+ new_items = wwid.filter_items(new_items, opt: options)
47
+
48
+ skipped = total - new_items.count
49
+ Doing.logger.debug('Skipped:' , %(#{skipped} items that didn't match filter criteria)) if skipped.positive?
50
50
 
51
51
  imported = []
52
52
 
@@ -15,10 +15,12 @@ module Doing
15
15
  end
16
16
 
17
17
  ##
18
- ## @brief Imports a Timing report
18
+ ## Imports a Timing report
19
19
  ##
20
- ## @param path (String) Path to JSON report file
21
- ## @param options (Hash) Additional Options
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?
@@ -66,9 +68,15 @@ module Doing
66
68
  total = new_items.count
67
69
  skipped = data.count - total
68
70
  Doing.logger.debug('Skipped:' , %(#{skipped} items, invalid type or no time interval)) if skipped.positive?
71
+
72
+ new_items = wwid.filter_items(new_items, opt: options)
73
+ filtered = skipped - new_items.count
74
+ Doing.logger.debug('Skipped:' , %(#{filtered} items that didn't match filter criteria)) if filtered.positive?
75
+
69
76
  new_items = wwid.dedup(new_items, options[:no_overlap])
70
- dups = total - new_items.count
77
+ dups = filtered - new_items.count
71
78
  Doing.logger.debug('Skipped:' , %(#{dups} items with overlapping times)) if dups.positive?
79
+
72
80
  wwid.content[section][:items].concat(new_items)
73
81
  Doing.logger.info('Imported:', %(#{new_items.count} items to #{section}))
74
82
  end
data/lib/doing/string.rb CHANGED
@@ -2,14 +2,59 @@
2
2
 
3
3
  module Doing
4
4
  ##
5
- ## @brief String helpers
5
+ ## String helpers
6
6
  ##
7
7
  class ::String
8
8
  include Doing::Color
9
- def to_rx(distance)
10
- gsub(/(.)/, "\\1.{0,#{distance}}")
9
+ ##
10
+ ## Determines if receiver is surrounded by slashes or starts with single quote
11
+ ##
12
+ ## @return True if regex, False otherwise.
13
+ ##
14
+ def is_rx?
15
+ self =~ %r{(^/.*?/$|^')}
16
+ end
17
+
18
+ ##
19
+ ## Convert string to fuzzy regex. Characters in words
20
+ ## can be separated by up to *distance* characters in
21
+ ## haystack, spaces indicate unlimited distance.
22
+ ##
23
+ ## @example "this word".to_rx(2) =>
24
+ ## /t.{0,3}h.{0,3}i.{0,3}s.{0,3}.*?w.{0,3}o.{0,3}r.{0,3}d/
25
+ ##
26
+ ## @param distance [Integer] Allowed distance
27
+ ## between characters
28
+ ## @param case_type The case type
29
+ ##
30
+ ## @return [Regexp] Regex pattern
31
+ ##
32
+ def to_rx(distance: 3, case_type: :smart)
33
+ case_sensitive = case case_type
34
+ when :smart
35
+ self =~ /[A-Z]/ ? true : false
36
+ when :sensitive
37
+ true
38
+ else
39
+ false
40
+ end
41
+
42
+ pattern = case dup.strip
43
+ when %r{^/.*?/$}
44
+ sub(%r{/(.*?)/}, '\1')
45
+ when /^'/
46
+ sub(/^'(.*?)'?$/, '\1')
47
+ else
48
+ split(/ +/).map { |w| w.split('').join(".{0,#{distance}}") }.join('.*?')
49
+ end
50
+ Regexp.new(pattern, !case_sensitive)
11
51
  end
12
52
 
53
+ ##
54
+ ## Test string for truthiness (0, "f", "false", "n", "no" all return false, case insensitive, otherwise true)
55
+ ##
56
+ ## @return [Boolean] String is truthy
57
+ ##
13
58
  def truthy?
14
59
  if self =~ /^(0|f(alse)?|n(o)?)$/i
15
60
  false
@@ -18,10 +63,18 @@ module Doing
18
63
  end
19
64
  end
20
65
 
66
+ ## @param (see #highlight_tags)
21
67
  def highlight_tags!(color = 'yellow')
22
68
  replace highlight_tags(color)
23
69
  end
24
70
 
71
+ ##
72
+ ## Colorize @tags with ANSI escapes
73
+ ##
74
+ ## @param color [String] color (see #Color)
75
+ ##
76
+ ## @return [String] string with @tags highlighted
77
+ ##
25
78
  def highlight_tags(color = 'yellow')
26
79
  escapes = scan(/(\e\[[\d;]+m)[^\e]+@/)
27
80
  tag_color = Doing::Color.send(color)
@@ -34,7 +87,7 @@ module Doing
34
87
  end
35
88
 
36
89
  ##
37
- ## @brief Test if line should be ignored
90
+ ## Test if line should be ignored
38
91
  ##
39
92
  ## @return [Boolean] line is empty or comment
40
93
  ##
@@ -44,7 +97,7 @@ module Doing
44
97
  end
45
98
 
46
99
  ##
47
- ## @brief Truncate to nearest word
100
+ ## Truncate to nearest word
48
101
  ##
49
102
  ## @param len The length
50
103
  ##
@@ -68,7 +121,7 @@ module Doing
68
121
  end
69
122
 
70
123
  ##
71
- ## @brief Truncate string in the middle
124
+ ## Truncate string in the middle
72
125
  ##
73
126
  ## @param len The length
74
127
  ## @param ellipsis The ellipsis
@@ -87,7 +140,7 @@ module Doing
87
140
  end
88
141
 
89
142
  ##
90
- ## @brief Remove color escape codes
143
+ ## Remove color escape codes
91
144
  ##
92
145
  ## @return clean string
93
146
  ##
@@ -100,7 +153,7 @@ module Doing
100
153
  end
101
154
 
102
155
  ##
103
- ## @brief Wrap string at word breaks, respecting tags
156
+ ## Wrap string at word breaks, respecting tags
104
157
  ##
105
158
  ## @param len [Integer] The length
106
159
  ## @param offset [Integer] (Optional) The width to pad each subsequent line
@@ -134,7 +187,7 @@ module Doing
134
187
  end
135
188
 
136
189
  ##
137
- ## @brief Capitalize on the first character on string
190
+ ## Capitalize on the first character on string
138
191
  ##
139
192
  ## @return Capitalized string
140
193
  ##
@@ -145,12 +198,12 @@ module Doing
145
198
  end
146
199
 
147
200
  ##
148
- ## @brief Convert a sort order string to a qualified type
201
+ ## Convert a sort order string to a qualified type
149
202
  ##
150
- ## @return (String) 'asc' or 'desc'
203
+ ## @return [String] 'asc' or 'desc'
151
204
  ##
152
- def normalize_order!
153
- replace normalize_order
205
+ def normalize_order!(default = 'asc')
206
+ replace normalize_order(default)
154
207
  end
155
208
 
156
209
  def normalize_order(default = 'asc')
@@ -165,12 +218,34 @@ module Doing
165
218
  end
166
219
 
167
220
  ##
168
- ## @brief Convert a boolean string to a symbol
221
+ ## Convert a case sensitivity string to a symbol
222
+ ##
223
+ ## @return Symbol :smart, :sensitive, :ignore
224
+ ##
225
+ def normalize_case!
226
+ replace normalize_case
227
+ end
228
+
229
+ def normalize_case(default = :smart)
230
+ case self
231
+ when /^c/i
232
+ :sensitive
233
+ when /^i/i
234
+ :ignore
235
+ when /^s/i
236
+ :smart
237
+ else
238
+ default.is_a?(Symbol) ? default : default.normalize_case
239
+ end
240
+ end
241
+
242
+ ##
243
+ ## Convert a boolean string to a symbol
169
244
  ##
170
245
  ## @return Symbol :and, :or, or :not
171
246
  ##
172
- def normalize_bool!
173
- replace normalize_bool
247
+ def normalize_bool!(default = :and)
248
+ replace normalize_bool(default)
174
249
  end
175
250
 
176
251
  def normalize_bool(default = :and)
@@ -268,7 +343,7 @@ module Doing
268
343
  end
269
344
 
270
345
  ##
271
- ## @brief Remove duplicate tags, leaving only first occurrence
346
+ ## Remove duplicate tags, leaving only first occurrence
272
347
  ##
273
348
  ## @return Deduplicated string
274
349
  ##
@@ -294,9 +369,9 @@ module Doing
294
369
  end
295
370
 
296
371
  ##
297
- ## @brief Turn raw urls into HTML links
372
+ ## Turn raw urls into HTML links
298
373
  ##
299
- ## @param opt (Hash) Additional Options
374
+ ## @param opt [Hash] Additional Options
300
375
  ##
301
376
  def link_urls!(opt = {})
302
377
  replace link_urls(opt)
data/lib/doing/symbol.rb CHANGED
@@ -2,15 +2,19 @@
2
2
 
3
3
  module Doing
4
4
  ##
5
- ## @brief Symbol helpers
5
+ ## Symbol helpers
6
6
  ##
7
7
  class ::Symbol
8
- def normalize_bool
9
- to_s.normalize_bool
8
+ def normalize_bool(default = :and)
9
+ to_s.normalize_bool(default)
10
10
  end
11
11
 
12
- def normalize_order
13
- to_s.normalize_order
12
+ def normalize_order(default = 'asc')
13
+ to_s.normalize_order(default)
14
+ end
15
+
16
+ def normalize_case
17
+ self
14
18
  end
15
19
  end
16
20
  end
data/lib/doing/time.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Doing
2
2
  ##
3
- ## @brief Date helpers
3
+ ## Date helpers
4
4
  ##
5
5
  class ::Time
6
6
  def relative_date
data/lib/doing/util.rb CHANGED
@@ -14,9 +14,9 @@ module Doing
14
14
  end
15
15
 
16
16
  ##
17
- ## @brief Test if command line tool is available
17
+ ## Test if command line tool is available
18
18
  ##
19
- ## @param cli (String) The name or path of the cli
19
+ ## @param cli [String] The name or path of the cli
20
20
  ##
21
21
  def exec_available(cli)
22
22
  return false if cli.nil?
@@ -40,9 +40,14 @@ module Doing
40
40
  end
41
41
  end
42
42
 
43
- # Non-destructive version of deep_merge_hashes! See that method.
43
+ # Non-destructive version of deep_merge_hashes! See that
44
+ # method.
45
+ #
46
+ # @return the merged hashes.
47
+ #
48
+ # @param [Hash] master_hash The master hash
49
+ # @param [Hash] other_hash The other hash
44
50
  #
45
- # Returns the merged hashes.
46
51
  def deep_merge_hashes(master_hash, other_hash)
47
52
  deep_merge_hashes!(master_hash.dup, other_hash)
48
53
  end
@@ -90,11 +95,11 @@ module Doing
90
95
  end
91
96
 
92
97
  ##
93
- ## @brief Write content to a file
98
+ ## Write content to a file
94
99
  ##
95
- ## @param file (String) The path to the file to (over)write
96
- ## @param content (String) The content to write to the file
97
- ## @param backup (Boolean) create a ~ backup
100
+ ## @param file [String] The path to the file to (over)write
101
+ ## @param content [String] The content to write to the file
102
+ ## @param backup [Boolean] create a ~ backup
98
103
  ##
99
104
  def write_to_file(file, content, backup: true)
100
105
  unless file
@@ -143,6 +148,8 @@ module Doing
143
148
  end
144
149
 
145
150
  def find_default_editor(editor_for = 'default')
151
+ # return nil unless $stdout.isatty || ENV['DOING_EDITOR_TEST']
152
+
146
153
  if ENV['DOING_EDITOR_TEST']
147
154
  return ENV['EDITOR']
148
155
  end
@@ -156,20 +163,20 @@ module Doing
156
163
 
157
164
  if editor_config[editor_for]
158
165
  editor = editor_config[editor_for]
159
- Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
166
+ # Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
160
167
  return editor unless editor.nil? || editor.empty?
161
168
  end
162
169
 
163
170
  if editor_for != 'editor' && editor_config['default']
164
171
  editor = editor_config['default']
165
- Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
172
+ # Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
166
173
  return editor unless editor.nil? || editor.empty?
167
174
  end
168
175
 
169
176
  editor ||= ENV['DOING_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
170
177
 
171
178
  unless editor.nil? || editor.empty?
172
- Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
179
+ # Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
173
180
  return editor
174
181
  end
175
182
 
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.0.6.pre'
2
+ VERSION = '2.0.10'
3
3
  end