term_utils 0.1.1 → 0.4.0
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/AUTHORS +1 -0
- data/CHANGELOG.md +51 -0
- data/COPYING +674 -0
- data/README.md +99 -0
- data/Rakefile +55 -0
- data/doc/TermUtils.html +138 -0
- data/doc/TermUtils/AP.html +394 -0
- data/doc/TermUtils/AP/Article.html +993 -0
- data/doc/TermUtils/AP/ArticleResult.html +584 -0
- data/doc/TermUtils/AP/Flag.html +756 -0
- data/doc/TermUtils/AP/NoSuchValueError.html +217 -0
- data/doc/TermUtils/AP/Parameter.html +1592 -0
- data/doc/TermUtils/AP/ParameterResult.html +980 -0
- data/doc/TermUtils/AP/ParameterWalkerHooks.html +409 -0
- data/doc/TermUtils/AP/ParseError.html +217 -0
- data/doc/TermUtils/AP/Parser.html +604 -0
- data/doc/TermUtils/AP/Result.html +837 -0
- data/doc/TermUtils/AP/Syntax.html +761 -0
- data/doc/TermUtils/AP/SyntaxError.html +217 -0
- data/doc/TermUtils/AP/Walker.html +686 -0
- data/doc/TermUtils/FF.html +128 -0
- data/doc/TermUtils/FF/Config.html +774 -0
- data/doc/TermUtils/FF/Context.html +585 -0
- data/doc/TermUtils/FF/Entry.html +626 -0
- data/doc/TermUtils/FF/Query.html +1085 -0
- data/doc/TermUtils/PropertyTreeNode.html +2113 -0
- data/doc/TermUtils/Tab.html +1486 -0
- data/doc/TermUtils/Tab/Column.html +1263 -0
- data/doc/TermUtils/Tab/Header.html +536 -0
- data/doc/TermUtils/Tab/Holder.html +1210 -0
- data/doc/TermUtils/Tab/Printer.html +967 -0
- data/doc/TermUtils/Tab/Table.html +1966 -0
- data/doc/TermUtils/Tab/TableError.html +217 -0
- data/doc/_index.html +387 -0
- data/doc/class_list.html +51 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +58 -0
- data/doc/css/style.css +496 -0
- data/doc/file.README.html +170 -0
- data/doc/file_list.html +56 -0
- data/doc/frames.html +17 -0
- data/doc/index.html +170 -0
- data/doc/js/app.js +314 -0
- data/doc/js/full_list.js +216 -0
- data/doc/js/jquery.js +4 -0
- data/doc/method_list.html +1539 -0
- data/doc/top-level-namespace.html +110 -0
- data/lib/term_utils.rb +11 -0
- data/lib/term_utils/ap.rb +70 -0
- data/lib/term_utils/ap/article.rb +74 -0
- data/lib/term_utils/ap/flag.rb +65 -0
- data/lib/term_utils/ap/parameter.rb +144 -0
- data/lib/term_utils/ap/parser.rb +211 -0
- data/lib/term_utils/ap/result.rb +244 -0
- data/lib/term_utils/ap/syntax.rb +96 -0
- data/lib/term_utils/ff.rb +27 -0
- data/lib/term_utils/ff/config.rb +55 -0
- data/lib/term_utils/ff/entry.rb +45 -0
- data/lib/term_utils/ff/query.rb +145 -0
- data/lib/term_utils/property_tree_node.rb +228 -0
- data/lib/term_utils/tab.rb +338 -88
- data/term_utils.gemspec +16 -0
- metadata +69 -7
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020 Thomas Baron
|
4
|
+
#
|
5
|
+
# This file is part of term_utils.
|
6
|
+
#
|
7
|
+
# term_utils is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, version 3 of the License.
|
10
|
+
#
|
11
|
+
# term_utils is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with term_utils. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module TermUtils
|
20
|
+
module AP
|
21
|
+
# Represents the argument list syntax. It holds a list of parameters.
|
22
|
+
class Syntax
|
23
|
+
# @return [Array<Parameter>]
|
24
|
+
attr_accessor :parameters
|
25
|
+
|
26
|
+
# Constructs a new Syntax.
|
27
|
+
def initialize
|
28
|
+
@parameters = []
|
29
|
+
end
|
30
|
+
|
31
|
+
# For dup method.
|
32
|
+
def initialize_dup(other)
|
33
|
+
super(other)
|
34
|
+
@parameters = other.parameters.map(&:dup) if other.parameters
|
35
|
+
end
|
36
|
+
|
37
|
+
# Finalizes this one. Internal use.
|
38
|
+
# @return [nil]
|
39
|
+
# @raise [SyntaxError]
|
40
|
+
def finalize!(opts = {})
|
41
|
+
opts[:anonymous] = 0 unless opts.key? :anonymous
|
42
|
+
opts[:flag_labels] = []
|
43
|
+
@parameters.each { |p| p.finalize!(opts) }
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# Creates and adds a new Parameter.
|
48
|
+
# @param id [Symbol, nil]
|
49
|
+
# @param opts [Hash]
|
50
|
+
# @option opts [Symbol] :id
|
51
|
+
# @option opts [Integer] :min_occurs
|
52
|
+
# @option opts [Integer] :max_occurs
|
53
|
+
# @return [Parameter]
|
54
|
+
def define_parameter(id = nil, opts = {}, &block)
|
55
|
+
if id
|
56
|
+
param = @parameters.find { |p| p.id == id }
|
57
|
+
if param
|
58
|
+
block.call(param) if block
|
59
|
+
return param
|
60
|
+
end
|
61
|
+
|
62
|
+
opts[:id] = id
|
63
|
+
end
|
64
|
+
new_parameter = TermUtils::AP::Parameter.new(opts)
|
65
|
+
@parameters << new_parameter
|
66
|
+
block.call(new_parameter) if block
|
67
|
+
new_parameter
|
68
|
+
end
|
69
|
+
|
70
|
+
# Fetches all flagged parameters and unflagged parameters.
|
71
|
+
# @return [Array]
|
72
|
+
def fetch_parameters
|
73
|
+
unflagged_params = []
|
74
|
+
flagged_params = {}
|
75
|
+
shortcut_flags = {}
|
76
|
+
@parameters.each do |p|
|
77
|
+
if p.flagged?
|
78
|
+
# Flagged
|
79
|
+
p.flags.each do |f|
|
80
|
+
flagged_params[f.label] = p
|
81
|
+
if f.long?
|
82
|
+
shortcut_flags["#{f.label}="] = f
|
83
|
+
else
|
84
|
+
shortcut_flags[f.label] = f
|
85
|
+
end
|
86
|
+
end
|
87
|
+
else
|
88
|
+
# Unflagged
|
89
|
+
unflagged_params << p
|
90
|
+
end
|
91
|
+
end
|
92
|
+
[unflagged_params, flagged_params, shortcut_flags]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020 Thomas Baron
|
4
|
+
#
|
5
|
+
# This file is part of term_utils.
|
6
|
+
#
|
7
|
+
# term_utils is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, version 3 of the License.
|
10
|
+
#
|
11
|
+
# term_utils is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with term_utils. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module TermUtils
|
20
|
+
# Provides a way to find files.
|
21
|
+
module FF
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'term_utils/ff/config'
|
26
|
+
require 'term_utils/ff/entry'
|
27
|
+
require 'term_utils/ff/query'
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020 Thomas Baron
|
4
|
+
#
|
5
|
+
# This file is part of term_utils.
|
6
|
+
#
|
7
|
+
# term_utils is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, version 3 of the License.
|
10
|
+
#
|
11
|
+
# term_utils is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with term_utils. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module TermUtils
|
20
|
+
module FF
|
21
|
+
# Represents a query configuration.
|
22
|
+
class Config
|
23
|
+
# @return [Array<Regexp>]
|
24
|
+
attr_accessor :ignore_list
|
25
|
+
# @return [Integer, nil]
|
26
|
+
attr_accessor :min_depth
|
27
|
+
# @return [Integer, nil]
|
28
|
+
attr_accessor :max_depth
|
29
|
+
# @return [Symbol, nil] Either `:forward`, `:reverse` or `nil` (default).
|
30
|
+
attr_accessor :sorting_mode
|
31
|
+
# @return [Proc, nil]
|
32
|
+
attr_accessor :sorting_compare
|
33
|
+
|
34
|
+
# Constructs a new Config.
|
35
|
+
def initialize
|
36
|
+
@ignore_list = []
|
37
|
+
@min_depth = nil
|
38
|
+
@max_depth = nil
|
39
|
+
@sorting_mode = nil
|
40
|
+
@sorting_compare = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Returns whether the search is ordered.
|
44
|
+
# @return [Boolean]
|
45
|
+
def sorted?
|
46
|
+
(@sorting_mode == :forward) || (@sorting_mode == :reverse)
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize_copy(other)
|
50
|
+
@ignore_list = other.ignore_list.dup
|
51
|
+
super
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020 Thomas Baron
|
4
|
+
#
|
5
|
+
# This file is part of term_utils.
|
6
|
+
#
|
7
|
+
# term_utils is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, version 3 of the License.
|
10
|
+
#
|
11
|
+
# term_utils is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with term_utils. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module TermUtils
|
20
|
+
module FF
|
21
|
+
# Represents an Entry of a Query result.
|
22
|
+
class Entry
|
23
|
+
# @return [Integer]
|
24
|
+
attr_accessor :index
|
25
|
+
# @return [String]
|
26
|
+
attr_accessor :name
|
27
|
+
# @return [Array<String>]
|
28
|
+
attr_accessor :relative_path_comps
|
29
|
+
# @return [String]
|
30
|
+
attr_accessor :path
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@index = nil
|
34
|
+
@name = nil
|
35
|
+
@relative_path_comps = nil
|
36
|
+
@path = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Integer]
|
40
|
+
def depth
|
41
|
+
@relative_path_comps.length
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020 Thomas Baron
|
4
|
+
#
|
5
|
+
# This file is part of term_utils.
|
6
|
+
#
|
7
|
+
# term_utils is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, version 3 of the License.
|
10
|
+
#
|
11
|
+
# term_utils is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with term_utils. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module TermUtils
|
20
|
+
module FF
|
21
|
+
# Query search context.
|
22
|
+
Context = Struct.new('Context', :config, :base_path, :block, :index_seq, :result)
|
23
|
+
# Represents a file system query.
|
24
|
+
class Query
|
25
|
+
# Constructs a new Query.
|
26
|
+
def initialize
|
27
|
+
@config = TermUtils::FF::Config.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize_copy(other)
|
31
|
+
@config = other.config.dup
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds a Regexp to ignore.
|
36
|
+
# @param regexp [Regexp]
|
37
|
+
# @return [Query]
|
38
|
+
def ignore(regexp)
|
39
|
+
@config.ignore_list << regexp
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
# Sets a minimum depth.
|
44
|
+
# @param depth [Integer]
|
45
|
+
# @return [Query]
|
46
|
+
def min_depth(depth)
|
47
|
+
@config.min_depth = depth
|
48
|
+
self
|
49
|
+
end
|
50
|
+
|
51
|
+
# Sets a maximum depth.
|
52
|
+
# @param depth [Integer]
|
53
|
+
# @return [Query]
|
54
|
+
def max_depth(depth)
|
55
|
+
@config.max_depth = depth
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
# Sets the sorting mode.
|
60
|
+
# @param mode [Symbol] Either `:forward`, `:reverse` or `nil` (default).
|
61
|
+
# @return [Query]
|
62
|
+
def sort(mode = :forward, &block)
|
63
|
+
@config.sorting_mode = mode
|
64
|
+
@config.sorting_compare = block
|
65
|
+
self
|
66
|
+
end
|
67
|
+
|
68
|
+
# Executes this one.
|
69
|
+
# @param path [String]
|
70
|
+
# @return [Array<Entry>]
|
71
|
+
def exec(path, &block)
|
72
|
+
ctx = Context.new
|
73
|
+
ctx.config = @config.dup
|
74
|
+
ctx.config.min_depth = 0 if ctx.config.min_depth.nil?
|
75
|
+
ctx.base_path = path
|
76
|
+
ctx.block = block
|
77
|
+
ctx.index_seq = 0
|
78
|
+
ctx.result = []
|
79
|
+
first_entry = TermUtils::FF::Entry.new
|
80
|
+
first_entry.name = path
|
81
|
+
first_entry.relative_path_comps = []
|
82
|
+
first_entry.path = path
|
83
|
+
if ctx.config.min_depth == 0
|
84
|
+
first_entry.index = ctx.index_seq
|
85
|
+
ctx.index_seq += 1
|
86
|
+
ctx.block.call(first_entry) if ctx.block
|
87
|
+
ctx.result << first_entry
|
88
|
+
end
|
89
|
+
if File.directory?(first_entry.path) && (ctx.config.max_depth.nil? || ctx.config.max_depth > 0)
|
90
|
+
TermUtils::FF::Query.search(ctx, first_entry)
|
91
|
+
end
|
92
|
+
ctx.result
|
93
|
+
end
|
94
|
+
|
95
|
+
# Searches a directory.
|
96
|
+
# @param ctx [Context]
|
97
|
+
# @param parent_entry [entry]
|
98
|
+
# @return [nil]
|
99
|
+
def self.search(ctx, parent_entry)
|
100
|
+
entries = Dir.entries(parent_entry.path)
|
101
|
+
unless ctx.config.sorting_mode.nil?
|
102
|
+
if ctx.config.sorting_compare.nil?
|
103
|
+
entries.sort!
|
104
|
+
else
|
105
|
+
entries.sort!(&ctx.config.sorting_compare)
|
106
|
+
end
|
107
|
+
if ctx.config.sorting_mode == :reverse
|
108
|
+
entries.reverse!
|
109
|
+
end
|
110
|
+
end
|
111
|
+
entries.each do |name|
|
112
|
+
next if %w[. ..].include? name
|
113
|
+
next unless accept_entry_name?(ctx, name)
|
114
|
+
|
115
|
+
new_entry = TermUtils::FF::Entry.new
|
116
|
+
new_entry.name = name
|
117
|
+
new_entry.relative_path_comps = parent_entry.relative_path_comps.dup.push(name)
|
118
|
+
new_entry.path = "#{ctx.base_path}/#{new_entry.relative_path_comps.join('/')}"
|
119
|
+
if ctx.config.min_depth <= new_entry.depth
|
120
|
+
new_entry.index = ctx.index_seq
|
121
|
+
ctx.index_seq += 1
|
122
|
+
ctx.block.call(new_entry) if ctx.block
|
123
|
+
ctx.result << new_entry
|
124
|
+
end
|
125
|
+
if File.directory?(new_entry.path) && (ctx.config.max_depth.nil? || ctx.config.max_depth > new_entry.depth)
|
126
|
+
TermUtils::FF::Query.search(ctx, new_entry)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Tests whether a given entry should be accepted.
|
132
|
+
# @param ctx [Context]
|
133
|
+
# @param name [String]
|
134
|
+
# @return [Boolean]
|
135
|
+
def self.accept_entry_name?(ctx, name)
|
136
|
+
ctx.config.ignore_list.each do |i|
|
137
|
+
if i.match? name
|
138
|
+
return false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
true
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,228 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# Copyright (C) 2020 Thomas Baron
|
4
|
+
#
|
5
|
+
# This file is part of term_utils.
|
6
|
+
#
|
7
|
+
# term_utils is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, version 3 of the License.
|
10
|
+
#
|
11
|
+
# term_utils is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with term_utils. If not, see <https://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
module TermUtils
|
20
|
+
# Represents a general-purpose tree node that holds a key-value pair.
|
21
|
+
class PropertyTreeNode
|
22
|
+
# @return [PropertyTreeNode]
|
23
|
+
attr_accessor :parent_node
|
24
|
+
# @return [Array<PropertyTreeNode>]
|
25
|
+
attr_accessor :child_nodes
|
26
|
+
# @return [Object]
|
27
|
+
attr_accessor :key
|
28
|
+
# @return [Object]
|
29
|
+
attr_accessor :value
|
30
|
+
|
31
|
+
# Creates a new PropertyTreeNode.
|
32
|
+
# @param opts [Hash]
|
33
|
+
# option opts [Object] :key
|
34
|
+
# option opts [Object] :value
|
35
|
+
def initialize(opts = {}, &block)
|
36
|
+
@parent_node = nil
|
37
|
+
@child_nodes = nil
|
38
|
+
@key = opts.fetch(:key, nil)
|
39
|
+
@value = opts.fetch(:value, nil)
|
40
|
+
block.call(self) if block
|
41
|
+
end
|
42
|
+
|
43
|
+
# For dup method.
|
44
|
+
def initialize_dup(other)
|
45
|
+
@parent_node = nil
|
46
|
+
if other.child_nodes
|
47
|
+
@child_nodes = []
|
48
|
+
other.child_nodes.each do |n|
|
49
|
+
new_node = n.dup
|
50
|
+
new_node.parent_node = self
|
51
|
+
@child_nodes << new_node
|
52
|
+
end
|
53
|
+
end
|
54
|
+
super
|
55
|
+
end
|
56
|
+
|
57
|
+
# Tests whether this one is the head of the tree (i.e. has no parent).
|
58
|
+
# @return [Boolean]
|
59
|
+
def head?
|
60
|
+
@parent_node == nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Tests whether this one is a leaf of the tree (i.e. has no child).
|
64
|
+
# @return [Boolean]
|
65
|
+
def leaf?
|
66
|
+
@child_nodes == nil
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the child node identified by a given key.
|
70
|
+
# @param key [Object]
|
71
|
+
# @return [PropertyTreeNode, nil]
|
72
|
+
def child_node(key)
|
73
|
+
if @child_nodes
|
74
|
+
@child_nodes.find { |n| n.key == key }
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a new node and adds it as a child.
|
79
|
+
# @param opts [Hash]
|
80
|
+
# @option opts [Object] :key
|
81
|
+
# @option opts [Object] :value
|
82
|
+
# @return [PropertyTreeNode]
|
83
|
+
def define_node(opts = {}, &block)
|
84
|
+
new_node = TermUtils::PropertyTreeNode.new(opts)
|
85
|
+
new_node.parent_node = self
|
86
|
+
@child_nodes = [] unless @child_nodes
|
87
|
+
@child_nodes << new_node
|
88
|
+
block.call(new_node) if block
|
89
|
+
new_node
|
90
|
+
end
|
91
|
+
|
92
|
+
# Builds the path of keys.
|
93
|
+
# @return [Array<Object>]
|
94
|
+
def path
|
95
|
+
p = @parent_node ? @parent_node.path : []
|
96
|
+
p << @key if @key
|
97
|
+
p
|
98
|
+
end
|
99
|
+
|
100
|
+
# Iterates over every node.
|
101
|
+
# @param opts [Hash]
|
102
|
+
# @option opts [Array] :path
|
103
|
+
# @option opts [Boolean] :leaf_only
|
104
|
+
# @return [nil]
|
105
|
+
def each_node(opts = {}, &block)
|
106
|
+
rpath = nil
|
107
|
+
if opts.key? :path
|
108
|
+
rpath = opts[:path].dup
|
109
|
+
end
|
110
|
+
dive = true
|
111
|
+
if @key
|
112
|
+
hide = false
|
113
|
+
if rpath
|
114
|
+
if rpath.shift == @key
|
115
|
+
unless rpath.empty?
|
116
|
+
hide = true
|
117
|
+
end
|
118
|
+
else
|
119
|
+
dive = false
|
120
|
+
hide = true
|
121
|
+
end
|
122
|
+
end
|
123
|
+
unless hide || (opts[:leaf_only] && @child_nodes)
|
124
|
+
if opts.key? :block
|
125
|
+
opts[:block].call(self)
|
126
|
+
elsif block
|
127
|
+
block.call(self)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end # if @key
|
131
|
+
if dive && @child_nodes
|
132
|
+
ropts = opts.dup
|
133
|
+
if rpath
|
134
|
+
if rpath.empty?
|
135
|
+
ropts.delete :path
|
136
|
+
else
|
137
|
+
ropts[:path] = rpath
|
138
|
+
end
|
139
|
+
end
|
140
|
+
if block
|
141
|
+
ropts[:block] = block
|
142
|
+
end
|
143
|
+
@child_nodes.each do |n|
|
144
|
+
n.each_node(ropts)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
nil
|
148
|
+
end
|
149
|
+
|
150
|
+
# Collects nodes.
|
151
|
+
# @param opts [Hash]
|
152
|
+
# @option opts [Array] :path
|
153
|
+
# @option opts [Boolean] :leaf_only
|
154
|
+
# @return [Array<PropertyTreeNode>]
|
155
|
+
def collect_nodes(opts = {})
|
156
|
+
nodes = []
|
157
|
+
each_node(opts) do |n|
|
158
|
+
nodes << n
|
159
|
+
end
|
160
|
+
nodes
|
161
|
+
end
|
162
|
+
|
163
|
+
# Collects node paths.
|
164
|
+
# @param opts [Hash]
|
165
|
+
# @option opts [Array] :path
|
166
|
+
# @option opts [Boolean] :leaf_only
|
167
|
+
# @return [Array<Array<Object>>]
|
168
|
+
def collect_paths(opts = {})
|
169
|
+
paths = []
|
170
|
+
each_node(opts) do |n|
|
171
|
+
paths << n.path
|
172
|
+
end
|
173
|
+
paths
|
174
|
+
end
|
175
|
+
|
176
|
+
# Collect node values.
|
177
|
+
# @param opts [Hash]
|
178
|
+
# @option opts [Array] :path
|
179
|
+
# @option opts [Boolean] :leaf_only
|
180
|
+
# @return [Array<Object>]
|
181
|
+
def collect_values(opts = {})
|
182
|
+
vals = []
|
183
|
+
each_node(opts) do |n|
|
184
|
+
vals << n.value if n.value
|
185
|
+
end
|
186
|
+
vals
|
187
|
+
end
|
188
|
+
|
189
|
+
# Finds the node identified by a given path of keys.
|
190
|
+
# @param path [Array<Object>]
|
191
|
+
# @return [PropertyTreeNode]
|
192
|
+
def find_node(path)
|
193
|
+
catch :found do
|
194
|
+
each_node(path: path) do |n|
|
195
|
+
throw :found, n
|
196
|
+
end
|
197
|
+
nil
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
# Tests whether the node identified by a given path of keys exists.
|
202
|
+
# @param path [Array<Object>]
|
203
|
+
# @return [Boolean]
|
204
|
+
def node_exists?(path)
|
205
|
+
find_node(path) != nil
|
206
|
+
end
|
207
|
+
|
208
|
+
# Evaluates the total number of nodes in the tree represented by this one.
|
209
|
+
# @param path [Array<Object>]
|
210
|
+
# @return [Integer]
|
211
|
+
def eval_child_count(path)
|
212
|
+
node = find_node(path)
|
213
|
+
if node
|
214
|
+
node.child_nodes ? node.child_nodes.length : 0
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# Finds the node identified by a given path of keys and returns its value.
|
219
|
+
# @param path [Array<Object>]
|
220
|
+
# @return [Object]
|
221
|
+
def find_node_value(path)
|
222
|
+
node = find_node(path)
|
223
|
+
if node
|
224
|
+
node.value
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|