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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +1 -0
  3. data/CHANGELOG.md +51 -0
  4. data/COPYING +674 -0
  5. data/README.md +99 -0
  6. data/Rakefile +55 -0
  7. data/doc/TermUtils.html +138 -0
  8. data/doc/TermUtils/AP.html +394 -0
  9. data/doc/TermUtils/AP/Article.html +993 -0
  10. data/doc/TermUtils/AP/ArticleResult.html +584 -0
  11. data/doc/TermUtils/AP/Flag.html +756 -0
  12. data/doc/TermUtils/AP/NoSuchValueError.html +217 -0
  13. data/doc/TermUtils/AP/Parameter.html +1592 -0
  14. data/doc/TermUtils/AP/ParameterResult.html +980 -0
  15. data/doc/TermUtils/AP/ParameterWalkerHooks.html +409 -0
  16. data/doc/TermUtils/AP/ParseError.html +217 -0
  17. data/doc/TermUtils/AP/Parser.html +604 -0
  18. data/doc/TermUtils/AP/Result.html +837 -0
  19. data/doc/TermUtils/AP/Syntax.html +761 -0
  20. data/doc/TermUtils/AP/SyntaxError.html +217 -0
  21. data/doc/TermUtils/AP/Walker.html +686 -0
  22. data/doc/TermUtils/FF.html +128 -0
  23. data/doc/TermUtils/FF/Config.html +774 -0
  24. data/doc/TermUtils/FF/Context.html +585 -0
  25. data/doc/TermUtils/FF/Entry.html +626 -0
  26. data/doc/TermUtils/FF/Query.html +1085 -0
  27. data/doc/TermUtils/PropertyTreeNode.html +2113 -0
  28. data/doc/TermUtils/Tab.html +1486 -0
  29. data/doc/TermUtils/Tab/Column.html +1263 -0
  30. data/doc/TermUtils/Tab/Header.html +536 -0
  31. data/doc/TermUtils/Tab/Holder.html +1210 -0
  32. data/doc/TermUtils/Tab/Printer.html +967 -0
  33. data/doc/TermUtils/Tab/Table.html +1966 -0
  34. data/doc/TermUtils/Tab/TableError.html +217 -0
  35. data/doc/_index.html +387 -0
  36. data/doc/class_list.html +51 -0
  37. data/doc/css/common.css +1 -0
  38. data/doc/css/full_list.css +58 -0
  39. data/doc/css/style.css +496 -0
  40. data/doc/file.README.html +170 -0
  41. data/doc/file_list.html +56 -0
  42. data/doc/frames.html +17 -0
  43. data/doc/index.html +170 -0
  44. data/doc/js/app.js +314 -0
  45. data/doc/js/full_list.js +216 -0
  46. data/doc/js/jquery.js +4 -0
  47. data/doc/method_list.html +1539 -0
  48. data/doc/top-level-namespace.html +110 -0
  49. data/lib/term_utils.rb +11 -0
  50. data/lib/term_utils/ap.rb +70 -0
  51. data/lib/term_utils/ap/article.rb +74 -0
  52. data/lib/term_utils/ap/flag.rb +65 -0
  53. data/lib/term_utils/ap/parameter.rb +144 -0
  54. data/lib/term_utils/ap/parser.rb +211 -0
  55. data/lib/term_utils/ap/result.rb +244 -0
  56. data/lib/term_utils/ap/syntax.rb +96 -0
  57. data/lib/term_utils/ff.rb +27 -0
  58. data/lib/term_utils/ff/config.rb +55 -0
  59. data/lib/term_utils/ff/entry.rb +45 -0
  60. data/lib/term_utils/ff/query.rb +145 -0
  61. data/lib/term_utils/property_tree_node.rb +228 -0
  62. data/lib/term_utils/tab.rb +338 -88
  63. data/term_utils.gemspec +16 -0
  64. 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