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.
- checksums.yaml +4 -4
- data/.yardoc/checksums +19 -16
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/CHANGELOG.md +51 -13
- data/Gemfile.lock +1 -1
- data/README.md +1 -1
- data/Rakefile +6 -3
- data/bin/doing +254 -103
- data/docs/doc/Array.html +74 -34
- data/docs/doc/BooleanTermParser/Clause.html +5 -5
- data/docs/doc/BooleanTermParser/Operator.html +4 -4
- data/docs/doc/BooleanTermParser/Query.html +8 -8
- data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
- data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
- data/docs/doc/BooleanTermParser.html +1 -1
- data/docs/doc/Doing/Color.html +4 -4
- data/docs/doc/Doing/Completion.html +2 -2
- data/docs/doc/Doing/Configuration.html +16 -18
- data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
- data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
- data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
- data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
- data/docs/doc/Doing/Errors/NoResults.html +2 -2
- data/docs/doc/Doing/Errors/PluginException.html +3 -3
- data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
- data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
- data/docs/doc/Doing/Errors.html +1 -1
- data/docs/doc/Doing/Hooks.html +6 -6
- data/docs/doc/Doing/Item.html +50 -16
- data/docs/doc/Doing/Items.html +10 -10
- data/docs/doc/Doing/LogAdapter.html +24 -24
- data/docs/doc/Doing/Note.html +7 -7
- data/docs/doc/Doing/Pager.html +4 -4
- data/docs/doc/Doing/Plugins.html +7 -7
- data/docs/doc/Doing/Prompt.html +16 -16
- data/docs/doc/Doing/Section.html +6 -6
- data/docs/doc/Doing/TemplateString.html +8 -8
- data/docs/doc/Doing/Types.html +206 -0
- data/docs/doc/Doing/Util/Backup.html +10 -10
- data/docs/doc/Doing/Util.html +16 -19
- data/docs/doc/Doing/WWID.html +65 -53
- data/docs/doc/Doing.html +4 -4
- data/docs/doc/GLI/Commands/Help.html +185 -0
- data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
- data/docs/doc/GLI/Commands.html +5 -3
- data/docs/doc/GLI.html +4 -2
- data/docs/doc/Hash.html +119 -21
- data/docs/doc/Numeric.html +5 -5
- data/docs/doc/PhraseParser/Operator.html +4 -4
- data/docs/doc/PhraseParser/PhraseClause.html +5 -5
- data/docs/doc/PhraseParser/Query.html +10 -10
- data/docs/doc/PhraseParser/QueryParser.html +2 -2
- data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
- data/docs/doc/PhraseParser/TermClause.html +5 -5
- data/docs/doc/PhraseParser.html +1 -1
- data/docs/doc/Status.html +7 -7
- data/docs/doc/String.html +206 -51
- data/docs/doc/Symbol.html +8 -8
- data/docs/doc/Time.html +6 -6
- data/docs/doc/_index.html +51 -14
- data/docs/doc/class_list.html +1 -1
- data/docs/doc/file.README.html +2 -2
- data/docs/doc/index.html +2 -2
- data/docs/doc/method_list.html +348 -252
- data/docs/doc/top-level-namespace.html +2 -93
- data/docs/index.md +1 -1
- data/doing.rdoc +177 -20
- data/example_plugin.rb +2 -2
- data/lib/completion/_doing.zsh +24 -24
- data/lib/completion/doing.bash +31 -20
- data/lib/completion/doing.fish +32 -10
- data/lib/doing/array.rb +5 -4
- data/lib/doing/array_chronify.rb +4 -3
- data/lib/doing/changelog/change.rb +115 -0
- data/lib/doing/changelog/changes.rb +73 -0
- data/lib/doing/changelog/entry.rb +21 -0
- data/lib/doing/changelog/version.rb +97 -0
- data/lib/doing/changelog.rb +6 -0
- data/lib/doing/completion/fish_completion.rb +2 -1
- data/lib/doing/configuration.rb +20 -14
- data/lib/doing/good.rb +64 -0
- data/lib/doing/hash.rb +28 -5
- data/lib/doing/help_monkey_patch.rb +31 -0
- data/lib/doing/hooks.rb +8 -4
- data/lib/doing/item.rb +24 -35
- data/lib/doing/log_adapter.rb +1 -1
- data/lib/doing/pager.rb +1 -1
- data/lib/doing/plugins/export/template_export.rb +9 -3
- data/lib/doing/plugins/import/calendar_import.rb +1 -1
- data/lib/doing/plugins/import/doing_import.rb +1 -1
- data/lib/doing/plugins/import/timing_import.rb +1 -1
- data/lib/doing/prompt.rb +4 -2
- data/lib/doing/string.rb +30 -12
- data/lib/doing/string_chronify.rb +1 -1
- data/lib/doing/template_string.rb +9 -2
- data/lib/doing/types.rb +23 -16
- data/lib/doing/util.rb +12 -11
- data/lib/doing/version.rb +1 -1
- data/lib/doing/wwid.rb +65 -46
- data/lib/doing.rb +3 -0
- data/lib/helpers/threaded_tests.rb +106 -99
- data/lib/helpers/threaded_tests_string.rb +50 -0
- metadata +12 -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
|
|
@@ -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])
|
data/lib/doing/configuration.rb
CHANGED
|
@@ -45,8 +45,7 @@ module Doing
|
|
|
45
45
|
'templates' => {
|
|
46
46
|
'default' => {
|
|
47
47
|
'date_format' => '%Y-%m-%d %H:%M',
|
|
48
|
-
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %
|
|
49
|
-
%yellow%interval%boldred%duration%dark%white%80_14┃ note',
|
|
48
|
+
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %boldmagenta[%boldwhite%-10section%boldmagenta]%reset %yellow%interval%boldred%duration%white%80_14┃ note',
|
|
50
49
|
'wrap_width' => 0,
|
|
51
50
|
'order' => 'asc'
|
|
52
51
|
},
|
|
@@ -63,8 +62,7 @@ module Doing
|
|
|
63
62
|
},
|
|
64
63
|
'recent' => {
|
|
65
64
|
'date_format' => '%_I:%M%P',
|
|
66
|
-
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %
|
|
67
|
-
%yellow%interval%boldred%duration%dark%white%80_14┃ note',
|
|
65
|
+
'template' => '%reset%cyan%shortdate %boldwhite%80║ title %boldmagenta[%boldwhite%-10section%boldmagenta]%reset %yellow%interval%boldred%duration%white%80_14┃ note',
|
|
68
66
|
'wrap_width' => 88,
|
|
69
67
|
'count' => 10,
|
|
70
68
|
'order' => 'asc'
|
|
@@ -160,7 +158,7 @@ module Doing
|
|
|
160
158
|
def choose_config(create: false)
|
|
161
159
|
return @config_file if @force_answer
|
|
162
160
|
|
|
163
|
-
if @additional_configs
|
|
161
|
+
if @additional_configs&.count&.positive? || create
|
|
164
162
|
choices = [@config_file].concat(@additional_configs)
|
|
165
163
|
choices.push('Create a new .doingrc in the current directory') if create && !File.exist?('.doingrc')
|
|
166
164
|
res = Doing::Prompt.choose_from(choices.uniq.sort.reverse,
|
|
@@ -190,7 +188,7 @@ module Doing
|
|
|
190
188
|
## matched, first match wins)
|
|
191
189
|
## @return [Array] ordered array of resolved keys
|
|
192
190
|
##
|
|
193
|
-
def resolve_key_path(keypath, create: false)
|
|
191
|
+
def resolve_key_path(keypath, create: false, distance: 2)
|
|
194
192
|
cfg = @settings
|
|
195
193
|
real_path = []
|
|
196
194
|
unless keypath =~ /^[.*]?$/
|
|
@@ -198,16 +196,24 @@ module Doing
|
|
|
198
196
|
while paths.length.positive? && !cfg.nil?
|
|
199
197
|
path = paths.shift
|
|
200
198
|
new_cfg = nil
|
|
201
|
-
cfg.each do |key, val|
|
|
202
|
-
next unless key =~ path.to_rx(distance: 4)
|
|
203
199
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
200
|
+
if cfg.is_a?(Hash)
|
|
201
|
+
matches = cfg.select { |key, val| key =~ path.to_rx(distance: distance) }
|
|
202
|
+
if matches.count.positive?
|
|
203
|
+
shortest = matches.keys.group_by(&:length).min.last[0]
|
|
204
|
+
real_path << shortest
|
|
205
|
+
new_cfg = matches[shortest]
|
|
206
|
+
end
|
|
207
|
+
else
|
|
208
|
+
new_cfg = cfg
|
|
207
209
|
end
|
|
208
210
|
|
|
209
211
|
if new_cfg.nil?
|
|
210
|
-
|
|
212
|
+
if distance < 5 && !create
|
|
213
|
+
return resolve_key_path(keypath, create: false, distance: distance + 1)
|
|
214
|
+
else
|
|
215
|
+
return nil unless create
|
|
216
|
+
end
|
|
211
217
|
|
|
212
218
|
resolved = real_path.count.positive? ? "Resolved #{real_path.join('->')}, but " : ''
|
|
213
219
|
Doing.logger.log_now(:warn, "#{resolved}#{path} is unknown")
|
|
@@ -306,7 +312,7 @@ module Doing
|
|
|
306
312
|
|
|
307
313
|
@ignore_local = opt[:ignore_local] if opt[:ignore_local]
|
|
308
314
|
|
|
309
|
-
config = read_config.
|
|
315
|
+
config = read_config.clone
|
|
310
316
|
|
|
311
317
|
plugin_config = Util.deep_merge_hashes(DEFAULTS['plugins'], config['plugins'] || {})
|
|
312
318
|
|
|
@@ -314,7 +320,7 @@ module Doing
|
|
|
314
320
|
|
|
315
321
|
Plugins.plugins.each do |_type, plugins|
|
|
316
322
|
plugins.each do |title, plugin|
|
|
317
|
-
plugin_config[title] = plugin[:config] if plugin[:config]
|
|
323
|
+
plugin_config[title] = plugin[:config] if plugin[:config].good?
|
|
318
324
|
config['export_templates'][title] ||= nil if plugin[:templates] && !plugin[:templates].empty?
|
|
319
325
|
end
|
|
320
326
|
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
|
@@ -6,14 +6,36 @@ module Doing
|
|
|
6
6
|
##
|
|
7
7
|
## Freeze all values in a hash
|
|
8
8
|
##
|
|
9
|
-
## @return
|
|
9
|
+
## @return Hash with all values frozen
|
|
10
10
|
##
|
|
11
11
|
def deep_freeze
|
|
12
|
-
|
|
12
|
+
chilled = {}
|
|
13
|
+
each do |k, v|
|
|
14
|
+
chilled[k] = v.is_a?(Hash) ? v.deep_freeze : v.freeze
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
chilled.freeze
|
|
13
18
|
end
|
|
14
19
|
|
|
15
20
|
def deep_freeze!
|
|
16
|
-
replace deep_freeze
|
|
21
|
+
replace deep_thaw.deep_freeze
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def deep_thaw
|
|
25
|
+
chilled = {}
|
|
26
|
+
each do |k, v|
|
|
27
|
+
chilled[k] = v.is_a?(Hash) ? v.deep_thaw : v.dup
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
chilled.dup
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def deep_thaw!
|
|
34
|
+
replace deep_thaw
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def clone
|
|
38
|
+
Marshal.load(Marshal.dump(self))
|
|
17
39
|
end
|
|
18
40
|
|
|
19
41
|
# Turn all keys into string
|
|
@@ -30,8 +52,9 @@ module Doing
|
|
|
30
52
|
|
|
31
53
|
# Set a nested hash value using an array
|
|
32
54
|
#
|
|
33
|
-
# @example
|
|
34
|
-
#
|
|
55
|
+
# @example
|
|
56
|
+
# {}.deep_set(['one', 'two'], 'value')
|
|
57
|
+
# # => { 'one' => { 'two' => 'value' } }
|
|
35
58
|
#
|
|
36
59
|
# @param path [Array] key path
|
|
37
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
|
|
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
|
-
|
|
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
|
|
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|
|