doing 2.1.21 → 2.1.25

Sign up to get free protection for your applications and to get access to all the features.
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