term_utils 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +6 -0
  3. data/COPYING +3 -3
  4. data/README.md +7 -1
  5. data/doc/TermUtils/AP/Article.html +991 -0
  6. data/doc/TermUtils/AP/Element.html +1025 -0
  7. data/doc/TermUtils/AP/Flag.html +539 -0
  8. data/doc/TermUtils/AP/Level.html +638 -0
  9. data/doc/TermUtils/AP/NoSuchValueError.html +217 -0
  10. data/doc/TermUtils/AP/Parameter.html +804 -0
  11. data/doc/TermUtils/AP/ParseError.html +217 -0
  12. data/doc/TermUtils/AP/Parser.html +572 -0
  13. data/doc/TermUtils/AP/Result.html +1029 -0
  14. data/doc/TermUtils/AP/ResultView.html +597 -0
  15. data/doc/TermUtils/AP/Syntax.html +1051 -0
  16. data/doc/TermUtils/AP/SyntaxError.html +217 -0
  17. data/doc/TermUtils/AP.html +505 -0
  18. data/doc/TermUtils/FF/Config.html +1 -1
  19. data/doc/TermUtils/FF/Cursor/Context.html +1 -1
  20. data/doc/TermUtils/FF/Cursor.html +1 -1
  21. data/doc/TermUtils/FF/Query.html +1 -1
  22. data/doc/TermUtils/FF.html +1 -1
  23. data/doc/TermUtils/PropertyTreeNode.html +1999 -0
  24. data/doc/TermUtils/Tab/Column.html +1 -1
  25. data/doc/TermUtils/Tab/Holder.html +1 -1
  26. data/doc/TermUtils/Tab/Printer.html +1 -1
  27. data/doc/TermUtils/Tab/Table.html +1 -1
  28. data/doc/TermUtils/Tab.html +1 -1
  29. data/doc/TermUtils.html +5 -3
  30. data/doc/_index.html +143 -1
  31. data/doc/class_list.html +1 -1
  32. data/doc/file.README.html +8 -2
  33. data/doc/index.html +8 -2
  34. data/doc/method_list.html +638 -22
  35. data/doc/top-level-namespace.html +1 -1
  36. data/lib/term_utils/ap/article.rb +68 -0
  37. data/lib/term_utils/ap/element.rb +78 -0
  38. data/lib/term_utils/ap/flag.rb +48 -0
  39. data/lib/term_utils/ap/level.rb +57 -0
  40. data/lib/term_utils/ap/no_such_value_error.rb +27 -0
  41. data/lib/term_utils/ap/parameter.rb +75 -0
  42. data/lib/term_utils/ap/parse_error.rb +27 -0
  43. data/lib/term_utils/ap/parser.rb +185 -0
  44. data/lib/term_utils/ap/result.rb +175 -0
  45. data/lib/term_utils/ap/syntax.rb +112 -0
  46. data/lib/term_utils/ap/syntax_error.rb +27 -0
  47. data/lib/term_utils/ap.rb +59 -0
  48. data/lib/term_utils/property_tree_node.rb +200 -0
  49. data/lib/term_utils.rb +1 -0
  50. data/term_utils.gemspec +2 -2
  51. metadata +29 -2
@@ -100,7 +100,7 @@
100
100
  </div>
101
101
 
102
102
  <div id="footer">
103
- Generated on Thu Oct 17 22:50:57 2019 by
103
+ Generated on Sun Nov 10 18:36:19 2019 by
104
104
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
105
105
  0.9.20 (ruby-2.6.5).
106
106
  </div>
@@ -0,0 +1,68 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Represents a Article.
21
+ class Article
22
+ # @return [Symbol]
23
+ attr_accessor :id
24
+ # @return [Integer]
25
+ attr_accessor :min_occurs
26
+ # @return [Integer]
27
+ attr_accessor :max_occurs
28
+ # @return [Symbol] `:integer`, `:string`
29
+ attr_accessor :type
30
+ # @return [String] `%d`, `%s`.
31
+ attr_accessor :format
32
+ # Constructs a new Article.
33
+ # @param opts [Hash]
34
+ # @option opts [Symbol] :id
35
+ # @option opts [Integer] :min_occurs Default value is `1`.
36
+ # @option opts [Integer] :max_occurs Default value is `1`.
37
+ # @option opts [Symbol] :type `:integer`, `:string`.
38
+ # @option opts [Symbol] :format
39
+ def initialize(opts = {})
40
+ @id = opts.fetch(:id, nil)
41
+ @min_occurs = opts.fetch(:min_occurs, 1)
42
+ @max_occurs = opts.fetch(:max_occurs, 1)
43
+ @type = opts.fetch(:type, :string)
44
+ @format = opts.fetch(:format, "%s")
45
+ end
46
+ # Finalizes this one. Internal use.
47
+ # @return [nil]
48
+ def finalize!(opts = {})
49
+ raise TermUtils::AP::SyntaxError, "min_occurs must be equal or greater than 0" unless (@min_occurs.is_a? Integer) && (@min_occurs >= 0)
50
+ raise TermUtils::AP::SyntaxError, "max_occurs must be equal or greater than min_occurs" unless !occur_bounded? || (@max_occurs >= @min_occurs)
51
+ unless @id
52
+ opts[:anonymous] += 1
53
+ @id = "anonymous#{opts[:anonymous]}".intern
54
+ end
55
+ end
56
+ # Tests whether this one has mutiple occurs.
57
+ # @return [Boolean]
58
+ def multiple_occurs?
59
+ (@max_occurs == nil) || (@max_occurs == :infinity) || ((@max_occurs.is_a? Integer) && (@max_occurs > 1))
60
+ end
61
+ # Tests whether the number of occurs are fixed.
62
+ # @return [Boolean]
63
+ def occur_bounded?
64
+ (@max_occurs != nil) && (@max_occurs != :infinity) && (@max_occurs.is_a? Integer)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,78 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Represents a syntax element (abstract).
21
+ class Element
22
+ # @return [Symbol]
23
+ attr_accessor :id
24
+ # @return [Integer]
25
+ attr_accessor :min_occurs
26
+ # @return [Integer]
27
+ attr_accessor :max_occurs
28
+ # @return [Array<TermUtils::AP::Flag>]
29
+ attr_accessor :flags
30
+ # For dup method.
31
+ def initialize_dup(other)
32
+ if other.flags
33
+ @flags = []
34
+ other.flags.each do |f|
35
+ @flags << f.dup
36
+ end
37
+ end
38
+ super
39
+ end
40
+ # Finalizes this one. Internal use.
41
+ # @return [nil]
42
+ def finalize!(opts = {})
43
+ raise TermUtils::AP::SyntaxError, "min_occurs must be equal or greater than 0" unless (@min_occurs.is_a? Integer) && (@min_occurs >= 0)
44
+ raise TermUtils::AP::SyntaxError, "max_occurs must be equal or greater than min_occurs" unless !occur_bounded? || (@max_occurs >= @min_occurs)
45
+ unless @id
46
+ opts[:anonymous] += 1
47
+ @id = "anonymous#{opts[:anonymous]}".intern
48
+ end
49
+ end
50
+ # Tests whether this one has mutiple occurs.
51
+ # @return [Boolean]
52
+ def multiple_occurs?
53
+ (@max_occurs == nil) || (@max_occurs == :infinity) || ((@max_occurs.is_a? Integer) && (@max_occurs > 1))
54
+ end
55
+ # Tests whether the number of occurs are fixed.
56
+ # @return [Boolean]
57
+ def occur_bounded?
58
+ (@max_occurs != nil) && (@max_occurs != :infinity) && (@max_occurs.is_a? Integer)
59
+ end
60
+ # Tests whether this one is flagged.
61
+ # @return [Boolean]
62
+ def flagged?
63
+ !@flags.empty?
64
+ end
65
+ # Adds a new Flag to this one.
66
+ # @param opts [Hash]
67
+ # @option opts [String] :label
68
+ # @option opts [Symbol] :flavor `:anchor`, `:long`, `:short`.
69
+ # @return [TermUtils::AP::Flag]
70
+ def define_flag(opts = {}, &block)
71
+ new_flag = TermUtils::AP::Flag.new(opts)
72
+ @flags << new_flag
73
+ block.call(new_flag) if block
74
+ new_flag
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,48 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Represents a Flag.
21
+ class Flag
22
+ # @return [String]
23
+ attr_accessor :label
24
+ # @return [Symbol] `:anchor`, `:long`, `:short`.
25
+ attr_accessor :flavor
26
+ # Constructs a new Flag.
27
+ # @param opts [Hash]
28
+ # @option opts [String] :label
29
+ # @option opts [Symbol] :flavor `:anchor`, `:long`, `:short`.
30
+ def initialize(opts = {})
31
+ @label = opts.fetch(:label, nil)
32
+ @flavor = opts.fetch(:flavor, nil)
33
+ end
34
+ # Returns the string representation of this one.
35
+ # @return [String]
36
+ def to_s
37
+ case @flavor
38
+ when :anchor
39
+ @label
40
+ when :long
41
+ "--%s" % @label
42
+ when :short
43
+ "-%s" % @label
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,57 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Represents an argument list subset. It must lead with a Flag. It has its
21
+ # own syntax.
22
+ class Level < TermUtils::AP::Element
23
+ # @return [TermUtils::AP::Syntax]
24
+ attr_accessor :syntax
25
+ # Constructs a new Level.
26
+ # @param opts [Hash]
27
+ # @option opts [Symbol] :id
28
+ # @option opts [Integer] :min_occurs Default value is `0`.
29
+ # @option opts [Integer] :max_occurs Default value is `1`.
30
+ def initialize(opts = {})
31
+ @id = opts.fetch(:id, nil)
32
+ @min_occurs = opts.fetch(:min_occurs, 0)
33
+ @max_occurs = opts.fetch(:max_occurs, 1)
34
+ @flags = []
35
+ @syntax = TermUtils::AP::Syntax.new
36
+ end
37
+ # For dup method.
38
+ def initialize_dup(other)
39
+ @syntax = other.syntax.dup
40
+ super
41
+ end
42
+ # Finalizes this one. Internal use.
43
+ # @return [nil]
44
+ def finalize!(opts = {})
45
+ super
46
+ raise TermUtils::AP::SyntaxError, "level must contain at least one flag" if @flags.empty?
47
+ @syntax.finalize!(opts)
48
+ end
49
+ # Defines the syntax.
50
+ # @return [TermUtils::AP::Syntax]
51
+ def define_syntax(&block)
52
+ block.call(@syntax) if block
53
+ @syntax
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,27 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # No such value error.
21
+ class NoSuchValueError < StandardError
22
+ def initialize(msg)
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,75 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Represents a Parameter.
21
+ class Parameter < TermUtils::AP::Element
22
+ # @return [Array<TermUtils::AP::Article>]
23
+ attr_accessor :articles
24
+ # Constructs a new Parameter.
25
+ # @param opts [Hash]
26
+ # @option opts [Symbol] :id
27
+ # @option opts [Integer] :min_occurs Default value is `0`.
28
+ # @option opts [Integer] :max_occurs Default value is `1`.
29
+ def initialize(opts = {})
30
+ @id = opts.fetch(:id, nil)
31
+ @min_occurs = opts.fetch(:min_occurs, 0)
32
+ @max_occurs = opts.fetch(:max_occurs, 1)
33
+ @flags = []
34
+ @articles = []
35
+ end
36
+ # For dup method.
37
+ def initialize_dup(other)
38
+ if other.articles
39
+ @articles = []
40
+ other.articles.each do |a|
41
+ @articles << a.dup
42
+ end
43
+ end
44
+ super
45
+ end
46
+ # Finalizes this one. Internal use.
47
+ # @return [nil]
48
+ def finalize!(opts = {})
49
+ super
50
+ @articles.each do |a|
51
+ a.finalize!(opts)
52
+ end
53
+ end
54
+ # Adds a new Article to this one.
55
+ # @param opts [Hash]
56
+ # @option opts [Symbol] :id
57
+ # @option opts [Integer] :min_occurs Default value is `1`.
58
+ # @option opts [Integer] :max_occurs Default value is `1`.
59
+ # @option opts [Symbol] :type `:integer`, `:string`.
60
+ # @option opts [Symbol] :format
61
+ # @return [TermUtils::AP::Article]
62
+ def define_article(opts = {}, &block)
63
+ new_article = TermUtils::AP::Article.new(opts)
64
+ @articles << new_article
65
+ block.call(new_article) if block
66
+ new_article
67
+ end
68
+ # Fetches all articles.
69
+ # @return [Array<TermUtils::AP::Article>]
70
+ def fetch_articles
71
+ @articles.collect { |a| a.dup }
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,27 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Parse error.
21
+ class ParseError < StandardError
22
+ def initialize(msg)
23
+ super
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,185 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # Copyright (C) 2019 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
+ module TermUtils
19
+ module AP
20
+ # Represents the argument list parser.
21
+ class Parser
22
+ def initialize
23
+ end
24
+ # Parses a given command.
25
+ # @param syntax [TermUtils::AP::Syntax]
26
+ # @param command [String]
27
+ # @param opts [Hash] `:program`.
28
+ # @option opts [Boolean] :program Whether the first argument is the program name.
29
+ # @return [TermUtils::AP::Result]
30
+ # @raise [TermUtils::AP::ParseError]
31
+ # @raise [TermUtils::AP::SyntaxError]
32
+ def parse_command(syntax, command, opts = {})
33
+ parse_arguments(syntax, command.split(" "), opts)
34
+ end
35
+ # Parses a given list of arguments.
36
+ # @param syntax [TermUtils::AP::Syntax]
37
+ # @param arguments [Array<String>]
38
+ # @param opts [Hash] `:program`.
39
+ # @option opts [Boolean] :program Whether the first argument is the program name.
40
+ # @return [TermUtils::AP::Result]
41
+ # @raise [TermUtils::AP::ParseError]
42
+ # @raise [TermUtils::AP::SyntaxError]
43
+ def parse_arguments(syntax, arguments, opts = {})
44
+ syntax = syntax.dup
45
+ syntax.finalize!
46
+ arguments = arguments.dup
47
+ res = TermUtils::AP::Result.new(syntax)
48
+ catch :done do
49
+ parse0(res.value, syntax, arguments, opts)
50
+ end
51
+ res
52
+ end
53
+ private
54
+ # Parses a given argument list.
55
+ # @param node [TermUtils::PropertyTreeNode]
56
+ # @param syntax [TermUtils::AP::Syntax]
57
+ # @param arguments [Array<String>]
58
+ def parse0(node, syntax, arguments, opts = {})
59
+ # puts "parse0"
60
+ opts = opts.dup
61
+ if opts[:program]
62
+ arguments.shift
63
+ opts.delete :program
64
+ end
65
+ throw :done if arguments.empty?
66
+ flagged_elems, unflagged_params = syntax.fetch_elements
67
+ fp_occ = {}
68
+ syntax.elements.each { |e| fp_occ[e.id] = 0 if e.flagged? }
69
+ up_occ = 0
70
+ loop do
71
+ break if arguments.empty?
72
+ # puts "# %s" % arguments.first
73
+ if arguments.first === "---"
74
+ arguments.shift
75
+ break
76
+ end
77
+ if flagged_elems.has_key? arguments.first
78
+ # Flagged parameter/level.
79
+ elem = flagged_elems[arguments.first]
80
+ raise TermUtils::AP::ParseError, "parameter reached its occur limit" if elem.occur_bounded? && (fp_occ[elem.id] >= elem.max_occurs)
81
+ fp_occ[elem.id] += 1
82
+ if elem.is_a? TermUtils::AP::Parameter
83
+ arguments.shift
84
+ sub_node = node.child_node(elem.id)
85
+ sub_node = node.define_node(:key => elem.id) unless sub_node
86
+ if elem.multiple_occurs?
87
+ sub_node.child_nodes = [] if sub_node.leaf?
88
+ idx = sub_node.child_nodes.length
89
+ sub_node = sub_node.define_node(:key => idx)
90
+ end
91
+ catch :param_done do
92
+ parse0_param(sub_node, elem, arguments, opts)
93
+ end
94
+ elsif elem.is_a? TermUtils::AP::Level
95
+ arguments.shift
96
+ sub_node = node.child_node(elem.id)
97
+ sub_node = node.define_node(:key => elem.id) unless sub_node
98
+ if elem.multiple_occurs?
99
+ sub_node.child_nodes = [] if sub_node.leaf?
100
+ idx = sub_node.child_nodes.length
101
+ sub_node = sub_node.define_node(:key => idx)
102
+ end
103
+ parse0(sub_node, elem.syntax, arguments, opts)
104
+ else
105
+ raise TermUtils::AP::ParseError, "internal error - wrong kind of syntax element"
106
+ end
107
+ else
108
+ # Unflagged parameter.
109
+ raise TermUtils::AP::ParseError, "unexpected unflagged parameter" if unflagged_params.empty?
110
+ raise TermUtils::AP::ParseError, "unexpected flagged parameter" if arguments.first.start_with? "-"
111
+ elem = unflagged_params.shift
112
+ sub_node = node.child_node(elem.id)
113
+ sub_node = node.define_node(:key => elem.id) unless sub_node
114
+ if elem.multiple_occurs?
115
+ sub_node.child_nodes = [] if sub_node.leaf?
116
+ idx = sub_node.child_nodes.length
117
+ sub_node = sub_node.define_node(:key => idx)
118
+ end
119
+ catch :param_done do
120
+ occ = up_occ
121
+ up_occ = 0
122
+ parse0_param(sub_node, elem, arguments, opts)
123
+ up_occ = occ
124
+ up_occ += 1
125
+ if elem.multiple_occurs? && (!elem.occur_bounded? || (up_occ < elem.max_occurs))
126
+ unflagged_params.unshift elem
127
+ else
128
+ up_occ = 0
129
+ end
130
+ end
131
+ end
132
+ end # loop
133
+ end
134
+ def parse0_param(node, param, arguments, opts = {})
135
+ arts = param.fetch_articles
136
+ occ = 0
137
+ loop do
138
+ if arguments.empty?
139
+ raise TermUtils::AP::ParseError, "unexpected end of parameter" if !arts.empty? && (occ < arts.first.min_occurs)
140
+ raise TermUtils::AP::ParseError, "unexpected end of parameter" if !arts.empty? && (self.class.eval_article_min_occurs(arts[1..-1]) > 0)
141
+ throw :done
142
+ end
143
+ break if arts.empty?
144
+ if arguments.first == "--"
145
+ # End of parameter.
146
+ raise TermUtils::AP::ParseError, "unexpected end of parameter" if !arts.empty? && (occ < arts.first.min_occurs)
147
+ raise TermUtils::AP::ParseError, "unexpected end of parameter" if !arts.empty? && (self.class.eval_article_min_occurs(arts[1..-1]) > 0)
148
+ arguments.shift
149
+ throw :param_done
150
+ elsif arguments.first == "-"
151
+ # End of article.
152
+ raise TermUtils::AP::ParseError, "unexpected article escape" if arts.empty?
153
+ raise TermUtils::AP::ParseError, "unexpected end of parameter" if !arts.empty? && (occ < arts.first.min_occurs)
154
+ arguments.shift
155
+ arts.shift
156
+ occ = 0
157
+ next
158
+ end
159
+ art = arts.first
160
+ sub_node = node.child_node(art.id)
161
+ sub_node = node.define_node(:key => art.id) unless sub_node
162
+ if art.multiple_occurs?
163
+ sub_node.child_nodes = [] if sub_node.leaf?
164
+ idx = sub_node.child_nodes.length
165
+ sub_node = sub_node.define_node(:key => idx)
166
+ end
167
+ sub_node.value = arguments.shift
168
+ occ += 1
169
+ if !art.multiple_occurs? || (art.occur_bounded? && (occ >= art.max_occurs))
170
+ arts.shift
171
+ occ = 0
172
+ end
173
+ end # loop
174
+ end
175
+ # Evaluates the added number of min occurs of a given array of articles.
176
+ # @param articles [Array<TermUtils::AP::Article>]
177
+ # @return [Integer]
178
+ def self.eval_article_min_occurs(articles)
179
+ occs = 0
180
+ articles.each { |a| occs += a.min_occurs }
181
+ occs
182
+ end
183
+ end
184
+ end
185
+ end