opt_parse_validator 0.0.11 → 0.0.12
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/lib/opt_parse_validator/errors.rb +4 -1
- data/lib/opt_parse_validator/options_file.rb +2 -2
- data/lib/opt_parse_validator/opts/array.rb +5 -0
- data/lib/opt_parse_validator/opts/base.rb +18 -2
- data/lib/opt_parse_validator/opts/boolean.rb +1 -1
- data/lib/opt_parse_validator/opts/choice.rb +14 -3
- data/lib/opt_parse_validator/opts/credentials.rb +1 -1
- data/lib/opt_parse_validator/opts/file_path.rb +1 -1
- data/lib/opt_parse_validator/opts/integer.rb +1 -1
- data/lib/opt_parse_validator/opts/integer_range.rb +13 -3
- data/lib/opt_parse_validator/opts/multi_choices.rb +56 -10
- data/lib/opt_parse_validator/opts/path.rb +5 -5
- data/lib/opt_parse_validator/opts/positive_integer.rb +1 -1
- data/lib/opt_parse_validator/opts/uri.rb +7 -0
- data/lib/opt_parse_validator/version.rb +1 -1
- data/lib/opt_parse_validator.rb +14 -3
- data/opt_parse_validator.gemspec +5 -4
- metadata +26 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43def9fd548b86ee8844a86c29be72114c4084d1
|
4
|
+
data.tar.gz: 4c7e6bf5a5013eb6f3a4a2461a8e1bc5781a2099
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0139f362ac63532f3fc770809f7e68a8db764c40dbc5fcb1463bd64abd832334b09236cb6dc7871424a08c863e179a2dc49929212802da81877d704f9b7984d6
|
7
|
+
data.tar.gz: bb6f8190fd84d757212fbb5c0aa7d97bd3255c3b5c6b327cbfb89167fada4fd437b7d46d63c4d7c0e00324b2785790413e68b3e044d973b55a349c34558b0604
|
@@ -36,12 +36,12 @@ module OptParseValidator
|
|
36
36
|
file_ext = File.extname(file_path).delete('.')
|
37
37
|
method_to_call = "parse_#{file_ext}"
|
38
38
|
|
39
|
-
fail "The format #{file_ext} is not supported" unless respond_to?(method_to_call, true) # The true allows to check protected & private methods
|
39
|
+
fail Error, "The format #{file_ext} is not supported" unless respond_to?(method_to_call, true) # The true allows to check protected & private methods
|
40
40
|
|
41
41
|
begin
|
42
42
|
method(method_to_call).call(file_path)
|
43
43
|
rescue
|
44
|
-
raise "Parse Error, #{file_path} seems to be malformed"
|
44
|
+
raise Error, "Parse Error, #{file_path} seems to be malformed"
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -1,6 +1,11 @@
|
|
1
1
|
module OptParseValidator
|
2
2
|
# Implementation of the Array Option
|
3
3
|
class OptArray < OptBase
|
4
|
+
# @return [ Void ]
|
5
|
+
def append_help_messages
|
6
|
+
option << "Separator to use between the values: '#{separator}'"
|
7
|
+
end
|
8
|
+
|
4
9
|
# @param [ String ] value
|
5
10
|
#
|
6
11
|
# @return [ Array ]
|
@@ -17,6 +17,13 @@ module OptParseValidator
|
|
17
17
|
def initialize(option, attrs = {})
|
18
18
|
@option = option
|
19
19
|
@attrs = attrs
|
20
|
+
|
21
|
+
append_help_messages if respond_to?(:append_help_messages)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [ Void ]
|
25
|
+
def append_help_messages
|
26
|
+
option << "Default: #{default}" if default
|
20
27
|
end
|
21
28
|
|
22
29
|
# @return [ Boolean ]
|
@@ -46,7 +53,7 @@ module OptParseValidator
|
|
46
53
|
# @param [ String ] value
|
47
54
|
def validate(value)
|
48
55
|
if value.nil? || value.to_s.empty?
|
49
|
-
fail 'Empty option value supplied' if value_if_empty.nil?
|
56
|
+
fail Error, 'Empty option value supplied' if value_if_empty.nil?
|
50
57
|
return value_if_empty
|
51
58
|
end
|
52
59
|
value
|
@@ -76,7 +83,7 @@ module OptParseValidator
|
|
76
83
|
unless @symbol
|
77
84
|
long_option = to_long
|
78
85
|
|
79
|
-
fail "Could not find option symbol for #{option}" unless long_option
|
86
|
+
fail Error, "Could not find option symbol for #{option}" unless long_option
|
80
87
|
|
81
88
|
@symbol = long_option.gsub(/^--/, '').gsub(/-/, '_').to_sym
|
82
89
|
end
|
@@ -98,5 +105,14 @@ module OptParseValidator
|
|
98
105
|
def to_s
|
99
106
|
to_sym.to_s
|
100
107
|
end
|
108
|
+
|
109
|
+
# @return [ Array<String> ]
|
110
|
+
def help_messages
|
111
|
+
first_message_index = option.index { |e| e[0] != '-' }
|
112
|
+
|
113
|
+
return [] unless first_message_index
|
114
|
+
|
115
|
+
option[first_message_index..-1]
|
116
|
+
end
|
101
117
|
end
|
102
118
|
end
|
@@ -6,12 +6,23 @@ module OptParseValidator
|
|
6
6
|
# :choices [ Array ] The available choices (mandatory)
|
7
7
|
# :case_sensitive [ Boolean ] Default: false
|
8
8
|
def initialize(option, attrs = {})
|
9
|
-
fail 'The :choices attribute is mandatory' unless attrs.key?(:choices)
|
10
|
-
fail 'The :choices attribute must be an array' unless attrs[:choices].is_a?(Array)
|
9
|
+
fail Error, 'The :choices attribute is mandatory' unless attrs.key?(:choices)
|
10
|
+
fail Error, 'The :choices attribute must be an array' unless attrs[:choices].is_a?(Array)
|
11
11
|
|
12
12
|
super(option, attrs)
|
13
13
|
end
|
14
14
|
|
15
|
+
# @return [ Void ]
|
16
|
+
def append_help_messages
|
17
|
+
msg = 'Available choices:'
|
18
|
+
|
19
|
+
choices.each do |choice|
|
20
|
+
msg += choice.to_s == default ? " #{choice} (default)," : " #{choice},"
|
21
|
+
end
|
22
|
+
|
23
|
+
option << msg[0..-2]
|
24
|
+
end
|
25
|
+
|
15
26
|
# @return [ String ]
|
16
27
|
# If :case_sensitive if false (or nil), the downcased value of the choice
|
17
28
|
# will be returned
|
@@ -23,7 +34,7 @@ module OptParseValidator
|
|
23
34
|
choices.map!(&:downcase)
|
24
35
|
end
|
25
36
|
|
26
|
-
fail "'#{value}' is not a valid choice, expected one " \
|
37
|
+
fail Error, "'#{value}' is not a valid choice, expected one " \
|
27
38
|
"of the followings: #{choices.join(',')}" unless choices.include?(value)
|
28
39
|
|
29
40
|
value
|
@@ -4,7 +4,7 @@ module OptParseValidator
|
|
4
4
|
# @return [ Hash ] A hash containing the :username and :password
|
5
5
|
def validate(value)
|
6
6
|
unless value.index(':')
|
7
|
-
fail 'Incorrect credentials format, username:password expected'
|
7
|
+
fail Error, 'Incorrect credentials format, username:password expected'
|
8
8
|
end
|
9
9
|
creds = value.split(':', 2)
|
10
10
|
|
@@ -1,16 +1,26 @@
|
|
1
1
|
module OptParseValidator
|
2
2
|
# Implementation of the Integer Range Option
|
3
3
|
class OptIntegerRange < OptBase
|
4
|
+
# @return [ Void ]
|
5
|
+
def append_help_messages
|
6
|
+
option << "Range separator to use: '#{separator}'"
|
7
|
+
option << "If no range is supplied, #{value_if_empty} will be used" if value_if_empty
|
8
|
+
end
|
9
|
+
|
4
10
|
# @param [ String ] value
|
5
11
|
#
|
6
12
|
# @return [ Range ]
|
7
13
|
def validate(value)
|
8
14
|
a = super(value).split(separator)
|
9
15
|
|
10
|
-
fail "Incorrect number of ranges found: #{a.size}, should be 2" unless a.size == 2
|
11
|
-
|
16
|
+
fail Error, "Incorrect number of ranges found: #{a.size}, should be 2" unless a.size == 2
|
17
|
+
|
18
|
+
first_integer = a.first.to_i
|
19
|
+
last_integer = a.last.to_i
|
20
|
+
|
21
|
+
fail Error, 'Argument is not a valid integer range' unless first_integer.to_s == a.first && last_integer.to_s == a.last
|
12
22
|
|
13
|
-
(
|
23
|
+
(first_integer..last_integer)
|
14
24
|
end
|
15
25
|
|
16
26
|
# @return [ String ]
|
@@ -7,12 +7,53 @@ module OptParseValidator
|
|
7
7
|
# @option attrs [ Array<Array> ] :incompatible
|
8
8
|
# @options attrs [ String ] :separator See OptArray#new
|
9
9
|
def initialize(option, attrs = {})
|
10
|
-
fail 'The :choices attribute is mandatory' unless attrs.key?(:choices)
|
11
|
-
fail 'The :choices attribute must be a hash' unless attrs[:choices].is_a?(Hash)
|
10
|
+
fail Error, 'The :choices attribute is mandatory' unless attrs.key?(:choices)
|
11
|
+
fail Error, 'The :choices attribute must be a hash' unless attrs[:choices].is_a?(Hash)
|
12
12
|
|
13
13
|
super(option, attrs)
|
14
14
|
end
|
15
15
|
|
16
|
+
def append_help_messages
|
17
|
+
option << 'Available Choices:'
|
18
|
+
|
19
|
+
append_choices_help_messages
|
20
|
+
|
21
|
+
option << "Multiple choices can be supplied, use the '#{separator}' char as a separator"
|
22
|
+
option << "If no choice is supplied, '#{value_if_empty}' will be used" if value_if_empty
|
23
|
+
|
24
|
+
append_incomptable_help_messages
|
25
|
+
end
|
26
|
+
|
27
|
+
def append_choices_help_messages
|
28
|
+
max_spaces = choices.keys.max.size
|
29
|
+
|
30
|
+
choices.each do |key, opt|
|
31
|
+
first_line_prefix = " #{key} #{' ' * (max_spaces - key.length)}"
|
32
|
+
other_lines_prefix = ' ' * first_line_prefix.size
|
33
|
+
|
34
|
+
opt_help_messages(opt).each_with_index do |message, index|
|
35
|
+
option << "#{index == 0 ? first_line_prefix : other_lines_prefix} #{message}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param [ OptBase ] opt
|
41
|
+
#
|
42
|
+
# @return [ Array<String> ]
|
43
|
+
def opt_help_messages(opt)
|
44
|
+
opt.help_messages.empty? ? [opt.to_s.humanize] : opt.help_messages
|
45
|
+
end
|
46
|
+
|
47
|
+
def append_incomptable_help_messages
|
48
|
+
return if incompatible.empty?
|
49
|
+
|
50
|
+
option << 'Incompatible choices (only one of each group/s can be used):'
|
51
|
+
|
52
|
+
incompatible.each do |a|
|
53
|
+
option << " - #{a.map(&:to_s).join(', ')}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
16
57
|
# @param [ String ] value
|
17
58
|
#
|
18
59
|
# @return [ Hash ]
|
@@ -42,24 +83,29 @@ module OptParseValidator
|
|
42
83
|
return [opt, Regexp.last_match[1]]
|
43
84
|
end
|
44
85
|
|
45
|
-
fail "Unknown choice: #{item}"
|
86
|
+
fail Error, "Unknown choice: #{item}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [ Array<Array<Symbol>> ]
|
90
|
+
def incompatible
|
91
|
+
[*attrs[:incompatible]]
|
46
92
|
end
|
47
93
|
|
48
94
|
# @param [ Hash ] values
|
49
95
|
#
|
50
96
|
# @return [ Hash ]
|
51
97
|
def verify_compatibility(values)
|
52
|
-
|
98
|
+
incompatible.each do |a|
|
53
99
|
last_match = ''
|
54
100
|
|
55
|
-
a.each do |
|
101
|
+
a.each do |key|
|
102
|
+
sym = choices[key].to_sym
|
103
|
+
|
56
104
|
next unless values.key?(sym)
|
57
105
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
fail "Incompatible choices detected: #{last_match}, #{sym}"
|
62
|
-
end
|
106
|
+
fail Error, "Incompatible choices detected: #{last_match}, #{key}" unless last_match.empty?
|
107
|
+
|
108
|
+
last_match = key
|
63
109
|
end
|
64
110
|
end
|
65
111
|
values
|
@@ -32,22 +32,22 @@ module OptParseValidator
|
|
32
32
|
|
33
33
|
# @param [ Pathname ] path
|
34
34
|
def check_file(path)
|
35
|
-
fail "'#{path}' is not a file" unless path.file? || attrs[:exists] == false
|
35
|
+
fail Error, "'#{path}' is not a file" unless path.file? || attrs[:exists] == false
|
36
36
|
end
|
37
37
|
|
38
38
|
# @param [ Pathname ] path
|
39
39
|
def check_directory(path)
|
40
|
-
fail "'#{path}' is not a directory" unless path.directory? || attrs[:exists] == false
|
40
|
+
fail Error, "'#{path}' is not a directory" unless path.directory? || attrs[:exists] == false
|
41
41
|
end
|
42
42
|
|
43
43
|
# @param [ Pathname ] path
|
44
44
|
def check_executable(path)
|
45
|
-
fail "'#{path}' is not executable" unless path.executable?
|
45
|
+
fail Error, "'#{path}' is not executable" unless path.executable?
|
46
46
|
end
|
47
47
|
|
48
48
|
# @param [ Pathname ] path
|
49
49
|
def check_readable(path)
|
50
|
-
fail "'#{path}' is not readable" unless path.readable?
|
50
|
+
fail Error, "'#{path}' is not readable" unless path.readable?
|
51
51
|
end
|
52
52
|
|
53
53
|
# If the path does not exist, it will check for the parent
|
@@ -55,7 +55,7 @@ module OptParseValidator
|
|
55
55
|
#
|
56
56
|
# @param [ Pathname ] path
|
57
57
|
def check_writable(path)
|
58
|
-
fail "'#{path}' is not writable" if path.exist? && !path.writable? || !path.parent.writable?
|
58
|
+
fail Error, "'#{path}' is not writable" if path.exist? && !path.writable? || !path.parent.writable?
|
59
59
|
end
|
60
60
|
end
|
61
61
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
module OptParseValidator
|
2
2
|
# Implementation of the URI Option
|
3
3
|
class OptURI < OptBase
|
4
|
+
# return [ Void ]
|
5
|
+
def append_help_messages
|
6
|
+
option << "Allowed Protocols: #{allowed_protocols.join(', ')}" unless allowed_protocols.empty?
|
7
|
+
option << "Default Protocol if none provided: #{default_protocol}" if default_protocol
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [ Array<String> ]
|
4
11
|
def allowed_protocols
|
5
12
|
@allowed_protocols ||= [*attrs[:protocols]]
|
6
13
|
end
|
data/lib/opt_parse_validator.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Gems
|
2
2
|
require 'addressable/uri'
|
3
|
+
require 'active_support/inflector'
|
3
4
|
# Standard Libs
|
4
5
|
require 'optparse'
|
5
6
|
require 'pathname'
|
@@ -35,8 +36,7 @@ module OptParseValidator
|
|
35
36
|
#
|
36
37
|
# @return [ void ]
|
37
38
|
def add_option(opt)
|
38
|
-
|
39
|
-
fail "The option #{opt.to_sym} is already used !" if @symbols_used.include?(opt.to_sym)
|
39
|
+
check_option(opt)
|
40
40
|
|
41
41
|
@opts << opt
|
42
42
|
@symbols_used << opt.to_sym
|
@@ -48,12 +48,23 @@ module OptParseValidator
|
|
48
48
|
@results[opt.to_sym] = opt.normalize(opt.validate(arg))
|
49
49
|
rescue => e
|
50
50
|
# Adds the long option name to the message
|
51
|
+
# And raises it as an OptParseValidator::Error if not already one
|
51
52
|
# e.g --proxy Invalid Scheme format.
|
52
|
-
raise e.class, "#{opt.to_long} #{e}"
|
53
|
+
raise e.is_a?(Error) ? e.class : Error, "#{opt.to_long} #{e}"
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
56
57
|
|
58
|
+
# Ensures the opt given is valid
|
59
|
+
#
|
60
|
+
# @param [ OptBase ] opt
|
61
|
+
#
|
62
|
+
# @return [ void ]
|
63
|
+
def check_option(opt)
|
64
|
+
fail Error, "The option is not an OptBase, #{opt.class} supplied" unless opt.is_a?(OptBase)
|
65
|
+
fail Error, "The option #{opt.to_sym} is already used !" if @symbols_used.include?(opt.to_sym)
|
66
|
+
end
|
67
|
+
|
57
68
|
# @return [ Hash ]
|
58
69
|
def results(argv = default_argv)
|
59
70
|
load_options_files
|
data/opt_parse_validator.gemspec
CHANGED
@@ -32,11 +32,12 @@ Gem::Specification.new do |s|
|
|
32
32
|
s.require_paths = ['lib']
|
33
33
|
|
34
34
|
s.add_dependency 'addressable', '~> 2.3'
|
35
|
+
s.add_dependency 'activesupport', '~> 4.2'
|
35
36
|
|
36
37
|
s.add_development_dependency 'rake', '~> 10.4'
|
37
|
-
s.add_development_dependency 'rspec', '~> 3.
|
38
|
-
s.add_development_dependency 'rspec-its', '~> 1.
|
38
|
+
s.add_development_dependency 'rspec', '~> 3.3'
|
39
|
+
s.add_development_dependency 'rspec-its', '~> 1.2'
|
39
40
|
s.add_development_dependency 'bundler', '~> 1.6'
|
40
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
41
|
-
s.add_development_dependency 'simplecov', '~> 0.
|
41
|
+
s.add_development_dependency 'rubocop', '~> 0.32'
|
42
|
+
s.add_development_dependency 'simplecov', '~> 0.10'
|
42
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: opt_parse_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WPScanTeam - Erwan le Rousseau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-07-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '4.2'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.2'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rake
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,28 +58,28 @@ dependencies:
|
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
61
|
+
version: '3.3'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
68
|
+
version: '3.3'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec-its
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
73
|
- - "~>"
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version: '1.
|
75
|
+
version: '1.2'
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
80
|
- - "~>"
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version: '1.
|
82
|
+
version: '1.2'
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: bundler
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,28 +100,28 @@ dependencies:
|
|
86
100
|
requirements:
|
87
101
|
- - "~>"
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '0.
|
103
|
+
version: '0.32'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - "~>"
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '0.
|
110
|
+
version: '0.32'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: simplecov
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
100
114
|
requirements:
|
101
115
|
- - "~>"
|
102
116
|
- !ruby/object:Gem::Version
|
103
|
-
version: '0.
|
117
|
+
version: '0.10'
|
104
118
|
type: :development
|
105
119
|
prerelease: false
|
106
120
|
version_requirements: !ruby/object:Gem::Requirement
|
107
121
|
requirements:
|
108
122
|
- - "~>"
|
109
123
|
- !ruby/object:Gem::Version
|
110
|
-
version: '0.
|
124
|
+
version: '0.10'
|
111
125
|
description: Testing Gem ...
|
112
126
|
email:
|
113
127
|
- erwan.lr@gmail.com
|
@@ -162,8 +176,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
176
|
version: '0'
|
163
177
|
requirements: []
|
164
178
|
rubyforge_project:
|
165
|
-
rubygems_version: 2.4.
|
179
|
+
rubygems_version: 2.4.8
|
166
180
|
signing_key:
|
167
181
|
specification_version: 4
|
168
182
|
summary: Testing Gem
|
169
183
|
test_files: []
|
184
|
+
has_rdoc:
|