help_parser 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,30 @@
1
+ @edge
2
+ Feature: Edge cases
3
+
4
+ Scenario: Redefinition of dictionary
5
+ For example, --help already maps to -h,
6
+ so if help text says different
7
+ we should get an ImplementationError.
8
+ * Given command "./examples/implementation_error_redefinition"
9
+ * Given option ""
10
+ * When we run command
11
+ * Then exception is "HELP_PARSER::ImplementationError"
12
+ * Then message matches "redefinition"
13
+
14
+ Scenario: Terminal
15
+ For example, -h defines the "user wants help" state.
16
+ If the help text tries to create another terminal state for -h,
17
+ we should get an ImplementationError.
18
+ * Given command "./examples/implementation_error_terminal"
19
+ * Given option ""
20
+ * When we run command
21
+ * Then exception is "HELP_PARSER::ImplementationError"
22
+ * Then message matches "terminal"
23
+
24
+ Scenario: Redifinition in help text
25
+ For example, it the help text says --zebra is -z and -a.
26
+ * Given command "./examples/implementation_error_duplicate_key"
27
+ * Given option ""
28
+ * When we run command
29
+ * Then exception is "HELP_PARSER::ImplementationError"
30
+ * Then message matches "redefinition"
@@ -0,0 +1,125 @@
1
+ @simple
2
+ Feature: Testing examples/simple
3
+
4
+ Background:
5
+ * Given command "./examples/simple"
6
+
7
+ Scenario: Version, short option: -v
8
+ * Given option "-v"
9
+ * When we run command
10
+ * Then exception is "HELP_PARSER::VersionException"
11
+ * Then message is "1.2.3"
12
+ * Then options[v] is "true"
13
+ * Then options[version] is "true"
14
+
15
+ Scenario: Version, long option: --version
16
+ * Given option "--version"
17
+ * When we run command
18
+ * Then exception is "HELP_PARSER::VersionException"
19
+ * Then message is "1.2.3"
20
+ * Then options[v] is "true"
21
+ * Then options[version] is "true"
22
+
23
+ Scenario: Help, short option: -h
24
+ * Given option "-h"
25
+ * When we run command
26
+ * Then exception is "HELP_PARSER::HelpException"
27
+ * Then message matches "^Usage:"
28
+ * Then options[h] is "true"
29
+ * Then options[help] is "true"
30
+
31
+ Scenario: Help, long option: --help
32
+ * Given option "--help"
33
+ * When we run command
34
+ * Then exception is "HELP_PARSER::HelpException"
35
+ * Then message matches "^Usage:"
36
+ * Then options[h] is "true"
37
+ * Then options[help] is "true"
38
+
39
+ Scenario: Duplicate with long option: -h --help
40
+ * Given option "-h --help"
41
+ * When we run command
42
+ * Then exception is "HELP_PARSER::UsageError"
43
+ * Then message matches "^duplicate"
44
+
45
+ Scenario: Duplicate with short option: --help -h
46
+ * Given option "-h --help"
47
+ * When we run command
48
+ * Then exception is "HELP_PARSER::UsageError"
49
+ * Then message matches "^duplicate"
50
+
51
+ Scenario: No options: ""
52
+ * Given option ""
53
+ * When we run command
54
+ * Then exception is ""
55
+ * Then message is ""
56
+ * Then options.empty?
57
+
58
+ Scenario: No comment: --nocomment
59
+ We don't need to comment a command line option in the help.
60
+ * Given option "--nocomment"
61
+ * When we run command
62
+ * Then exception is ""
63
+ * Then message is ""
64
+ * Then options[nocomment] is "true"
65
+ * Then options.length is 1
66
+
67
+ Scenario: Long option values, String: --long=aStringValue
68
+ * Given option "--long=aStringValue"
69
+ * When we run command
70
+ * Then options[long] is "aStringValue"
71
+
72
+ Scenario: Long option values, Integer: --long=42
73
+ * Given option "--long=42"
74
+ * When we run command
75
+ * Then options[long] is "42"
76
+ * Then options[long] kind of Integer
77
+
78
+ Scenario: Long option values, default true: --long
79
+ * Given option "--long"
80
+ * When we run command
81
+ * Then options[long] is "true"
82
+
83
+ Scenario: Long option values, negated: --no-long
84
+ * Given option "--no-long"
85
+ * When we run command
86
+ * Then options[long] is "false"
87
+
88
+ Scenario: Long option values, Array: long=1,2,3
89
+ * Given option "--long=1,2,3"
90
+ * When we run command
91
+ * Then options[long] kind of Array
92
+
93
+ Scenario: Three non synonim-ed keys: -k, -V, --nocomment
94
+ * Given options "--nocomment -k -V"
95
+ * When we run command
96
+ * Then options.length is 3
97
+ * Then options[k] is "true"
98
+ * Then options[V] is "true"
99
+ * Then options[nocomment] is "true"
100
+
101
+ Scenario: One synonim-ed key: -s
102
+ * Given options "-s"
103
+ * When we run command
104
+ * Then options.length is 2
105
+ * Then options[s] is "true"
106
+ * Then options[long] is "true"
107
+
108
+ Scenario: One synonim-ed key: --long=abc
109
+ * Given options "--long=abc"
110
+ * When we run command
111
+ * Then options.length is 2
112
+ * Then options[s] is "abc"
113
+ * Then options[long] is "abc"
114
+
115
+ Scenario: Attempting to set a negation: --no-long=NotAllowed
116
+ * Given options "--no-long=NotAllowed"
117
+ * When we run command
118
+ * Then exception is "HELP_PARSER::UsageError"
119
+ * Then message matches "no-long=NotAllowed"
120
+
121
+ Scenario: User passed undefined option: --cacahuates
122
+ * Given option "--cacahuates"
123
+ * When we run command
124
+ * Then exception is "HELP_PARSER::UsageError"
125
+ * Then message matches "not.*valid.*cacahuates"
@@ -0,0 +1,80 @@
1
+ require 'json'
2
+ require 'open3'
3
+
4
+ Given /Given command "([^"]*)"/ do |command|
5
+ @command = command
6
+ end
7
+
8
+ Given /Given option(s?) "([^"]*)"/ do |p, options|
9
+ @options = options
10
+ end
11
+
12
+ When /When we run command/ do
13
+ @stdout, @stderr, @status = Open3.capture3("#{@command} #{@options}")
14
+ begin
15
+ @json = JSON.parse @stdout
16
+ rescue StandardError
17
+ @json = {}
18
+ end
19
+ end
20
+
21
+ Then /Then exit status is "(\d+)"/ do |status|
22
+ unless @status.exit_status == status.to_i
23
+ raise "Got #{@status.exit_status} instead of #{status}"
24
+ end
25
+ end
26
+
27
+ Then /Then (\w+) is "([^"]*)"/ do |key, expected|
28
+ value = @json[key].to_s
29
+ unless value == expected
30
+ raise "Got '#{value}' instead of '#{expected}'"
31
+ end
32
+ end
33
+
34
+ Then /Then (\w+) matches "([^"]*)"/ do |key, expected|
35
+ value = @json[key]
36
+ unless value =~ /#{expected}/
37
+ raise "'#{expected}' did not match:\n#{value}"
38
+ end
39
+ end
40
+
41
+ Then /Then options\[(\w+)\] is "([^*]*)"/ do |key,expected|
42
+ options = @json['options']
43
+ value = (options)? options[key].to_s : ''
44
+ unless expected == value
45
+ raise "Got '#{value}' instead of '#{expected}'"
46
+ end
47
+ end
48
+
49
+ Then /Then options\[(\w+)\] kind of (\w+)/ do |key, type|
50
+ options = @json['options']
51
+ value = options[key]
52
+ case type
53
+ when 'Integer'
54
+ raise "Not an integer" unless value.kind_of?(Integer)
55
+ when 'Array'
56
+ raise "Not an array" unless value.kind_of?(Array)
57
+ else
58
+ raise "Unrecognized type #{type}"
59
+ end
60
+ end
61
+
62
+ Then /Then options.empty\?/ do
63
+ options = @json['options']
64
+ raise "options not empty!" unless options.empty?
65
+ end
66
+
67
+ Then /Then options.length is (\d+)/ do |expected|
68
+ expected = expected.to_i
69
+ options = @json['options']
70
+ actual = options.length
71
+ raise "Length was #{actual}, not #{expected}." unless actual == expected
72
+ end
73
+
74
+ =begin
75
+ Then // do ||
76
+ unless ==
77
+ raise "Got '#{@json['']}' instead of '#{}'"
78
+ end
79
+ end
80
+ =end
@@ -0,0 +1,131 @@
1
+ @suite
2
+ Feature: Testing examples/command_suite
3
+
4
+ Background:
5
+ * Given command "./examples/command_suite"
6
+
7
+ Scenario: Version: -v
8
+ * Given option "-v"
9
+ * When we run command
10
+ * Then message is "10.02.3"
11
+ * Then exception is "HELP_PARSER::VersionException"
12
+ * Then options[v] is "true"
13
+ * Then options[version] is "true"
14
+ * Then command is ""
15
+
16
+ Scenario: Help: --help
17
+ * Given option "--help"
18
+ * When we run command
19
+ * Then message matches "^This is a test script"
20
+ * Then exception is "HELP_PARSER::HelpException"
21
+ * Then options[h] is "true"
22
+ * Then options[help] is "true"
23
+ * Then command is ""
24
+
25
+ Scenario: First Version: first --version
26
+ * Given option "first --version"
27
+ * When we run command
28
+ * Then message is "10.02.3"
29
+ * Then exception is "HELP_PARSER::VersionException"
30
+ * Then options[v] is "true"
31
+ * Then options[version] is "true"
32
+ * Then command is "first"
33
+
34
+ Scenario: First Help: first -h
35
+ * Given option "first --h"
36
+ * When we run command
37
+ * Then message matches "^command_suite-first"
38
+ * Then exception is "HELP_PARSER::HelpException"
39
+ * Then options[h] is "true"
40
+ * Then options[help] is "true"
41
+ * Then command is "first"
42
+
43
+ Scenario: Second Version: second --version
44
+ * Given option "second --version"
45
+ * When we run command
46
+ * Then message is "10.02.3"
47
+ * Then exception is "HELP_PARSER::VersionException"
48
+ * Then options[v] is "true"
49
+ * Then options[version] is "true"
50
+ * Then command is "second"
51
+
52
+ Scenario: Second Help: second -h
53
+ * Given option "second --h"
54
+ * When we run command
55
+ * Then message matches "^command_suite-second"
56
+ * Then exception is "HELP_PARSER::HelpException"
57
+ * Then options[h] is "true"
58
+ * Then options[help] is "true"
59
+ * Then command is "second"
60
+
61
+ Scenario: ""
62
+ * Given option ""
63
+ * When we run command
64
+ * Then message is "Need command."
65
+ * Then exception is "HELP_PARSER::UsageError"
66
+
67
+ Scenario: "first"
68
+ * Given option "first"
69
+ * When we run command
70
+ #
71
+ * Then string is "string1"
72
+ * Then float is "1.0"
73
+ * Then integer is "1"
74
+ #
75
+ * Then cstring is "string1"
76
+ * Then cfloat is "1.0"
77
+ * Then cinteger is "1"
78
+ #
79
+ * Then command is "first"
80
+
81
+ Scenario: "first --string --float --integer"
82
+ * Given options "first --string --float --integer"
83
+ * When we run command
84
+ #
85
+ * Then string is "string1"
86
+ * Then float is "1.0"
87
+ * Then integer is "1"
88
+ #
89
+ * Then cstring is "string2"
90
+ * Then cfloat is "2.0"
91
+ * Then cinteger is "2"
92
+ #
93
+ * Then command is "first"
94
+
95
+ Scenario: "--string --float --integer second --string=string3 --float=3.0 --integer=3"
96
+ * Given options "--string --float --integer second --string=string3 --float=3.0 --integer=3"
97
+ * When we run command
98
+ #
99
+ * Then string is "string2"
100
+ * Then float is "2.0"
101
+ * Then integer is "2"
102
+ #
103
+ * Then cstring is "string3"
104
+ * Then cfloat is "3.0"
105
+ * Then cinteger is "3"
106
+ #
107
+ * Then command is "second"
108
+
109
+ Scenario: "--string=1 second"
110
+ * Given options "--string=1 second"
111
+ * When we run command
112
+ * Then exception is "HELP_PARSER::UsageError"
113
+ * Then message matches "^type error.*String"
114
+
115
+ Scenario: "second --integer=string"
116
+ * Given options "second --integer=string"
117
+ * When we run command
118
+ * Then exception is "HELP_PARSER::UsageError"
119
+ * Then message matches "^type error.*Fixnum"
120
+
121
+ Scenario: "first --float=1"
122
+ * Given options "first --float=1"
123
+ * When we run command
124
+ * Then exception is "HELP_PARSER::UsageError"
125
+ * Then message matches "^type error.*Float"
126
+
127
+ Scenario: "--array=seven first"
128
+ * Given options "--array=seven first"
129
+ * When we run command
130
+ * Then exception is "HELP_PARSER::UsageError"
131
+ * Then message matches "^type error.*Array"
@@ -0,0 +1,52 @@
1
+ Gem::Specification.new do |s|
2
+
3
+ s.name = 'help_parser'
4
+ s.version = '1.0.2'
5
+
6
+ s.homepage = 'https://github.com/carlosjhr64/help_parser'
7
+
8
+ s.author = 'CarlosJHR64'
9
+ s.email = 'carlosjhr64@gmail.com'
10
+
11
+ s.date = '2013-12-13'
12
+ s.licenses = ['MIT']
13
+
14
+ s.description = <<DESCRIPTION
15
+ _HelpParser_ - Parses your help text to define your command line options.
16
+ DESCRIPTION
17
+
18
+ s.summary = <<SUMMARY
19
+ _HelpParser_ - Parses your help text to define your command line options.
20
+ SUMMARY
21
+
22
+ s.extra_rdoc_files = ['README.rdoc']
23
+ s.rdoc_options = ["--main", "README.rdoc"]
24
+
25
+ s.require_paths = ["lib"]
26
+ s.files = %w(
27
+ History.txt
28
+ Manifest.txt
29
+ README.rdoc
30
+ Rakefile
31
+ TODO.txt
32
+ examples/command_suite
33
+ examples/implementation_error_duplicate_key
34
+ examples/implementation_error_redefinition
35
+ examples/implementation_error_terminal
36
+ examples/simple
37
+ features/edge.feature
38
+ features/simple.feature
39
+ features/step_definitions/help_parser_steps.rb
40
+ features/suite.feature
41
+ help_parser.gemspec
42
+ lib/help_parser.rb
43
+ lib/help_parser/help_parser.rb
44
+ lib/help_parser/version.rb
45
+ tasks/gemspecker.rb
46
+ tasks/manifester.rb
47
+ tasks/syntaxer.rb
48
+ tasks/unit_tests.rb
49
+ test/help_parser.rb
50
+ )
51
+
52
+ end
@@ -0,0 +1,2 @@
1
+ require 'help_parser/version.rb'
2
+ require 'help_parser/help_parser.rb'
@@ -0,0 +1,285 @@
1
+ module HELP_PARSER
2
+
3
+ # **UsageError** is an error when the user passed command
4
+ # line options that are inconsistent with expectations.
5
+ # The raise in a class method is as follows:
6
+ # raise UsageError, [message, self]
7
+ # The object that raised the error will be available as:
8
+ # $!.obj
9
+ class UsageError < StandardError
10
+ attr_accessor :obj
11
+ def initialize(array)
12
+ self.obj = array.pop
13
+ msg = array.pop
14
+ super(msg)
15
+ end
16
+ end
17
+ # **ImplementationError** is an error due to a
18
+ # inconsistent help text. The raise in a class method is
19
+ # as follows:
20
+ # raise ImplementationError, [message, self]
21
+ # The object that raised the error will be available as:
22
+ # $!.obj
23
+ class ImplementationError < StandardError
24
+ attr_accessor :obj
25
+ def initialize(array)
26
+ self.obj = array.pop
27
+ msg = array.pop
28
+ super(msg)
29
+ end
30
+ end
31
+
32
+ # UsageException is an actual exception to normal flow.
33
+ # For example, when a user asks for help or version
34
+ # number in the command line options. The raise in a
35
+ # class method is as follows:
36
+ # raise UsageException, [message, self]
37
+ # The object that raised the exception will be available
38
+ # as:
39
+ # $!.obj
40
+ class UsageException < Exception
41
+ attr_accessor :obj
42
+ def initialize(array)
43
+ self.obj = array.pop
44
+ msg = array.pop
45
+ super(msg)
46
+ end
47
+ end
48
+
49
+ # HelpException is a type of UsageException, where the
50
+ # user asks for help in the command line options. The
51
+ # raise in a class method is as follows:
52
+ # raise HelpException, self
53
+ # The object that raised the exception will be available
54
+ # as:
55
+ # $!.obj
56
+ # The message will be the help text:
57
+ # $!.message == $!.obj.help # => true
58
+ class HelpException < UsageException
59
+ def initialize(help_parser)
60
+ super([help_parser.help, help_parser])
61
+ end
62
+ end
63
+
64
+ # VersionException is a type of UsageException, where the
65
+ # user asks for version in the command line options. The
66
+ # raise in a class method is as follows:
67
+ # raise VersionException, self
68
+ # The object that raised the exception will be available
69
+ # as:
70
+ # $!.obj
71
+ # The message will be the version text:
72
+ # $!.message == $!.obj.version # => true
73
+ class VersionException < UsageException
74
+ def initialize(help_parser)
75
+ super([help_parser.version, help_parser])
76
+ end
77
+ end
78
+
79
+ module Errors
80
+ # HelpParser#usage_error will have make the HelpParser
81
+ # object raise a UsageError error with the given message.
82
+ def usage_error(msg)
83
+ raise UsageError, [msg, self]
84
+ end
85
+
86
+ # HelpParser#implementation_error will have make the
87
+ # HelpParser object raise a UsageError error with the
88
+ # given message.
89
+ def implementation_error(msg)
90
+ raise ImplementationError, [msg, self]
91
+ end
92
+ end
93
+
94
+ class HelpParser < Hash
95
+ include Errors
96
+
97
+ # I'm wrapping class functions in a Function module.
98
+ module Function
99
+
100
+ # I'm wrapping Function's helper functions in a Private
101
+ # module.
102
+ module Private
103
+ # HelpParser::Function::Private.to_value
104
+ def to_value(string)
105
+ case string
106
+ when /^-?\d+$/
107
+ return string.to_i
108
+ when /^-?\d+\.\d+$/
109
+ return string.to_f
110
+ when /,/
111
+ return string.split(',').map{|s| to_value(s)}
112
+ end
113
+ return string
114
+ end
115
+ end
116
+ extend Private
117
+
118
+ # HelpParser::Function.str2sym converts String keys to
119
+ # Symbol. Symbol keys can have '-', but it's cumbersome
120
+ # notation:
121
+ # :"a-b"
122
+ # So I translate it to underscore:
123
+ # :a_b
124
+ def str2sym(str)
125
+ str.gsub('-','_').to_sym
126
+ end
127
+
128
+ # HelpParser#parse parses the @argv for command line
129
+ # options, shifting them out, and passes on the key-value
130
+ # pairs to the block. The keys are translated to their
131
+ # short version if available, and the values are converted
132
+ # to their best interpreted form as per Funtion.to_value.
133
+ # Furthermore, no-key values are negated.
134
+ def parse(argv, obj, &block)
135
+ while argv[0] and argv[0][0]=='-'
136
+ option = argv.shift[1..-1]
137
+ if option[0]=='-'
138
+ loption, value = option[1..-1].split('=', 2)
139
+ if loption=~/no-(\w.*)$/
140
+ loption = $1
141
+ if value
142
+ raise UsageError, ["no-key should not have value: no-#{loption}=#{value}", obj]
143
+ end
144
+ value = false
145
+ end
146
+ if value.nil?
147
+ value = true
148
+ block.call loption, value
149
+ else
150
+ block.call loption, Function.to_value(value)
151
+ end
152
+ else
153
+ # These are single character options...
154
+ option.each_char do |c|
155
+ block.call c, true
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+ extend Function
162
+
163
+ def parse(&block)
164
+ HelpParser.parse(@argv, self, &block)
165
+ end
166
+
167
+
168
+ # HelpParser.new(version, help, argv=ARGV, dict={})
169
+ # Not necessarily in that order, see the code.
170
+ attr_reader :version, :help, :dict
171
+ def initialize(*parameters)
172
+ super()
173
+
174
+ # Figure out what parameters you were given...
175
+ @argv = parameters.detect{|parameter| parameter.class == Array} || ARGV
176
+ @dict = parameters.detect{|parameter| parameter.class == Hash } || {}
177
+ parameters = parameters.select{|parameter| parameter.class == String}
178
+ @version = parameters.shift
179
+ @help = parameters.pop
180
+
181
+ raise "Need help" unless @help
182
+ raise "Need version" unless @version
183
+
184
+ # We ensure the following two mappings...
185
+ @dict[:help] = :h
186
+ @dict[:version] = :v
187
+
188
+ # Using the help for the options definition
189
+ @help.split("\n").select{|l|
190
+ (l=~/^\s*-/)
191
+ }.map{|l|
192
+ l.strip.split(/[,\s]+/)[0..1].select{|o|
193
+ o[0]=='-'
194
+ }.map{|o|
195
+ HelpParser.str2sym o.sub(/--?/,'').sub(/=.*$/,'')
196
+ }.reverse
197
+ }.each do |k,v|
198
+ unless @dict[k].nil?
199
+ # This is an implementation error. The help text is inconsistent.
200
+ # Note that we may have been given @dict, and we're verifying the help.
201
+ implementation_error "#{k} redefinition from #{@dict[k]} to #{v}." unless @dict[k]==v
202
+ end
203
+ @dict[k]=v
204
+ end
205
+
206
+ # Values must be terminal states, that is for example:
207
+ # if :version => :v, then :v => nil.
208
+ terminals = []
209
+ @dict.each do |k,v|
210
+ next if v.nil?
211
+ if @dict.has_key?(v)
212
+ unless @dict[v].nil?
213
+ implementation_error "Expected terminal #{v}: #{k} => #{v} => #{@dict[v]}"
214
+ end
215
+ else
216
+ terminals.push(v)
217
+ end
218
+ end
219
+ terminals.each{|v| @dict[v] = nil}
220
+
221
+ # Parsing command line options
222
+ parse do |opt, value|
223
+ key = HelpParser.str2sym opt
224
+ # Translate key to the terminal key.
225
+ key = @dict[key] unless @dict[key].nil?
226
+ # Ensure user only uses the defined keys.
227
+ usage_error "not a valid option: #{opt}" unless @dict.has_key?(key)
228
+ # As we parse ARGV, we should only be setting keys once.
229
+ usage_error "duplicate command line option: #{opt}" if self.has_key?(key)
230
+ self[key] = value
231
+ end
232
+
233
+ # The parse takes all options to its terminal value.
234
+ # Now set the synonims...
235
+ @dict.each do |synonim, terminal|
236
+ next if terminal.nil?
237
+ if self.has_key?(terminal)
238
+ # I did not mean for the synonyms to have been set yet, so if I do,
239
+ # I have a bug somewhere.
240
+ raise "unexpected key overwrite" if self.has_key?(synonim)
241
+ self[synonim] = self[terminal]
242
+ end
243
+ end
244
+
245
+ # Did the user ask for help or version?
246
+ raise HelpException, self if self[:h]==true
247
+ raise VersionException, self if self[:v]==true
248
+ end
249
+
250
+ # HelpParser#defaults is a helper method to []
251
+ def defaults(symbol, default1, default2=default1)
252
+ type = (default2 || default1).class
253
+ a = self[symbol]
254
+ value = (a.nil?)? default1 : a
255
+ value = default2 if value==true
256
+ # !value is true if value is false or nil.
257
+ usage_error "type error: #{symbol} needs to be #{type}" unless !value or value.class == type
258
+ return value
259
+ end
260
+
261
+ # HelpParser#defaults! is used to replace value with a
262
+ # default in the hash, self.
263
+ def defaults!(symbol, default1, default2)
264
+ self[symbol] = defaults(symbol, default1, default2)
265
+ end
266
+
267
+ # HelpParser#[k, default1=nil, default2=nil]
268
+ # Basically, for #[k, default1, default2]:
269
+ # value = help_parser[k]
270
+ # case value
271
+ # when nil then default1
272
+ # when true then default2
273
+ # else value
274
+ # end
275
+ # For #[k, default1]:
276
+ # value = help_parser[k] || default1
277
+ # For #[k]:
278
+ # help_parser[k]
279
+ # Raises a UsageError if the value is not of the expected
280
+ # type as given by the last default.
281
+ def [](k, *defaults12)
282
+ (defaults12.length==0)? super(k) : defaults(k, *defaults12)
283
+ end
284
+ end
285
+ end