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,211 @@
|
|
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 parser.
|
22
|
+
class Parser
|
23
|
+
# Constructs a new Parser.
|
24
|
+
def initialize
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parses a given list of arguments.
|
28
|
+
# @param syntax [Syntax]
|
29
|
+
# @param arguments [Array<String>]
|
30
|
+
# @param opts [Hash]
|
31
|
+
# @return [Result]
|
32
|
+
# @raise [ParseError]
|
33
|
+
# @raise [SyntaxError]
|
34
|
+
def parse_arguments(syntax, arguments, opts = {}, &block)
|
35
|
+
syntax = syntax.dup
|
36
|
+
syntax.finalize!
|
37
|
+
arguments = arguments.dup
|
38
|
+
res = TermUtils::AP::Result.new(syntax)
|
39
|
+
catch :done do
|
40
|
+
parse0(res, syntax, arguments, opts)
|
41
|
+
end
|
42
|
+
res.remaining_arguments = arguments
|
43
|
+
res.walk(&block) if block
|
44
|
+
res
|
45
|
+
end
|
46
|
+
|
47
|
+
# Tests whether a given sample matches a shortcut flag.
|
48
|
+
# @param shortcut_flags [Hash<String, Flag>]
|
49
|
+
# @param arg [String]
|
50
|
+
# @return [Array<String>, nil] Replacements on success, nil otherwise.
|
51
|
+
def self.match_shortcut_flag(shortcut_flags, arg)
|
52
|
+
shortcut_flags.each do |label, flag|
|
53
|
+
next unless arg.start_with? label
|
54
|
+
|
55
|
+
return [flag.label, arg[label.length..-1]]
|
56
|
+
end
|
57
|
+
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
|
61
|
+
# Evaluates the added number of min occurs of a given array of articles.
|
62
|
+
# @param articles [Array<TermUtils::AP::Article>]
|
63
|
+
# @return [Integer]
|
64
|
+
def self.eval_article_min_occurs(articles)
|
65
|
+
articles.inject(0) { |acc, a| acc + a.min_occurs }
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
# Parses a given argument list.
|
71
|
+
# @param result [Result]
|
72
|
+
# @param syntax [Syntax]
|
73
|
+
# @param arguments [Array<String>]
|
74
|
+
# @raise [ParseError]
|
75
|
+
def parse0(result, syntax, arguments, opts = {})
|
76
|
+
unflagged_params, flagged_params, shortcut_flags = syntax.fetch_parameters
|
77
|
+
fp_occ = {}
|
78
|
+
syntax.parameters.each { |p| fp_occ[p.id] = 0 if p.flagged? }
|
79
|
+
up_occ = 0
|
80
|
+
loop do
|
81
|
+
break if arguments.empty?
|
82
|
+
|
83
|
+
if arguments.first.start_with?('-') && !%w[- --].include?(arguments.first)
|
84
|
+
# Flagged
|
85
|
+
unless flagged_params.key? arguments.first
|
86
|
+
# Unknown flag
|
87
|
+
# Try shortcut flag
|
88
|
+
flag, arg = self.class.match_shortcut_flag(shortcut_flags, arguments.first)
|
89
|
+
if flag && arg
|
90
|
+
# Shortcut match
|
91
|
+
arguments.shift
|
92
|
+
arguments.unshift arg
|
93
|
+
arguments.unshift flag
|
94
|
+
end
|
95
|
+
end
|
96
|
+
unless flagged_params.key? arguments.first
|
97
|
+
# Unknown flag
|
98
|
+
# End of parsing
|
99
|
+
raise TermUtils::AP::ParseError, 'flagged parameter unexpected' if opts.fetch(:strict, false)
|
100
|
+
|
101
|
+
break
|
102
|
+
end
|
103
|
+
|
104
|
+
param = flagged_params[arguments.first]
|
105
|
+
if param.occur_bounded? && (fp_occ[param.id] >= param.max_occurs)
|
106
|
+
# Max occurs reached
|
107
|
+
raise TermUtils::AP::ParseError, "occur limit reached (#{param.id})" if opts.fetch(:strict, false)
|
108
|
+
|
109
|
+
break
|
110
|
+
end
|
111
|
+
|
112
|
+
fp_occ[param.id] += 1
|
113
|
+
arguments.shift
|
114
|
+
param_res = TermUtils::AP::ParameterResult.new(result, param)
|
115
|
+
parse0_param(param_res, param, arguments)
|
116
|
+
else
|
117
|
+
# Unflagged
|
118
|
+
if unflagged_params.empty?
|
119
|
+
# End of parsing
|
120
|
+
raise TermUtils::AP::ParseError, 'unflagged parameter unexpected' if opts.fetch(:strict, false)
|
121
|
+
|
122
|
+
break
|
123
|
+
end
|
124
|
+
|
125
|
+
param = unflagged_params.first
|
126
|
+
if arguments.first == '--'
|
127
|
+
# End of parameter
|
128
|
+
raise TermUtils::AP::ParseError, "parameter not consumed (#{param.id})" if up_occ < param.min_occurs
|
129
|
+
|
130
|
+
arguments.shift
|
131
|
+
unflagged_params.shift
|
132
|
+
up_occ = 0
|
133
|
+
next
|
134
|
+
end
|
135
|
+
|
136
|
+
up_occ += 1
|
137
|
+
param_res = TermUtils::AP::ParameterResult.new(result, param)
|
138
|
+
case parse0_param(param_res, param, arguments)
|
139
|
+
when :esc_param
|
140
|
+
raise TermUtils::AP::ParseError, "parameter not consumed (#{param.id})" if up_occ < param.min_occurs
|
141
|
+
|
142
|
+
unflagged_params.shift
|
143
|
+
up_occ = 0
|
144
|
+
else
|
145
|
+
if !param.multiple_occurs? || (param.occur_bounded? && (up_occ >= param.max_occurs))
|
146
|
+
unflagged_params.shift
|
147
|
+
up_occ = 0
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end # loop
|
152
|
+
# Check min occurs
|
153
|
+
syntax.parameters.each do |p|
|
154
|
+
next if result.find_parameters(p.id).length >= p.min_occurs
|
155
|
+
|
156
|
+
raise TermUtils::AP::ParseError, "parameter not consumed (#{p.id})"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Parses with a given Parameter.
|
161
|
+
# @param result [ParameterResult]
|
162
|
+
# @param param [Parameter]
|
163
|
+
# @param arguments [Array<String>]
|
164
|
+
# @return [Symbol, nil] `:esc_param`, or nil.
|
165
|
+
def parse0_param(result, param, arguments)
|
166
|
+
arts = param.fetch_articles
|
167
|
+
occ = 0
|
168
|
+
loop do
|
169
|
+
break if arts.empty?
|
170
|
+
|
171
|
+
if arguments.empty?
|
172
|
+
# End of arguments
|
173
|
+
raise TermUtils::AP::ParseError, 'article not consumed' if occ < arts.first.min_occurs
|
174
|
+
raise TermUtils::AP::ParseError, 'article not consumed' if self.class.eval_article_min_occurs(arts[1..-1]) > 0
|
175
|
+
|
176
|
+
break
|
177
|
+
end
|
178
|
+
|
179
|
+
if arguments.first == '-'
|
180
|
+
# End of article
|
181
|
+
raise TermUtils::AP::ParseError, 'article not consumed' if occ < arts.first.min_occurs
|
182
|
+
|
183
|
+
arguments.shift
|
184
|
+
arts.shift
|
185
|
+
occ = 0
|
186
|
+
next
|
187
|
+
elsif arguments.first.start_with? '-'
|
188
|
+
# End of parameter
|
189
|
+
raise TermUtils::AP::ParseError, 'article not consumed' if occ < arts.first.min_occurs
|
190
|
+
raise TermUtils::AP::ParseError, 'article not consumed' if self.class.eval_article_min_occurs(arts[1..-1]) > 0
|
191
|
+
|
192
|
+
if arguments.first == '--'
|
193
|
+
arguments.shift
|
194
|
+
return :esc_param
|
195
|
+
end
|
196
|
+
|
197
|
+
break
|
198
|
+
end
|
199
|
+
art = arts.first
|
200
|
+
TermUtils::AP::ArticleResult.new(result, art, arguments.shift)
|
201
|
+
occ += 1
|
202
|
+
if !art.multiple_occurs? || (art.occur_bounded? && (occ >= art.max_occurs))
|
203
|
+
arts.shift
|
204
|
+
occ = 0
|
205
|
+
end
|
206
|
+
end # loop
|
207
|
+
nil
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,244 @@
|
|
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 an argument parsing Result.
|
22
|
+
class Result
|
23
|
+
# @return [Syntax]
|
24
|
+
attr_reader :parameter
|
25
|
+
# @return [Array<ParameterResult>]
|
26
|
+
attr_reader :results
|
27
|
+
# @return [Array<String>]
|
28
|
+
attr_accessor :remaining_arguments
|
29
|
+
|
30
|
+
# Constructs a new Result.
|
31
|
+
# @param syntax [Syntax]
|
32
|
+
def initialize(syntax)
|
33
|
+
@syntax = syntax
|
34
|
+
@results = []
|
35
|
+
@remaining_arguments = nil
|
36
|
+
end
|
37
|
+
|
38
|
+
# Adds a ParameterResult.
|
39
|
+
# @param result [ParameterResult]
|
40
|
+
def add_result(result)
|
41
|
+
@results << result
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the first ParameterResult for a given parameter id.
|
45
|
+
# @param id [Symbol]
|
46
|
+
# @return [ParameterResult]
|
47
|
+
def find_parameter(id)
|
48
|
+
@results.find { |r| r.param_id == id }
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns all ParameterResult(s) for a given parameter id.
|
52
|
+
# @param id [Symbol]
|
53
|
+
# @return [Array<ParameterResult>]
|
54
|
+
def find_parameters(id)
|
55
|
+
@results.find_all { |r| r.param_id == id }
|
56
|
+
end
|
57
|
+
|
58
|
+
# Walks through this one.
|
59
|
+
def walk(&block)
|
60
|
+
walker = TermUtils::AP::Walker.new
|
61
|
+
block.call(walker)
|
62
|
+
@results.each do |p|
|
63
|
+
p.results.each do |a|
|
64
|
+
walker.notify_article(a)
|
65
|
+
end
|
66
|
+
walker.notify_parameter(p)
|
67
|
+
end
|
68
|
+
walker.notify_finished(@remaining_arguments)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Represents a result for a parameter.
|
73
|
+
class ParameterResult
|
74
|
+
# @return [Parameter]
|
75
|
+
attr_accessor :parameter
|
76
|
+
# @return [Array<ArticleResult>]
|
77
|
+
attr_accessor :results
|
78
|
+
|
79
|
+
# Constructs a new ParameterResult.
|
80
|
+
# @param parent [Result]
|
81
|
+
# @param parameter [Parameter]
|
82
|
+
def initialize(parent, parameter)
|
83
|
+
@parent = parent
|
84
|
+
@parent.add_result(self)
|
85
|
+
@parameter = parameter
|
86
|
+
@results = []
|
87
|
+
end
|
88
|
+
|
89
|
+
# Adds an ArticleResult.
|
90
|
+
# @param result [ArticleResult]
|
91
|
+
def add_result(result)
|
92
|
+
@results << result
|
93
|
+
end
|
94
|
+
|
95
|
+
# @return [Symbol]
|
96
|
+
def param_id
|
97
|
+
@parameter.id
|
98
|
+
end
|
99
|
+
|
100
|
+
# Returns the first ArticleResult for a given article id.
|
101
|
+
# @param id [Symbol]
|
102
|
+
# @return [ArticleResult]
|
103
|
+
def find_article(id)
|
104
|
+
@results.find { |r| r.art_id == id }
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns all ArticleResult(s) for a given article id.
|
108
|
+
# @param id [Symbol]
|
109
|
+
# @return [Array<Result>]
|
110
|
+
def find_articles(id)
|
111
|
+
@results.find_all { |r| r.art_id == id }
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the value of the first ArticleResult.
|
115
|
+
# @param id [Symbol] Filter of article id.
|
116
|
+
# @return [Object]
|
117
|
+
def value(id = nil)
|
118
|
+
return @results.first.value unless id
|
119
|
+
|
120
|
+
find_article(id).value
|
121
|
+
end
|
122
|
+
|
123
|
+
# Returns the value of all ArticleResult(s).
|
124
|
+
# @param id [Symbol] Filter of article id.
|
125
|
+
# @return [Array<Object>]
|
126
|
+
def values(id = nil)
|
127
|
+
return @results.map(&:value) unless id
|
128
|
+
|
129
|
+
vals = []
|
130
|
+
@results.each do |r|
|
131
|
+
next if r.art_id != id
|
132
|
+
|
133
|
+
vals << r.values
|
134
|
+
end
|
135
|
+
vals
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Represents a result for an article.
|
140
|
+
class ArticleResult
|
141
|
+
# @return [ParameterResult]
|
142
|
+
attr_accessor :parent
|
143
|
+
# @return [Article]
|
144
|
+
attr_accessor :article
|
145
|
+
# @return [Object]
|
146
|
+
attr_accessor :value
|
147
|
+
|
148
|
+
# Constructs a new ArticleResult.
|
149
|
+
# @param parent [ParameterResult]
|
150
|
+
# @param article [Article]
|
151
|
+
# @param value [Object]
|
152
|
+
def initialize(parent, article, value)
|
153
|
+
@parent = parent
|
154
|
+
@parent.add_result(self)
|
155
|
+
@article = article
|
156
|
+
@value = value
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Symbol]
|
160
|
+
def art_id
|
161
|
+
@article.id
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Represents a Result Walker.
|
166
|
+
class Walker
|
167
|
+
# Constructs a new Walker.
|
168
|
+
def initialize
|
169
|
+
@anonymous_parameter_hook = nil
|
170
|
+
@anonymous_article_hook = nil
|
171
|
+
@parameter_hooks = {}
|
172
|
+
@finished_hook = nil
|
173
|
+
end
|
174
|
+
|
175
|
+
# Registers a parameter hook.
|
176
|
+
def parameter(param_id = nil, &block)
|
177
|
+
unless param_id
|
178
|
+
# Anonymous parameter hook
|
179
|
+
@anonymous_parameter_hook = block
|
180
|
+
return
|
181
|
+
end
|
182
|
+
|
183
|
+
@parameter_hooks[param_id] = TermUtils::AP::ParameterWalkerHooks.new unless @parameter_hooks.key?(param_id)
|
184
|
+
@parameter_hooks[param_id].hook = block
|
185
|
+
end
|
186
|
+
|
187
|
+
# Registers an article hook.
|
188
|
+
def article(param_id = nil, art_id = nil, &block)
|
189
|
+
unless param_id
|
190
|
+
# Anonymous article hook
|
191
|
+
@anonymous_article_hook = block
|
192
|
+
return
|
193
|
+
end
|
194
|
+
|
195
|
+
unless art_id
|
196
|
+
# Anonymous article hook
|
197
|
+
@parameter_hooks[param_id] = TermUtils::AP::ParameterWalkerHooks.new unless @parameter_hooks.key?(param_id)
|
198
|
+
@parameter_hooks[param_id].anonymous_article_hook = block
|
199
|
+
return
|
200
|
+
end
|
201
|
+
|
202
|
+
@parameter_hooks[param_id] = TermUtils::AP::ParameterWalkerHooks.new unless @parameter_hooks.key?(param_id)
|
203
|
+
@parameter_hooks[param_id].article_hooks ||= {}
|
204
|
+
@parameter_hooks[param_id].article_hooks[art_id] = block
|
205
|
+
end
|
206
|
+
|
207
|
+
# Registers a walk finished hook.
|
208
|
+
def finished(&block)
|
209
|
+
@finished_hook = block
|
210
|
+
end
|
211
|
+
|
212
|
+
# Calls parameter hooks.
|
213
|
+
def notify_parameter(parameter)
|
214
|
+
# (1of2) ID parameter hook
|
215
|
+
param_hooks = @parameter_hooks[parameter.param_id]
|
216
|
+
param_hooks.hook.call(parameter) if param_hooks && param_hooks.hook
|
217
|
+
# (2of2) Anonymous parameter hook
|
218
|
+
@anonymous_parameter_hook.call(parameter) if @anonymous_parameter_hook
|
219
|
+
end
|
220
|
+
|
221
|
+
# Calls article hooks.
|
222
|
+
def notify_article(article)
|
223
|
+
# (1of2) ID article hook
|
224
|
+
param_hooks = @parameter_hooks[article.parent.param_id]
|
225
|
+
if param_hooks
|
226
|
+
# ID article hook
|
227
|
+
param_hooks.article_hooks[article.art_id].call(article) if param_hooks.article_hooks && param_hooks.article_hooks.key?(article.art_id)
|
228
|
+
# Anonymous article hook
|
229
|
+
param_hooks.anonymous_article_hook.call(article) if param_hooks.anonymous_article_hook
|
230
|
+
end
|
231
|
+
# (2of2) Anonymous article hook
|
232
|
+
@anonymous_article_hook.call(article) if @anonymous_article_hook
|
233
|
+
end
|
234
|
+
|
235
|
+
# Calls finished hook.
|
236
|
+
def notify_finished(remaining_arguments)
|
237
|
+
@finished_hook.call(remaining_arguments) if @finished_hook
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
# Parameter hooks for Walker.
|
242
|
+
ParameterWalkerHooks = Struct.new('ParameterWalkerHooks', :hook, :anonymous_article_hook, :article_hooks)
|
243
|
+
end
|
244
|
+
end
|