doing 2.1.22 → 2.1.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +17 -14
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +323 -111
  6. data/Gemfile.lock +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +2 -1
  9. data/bin/commands/add_section.rb +13 -0
  10. data/bin/commands/again.rb +99 -0
  11. data/bin/commands/archive.rb +96 -0
  12. data/bin/commands/cancel.rb +102 -0
  13. data/bin/commands/changes.rb +42 -0
  14. data/bin/commands/choose.rb +9 -0
  15. data/bin/commands/colors.rb +19 -0
  16. data/bin/commands/commands.rb +87 -0
  17. data/bin/commands/commands_accepting.rb +25 -0
  18. data/bin/commands/completion.rb +24 -0
  19. data/bin/commands/config.rb +245 -0
  20. data/bin/commands/done.rb +249 -0
  21. data/bin/commands/finish.rb +149 -0
  22. data/bin/commands/flag.rb +126 -0
  23. data/bin/commands/grep.rb +124 -0
  24. data/bin/commands/import.rb +101 -0
  25. data/bin/commands/install_fzf.rb +17 -0
  26. data/bin/commands/last.rb +114 -0
  27. data/bin/commands/meanwhile.rb +86 -0
  28. data/bin/commands/note.rb +130 -0
  29. data/bin/commands/now.rb +151 -0
  30. data/bin/commands/on.rb +66 -0
  31. data/bin/commands/open.rb +53 -0
  32. data/bin/commands/plugins.rb +23 -0
  33. data/bin/commands/recent.rb +78 -0
  34. data/bin/commands/redo.rb +22 -0
  35. data/bin/commands/reset.rb +106 -0
  36. data/bin/commands/rotate.rb +73 -0
  37. data/bin/commands/sections.rb +11 -0
  38. data/bin/commands/select.rb +123 -0
  39. data/bin/commands/show.rb +231 -0
  40. data/bin/commands/since.rb +64 -0
  41. data/bin/commands/tag.rb +179 -0
  42. data/bin/commands/tag_dir.rb +29 -0
  43. data/bin/commands/tags.rb +93 -0
  44. data/bin/commands/template.rb +61 -0
  45. data/bin/commands/today.rb +65 -0
  46. data/bin/commands/undo.rb +49 -0
  47. data/bin/commands/view.rb +238 -0
  48. data/bin/commands/views.rb +11 -0
  49. data/bin/commands/yesterday.rb +73 -0
  50. data/bin/doing +54 -3505
  51. data/docs/doc/Array.html +79 -11
  52. data/docs/doc/BooleanTermParser/Clause.html +5 -5
  53. data/docs/doc/BooleanTermParser/Operator.html +4 -4
  54. data/docs/doc/BooleanTermParser/Query.html +8 -8
  55. data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
  56. data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
  57. data/docs/doc/BooleanTermParser.html +1 -1
  58. data/docs/doc/Doing/Color.html +4 -4
  59. data/docs/doc/Doing/Completion.html +2 -2
  60. data/docs/doc/Doing/Configuration.html +17 -18
  61. data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
  62. data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
  63. data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
  64. data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
  65. data/docs/doc/Doing/Errors/NoResults.html +2 -2
  66. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  67. data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
  68. data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
  69. data/docs/doc/Doing/Errors.html +1 -1
  70. data/docs/doc/Doing/Hooks.html +6 -6
  71. data/docs/doc/Doing/Item.html +50 -16
  72. data/docs/doc/Doing/Items.html +10 -10
  73. data/docs/doc/Doing/LogAdapter.html +24 -24
  74. data/docs/doc/Doing/Note.html +7 -7
  75. data/docs/doc/Doing/Pager.html +4 -4
  76. data/docs/doc/Doing/Plugins.html +7 -7
  77. data/docs/doc/Doing/Prompt.html +59 -14
  78. data/docs/doc/Doing/Section.html +6 -6
  79. data/docs/doc/Doing/TemplateString.html +8 -8
  80. data/docs/doc/Doing/Types.html +206 -0
  81. data/docs/doc/Doing/Util/Backup.html +10 -10
  82. data/docs/doc/Doing/Util.html +16 -19
  83. data/docs/doc/Doing/WWID.html +65 -53
  84. data/docs/doc/Doing.html +3 -3
  85. data/docs/doc/FalseClass.html +201 -0
  86. data/docs/doc/GLI/Commands/Help.html +185 -0
  87. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  88. data/docs/doc/GLI/Commands.html +5 -3
  89. data/docs/doc/GLI.html +4 -2
  90. data/docs/doc/Hash.html +47 -21
  91. data/docs/doc/Numeric.html +5 -5
  92. data/docs/doc/Object.html +203 -0
  93. data/docs/doc/PhraseParser/Operator.html +4 -4
  94. data/docs/doc/PhraseParser/PhraseClause.html +5 -5
  95. data/docs/doc/PhraseParser/Query.html +10 -10
  96. data/docs/doc/PhraseParser/QueryParser.html +2 -2
  97. data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
  98. data/docs/doc/PhraseParser/TermClause.html +5 -5
  99. data/docs/doc/PhraseParser.html +1 -1
  100. data/docs/doc/Status.html +7 -7
  101. data/docs/doc/String.html +144 -51
  102. data/docs/doc/Symbol.html +8 -8
  103. data/docs/doc/Time.html +6 -6
  104. data/docs/doc/TrueClass.html +201 -0
  105. data/docs/doc/_index.html +46 -16
  106. data/docs/doc/class_list.html +1 -1
  107. data/docs/doc/file.README.html +2 -2
  108. data/docs/doc/index.html +2 -2
  109. data/docs/doc/method_list.html +292 -212
  110. data/docs/doc/top-level-namespace.html +2 -2
  111. data/docs/index.md +1 -1
  112. data/doing.rdoc +178 -16
  113. data/example_plugin.rb +2 -2
  114. data/lib/completion/_doing.zsh +27 -27
  115. data/lib/completion/doing.bash +31 -20
  116. data/lib/completion/doing.fish +33 -11
  117. data/lib/doing/array.rb +2 -2
  118. data/lib/doing/changelog/change.rb +115 -0
  119. data/lib/doing/changelog/changes.rb +73 -0
  120. data/lib/doing/changelog/entry.rb +21 -0
  121. data/lib/doing/changelog/version.rb +97 -0
  122. data/lib/doing/changelog.rb +6 -0
  123. data/lib/doing/completion/fish_completion.rb +2 -1
  124. data/lib/doing/configuration.rb +20 -13
  125. data/lib/doing/good.rb +64 -0
  126. data/lib/doing/hash.rb +7 -2
  127. data/lib/doing/help_monkey_patch.rb +31 -0
  128. data/lib/doing/hooks.rb +8 -4
  129. data/lib/doing/item.rb +24 -35
  130. data/lib/doing/pager.rb +1 -0
  131. data/lib/doing/plugins/export/template_export.rb +1 -1
  132. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  133. data/lib/doing/plugins/import/doing_import.rb +1 -1
  134. data/lib/doing/plugins/import/timing_import.rb +1 -1
  135. data/lib/doing/prompt.rb +8 -0
  136. data/lib/doing/string.rb +20 -11
  137. data/lib/doing/string_chronify.rb +1 -1
  138. data/lib/doing/template_string.rb +2 -2
  139. data/lib/doing/types.rb +3 -0
  140. data/lib/doing/util.rb +12 -11
  141. data/lib/doing/version.rb +1 -1
  142. data/lib/doing/wwid.rb +62 -37
  143. data/lib/doing.rb +2 -0
  144. data/lib/examples/commands/wiki.rb +6 -7
  145. data/lib/helpers/threaded_tests.rb +61 -71
  146. data/lib/helpers/threaded_tests_string.rb +50 -0
  147. metadata +56 -2
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # A single version's entries
5
+ class Change
6
+ attr_reader :version, :content
7
+
8
+ attr_accessor :entries
9
+
10
+ def initialize(version, content)
11
+ @version = Version.new(version)
12
+ @content = content
13
+ parse_entries
14
+ end
15
+
16
+ def parse_entries
17
+ @entries = []
18
+ types = @content.scan(/(?<=\n|\A)#### (NEW|IMPROVED|FIXED)(.*?)(?=\n####|\Z)/m)
19
+ types.each do |type|
20
+ type[1].scan(/\s*- +(.*?)$/).each do |entry|
21
+ @entries << Entry.new(entry[0].strip, type[0])
22
+ end
23
+ end
24
+ end
25
+
26
+ def search_entries(search_string)
27
+ case_type = :ignore
28
+
29
+ matches = []
30
+
31
+ if search_string.is_rx?
32
+ matches = @entries.select { |e| e.string =~ search_string.to_rx(distance: 2, case_type: case_type) }
33
+ else
34
+ query = search_string.gsub(/(-)?--/, '\1]]').to_phrase_query
35
+
36
+ if query[:must].nil? && query[:must_not].nil?
37
+ query[:must] = query[:should]
38
+ query[:should] = []
39
+ end
40
+
41
+ @entries.each do |entry|
42
+ m = no_searches?(entry.string, query[:must_not])
43
+ m &&= all_searches?(entry.string, query[:must])
44
+ m &&= any_searches?(entry.string, query[:should])
45
+ matches << entry if m
46
+ end
47
+ end
48
+
49
+ @entries = matches.count.positive? ? matches : nil
50
+ end
51
+
52
+ def to_h
53
+ { version: @version, content: @content }
54
+ end
55
+
56
+ def to_s
57
+ out = ["### #{@version}"]
58
+ items = {
59
+ new: [],
60
+ improved: [],
61
+ fixed: [],
62
+ other: []
63
+ }
64
+ @entries.each do |e|
65
+ type = e.type.downcase.to_sym
66
+ if items.key?(type)
67
+ items[type] << e
68
+ else
69
+ items[:other] << e
70
+ end
71
+ end
72
+
73
+ items.each do |type, members|
74
+ if members.count.positive?
75
+ out << "#### #{type.to_s.capitalize}"
76
+ out << members.map(&:to_s).join("\n")
77
+ end
78
+ end
79
+
80
+ out.join("\n\n")
81
+ end
82
+
83
+ private
84
+
85
+ def all_searches?(text, searches)
86
+ return true if searches.nil? || searches.empty?
87
+
88
+ searches.each do |s|
89
+ rx = Regexp.new(s.wildcard_to_rx, true)
90
+ return false unless text =~ rx
91
+ end
92
+ true
93
+ end
94
+
95
+ def no_searches?(text, searches)
96
+ return true if searches.nil? || searches.empty?
97
+
98
+ searches.each do |s|
99
+ rx = Regexp.new(s.wildcard_to_rx, true)
100
+ return false if text =~ rx
101
+ end
102
+ true
103
+ end
104
+
105
+ def any_searches?(text, searches)
106
+ return true if searches.nil? || searches.empty?
107
+
108
+ searches.each do |s|
109
+ rx = Regexp.new(s.wildcard_to_rx, true)
110
+ return true if text =~ rx
111
+ end
112
+ false
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # A collection of Changes
5
+ class Changes
6
+ attr_reader :changes
7
+
8
+ def initialize(lookup: nil, search: nil)
9
+ changelog = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'CHANGELOG.md'))
10
+ raise 'Error locating changelog' unless File.exist?(changelog)
11
+
12
+ @content = IO.read(changelog)
13
+ parse_changes(lookup, search)
14
+ end
15
+
16
+ def latest
17
+ @changes[0].to_s.force_encoding('utf-8')
18
+ end
19
+
20
+ def to_s
21
+ @changes.map(&:to_s).join("\n\n").force_encoding('utf-8')
22
+ end
23
+
24
+ private
25
+
26
+ def parse_changes(lookup, search)
27
+ change_rx = /(?<=\n|\A)### (\d+\.\d+\.\d+(?:\w*))(.*?)(?=\n### |\Z)/m
28
+ @changes = @content.scan(change_rx).each_with_object([]) do |m, a|
29
+ next if m[0].nil? || m[1].nil?
30
+
31
+ a << Change.new(m[0], m[1].strip)
32
+ end
33
+
34
+ lookup(lookup) unless lookup.nil?
35
+ search(search) unless search.nil?
36
+ end
37
+
38
+ def lookup(lookup_version)
39
+ range = []
40
+
41
+ if lookup_version =~ /([\d.]+) *-+ *([\d.]+)/
42
+ m = Regexp.last_match
43
+ lookup("> #{m[1]}")
44
+ lookup("< #{m[2]}")
45
+ elsif lookup_version.scan(/[<>]/).count > 1
46
+ params = lookup_version.scan(/[<>] [\d.]+/)
47
+ params.each { |query| lookup(query) }
48
+ else
49
+ comp = case lookup_version
50
+ when /(<|prior|before|older)/
51
+ :older
52
+ when />|since|after|newer/
53
+ :newer
54
+ else
55
+ :equal
56
+ end
57
+ version = Version.new(lookup_version)
58
+
59
+ @changes.select! do |change|
60
+ change.version.compare(version, comp)
61
+ end
62
+ end
63
+ end
64
+
65
+ def search(query)
66
+ @changes.map do |c|
67
+ c.entries = c.search_entries(query)
68
+ end
69
+
70
+ @changes.delete_if { |c| c.nil? || c.entries.nil? }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # An individual changelog item
5
+ class Entry
6
+ attr_reader :type, :string
7
+
8
+ def initialize(string, type)
9
+ @string = string
10
+ @type = type
11
+ end
12
+
13
+ def clean(string)
14
+ string.gsub(/\|/, '\|')
15
+ end
16
+
17
+ def to_s
18
+ "- #{clean(@string)}"
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # Semantic versioning
5
+ class Version
6
+ attr_reader :maj, :min, :patch
7
+
8
+ def initialize(string)
9
+ @maj, @min, @patch = version_to_a(string)
10
+ end
11
+
12
+ def version_to_a(string)
13
+ raise 'Version not a string' unless string.is_a?(String)
14
+
15
+ v = string.match(/(?<maj>\d+)(?:\.(?<min>[\d*?]+))?(?:\.(?<patch>[\d*?]+))?/)
16
+
17
+ raise 'Error parsing semantic version string' if v.nil?
18
+
19
+ maj = v['maj'].to_i
20
+ min = case v['min']
21
+ when /[*?]/
22
+ v['min'].sub(/(\d+)?[^\d]/, '\1\d+')
23
+ when /^[0-9]+$/
24
+ v['min'].to_i
25
+ end
26
+ pat = case v['patch']
27
+ when /[*?]/
28
+ v['patch'].sub(/(\d+)?[^\d]/, '\1\d+')
29
+ when /^[0-9]+$/
30
+ v['patch'].to_i
31
+ end
32
+ [maj, min, pat]
33
+ end
34
+
35
+ def wild?(val)
36
+ val.is_a?(String)
37
+ end
38
+
39
+
40
+ def compare(other, comp)
41
+ case comp
42
+ when :older
43
+ if @maj <= other.maj
44
+ if @maj < other.maj
45
+ true
46
+ elsif @maj == other.maj && (other.min.nil? || @min < other.min)
47
+ true
48
+ elsif @maj == other.maj && @min == other.min
49
+ other.patch.nil? ? false : @patch < other.patch
50
+ else
51
+ false
52
+ end
53
+ else
54
+ false
55
+ end
56
+ when :newer
57
+ if @maj >= other.maj
58
+ if @maj > other.maj
59
+ true
60
+ elsif @maj == other.maj && (other.min.nil? || @min > other.min)
61
+ true
62
+ elsif @maj == other.maj && @min == other.min
63
+ other.patch.nil? || @patch >= other.patch
64
+ else
65
+ false
66
+ end
67
+ else
68
+ false
69
+ end
70
+ when :equal
71
+ if @maj == other.maj
72
+ if other.min.nil?
73
+ true
74
+ elsif wild?(other.min)
75
+ @min.to_s =~ /^#{other.min}/ ? true : false
76
+ else
77
+ if @min == other.min
78
+ if other.patch.nil?
79
+ true
80
+ elsif wild?(other.patch)
81
+ @patch.to_s =~ /^#{other.patch}/ ? true : false
82
+ else
83
+ @patch == other.patch
84
+ end
85
+ else
86
+ false
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ def to_s
94
+ "#{@maj}.#{@min || 0}.#{@patch || 0}"
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'changelog/version'
4
+ require_relative 'changelog/entry'
5
+ require_relative 'changelog/change'
6
+ require_relative 'changelog/changes'
@@ -123,8 +123,9 @@ module Doing
123
123
  complete -f -c doing -n '__fish_doing_using_command view' -a '(__fish_doing_complete_views)'
124
124
  complete -f -c doing -n '__fish_doing_using_command template' -a '(__fish_doing_complete_templates)'
125
125
  complete -f -c doing -s t -l type -x -n '__fish_doing_using_command import' -a '(__fish_doing_import_plugins)'
126
+ complete -f -c doing -n '__fish_doing_using_command help' -a '(__fish_doing_subcommands)'
126
127
 
127
- complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
128
+ # complete -xc doing -n '__fish_seen_subcommand_from help; and not __fish_seen_subcommand_from (doing help -c)' -a "(doing help -c)"
128
129
 
129
130
  function __fish_doing_complete_args
130
131
  for cmd in (doing commands_accepting -c $argv[1])
@@ -29,6 +29,7 @@ module Doing
29
29
  'plugin_path' => File.join(Util.user_home, '.config', 'doing', 'plugins'),
30
30
  'command_path' => File.join(Util.user_home, '.config', 'doing', 'commands')
31
31
  },
32
+ 'disabled_commands' => [],
32
33
  'doing_file' => '~/.local/share/doing/what_was_i_doing.md',
33
34
  'doing_file_sort' => 'desc',
34
35
  'backup_dir' => '~/.local/share/doing/doing_backup',
@@ -45,8 +46,7 @@ module Doing
45
46
  'templates' => {
46
47
  'default' => {
47
48
  'date_format' => '%Y-%m-%d %H:%M',
48
- 'template' => '%reset%cyan%shortdate %boldwhite%80║ title %dark%boldmagenta[%boldwhite%-10section%boldmagenta]%reset
49
- %yellow%interval%boldred%duration%dark%white%80_14┃ note',
49
+ 'template' => '%reset%cyan%shortdate %boldwhite%80║ title %boldmagenta[%boldwhite%-10section%boldmagenta]%reset %yellow%interval%boldred%duration%white%80_14┃ note',
50
50
  'wrap_width' => 0,
51
51
  'order' => 'asc'
52
52
  },
@@ -63,8 +63,7 @@ module Doing
63
63
  },
64
64
  'recent' => {
65
65
  'date_format' => '%_I:%M%P',
66
- 'template' => '%reset%cyan%shortdate %boldwhite%80║ title %dark%boldmagenta[%boldwhite%-10section%boldmagenta]%reset
67
- %yellow%interval%boldred%duration%dark%white%80_14┃ note',
66
+ 'template' => '%reset%cyan%shortdate %boldwhite%80║ title %boldmagenta[%boldwhite%-10section%boldmagenta]%reset %yellow%interval%boldred%duration%white%80_14┃ note',
68
67
  'wrap_width' => 88,
69
68
  'count' => 10,
70
69
  'order' => 'asc'
@@ -190,7 +189,7 @@ module Doing
190
189
  ## matched, first match wins)
191
190
  ## @return [Array] ordered array of resolved keys
192
191
  ##
193
- def resolve_key_path(keypath, create: false)
192
+ def resolve_key_path(keypath, create: false, distance: 2)
194
193
  cfg = @settings
195
194
  real_path = []
196
195
  unless keypath =~ /^[.*]?$/
@@ -198,16 +197,24 @@ module Doing
198
197
  while paths.length.positive? && !cfg.nil?
199
198
  path = paths.shift
200
199
  new_cfg = nil
201
- cfg.each do |key, val|
202
- next unless key =~ path.to_rx(distance: 4)
203
200
 
204
- real_path << key
205
- new_cfg = val
206
- break
201
+ if cfg.is_a?(Hash)
202
+ matches = cfg.select { |key, val| key =~ path.to_rx(distance: distance) }
203
+ if matches.count.positive?
204
+ shortest = matches.keys.group_by(&:length).min.last[0]
205
+ real_path << shortest
206
+ new_cfg = matches[shortest]
207
+ end
208
+ else
209
+ new_cfg = cfg
207
210
  end
208
211
 
209
212
  if new_cfg.nil?
210
- return nil unless create
213
+ if distance < 5 && !create
214
+ return resolve_key_path(keypath, create: false, distance: distance + 1)
215
+ else
216
+ return nil unless create
217
+ end
211
218
 
212
219
  resolved = real_path.count.positive? ? "Resolved #{real_path.join('->')}, but " : ''
213
220
  Doing.logger.log_now(:warn, "#{resolved}#{path} is unknown")
@@ -306,7 +313,7 @@ module Doing
306
313
 
307
314
  @ignore_local = opt[:ignore_local] if opt[:ignore_local]
308
315
 
309
- config = read_config.dup
316
+ config = read_config.clone
310
317
 
311
318
  plugin_config = Util.deep_merge_hashes(DEFAULTS['plugins'], config['plugins'] || {})
312
319
 
@@ -314,7 +321,7 @@ module Doing
314
321
 
315
322
  Plugins.plugins.each do |_type, plugins|
316
323
  plugins.each do |title, plugin|
317
- plugin_config[title] = plugin[:config] if plugin[:config] && !plugin[:config].empty?
324
+ plugin_config[title] = plugin[:config] if plugin[:config].good?
318
325
  config['export_templates'][title] ||= nil if plugin[:templates] && !plugin[:templates].empty?
319
326
  end
320
327
  end
data/lib/doing/good.rb ADDED
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Doing
4
+ # Object helpers
5
+ class ::Object
6
+ ##
7
+ ## Tests if object is nil or empty
8
+ ##
9
+ ## @return [Boolean] true if object is defined and
10
+ ## has content
11
+ ##
12
+ def good?
13
+ !nil? && !empty?
14
+ end
15
+ end
16
+
17
+ class ::String
18
+ ##
19
+ ## Tests if object is nil or empty
20
+ ##
21
+ ## @return [Boolean] true if object is defined and
22
+ ## has content
23
+ ##
24
+ def good?
25
+ !strip.empty?
26
+ end
27
+ end
28
+
29
+ class ::Array
30
+ ##
31
+ ## Tests if object is nil or empty
32
+ ##
33
+ ## @return [Boolean] true if object is defined and
34
+ ## has content
35
+ ##
36
+ def good?
37
+ !nil? && !empty?
38
+ end
39
+ end
40
+
41
+ class ::FalseClass
42
+ ##
43
+ ## Tests if object is nil or empty
44
+ ##
45
+ ## @return [Boolean] true if object is defined and
46
+ ## has content
47
+ ##
48
+ def good?
49
+ false
50
+ end
51
+ end
52
+
53
+ class ::TrueClass
54
+ ##
55
+ ## Tests if object is nil or empty
56
+ ##
57
+ ## @return [Boolean] true if object is defined and
58
+ ## has content
59
+ ##
60
+ def good?
61
+ true
62
+ end
63
+ end
64
+ end
data/lib/doing/hash.rb CHANGED
@@ -34,6 +34,10 @@ module Doing
34
34
  replace deep_thaw
35
35
  end
36
36
 
37
+ def clone
38
+ Marshal.load(Marshal.dump(self))
39
+ end
40
+
37
41
  # Turn all keys into string
38
42
  #
39
43
  # Return a copy of the hash where all its keys are strings
@@ -48,8 +52,9 @@ module Doing
48
52
 
49
53
  # Set a nested hash value using an array
50
54
  #
51
- # @example `{}.deep_set(['one', 'two'], 'value')`
52
- # @example `=> { 'one' => { 'two' => 'value' } }
55
+ # @example
56
+ # {}.deep_set(['one', 'two'], 'value')
57
+ # # => { 'one' => { 'two' => 'value' } }
53
58
  #
54
59
  # @param path [Array] key path
55
60
  # @param value The value
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GLI
4
+ module Commands
5
+ # Help Command Monkeypatch for paginated output
6
+ class Help < Command
7
+ def show_help(global_options,options,arguments,out,error)
8
+ Doing::Pager.paginate = true
9
+
10
+ command_finder = HelpModules::CommandFinder.new(@app,arguments,error)
11
+ if options[:c]
12
+ help_output = HelpModules::HelpCompletionFormat.new(@app,command_finder,arguments).format
13
+ out.puts help_output unless help_output.nil?
14
+ elsif arguments.empty? || options[:c]
15
+ Doing::Pager.page HelpModules::GlobalHelpFormat.new(@app,@sorter,@text_wrapping_class).format
16
+ else
17
+ name = arguments.shift
18
+ command = command_finder.find_command(name)
19
+ unless command.nil?
20
+ Doing::Pager.page HelpModules::CommandHelpFormat.new(
21
+ command,
22
+ @app,
23
+ @sorter,
24
+ @synopsis_formatter_class,
25
+ @text_wrapping_class).format
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/doing/hooks.rb CHANGED
@@ -10,8 +10,8 @@ module Doing
10
10
  post_local_config: [], # wwid
11
11
  post_read: [], # wwid
12
12
  pre_entry_add: [], # wwid, new_entry
13
- post_entry_added: [], # wwid, new_entry.dup
14
- post_entry_updated: [], # wwid, entry
13
+ post_entry_added: [], # wwid, new_entry
14
+ post_entry_updated: [], # wwid, entry, old_entry
15
15
  post_entry_removed: [], # wwid, entry.dup
16
16
  pre_export: [], # wwid, format, entries
17
17
  pre_write: [], # wwid, file
@@ -23,7 +23,11 @@ module Doing
23
23
 
24
24
  # register hook(s) to be called later, public API
25
25
  def self.register(event, priority: DEFAULT_PRIORITY, &block)
26
- register_one(event, priority_value(priority), &block)
26
+ if event.is_a?(Array)
27
+ event.each { |ev| register_one(ev, priority_value(priority), &block) }
28
+ else
29
+ register_one(event, priority_value(priority), &block)
30
+ end
27
31
  end
28
32
 
29
33
  # Ensure the priority is a Fixnum
@@ -53,7 +57,7 @@ module Doing
53
57
 
54
58
  def self.trigger(event, *args)
55
59
  hooks = @registry[event]
56
- return if hooks.nil? || hooks.empty?
60
+ return unless hooks.good?
57
61
 
58
62
  # sort and call hooks according to priority and load order
59
63
  hooks.sort_by { |h| @hook_priority[h] }.each do |hook|