doing 2.1.21 → 2.1.25

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +19 -16
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +51 -13
  6. data/Gemfile.lock +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +6 -3
  9. data/bin/doing +254 -103
  10. data/docs/doc/Array.html +74 -34
  11. data/docs/doc/BooleanTermParser/Clause.html +5 -5
  12. data/docs/doc/BooleanTermParser/Operator.html +4 -4
  13. data/docs/doc/BooleanTermParser/Query.html +8 -8
  14. data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
  15. data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
  16. data/docs/doc/BooleanTermParser.html +1 -1
  17. data/docs/doc/Doing/Color.html +4 -4
  18. data/docs/doc/Doing/Completion.html +2 -2
  19. data/docs/doc/Doing/Configuration.html +16 -18
  20. data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
  21. data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
  22. data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
  23. data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
  24. data/docs/doc/Doing/Errors/NoResults.html +2 -2
  25. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  26. data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
  27. data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
  28. data/docs/doc/Doing/Errors.html +1 -1
  29. data/docs/doc/Doing/Hooks.html +6 -6
  30. data/docs/doc/Doing/Item.html +50 -16
  31. data/docs/doc/Doing/Items.html +10 -10
  32. data/docs/doc/Doing/LogAdapter.html +24 -24
  33. data/docs/doc/Doing/Note.html +7 -7
  34. data/docs/doc/Doing/Pager.html +4 -4
  35. data/docs/doc/Doing/Plugins.html +7 -7
  36. data/docs/doc/Doing/Prompt.html +16 -16
  37. data/docs/doc/Doing/Section.html +6 -6
  38. data/docs/doc/Doing/TemplateString.html +8 -8
  39. data/docs/doc/Doing/Types.html +206 -0
  40. data/docs/doc/Doing/Util/Backup.html +10 -10
  41. data/docs/doc/Doing/Util.html +16 -19
  42. data/docs/doc/Doing/WWID.html +65 -53
  43. data/docs/doc/Doing.html +4 -4
  44. data/docs/doc/GLI/Commands/Help.html +185 -0
  45. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  46. data/docs/doc/GLI/Commands.html +5 -3
  47. data/docs/doc/GLI.html +4 -2
  48. data/docs/doc/Hash.html +119 -21
  49. data/docs/doc/Numeric.html +5 -5
  50. data/docs/doc/PhraseParser/Operator.html +4 -4
  51. data/docs/doc/PhraseParser/PhraseClause.html +5 -5
  52. data/docs/doc/PhraseParser/Query.html +10 -10
  53. data/docs/doc/PhraseParser/QueryParser.html +2 -2
  54. data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
  55. data/docs/doc/PhraseParser/TermClause.html +5 -5
  56. data/docs/doc/PhraseParser.html +1 -1
  57. data/docs/doc/Status.html +7 -7
  58. data/docs/doc/String.html +206 -51
  59. data/docs/doc/Symbol.html +8 -8
  60. data/docs/doc/Time.html +6 -6
  61. data/docs/doc/_index.html +51 -14
  62. data/docs/doc/class_list.html +1 -1
  63. data/docs/doc/file.README.html +2 -2
  64. data/docs/doc/index.html +2 -2
  65. data/docs/doc/method_list.html +348 -252
  66. data/docs/doc/top-level-namespace.html +2 -93
  67. data/docs/index.md +1 -1
  68. data/doing.rdoc +177 -20
  69. data/example_plugin.rb +2 -2
  70. data/lib/completion/_doing.zsh +24 -24
  71. data/lib/completion/doing.bash +31 -20
  72. data/lib/completion/doing.fish +32 -10
  73. data/lib/doing/array.rb +5 -4
  74. data/lib/doing/array_chronify.rb +4 -3
  75. data/lib/doing/changelog/change.rb +115 -0
  76. data/lib/doing/changelog/changes.rb +73 -0
  77. data/lib/doing/changelog/entry.rb +21 -0
  78. data/lib/doing/changelog/version.rb +97 -0
  79. data/lib/doing/changelog.rb +6 -0
  80. data/lib/doing/completion/fish_completion.rb +2 -1
  81. data/lib/doing/configuration.rb +20 -14
  82. data/lib/doing/good.rb +64 -0
  83. data/lib/doing/hash.rb +28 -5
  84. data/lib/doing/help_monkey_patch.rb +31 -0
  85. data/lib/doing/hooks.rb +8 -4
  86. data/lib/doing/item.rb +24 -35
  87. data/lib/doing/log_adapter.rb +1 -1
  88. data/lib/doing/pager.rb +1 -1
  89. data/lib/doing/plugins/export/template_export.rb +9 -3
  90. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  91. data/lib/doing/plugins/import/doing_import.rb +1 -1
  92. data/lib/doing/plugins/import/timing_import.rb +1 -1
  93. data/lib/doing/prompt.rb +4 -2
  94. data/lib/doing/string.rb +30 -12
  95. data/lib/doing/string_chronify.rb +1 -1
  96. data/lib/doing/template_string.rb +9 -2
  97. data/lib/doing/types.rb +23 -16
  98. data/lib/doing/util.rb +12 -11
  99. data/lib/doing/version.rb +1 -1
  100. data/lib/doing/wwid.rb +65 -46
  101. data/lib/doing.rb +3 -0
  102. data/lib/helpers/threaded_tests.rb +106 -99
  103. data/lib/helpers/threaded_tests_string.rb +50 -0
  104. metadata +12 -2
data/lib/doing/item.rb CHANGED
@@ -125,11 +125,11 @@ module Doing
125
125
  return true if same_time?(item_b)
126
126
 
127
127
  start_a = date
128
- interval = interval
129
- end_a = interval ? start_a + interval.to_i : start_a
128
+ a_interval = interval
129
+ end_a = a_interval ? start_a + a_interval.to_i : start_a
130
130
  start_b = item_b.date
131
- interval = item_b.interval
132
- end_b = interval ? start_b + interval.to_i : start_b
131
+ b_interval = item_b.interval
132
+ end_b = b_interval ? start_b + b_interval.to_i : start_b
133
133
  (start_a >= start_b && start_a <= end_b) || (end_a >= start_b && end_a <= end_b) || (start_a < start_b && end_a > end_b)
134
134
  end
135
135
 
@@ -216,8 +216,8 @@ module Doing
216
216
  ##
217
217
  def tags?(tags, bool = :and, negate: false)
218
218
  if bool == :pattern
219
- tags = tags.join(' ') if tags.is_a?(Array)
220
- matches = tag_pattern?(tags.gsub(/ *, */, ' '))
219
+ tags = tags.to_tags.tags_to_array.join(' ')
220
+ matches = tag_pattern?(tags)
221
221
 
222
222
  return negate ? !matches : matches
223
223
  end
@@ -283,7 +283,7 @@ module Doing
283
283
  new_title = @title.gsub(rx) { |m| yellow(m) }
284
284
  new_note.add(@note.to_s.gsub(rx) { |m| yellow(m) })
285
285
  else
286
- query = to_phrase_query(search.strip)
286
+ query = search.strip.to_phrase_query
287
287
 
288
288
  if query[:must].nil? && query[:must_not].nil?
289
289
  query[:must] = query[:should]
@@ -319,7 +319,7 @@ module Doing
319
319
  if search.is_rx? || matching == :fuzzy
320
320
  matches = @title + @note.to_s =~ search.to_rx(distance: distance, case_type: case_type)
321
321
  else
322
- query = to_phrase_query(search.strip)
322
+ query = search.strip.to_phrase_query
323
323
 
324
324
  if query[:must].nil? && query[:must_not].nil?
325
325
  query[:must] = query[:should]
@@ -399,7 +399,7 @@ module Doing
399
399
 
400
400
  # outputs item in Doing file format, including leading tab
401
401
  def to_s
402
- "\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title}#{@note.empty? ? '' : "\n#{@note}"}"
402
+ "\t- #{@date.strftime('%Y-%m-%d %H:%M')} | #{@title}#{@note.good? ? "\n#{@note}" : ''}"
403
403
  end
404
404
 
405
405
  ##
@@ -429,6 +429,10 @@ module Doing
429
429
  %(<Doing::Item @date=#{@date}>)
430
430
  end
431
431
 
432
+ def clone
433
+ Marshal.load(Marshal.dump(self))
434
+ end
435
+
432
436
  private
433
437
 
434
438
  def should?(key)
@@ -457,7 +461,7 @@ module Doing
457
461
  end
458
462
 
459
463
  def all_searches?(searches, case_type: :smart)
460
- return true if searches.nil? || searches.empty?
464
+ return true unless searches.good?
461
465
 
462
466
  text = @title + @note.to_s
463
467
  searches.each do |s|
@@ -468,7 +472,7 @@ module Doing
468
472
  end
469
473
 
470
474
  def no_searches?(searches, case_type: :smart)
471
- return true if searches.nil? || searches.empty?
475
+ return true unless searches.good?
472
476
 
473
477
  text = @title + @note.to_s
474
478
  searches.each do |s|
@@ -479,7 +483,7 @@ module Doing
479
483
  end
480
484
 
481
485
  def any_searches?(searches, case_type: :smart)
482
- return true if searches.nil? || searches.empty?
486
+ return true unless searches.good?
483
487
 
484
488
  text = @title + @note.to_s
485
489
  searches.each do |s|
@@ -490,7 +494,7 @@ module Doing
490
494
  end
491
495
 
492
496
  def all_tags?(tags)
493
- return true if tags.nil? || tags.empty?
497
+ return true unless tags.good?
494
498
 
495
499
  tags.each do |tag|
496
500
  return false unless @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
@@ -499,7 +503,7 @@ module Doing
499
503
  end
500
504
 
501
505
  def no_tags?(tags)
502
- return true if tags.nil? || tags.empty?
506
+ return true unless tags.good?
503
507
 
504
508
  tags.each do |tag|
505
509
  return false if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
@@ -508,7 +512,7 @@ module Doing
508
512
  end
509
513
 
510
514
  def any_tags?(tags)
511
- return true if tags.nil? || tags.empty?
515
+ return true unless tags.good?
512
516
 
513
517
  tags.each do |tag|
514
518
  return true if @title =~ /@#{tag.wildcard_to_rx}(?= |\(|\Z)/i
@@ -537,7 +541,7 @@ module Doing
537
541
  end
538
542
 
539
543
  def any_values?(queries)
540
- return true if queries.nil? || queries.empty?
544
+ return true unless queries.good?
541
545
 
542
546
  queries.each do |q|
543
547
  parts = split_value_query(q)
@@ -547,7 +551,7 @@ module Doing
547
551
  end
548
552
 
549
553
  def all_values?(queries)
550
- return true if queries.nil? || queries.empty?
554
+ return true unless queries.good?
551
555
 
552
556
  queries.each do |q|
553
557
  parts = split_value_query(q)
@@ -557,7 +561,7 @@ module Doing
557
561
  end
558
562
 
559
563
  def no_values?(queries)
560
- return true if queries.nil? || queries.empty?
564
+ return true unless queries.good?
561
565
 
562
566
  queries.each do |q|
563
567
  parts = split_value_query(q)
@@ -612,29 +616,14 @@ module Doing
612
616
  end
613
617
  end
614
618
 
615
- def to_query(query)
616
- parser = BooleanTermParser::QueryParser.new
617
- transformer = BooleanTermParser::QueryTransformer.new
618
- parse_tree = parser.parse(query)
619
- transformer.apply(parse_tree).to_elasticsearch
620
- end
621
-
622
- def to_phrase_query(query)
623
- parser = PhraseParser::QueryParser.new
624
- transformer = PhraseParser::QueryTransformer.new
625
- parse_tree = parser.parse(query)
626
- transformer.apply(parse_tree).to_elasticsearch
627
- end
628
-
629
619
  def tag_pattern?(tags)
630
- query = to_query(tags)
620
+ query = tags.to_query
631
621
 
632
622
  no_tags?(query[:must_not]) && all_tags?(query[:must]) && any_tags?(query[:should])
633
623
  end
634
624
 
635
625
  def split_tags(tags)
636
- tags = tags.split(/ *, */) if tags.is_a? String
637
- tags.map { |t| t.strip.add_at }
626
+ tags.to_tags.tags_to_array
638
627
  end
639
628
  end
640
629
  end
@@ -356,7 +356,7 @@ module Doing
356
356
  next if data[:count].zero?
357
357
 
358
358
  count = data[:count]
359
- tags = data[:tag] ? data[:tag].uniq.map { |t| "@#{t}".cyan }.join(', ') : 'tags'
359
+ tags = data[:tag] ? data[:tag].uniq.map { |t| t.add_at.cyan }.join(', ') : 'tags'
360
360
  topic, m = format_counter(key, data)
361
361
  message = m.dup
362
362
  message.sub!(/%count/, count.to_s)
data/lib/doing/pager.rb CHANGED
@@ -54,7 +54,7 @@ module Doing
54
54
  read_io.close
55
55
  write_io.write(text)
56
56
  write_io.close
57
- rescue SystemCallError => e
57
+ rescue SystemCallError # => e
58
58
  # raise Errors::DoingStandardError, "Pager error, #{e}"
59
59
  end
60
60
 
@@ -49,6 +49,8 @@ module Doing
49
49
  note = []
50
50
  end
51
51
 
52
+ placeholders['tags'] = item.tags
53
+
52
54
  placeholders['date'] = item.date.strftime(opt[:format])
53
55
 
54
56
  interval = wwid.get_interval(item, record: true, formatted: false) if opt[:times]
@@ -56,8 +58,10 @@ module Doing
56
58
  interval = case opt[:interval_format].to_sym
57
59
  when :human
58
60
  interval.time_string(format: :hm)
59
- else
61
+ when :text
60
62
  interval.time_string(format: :clock)
63
+ else
64
+ interval.time_string(format: opt[:interval_format].to_sym)
61
65
  end
62
66
  end
63
67
 
@@ -69,8 +73,10 @@ module Doing
69
73
  duration = case opt[:interval_format].to_sym
70
74
  when :human
71
75
  duration.time_string(format: :hm)
72
- else
76
+ when :text
73
77
  duration.time_string(format: :clock)
78
+ else
79
+ duration.time_string(format: opt[:interval_format].to_sym)
74
80
  end
75
81
  end
76
82
  duration ||= ''
@@ -119,7 +125,7 @@ module Doing
119
125
 
120
126
  output.gsub!(/\\%/, '%')
121
127
 
122
- output.highlight_search!(opt[:search]) if opt[:search] && !opt[:not] && opt[:hilite]
128
+ output.highlight_search!(opt[:search]) if opt[:template] =~ /^temp/ && opt[:search] && !opt[:not] && opt[:hilite]
123
129
 
124
130
  out += "#{output}\n"
125
131
  end
@@ -89,7 +89,7 @@ module Doing
89
89
 
90
90
  wwid.content.concat(new_items)
91
91
 
92
- new_items.map { |item| Hooks.trigger :post_entry_added, self, item.dup }
92
+ new_items.map { |item| Hooks.trigger :post_entry_added, self, item }
93
93
 
94
94
  Doing.logger.info(%(Imported #{new_items.count} items to #{section}))
95
95
  end
@@ -93,7 +93,7 @@ module Doing
93
93
  wwid.content.add_section(item.section) unless wwid.content.section?(item.section)
94
94
  Hooks.trigger :pre_entry_add, self, item
95
95
  wwid.content.push(item)
96
- Hooks.trigger :post_entry_added, self, item.dup
96
+ Hooks.trigger :post_entry_added, self, item
97
97
  end
98
98
 
99
99
  Doing.logger.info('Imported:', "#{imported.count} items")
@@ -93,7 +93,7 @@ module Doing
93
93
 
94
94
  wwid.content.concat(new_items)
95
95
 
96
- new_items.map { |item| Hooks.trigger :post_entry_added, self, item.dup }
96
+ new_items.map { |item| Hooks.trigger :post_entry_added, self, item }
97
97
 
98
98
  Doing.logger.info('Imported:', %(#{new_items.count} items to #{section}))
99
99
  end
data/lib/doing/prompt.rb CHANGED
@@ -42,7 +42,7 @@ module Doing
42
42
  end
43
43
  end
44
44
 
45
- def read_lines(prompt: 'Enter text', completions: [])
45
+ def read_lines(prompt: 'Enter text', completions: [], default_response: '')
46
46
  $stdin.reopen('/dev/tty')
47
47
  return default_response if @default_answer
48
48
 
@@ -72,8 +72,10 @@ module Doing
72
72
  res.join("\n").strip
73
73
  end
74
74
 
75
- def request_lines(prompt: 'Enter text')
75
+ def request_lines(prompt: 'Enter text', default_response: '')
76
76
  $stdin.reopen('/dev/tty')
77
+ return default_response if @default_answer
78
+
77
79
  ask_note = []
78
80
  reader = TTY::Reader.new(interrupt: -> { raise Errors::UserCancelled }, track_history: false)
79
81
  puts "#{boldgreen(prompt.sub(/:?$/, ':'))} #{yellow('Hit return for a new line, ')}#{boldwhite('enter a blank line (')}#{boldyellow('return twice')}#{boldwhite(') to end editing')}"
data/lib/doing/string.rb CHANGED
@@ -20,7 +20,9 @@ module Doing
20
20
  ## can be separated by up to *distance* characters in
21
21
  ## haystack, spaces indicate unlimited distance.
22
22
  ##
23
- ## @example `"this word".to_rx(2) => /t.{0,3}h.{0,3}i.{0,3}s.{0,3}.*?w.{0,3}o.{0,3}r.{0,3}d/`
23
+ ## @example
24
+ ## "this word".to_rx(3)
25
+ ## # => /t.{0,3}h.{0,3}i.{0,3}s.{0,3}.*?w.{0,3}o.{0,3}r.{0,3}d/
24
26
  ##
25
27
  ## @param distance [Integer] Allowed distance
26
28
  ## between characters
@@ -53,6 +55,20 @@ module Doing
53
55
  Regexp.new(pattern, !case_sensitive)
54
56
  end
55
57
 
58
+ def to_phrase_query
59
+ parser = PhraseParser::QueryParser.new
60
+ transformer = PhraseParser::QueryTransformer.new
61
+ parse_tree = parser.parse(self)
62
+ transformer.apply(parse_tree).to_elasticsearch
63
+ end
64
+
65
+ def to_query
66
+ parser = BooleanTermParser::QueryParser.new
67
+ transformer = BooleanTermParser::QueryTransformer.new
68
+ parse_tree = parser.parse(self)
69
+ transformer.apply(parse_tree).to_elasticsearch
70
+ end
71
+
56
72
  ##
57
73
  ## Test string for truthiness (0, "f", "false", "n", "no" all return false, case insensitive, otherwise true)
58
74
  ##
@@ -92,7 +108,7 @@ module Doing
92
108
  escapes = scan(/(\e\[[\d;]+m)[^\e]+@/)
93
109
  color = color.split(' ') unless color.is_a?(Array)
94
110
  tag_color = color.each_with_object([]) { |c, arr| arr << Doing::Color.send(c) }.join('')
95
- last_color = if !escapes.empty?
111
+ last_color = if escapes.good?
96
112
  (escapes.count > 1 ? escapes[-2..-1] : [escapes[-1]]).map { |v| v[0] }.join('')
97
113
  else
98
114
  Doing::Color.default
@@ -101,13 +117,6 @@ module Doing
101
117
  gsub(/(\s|m)(@[^ ("']+)/, "\\1#{tag_color}\\2#{last_color}")
102
118
  end
103
119
 
104
- def to_phrase_query(query)
105
- parser = PhraseParser::QueryParser.new
106
- transformer = PhraseParser::QueryTransformer.new
107
- parse_tree = parser.parse(query)
108
- transformer.apply(parse_tree).to_elasticsearch
109
- end
110
-
111
120
  def ignore_case(search, case_type)
112
121
  (case_type == :smart && search !~ /[A-Z]/) || case_type == :ignore
113
122
  end
@@ -127,7 +136,7 @@ module Doing
127
136
  rx = search.to_rx(distance: distance, case_type: case_type)
128
137
  out.gsub!(rx) { |m| m.bgyellow.black }
129
138
  else
130
- query = to_phrase_query(search.strip)
139
+ query = search.strip.to_phrase_query
131
140
 
132
141
  if query[:must].nil? && query[:must_not].nil?
133
142
  query[:must] = query[:should]
@@ -449,7 +458,7 @@ module Doing
449
458
  ## @return [String] Regular expression string
450
459
  ##
451
460
  def wildcard_to_rx
452
- gsub(/\?/, '\S').gsub(/\*/, '\S*?')
461
+ gsub(/\?/, '\S').gsub(/\*/, '\S*?').gsub(/\]\]/, '--')
453
462
  end
454
463
 
455
464
  ##
@@ -458,7 +467,16 @@ module Doing
458
467
  ## @return [String] @string
459
468
  ##
460
469
  def add_at
461
- strip.sub(/^([+-]*)@/, '\1')
470
+ strip.sub(/^([+-]*)@?/, '\1@')
471
+ end
472
+
473
+ ##
474
+ ## Removes @ prefix if needed, maintains +/- prefix
475
+ ##
476
+ ## @return [String] string without @ prefix
477
+ ##
478
+ def remove_at
479
+ strip.sub(/^([+-]*)@?/, '\1')
462
480
  end
463
481
 
464
482
  ##
@@ -173,7 +173,7 @@ module Doing
173
173
  ## @return [Array<DateTime>] Start and end dates as
174
174
  ## array
175
175
  ## @example Process a natural language date range
176
- ## "mon 3pm to mon 5pm".split_date_range
176
+ ## "mon 3pm to mon 5pm".split_date_range
177
177
  ##
178
178
  def split_date_range
179
179
  time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
@@ -131,7 +131,7 @@ module Doing
131
131
 
132
132
  after = m['after']
133
133
 
134
- if value.nil? || value.empty?
134
+ if !value.good?
135
135
  after
136
136
  else
137
137
  pad = m['width'].to_i
@@ -146,6 +146,13 @@ module Doing
146
146
  end
147
147
  indent ||= placeholder =~ /^title/ ? '' : "\t"
148
148
  prefix = m['prefix']
149
+
150
+ if placeholder =~ /^tags/
151
+ prefix ||= ''
152
+ value = value.map { |t| "#{prefix}#{t.sub(/^#{prefix}?/, '')}" }.join(' ')
153
+ prefix = ''
154
+ end
155
+
149
156
  if placeholder =~ /^title/
150
157
  color = last_color + color
151
158
 
@@ -176,7 +183,7 @@ module Doing
176
183
  ' '
177
184
  else
178
185
  line = l.gsub(/%/, '\%').strip.wrap(width, pad: pad, indent: indent, offset: 0, prefix: prefix, color: last_color, after: after, reset: reset, pad_first: true)
179
- line.highlight_tags!(tags_color, last_color: last_color) unless !tags_color || tags_color.nil? || tags_color.empty?
186
+ line.highlight_tags!(tags_color, last_color: last_color) unless !tags_color || !tags_color.good?
180
187
  "#{line} "
181
188
  end
182
189
  end.join("\n")
data/lib/doing/types.rb CHANGED
@@ -1,19 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i
4
- REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i
5
- REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/
6
- REGEX_CLOCK = '(?:\d{1,2}+(?::\d{1,2}+)?(?: *(?:am|pm))?|midnight|noon)'
7
- REGEX_TIME = /^#{REGEX_CLOCK}$/i
8
- REGEX_DAY = /^(mon|tue|wed|thur?|fri|sat|sun)(\w+(day)?)?$/i
9
- REGEX_RANGE_INDICATOR = ' +(?:to|through|thru|(?:un)?til|-+) +'
10
- REGEX_RANGE = /^\S+#{REGEX_RANGE_INDICATOR}+\S+/i
11
- REGEX_TIME_RANGE = /^#{REGEX_CLOCK}#{REGEX_RANGE_INDICATOR}#{REGEX_CLOCK}$/i
3
+ module Doing
4
+ module Types
5
+ REGEX_BOOL = /^(?:and|all|any|or|not|none|p(?:at(?:tern)?)?)$/i.freeze
6
+ REGEX_SORT_ORDER = /^(?:a(?:sc)?|d(?:esc)?)$/i.freeze
7
+ REGEX_VALUE_QUERY = /^(?:!)?@?(?:\S+) +(?:!?[<>=][=*]?|[$*^]=) +(?:.*?)$/.freeze
8
+ REGEX_CLOCK = '(?:\d{1,2}+(?::\d{1,2}+)?(?: *(?:am|pm))?|midnight|noon)'
9
+ REGEX_TIME = /^#{REGEX_CLOCK}$/i.freeze
10
+ REGEX_DAY = /^(mon|tue|wed|thur?|fri|sat|sun)(\w+(day)?)?$/i.freeze
11
+ REGEX_RANGE_INDICATOR = ' +(?:to|through|thru|(?:un)?til|-+) +'
12
+ REGEX_RANGE = /^\S+#{REGEX_RANGE_INDICATOR}+\S+/i.freeze
13
+ REGEX_TIME_RANGE = /^#{REGEX_CLOCK}#{REGEX_RANGE_INDICATOR}#{REGEX_CLOCK}$/i.freeze
12
14
 
13
- InvalidExportType = Class.new(RuntimeError)
14
- MissingConfigFile = Class.new(RuntimeError)
15
- TagArray = Class.new(Array)
16
- DateBeginString = Class.new(DateTime)
17
- DateEndString = Class.new(DateTime)
18
- DateRangeString = Class.new(Array)
19
- DateIntervalString = Class.new(DateTime)
15
+ InvalidExportType = Class.new(RuntimeError)
16
+ MissingConfigFile = Class.new(RuntimeError)
17
+
18
+ TagArray = Class.new(Array)
19
+ TemplateName = Class.new(String)
20
+ DateBeginString = Class.new(DateTime)
21
+ DateEndString = Class.new(DateTime)
22
+ DateRangeString = Class.new(Array)
23
+ DateRangeOptionalString = Class.new(Array)
24
+ DateIntervalString = Class.new(DateTime)
25
+ end
26
+ end
data/lib/doing/util.rb CHANGED
@@ -19,7 +19,7 @@ module Doing
19
19
  ## @param cli [String] The name or path of the cli
20
20
  ##
21
21
  def exec_available(cli)
22
- return false if cli.nil?
22
+ return false unless cli.good?
23
23
 
24
24
  !TTY::Which.which(cli).nil?
25
25
  end
@@ -27,11 +27,12 @@ module Doing
27
27
  ##
28
28
  ## Return the first valid executable from a list of commands
29
29
  ##
30
- ## @example `Doing::Util.first_available_exec('bat', 'less -Xr', 'more -r', 'cat')`
30
+ ## @example
31
+ ## Doing::Util.first_available_exec('bat', 'less -Xr', 'more -r', 'cat')
31
32
  ##
32
33
  def first_available_exec(*commands)
33
34
  commands.compact.map(&:strip).reject(&:empty?).uniq
34
- .find { |cmd| exec_available(cmd.split.first) }
35
+ .find { |cmd| exec_available(cmd.split.first) }
35
36
  end
36
37
 
37
38
  def merge_default_proc(target, overwrite)
@@ -55,7 +56,7 @@ module Doing
55
56
  # @param [Hash] other_hash The other hash
56
57
  #
57
58
  def deep_merge_hashes(master_hash, other_hash)
58
- deep_merge_hashes!(master_hash.dup, other_hash)
59
+ deep_merge_hashes!(master_hash.clone, other_hash)
59
60
  end
60
61
 
61
62
  # Merges a master hash with another hash, recursively.
@@ -156,32 +157,32 @@ module Doing
156
157
  def find_default_editor(editor_for = 'default')
157
158
  # return nil unless $stdout.isatty || ENV['DOING_EDITOR_TEST']
158
159
 
159
- if ENV['DOING_EDITOR_TEST']
160
- return ENV['EDITOR']
161
- end
160
+ return ENV['EDITOR'] if ENV['DOING_EDITOR_TEST']
162
161
 
163
162
  editor_config = Doing.config.settings['editors']
164
163
 
165
164
  if editor_config.is_a?(String)
166
- Doing.logger.warn('Deprecated:', "Please update your configuration, 'editors' should be a mapping. Delete the key and run `doing config --update`.")
165
+ msg = "Please update your configuration, 'editors' should be a mapping."
166
+ msg << ' Delete the key and run `doing config --update`.'
167
+ Doing.logger.warn('Deprecated:', msg)
167
168
  return editor_config
168
169
  end
169
170
 
170
171
  if editor_config[editor_for]
171
172
  editor = editor_config[editor_for]
172
173
  # Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
173
- return editor unless editor.nil? || editor.empty?
174
+ return editor unless editor.good?
174
175
  end
175
176
 
176
177
  if editor_for != 'editor' && editor_config['default']
177
178
  editor = editor_config['default']
178
179
  # Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
179
- return editor unless editor.nil? || editor.empty?
180
+ return editor unless editor.good?
180
181
  end
181
182
 
182
183
  editor ||= ENV['DOING_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
183
184
 
184
- unless editor.nil? || editor.empty?
185
+ unless editor.good?
185
186
  # Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
186
187
  return editor
187
188
  end
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.21'
2
+ VERSION = '2.1.25'
3
3
  end