doing 2.1.24 → 2.1.25

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +11 -10
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +2 -1
  9. data/bin/doing +81 -37
  10. data/docs/doc/Array.html +70 -7
  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 +14 -16
  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 +14 -14
  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 +6 -1
  40. data/docs/doc/Doing/Util/Backup.html +10 -10
  41. data/docs/doc/Doing/Util.html +15 -15
  42. data/docs/doc/Doing/WWID.html +65 -53
  43. data/docs/doc/Doing.html +3 -3
  44. data/docs/doc/GLI/Commands/Help.html +3 -3
  45. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  46. data/docs/doc/GLI/Commands.html +1 -1
  47. data/docs/doc/GLI.html +1 -1
  48. data/docs/doc/Hash.html +45 -11
  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 +107 -44
  59. data/docs/doc/Symbol.html +8 -8
  60. data/docs/doc/Time.html +6 -6
  61. data/docs/doc/_index.html +41 -18
  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 +369 -313
  66. data/docs/doc/top-level-namespace.html +2 -2
  67. data/doing.rdoc +19 -11
  68. data/example_plugin.rb +2 -2
  69. data/lib/completion/_doing.zsh +12 -12
  70. data/lib/completion/doing.bash +2 -2
  71. data/lib/completion/doing.fish +9 -8
  72. data/lib/doing/changelog/changes.rb +1 -1
  73. data/lib/doing/configuration.rb +4 -6
  74. data/lib/doing/good.rb +64 -0
  75. data/lib/doing/hash.rb +4 -0
  76. data/lib/doing/hooks.rb +3 -3
  77. data/lib/doing/item.rb +14 -10
  78. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  79. data/lib/doing/plugins/import/doing_import.rb +1 -1
  80. data/lib/doing/plugins/import/timing_import.rb +1 -1
  81. data/lib/doing/string.rb +1 -1
  82. data/lib/doing/template_string.rb +2 -2
  83. data/lib/doing/types.rb +1 -0
  84. data/lib/doing/util.rb +10 -10
  85. data/lib/doing/version.rb +1 -1
  86. data/lib/doing/wwid.rb +40 -18
  87. data/lib/doing.rb +1 -0
  88. data/lib/helpers/threaded_tests.rb +35 -64
  89. data/lib/helpers/threaded_tests_string.rb +50 -0
  90. metadata +4 -2
@@ -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
@@ -183,7 +183,7 @@ module Doing
183
183
  ' '
184
184
  else
185
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)
186
- 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?
187
187
  "#{line} "
188
188
  end
189
189
  end.join("\n")
data/lib/doing/types.rb CHANGED
@@ -20,6 +20,7 @@ module Doing
20
20
  DateBeginString = Class.new(DateTime)
21
21
  DateEndString = Class.new(DateTime)
22
22
  DateRangeString = Class.new(Array)
23
+ DateRangeOptionalString = Class.new(Array)
23
24
  DateIntervalString = Class.new(DateTime)
24
25
  end
25
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
@@ -32,7 +32,7 @@ module Doing
32
32
  ##
33
33
  def first_available_exec(*commands)
34
34
  commands.compact.map(&:strip).reject(&:empty?).uniq
35
- .find { |cmd| exec_available(cmd.split.first) }
35
+ .find { |cmd| exec_available(cmd.split.first) }
36
36
  end
37
37
 
38
38
  def merge_default_proc(target, overwrite)
@@ -56,7 +56,7 @@ module Doing
56
56
  # @param [Hash] other_hash The other hash
57
57
  #
58
58
  def deep_merge_hashes(master_hash, other_hash)
59
- deep_merge_hashes!(master_hash.dup, other_hash)
59
+ deep_merge_hashes!(master_hash.clone, other_hash)
60
60
  end
61
61
 
62
62
  # Merges a master hash with another hash, recursively.
@@ -157,32 +157,32 @@ module Doing
157
157
  def find_default_editor(editor_for = 'default')
158
158
  # return nil unless $stdout.isatty || ENV['DOING_EDITOR_TEST']
159
159
 
160
- if ENV['DOING_EDITOR_TEST']
161
- return ENV['EDITOR']
162
- end
160
+ return ENV['EDITOR'] if ENV['DOING_EDITOR_TEST']
163
161
 
164
162
  editor_config = Doing.config.settings['editors']
165
163
 
166
164
  if editor_config.is_a?(String)
167
- 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)
168
168
  return editor_config
169
169
  end
170
170
 
171
171
  if editor_config[editor_for]
172
172
  editor = editor_config[editor_for]
173
173
  # Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
174
- return editor unless editor.nil? || editor.empty?
174
+ return editor unless editor.good?
175
175
  end
176
176
 
177
177
  if editor_for != 'editor' && editor_config['default']
178
178
  editor = editor_config['default']
179
179
  # Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
180
- return editor unless editor.nil? || editor.empty?
180
+ return editor unless editor.good?
181
181
  end
182
182
 
183
183
  editor ||= ENV['DOING_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
184
184
 
185
- unless editor.nil? || editor.empty?
185
+ unless editor.good?
186
186
  # Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
187
187
  return editor
188
188
  end
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.24'
2
+ VERSION = '2.1.25'
3
3
  end
data/lib/doing/wwid.rb CHANGED
@@ -338,6 +338,7 @@ module Doing
338
338
  ## @option opt :note [Array] item note (will be converted if value is String)
339
339
  ## @option opt :back [Date] backdate
340
340
  ## @option opt :timed [Boolean] new item is timed entry, marks previous entry as @done
341
+ ## @option opt :done [Date] If set, adds a @done tag to new entry
341
342
  ##
342
343
  def add_item(title, section = nil, opt)
343
344
  opt ||= {}
@@ -360,9 +361,18 @@ module Doing
360
361
 
361
362
  title.compress!
362
363
  entry = Item.new(opt[:back], title.strip, section)
364
+
365
+ if opt[:done] && entry.should_finish?
366
+ if entry.should_time?
367
+ entry.tag('done', value: opt[:done])
368
+ else
369
+ entry.tag('done')
370
+ end
371
+ end
372
+
363
373
  entry.note = note
364
374
 
365
- items = @content.dup
375
+ items = @content.clone
366
376
  if opt[:timed]
367
377
  items.reverse!
368
378
  items.each_with_index do |i, x|
@@ -380,7 +390,8 @@ module Doing
380
390
  # logger.count(:added, level: :debug)
381
391
  logger.info('New entry:', %(added "#{entry.date.relative_date}: #{entry.title}" to #{section}))
382
392
 
383
- Hooks.trigger :post_entry_added, self, entry.dup
393
+ Hooks.trigger :post_entry_added, self, entry
394
+ entry
384
395
  end
385
396
 
386
397
  ##
@@ -474,6 +485,7 @@ module Doing
474
485
  #
475
486
  def repeat_item(item, opt)
476
487
  opt ||= {}
488
+ old_item = item.clone
477
489
  if item.should_finish?
478
490
  if item.should_time?
479
491
  finish_date = verify_duration(item.date, Time.now, title: item.title)
@@ -481,7 +493,7 @@ module Doing
481
493
  else
482
494
  item.title.tag!('done')
483
495
  end
484
- Hooks.trigger :post_entry_updated, self, item
496
+ Hooks.trigger :post_entry_updated, self, item, old_item
485
497
  end
486
498
 
487
499
  # Remove @done tag
@@ -651,7 +663,7 @@ module Doing
651
663
 
652
664
  if items.nil? || items.empty?
653
665
  section = opt[:section] ? guess_section(opt[:section]) : 'All'
654
- items = section =~ /^all$/i ? @content.dup : @content.in_section(section)
666
+ items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
655
667
  end
656
668
 
657
669
  opt[:time_filter] = [nil, nil]
@@ -847,7 +859,7 @@ module Doing
847
859
  note.map!(&:strip)
848
860
  note.delete_if(&:ignore?)
849
861
  item = items[i]
850
- old_item = item.dup
862
+ old_item = item.clone
851
863
  item.date = date || items[i].date
852
864
  item.title = title
853
865
  item.note = note
@@ -855,7 +867,7 @@ module Doing
855
867
  Doing.logger.count(:skipped, level: :debug)
856
868
  else
857
869
  Doing.logger.count(:updated)
858
- Hooks.trigger :post_entry_updated, self, item
870
+ Hooks.trigger :post_entry_updated, self, item, old_item
859
871
  end
860
872
  end
861
873
  end
@@ -1045,9 +1057,10 @@ module Doing
1045
1057
  else
1046
1058
  opt[:resume]
1047
1059
  end
1060
+ old_item = item.clone
1048
1061
  new_entry = reset_item(item, date: date, resume: res)
1049
1062
  @content.update_item(item, new_entry)
1050
- Hooks.trigger :post_entry_updated, self, new_entry
1063
+ Hooks.trigger :post_entry_updated, self, new_entry, old_item
1051
1064
  end
1052
1065
  write(@doing_file)
1053
1066
 
@@ -1062,8 +1075,9 @@ module Doing
1062
1075
  if opt[:flag]
1063
1076
  tag = @config['marker_tag'] || 'flagged'
1064
1077
  items.map! do |i|
1078
+ old_item = i.clone
1065
1079
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1066
- Hooks.trigger :post_entry_updated, self, i
1080
+ Hooks.trigger :post_entry_updated, self, i, old_item
1067
1081
  end
1068
1082
  end
1069
1083
 
@@ -1071,9 +1085,10 @@ module Doing
1071
1085
  tag = 'done'
1072
1086
  items.map! do |i|
1073
1087
  if i.should_finish?
1088
+ old_item = i.clone
1074
1089
  should_date = !opt[:cancel] && i.should_time?
1075
1090
  i.tag(tag, date: should_date, remove: opt[:remove], single: single)
1076
- Hooks.trigger :post_entry_updated, self, i
1091
+ Hooks.trigger :post_entry_updated, self, i, old_item
1077
1092
  end
1078
1093
  end
1079
1094
  end
@@ -1087,8 +1102,9 @@ module Doing
1087
1102
  else
1088
1103
  logger.count(:added_tags)
1089
1104
  logger.write(items.count == 1 ? :info : :debug, 'Tagged:', new_title)
1105
+ old_item = i.clone
1090
1106
  i.title = new_title
1091
- Hooks.trigger :post_entry_updated, self, i
1107
+ Hooks.trigger :post_entry_updated, self, i, old_item
1092
1108
  end
1093
1109
  end
1094
1110
  end
@@ -1096,17 +1112,19 @@ module Doing
1096
1112
  if opt[:tag]
1097
1113
  tag = opt[:tag]
1098
1114
  items.map! do |i|
1115
+ old_item = i.clone
1099
1116
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1100
1117
  i.expand_date_tags(@config['date_tags'])
1101
- Hooks.trigger :post_entry_updated, self, i
1118
+ Hooks.trigger :post_entry_updated, self, i, old_item
1102
1119
  end
1103
1120
  end
1104
1121
 
1105
1122
  if opt[:archive] || opt[:move]
1106
1123
  section = opt[:archive] ? 'Archive' : guess_section(opt[:move])
1107
1124
  items.map! do |i|
1125
+ old_item = i.clone
1108
1126
  i.move_to(section, label: true)
1109
- Hooks.trigger :post_entry_updated, self, i
1127
+ Hooks.trigger :post_entry_updated, self, i, old_item
1110
1128
  end
1111
1129
  end
1112
1130
 
@@ -1228,6 +1246,7 @@ module Doing
1228
1246
  end
1229
1247
 
1230
1248
  items.each do |item|
1249
+ old_item = item.clone
1231
1250
  added = []
1232
1251
  removed = []
1233
1252
 
@@ -1322,7 +1341,7 @@ module Doing
1322
1341
  end
1323
1342
 
1324
1343
  item.expand_date_tags(@config['date_tags'])
1325
- Hooks.trigger :post_entry_updated, self, item
1344
+ Hooks.trigger :post_entry_updated, self, item, old_item
1326
1345
  end
1327
1346
 
1328
1347
  write(@doing_file)
@@ -1361,6 +1380,7 @@ module Doing
1361
1380
  return
1362
1381
  end
1363
1382
 
1383
+ old_item = item.clone
1364
1384
  content = ["#{item.date.strftime('%F %R')} | #{item.title.dup}"]
1365
1385
  content << item.note.strip_lines.join("\n") unless item.note.empty?
1366
1386
  new_item = fork_editor(content.join("\n"))
@@ -1376,7 +1396,7 @@ module Doing
1376
1396
  item.title = title
1377
1397
  item.note.add(note, replace: true)
1378
1398
  logger.info('Edited:', item.title)
1379
- Hooks.trigger :post_entry_updated, self, item.dup
1399
+ Hooks.trigger :post_entry_updated, self, item, old_item
1380
1400
 
1381
1401
  write(@doing_file)
1382
1402
  end
@@ -1413,6 +1433,7 @@ module Doing
1413
1433
  found_items = 0
1414
1434
 
1415
1435
  @content.each_with_index do |item, i|
1436
+ old_item = i.clone
1416
1437
  next unless item.section == opt[:section] || opt[:section] =~ /all/i
1417
1438
 
1418
1439
  next unless item.title =~ /@#{tag}/
@@ -1431,7 +1452,7 @@ module Doing
1431
1452
  logger.count(:completed)
1432
1453
  logger.info('Completed:', item.title)
1433
1454
  end
1434
- Hooks.trigger :post_entry_updated, self, item
1455
+ Hooks.trigger :post_entry_updated, self, item, old_item
1435
1456
  end
1436
1457
 
1437
1458
 
@@ -1492,7 +1513,7 @@ module Doing
1492
1513
 
1493
1514
  unless ((!tags.empty? && !item.tags?(tags, bool)) || (opt[:search] && !item.search(opt[:search].to_s)) || (opt[:before] && item.date >= cutoff))
1494
1515
  new_item = @content.delete(item)
1495
- Hooks.trigger :post_entry_removed, self, item.dup
1516
+ Hooks.trigger :post_entry_removed, self, item.clone
1496
1517
  raise DoingRuntimeError, "Error deleting item: #{item}" if new_item.nil?
1497
1518
 
1498
1519
  new_content.add_section(new_item.section, log: false)
@@ -2202,7 +2223,7 @@ EOS
2202
2223
 
2203
2224
  filename ||= @config['doing_file']
2204
2225
  init_doing_file(filename)
2205
- current_content = @content.dup
2226
+ current_content = @content.clone
2206
2227
  backup_file = Util::Backup.last_backup(filename, count: 1)
2207
2228
  raise DoingRuntimeError, 'No undo history to diff' if backup_file.nil?
2208
2229
 
@@ -2321,8 +2342,9 @@ EOS
2321
2342
  item
2322
2343
  else
2323
2344
  counter += 1
2345
+ old_item = item.clone
2324
2346
  item.move_to(destination, label: label, log: false)
2325
- Hooks.trigger :post_entry_updated, self, item.dup
2347
+ Hooks.trigger :post_entry_updated, self, item, old_item
2326
2348
  item
2327
2349
  end
2328
2350
  end
data/lib/doing.rb CHANGED
@@ -31,6 +31,7 @@ require_relative 'doing/template_string'
31
31
  require_relative 'doing/string'
32
32
  require_relative 'doing/time'
33
33
  require_relative 'doing/array'
34
+ require_relative 'doing/good'
34
35
  require_relative 'doing/symbol'
35
36
  require_relative 'doing/util'
36
37
  require_relative 'doing/util_backup'
@@ -2,64 +2,21 @@
2
2
 
3
3
  require 'tty-spinner'
4
4
  require 'tty-progressbar'
5
- require './lib/doing'
6
5
  require 'open3'
7
6
  require 'shellwords'
7
+ require 'fileutils'
8
8
 
9
- class ::String
10
- include Doing::Color
11
-
12
- def highlight_errors
13
- cols = `tput cols`.strip.to_i
14
-
15
- string = dup
16
-
17
- errs = string.scan(/(?<==\n)(?:Failure|Error):.*?(?=\n=+)/m)
18
-
19
- errs.map! do |error|
20
- err = error.dup
21
-
22
- err.gsub!(%r{^(/.*?/)([^/:]+):(\d+):in (.*?)$}) do
23
- m = Regexp.last_match
24
- "#{m[1].white}#{m[2].bold.white}:#{m[3].yellow}:in #{m[4].cyan}"
25
- end
26
- err.gsub!(/(Failure|Error): (.*?)\((.*?)\):\n (.*?)(?=\n)/m) do
27
- m = Regexp.last_match
28
- [
29
- m[1].bold.boldbgred.white,
30
- m[3].bold.boldbgcyan.white,
31
- m[2].bold.boldbgyellow.black,
32
- " #{m[4]} ".bold.boldbgwhite.black.reset
33
- ].join(':'.boldblack.boldbgblack.reset)
34
- end
35
- err.gsub!(/(<.*?>) (was expected to) (.*?)\n( *<.*?>)./m) do
36
- m = Regexp.last_match
37
- "#{m[1].bold.green} #{m[2].white} #{m[3].boldwhite.boldbgred.reset}\n#{m[4].bold.white}"
38
- end
39
- err.gsub!(/(Finished in) ([\d.]+) (seconds)/) do
40
- m = Regexp.last_match
41
- "#{m[1].green} #{m[2].bold.white} #{m[3].green}"
42
- end
43
- err.gsub!(/(\d+) (failures)/) do
44
- m = Regexp.last_match
45
- "#{m[1].bold.red} #{m[2].red}"
46
- end
47
- err.gsub!(/100% passed/) do |m|
48
- m.bold.green
49
- end
50
-
51
- err
52
- end
53
-
54
- errs.join("\n#{('=' * cols).blue}\n")
55
- end
56
- end
9
+ $LOAD_PATH.unshift File.join(__dir__, '..')
10
+ require 'doing'
11
+ require 'helpers/threaded_tests_string'
57
12
 
58
13
  class ThreadedTests
59
14
  include Doing::Color
15
+ include ThreadedTestString
60
16
 
61
17
  def run(pattern: '*', max_threads: 8, max_tests: 0)
62
18
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
19
+ @results = File.expand_path('results.log')
63
20
 
64
21
  max_threads = 1000 if max_threads == 0
65
22
 
@@ -90,13 +47,21 @@ class ThreadedTests
90
47
  ].join('')
91
48
  progress = TTY::ProgressBar::Multi.new(banner,
92
49
  width: 12,
50
+ clear: true,
93
51
  hide_cursor: true)
94
52
  @children = []
95
53
  tests.each do |t|
96
54
  test_name = File.basename(t, '.rb').sub(/doing_(.*?)_test/, '\1')
97
55
  new_sp = progress.register("[#{':bar'.cyan}] #{test_name.bold.white}:status",
98
- total: 4, width: 1, head: ' ', unknown: ' ', hide_cursor: true, clear: true)
99
- @children.push([test_name, new_sp, nil])
56
+ total: tests.count + 8,
57
+ width: 1,
58
+ head: ' ',
59
+ unknown: ' ',
60
+ hide_cursor: true,
61
+ clear: true)
62
+ status = ': waiting'.dark.yellow.reset
63
+ @children.push([test_name, new_sp, status])
64
+ # new_sp.advance(status: ': waiting'.dark.yellow.reset)
100
65
  end
101
66
 
102
67
  @elapsed = 0.0
@@ -140,30 +105,36 @@ class ThreadedTests
140
105
  rescue
141
106
  progress.stop
142
107
  end
108
+ ensure
109
+ FileUtils.rm(@results)
143
110
  end
144
111
 
145
112
  def run_test(s)
146
-
147
113
  bar = s[1]
148
- bar.advance(status: ": #{'running'.green}")
114
+ s[2] = ": #{'running'.green}"
115
+ bar.advance(status: s[2])
149
116
 
150
117
  if @running_tests.count.positive?
151
- prev_bar = @running_tests[-1][1]
152
- unless prev_bar.complete?
153
- prev_bar.update(head: ' ', unfinished: ' ')
154
- prev_bar.advance(status: ": #{'running'.green}")
118
+ @running_tests.each do |b|
119
+ prev_bar = b[1]
120
+ if prev_bar.complete?
121
+ prev_bar.reset
122
+ prev_bar.advance(status: b[2])
123
+ prev_bar.finish
124
+ else
125
+ prev_bar.update(head: ' ', unfinished: ' ')
126
+ prev_bar.advance(status: b[2])
127
+ end
155
128
  end
156
129
  end
157
130
 
158
131
  @running_tests.push(s)
159
-
160
-
161
- out, _err, status = Open3.capture3(ENV, 'rake', "test:#{s[0]}", stdin_data: nil)
132
+ out, _err, status = Open3.capture3(ENV, "rake test:#{s[0]} | tee #{@results}", stdin_data: nil)
162
133
  unless status.success?
163
134
  m = out.match(/(?<fail>\d+) failures, (?<err>\d+) errors/)
164
- status = ": #{m['fail'].bold.red} #{'failures'.red}, #{m['err'].bold.red} #{'errors'.red}"
135
+ s[2] = ": #{m['fail'].bold.red} #{'failures'.red}, #{m['err'].bold.red} #{'errors'.red}"
165
136
  bar.update(head: '✖'.boldred)
166
- bar.advance(head: '✖'.boldred, status: status)
137
+ bar.advance(head: '✖'.boldred, status: s[2])
167
138
 
168
139
  # errs = out.scan(/(?:Failure|Error): [\w_]+\((?:.*?)\):(?:.*?)(?=\n=======)/m)
169
140
  @error_out.push(out.highlight_errors)
@@ -175,7 +146,7 @@ class ThreadedTests
175
146
 
176
147
  time = out.match(/^Finished in (?<time>\d+\.\d+) seconds\./)
177
148
  count = out.match(/^(?<tests>\d+) tests, (?<assrt>\d+) assertions, (?<fails>\d+) failures, (?<errs>\d+) errors/)
178
- status = [
149
+ s[2] = [
179
150
  ': ',
180
151
  count['tests'].green,
181
152
  '/',
@@ -190,7 +161,7 @@ class ThreadedTests
190
161
  's'
191
162
  ].join('')
192
163
  bar.update(head: '✔'.boldgreen)
193
- bar.advance(head: '✔'.boldgreen, status: status)
164
+ bar.advance(head: '✔'.boldgreen, status: s[2])
194
165
  @test_total += count['tests'].to_i
195
166
  @assrt_total += count['assrt'].to_i
196
167
  @elapsed += time['time'].to_f
@@ -0,0 +1,50 @@
1
+ module ThreadedTestString
2
+ class ::String
3
+ include Doing::Color
4
+
5
+ def highlight_errors
6
+ cols = `tput cols`.strip.to_i
7
+
8
+ string = dup
9
+
10
+ errs = string.scan(/(?<==\n)(?:Failure|Error):.*?(?=\n=+)/m)
11
+
12
+ errs.map! do |error|
13
+ err = error.dup
14
+
15
+ err.gsub!(%r{^(/.*?/)([^/:]+):(\d+):in (.*?)$}) do
16
+ m = Regexp.last_match
17
+ "#{m[1].white}#{m[2].bold.white}:#{m[3].yellow}:in #{m[4].cyan}"
18
+ end
19
+ err.gsub!(/(Failure|Error): (.*?)\((.*?)\):\n (.*?)(?=\n)/m) do
20
+ m = Regexp.last_match
21
+ [
22
+ m[1].bold.boldbgred.white,
23
+ m[3].bold.boldbgcyan.white,
24
+ m[2].bold.boldbgyellow.black,
25
+ " #{m[4]} ".bold.boldbgwhite.black.reset
26
+ ].join(':'.boldblack.boldbgblack.reset)
27
+ end
28
+ err.gsub!(/(<.*?>) (was expected to) (.*?)\n( *<.*?>)./m) do
29
+ m = Regexp.last_match
30
+ "#{m[1].bold.green} #{m[2].white} #{m[3].boldwhite.boldbgred.reset}\n#{m[4].bold.white}"
31
+ end
32
+ err.gsub!(/(Finished in) ([\d.]+) (seconds)/) do
33
+ m = Regexp.last_match
34
+ "#{m[1].green} #{m[2].bold.white} #{m[3].green}"
35
+ end
36
+ err.gsub!(/(\d+) (failures)/) do
37
+ m = Regexp.last_match
38
+ "#{m[1].bold.red} #{m[2].red}"
39
+ end
40
+ err.gsub!(/100% passed/) do |m|
41
+ m.bold.green
42
+ end
43
+
44
+ err
45
+ end
46
+
47
+ errs.join("\n#{('=' * cols).blue}\n")
48
+ end
49
+ end
50
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.24
4
+ version: 2.1.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-22 00:00:00.000000000 Z
11
+ date: 2022-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -555,6 +555,7 @@ files:
555
555
  - lib/doing/completion/zsh_completion.rb
556
556
  - lib/doing/configuration.rb
557
557
  - lib/doing/errors.rb
558
+ - lib/doing/good.rb
558
559
  - lib/doing/hash.rb
559
560
  - lib/doing/help_monkey_patch.rb
560
561
  - lib/doing/hooks.rb
@@ -687,6 +688,7 @@ files:
687
688
  - lib/helpers/fzf/test/test_go.rb
688
689
  - lib/helpers/fzf/uninstall
689
690
  - lib/helpers/threaded_tests.rb
691
+ - lib/helpers/threaded_tests_string.rb
690
692
  - lib/templates/doing-dayone-entry.erb
691
693
  - lib/templates/doing-dayone.erb
692
694
  - lib/templates/doing-markdown.erb