term_utils 0.1.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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