gli_aziz_light 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (104) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +13 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +17 -0
  6. data/CONTRIBUTING.md +23 -0
  7. data/Gemfile +8 -0
  8. data/LICENSE.txt +201 -0
  9. data/ObjectModel.graffle +1191 -0
  10. data/README.rdoc +109 -0
  11. data/Rakefile +126 -0
  12. data/bin/gli +59 -0
  13. data/bin/report_on_rake_results +10 -0
  14. data/bin/test_all_rubies.sh +6 -0
  15. data/features/gli_executable.feature +90 -0
  16. data/features/gli_init.feature +232 -0
  17. data/features/step_definitions/gli_executable_steps.rb +18 -0
  18. data/features/step_definitions/gli_init_steps.rb +11 -0
  19. data/features/step_definitions/todo_steps.rb +88 -0
  20. data/features/support/env.rb +53 -0
  21. data/features/todo.feature +413 -0
  22. data/features/todo_legacy.feature +128 -0
  23. data/gli.cheat +95 -0
  24. data/gli.gemspec +34 -0
  25. data/gli.rdoc +73 -0
  26. data/lib/gli.rb +35 -0
  27. data/lib/gli/app.rb +286 -0
  28. data/lib/gli/app_support.rb +341 -0
  29. data/lib/gli/command.rb +171 -0
  30. data/lib/gli/command_finder.rb +41 -0
  31. data/lib/gli/command_line_option.rb +34 -0
  32. data/lib/gli/command_line_token.rb +63 -0
  33. data/lib/gli/command_support.rb +181 -0
  34. data/lib/gli/commands/compound_command.rb +42 -0
  35. data/lib/gli/commands/doc.rb +231 -0
  36. data/lib/gli/commands/help.rb +95 -0
  37. data/lib/gli/commands/help_modules/arg_name_formatter.rb +20 -0
  38. data/lib/gli/commands/help_modules/command_finder.rb +60 -0
  39. data/lib/gli/commands/help_modules/command_help_format.rb +156 -0
  40. data/lib/gli/commands/help_modules/global_help_format.rb +70 -0
  41. data/lib/gli/commands/help_modules/help_completion_format.rb +31 -0
  42. data/lib/gli/commands/help_modules/list_formatter.rb +23 -0
  43. data/lib/gli/commands/help_modules/one_line_wrapper.rb +18 -0
  44. data/lib/gli/commands/help_modules/options_formatter.rb +49 -0
  45. data/lib/gli/commands/help_modules/text_wrapper.rb +53 -0
  46. data/lib/gli/commands/help_modules/tty_only_wrapper.rb +23 -0
  47. data/lib/gli/commands/help_modules/verbatim_wrapper.rb +16 -0
  48. data/lib/gli/commands/initconfig.rb +74 -0
  49. data/lib/gli/commands/rdoc_document_listener.rb +116 -0
  50. data/lib/gli/commands/scaffold.rb +401 -0
  51. data/lib/gli/dsl.rb +226 -0
  52. data/lib/gli/exceptions.rb +71 -0
  53. data/lib/gli/flag.rb +68 -0
  54. data/lib/gli/gli_option_block_parser.rb +84 -0
  55. data/lib/gli/gli_option_parser.rb +156 -0
  56. data/lib/gli/option_parser_factory.rb +81 -0
  57. data/lib/gli/option_parsing_result.rb +21 -0
  58. data/lib/gli/options.rb +23 -0
  59. data/lib/gli/switch.rb +35 -0
  60. data/lib/gli/terminal.rb +101 -0
  61. data/lib/gli/version.rb +5 -0
  62. data/test/apps/README.md +2 -0
  63. data/test/apps/todo/Gemfile +2 -0
  64. data/test/apps/todo/README.rdoc +6 -0
  65. data/test/apps/todo/Rakefile +23 -0
  66. data/test/apps/todo/bin/todo +63 -0
  67. data/test/apps/todo/lib/todo/commands/create.rb +24 -0
  68. data/test/apps/todo/lib/todo/commands/list.rb +63 -0
  69. data/test/apps/todo/lib/todo/commands/ls.rb +47 -0
  70. data/test/apps/todo/lib/todo/commands/make.rb +52 -0
  71. data/test/apps/todo/lib/todo/version.rb +3 -0
  72. data/test/apps/todo/test/tc_nothing.rb +14 -0
  73. data/test/apps/todo/todo.gemspec +23 -0
  74. data/test/apps/todo/todo.rdoc +5 -0
  75. data/test/apps/todo_legacy/Gemfile +2 -0
  76. data/test/apps/todo_legacy/README.rdoc +6 -0
  77. data/test/apps/todo_legacy/Rakefile +23 -0
  78. data/test/apps/todo_legacy/bin/todo +61 -0
  79. data/test/apps/todo_legacy/lib/todo/commands/create.rb +24 -0
  80. data/test/apps/todo_legacy/lib/todo/commands/list.rb +63 -0
  81. data/test/apps/todo_legacy/lib/todo/commands/ls.rb +47 -0
  82. data/test/apps/todo_legacy/lib/todo/version.rb +3 -0
  83. data/test/apps/todo_legacy/test/tc_nothing.rb +14 -0
  84. data/test/apps/todo_legacy/todo.gemspec +23 -0
  85. data/test/apps/todo_legacy/todo.rdoc +5 -0
  86. data/test/apps/todo_plugins/commands/third.rb +1 -0
  87. data/test/config.yaml +10 -0
  88. data/test/fake_std_out.rb +30 -0
  89. data/test/init_simplecov.rb +8 -0
  90. data/test/option_test_helper.rb +13 -0
  91. data/test/tc_command.rb +508 -0
  92. data/test/tc_compound_command.rb +22 -0
  93. data/test/tc_doc.rb +325 -0
  94. data/test/tc_flag.rb +62 -0
  95. data/test/tc_gli.rb +773 -0
  96. data/test/tc_help.rb +387 -0
  97. data/test/tc_options.rb +43 -0
  98. data/test/tc_subcommand_parsing.rb +104 -0
  99. data/test/tc_subcommands.rb +260 -0
  100. data/test/tc_switch.rb +55 -0
  101. data/test/tc_terminal.rb +100 -0
  102. data/test/tc_verbatim_wrapper.rb +36 -0
  103. data/test/test_helper.rb +20 -0
  104. metadata +330 -0
@@ -0,0 +1,387 @@
1
+ require 'test_helper'
2
+
3
+ class TC_testHelp < Clean::Test::TestCase
4
+ include TestHelper
5
+
6
+ def setup
7
+ @option_index = 0
8
+ @real_columns = ENV['COLUMNS']
9
+ ENV['COLUMNS'] = '1024'
10
+ @output = StringIO.new
11
+ @error = StringIO.new
12
+ @command_names_used = []
13
+ # Reset help command to its default state
14
+ GLI::Commands::Help.skips_pre = true
15
+ GLI::Commands::Help.skips_post = true
16
+ GLI::Commands::Help.skips_around = true
17
+ end
18
+
19
+ def teardown
20
+ ENV['COLUMNS'] = @real_columns
21
+ end
22
+
23
+ class TestApp
24
+ include GLI::App
25
+ end
26
+
27
+ test_that "the help command is configured properly when created" do
28
+ Given {
29
+ app = TestApp.new
30
+ app.subcommand_option_handling :normal
31
+ @command = GLI::Commands::Help.new(app,@output,@error)
32
+ }
33
+ Then {
34
+ assert_equal 'help',@command.name.to_s
35
+ assert_nil @command.aliases
36
+ assert_equal 'command',@command.arguments_description
37
+ assert_not_nil @command.description
38
+ assert_not_nil @command.long_description
39
+ assert @command.skips_pre
40
+ assert @command.skips_post
41
+ assert @command.skips_around
42
+ }
43
+ end
44
+
45
+ test_that "the help command can be configured to skip things declaratively" do
46
+ Given {
47
+ app = TestApp.new
48
+ app.subcommand_option_handling :normal
49
+ @command = GLI::Commands::Help.new(app,@output,@error)
50
+ GLI::Commands::Help.skips_pre = false
51
+ GLI::Commands::Help.skips_post = false
52
+ GLI::Commands::Help.skips_around = false
53
+ }
54
+ Then {
55
+ assert !@command.skips_pre
56
+ assert !@command.skips_post
57
+ assert !@command.skips_around
58
+ }
59
+ end
60
+
61
+ test_that "the help command can be configured to skip things declaratively regardless of when it the object was created" do
62
+ Given {
63
+ GLI::Commands::Help.skips_pre = false
64
+ GLI::Commands::Help.skips_post = false
65
+ GLI::Commands::Help.skips_around = false
66
+ app = TestApp.new
67
+ app.subcommand_option_handling :normal
68
+ @command = GLI::Commands::Help.new(app,@output,@error)
69
+ }
70
+ Then {
71
+ assert !@command.skips_pre
72
+ assert !@command.skips_post
73
+ assert !@command.skips_around
74
+ }
75
+ end
76
+
77
+ test_that "invoking help with no arguments results in listing all commands and global options" do
78
+ Given a_GLI_app
79
+ And {
80
+ @command = GLI::Commands::Help.new(@app,@output,@error)
81
+ }
82
+ When {
83
+ @command.execute({},{},[])
84
+ }
85
+ Then {
86
+ assert_top_level_help_output
87
+ }
88
+ end
89
+
90
+ test_that "invoking help with a command that doesn't exist shows an error" do
91
+ Given a_GLI_app
92
+ And {
93
+ @command = GLI::Commands::Help.new(@app,@output,@error)
94
+ @unknown_command_name = any_command_name
95
+ }
96
+ When {
97
+ @command.execute({},{},[@unknown_command_name])
98
+ }
99
+ Then {
100
+ assert_error_contained(/error: Unknown command '#{@unknown_command_name}'./)
101
+ }
102
+ end
103
+
104
+ test_that "invoking help with a known command shows help for that command" do
105
+ Given a_GLI_app
106
+ And {
107
+ @command_name = cm = any_command_name
108
+ @desc = d = any_desc
109
+ @long_desc = ld = any_desc
110
+ @switch = s = any_option
111
+ @switch_desc = sd = any_desc
112
+ @flag = f = any_option
113
+ @flag_desc = fd = any_desc
114
+
115
+ @app.instance_eval do
116
+ desc d
117
+ long_desc ld
118
+ command cm do |c|
119
+
120
+ c.desc sd
121
+ c.switch s
122
+
123
+ c.desc fd
124
+ c.flag f
125
+
126
+ c.action {}
127
+ end
128
+ end
129
+ @command = GLI::Commands::Help.new(@app,@output,@error)
130
+ }
131
+ When {
132
+ @command.execute({},{},[@command_name])
133
+ }
134
+ Then {
135
+ assert_output_contained(@command_name,"Name of the command")
136
+ assert_output_contained(@desc,"Short description")
137
+ assert_output_contained(@long_desc,"Long description")
138
+ assert_output_contained("-" + @switch,"command switch")
139
+ assert_output_contained(@switch_desc,"switch description")
140
+ assert_output_contained("-" + @flag,"command flag")
141
+ assert_output_contained(@flag_desc,"flag description")
142
+ }
143
+ end
144
+
145
+ test_that 'invoking help for an app with no global options omits [global options] from the usage string' do
146
+ Given a_GLI_app(:no_options)
147
+ And {
148
+ @command = GLI::Commands::Help.new(@app,@output,@error)
149
+ }
150
+ When {
151
+ @command.execute({},{},[])
152
+ }
153
+ Then {
154
+ refute_output_contained(/\[global options\] command \[command options\] \[arguments\.\.\.\]/)
155
+ refute_output_contained('GLOBAL OPTIONS')
156
+ assert_output_contained(/command \[command options\] \[arguments\.\.\.\]/)
157
+ }
158
+ end
159
+
160
+ test_that "invoking help with a known command when no global options are present omits [global options] from the usage string" do
161
+ Given a_GLI_app(:no_options)
162
+ And {
163
+ @command_name = cm = any_command_name
164
+ @desc = d = any_desc
165
+ @long_desc = ld = any_desc
166
+ @switch = s = any_option
167
+ @switch_desc = sd = any_desc
168
+ @flag = f = any_option
169
+ @flag_desc = fd = any_desc
170
+
171
+ @app.instance_eval do
172
+ desc d
173
+ long_desc ld
174
+ command cm do |c|
175
+
176
+ c.desc sd
177
+ c.switch s
178
+
179
+ c.desc fd
180
+ c.flag f
181
+
182
+ c.action {}
183
+ end
184
+ end
185
+ @command = GLI::Commands::Help.new(@app,@output,@error)
186
+ }
187
+ When {
188
+ @command.execute({},{},[@command_name])
189
+ }
190
+ Then {
191
+ refute_output_contained(/\[global options\]/)
192
+ assert_output_contained(/\[command options\]/)
193
+ assert_output_contained('COMMAND OPTIONS')
194
+ }
195
+ end
196
+
197
+ test_that "invoking help with a known command when no global options nor command options are present omits [global options] and [command options] from the usage string" do
198
+ Given a_GLI_app(:no_options)
199
+ And {
200
+ @command_name = cm = any_command_name
201
+ @desc = d = any_desc
202
+ @long_desc = ld = any_desc
203
+
204
+ @app.instance_eval do
205
+ desc d
206
+ long_desc ld
207
+ command cm do |c|
208
+ c.action {}
209
+ end
210
+ end
211
+ @command = GLI::Commands::Help.new(@app,@output,@error)
212
+ }
213
+ When {
214
+ @command.execute({},{},[@command_name])
215
+ }
216
+ Then {
217
+ refute_output_contained(/\[global options\]/)
218
+ refute_output_contained(/\[command options\]/)
219
+ refute_output_contained('COMMAND OPTIONS')
220
+ }
221
+ end
222
+
223
+ test_that "invoking help with a known command that has no command options omits [command options] from the usage string" do
224
+ Given a_GLI_app
225
+ And {
226
+ @command_name = cm = any_command_name
227
+ @desc = d = any_desc
228
+ @long_desc = ld = any_desc
229
+
230
+ @app.instance_eval do
231
+ desc d
232
+ long_desc ld
233
+ command cm do |c|
234
+ c.action {}
235
+ end
236
+ end
237
+ @command = GLI::Commands::Help.new(@app,@output,@error)
238
+ }
239
+ When {
240
+ @command.execute({},{},[@command_name])
241
+ }
242
+ Then {
243
+ assert_output_contained(/\[global options\]/)
244
+ refute_output_contained(/\[command options\]/)
245
+ refute_output_contained('COMMAND OPTIONS')
246
+ }
247
+ end
248
+
249
+ test_that "omitting default_description doesn't blow up" do
250
+ Given {
251
+ app = TestApp.new
252
+ app.instance_eval do
253
+ subcommand_option_handling :normal
254
+ command :top do |top|
255
+ top.command :list do |list|
256
+ list.action do |g,o,a|
257
+ end
258
+ end
259
+
260
+ top.command :new do |new|
261
+ new.action do |g,o,a|
262
+ end
263
+ end
264
+
265
+ top.default_command :list
266
+ end
267
+ end
268
+ @command = GLI::Commands::Help.new(app,@output,@error)
269
+ }
270
+ When {
271
+ @code = lambda { @command.execute({},{},['top']) }
272
+ }
273
+ Then {
274
+ assert_nothing_raised(&@code)
275
+ }
276
+ end
277
+
278
+ private
279
+
280
+ def a_GLI_app(omit_options=false)
281
+ lambda {
282
+ @program_description = program_description = any_desc
283
+ @flags = flags = [
284
+ [any_desc.strip,any_arg_name,[any_option]],
285
+ [any_desc.strip,any_arg_name,[any_option,any_long_option]],
286
+ ]
287
+ @switches = switches = [
288
+ [any_desc.strip,[any_option]],
289
+ [any_desc.strip,[any_option,any_long_option]],
290
+ ]
291
+
292
+ @commands = commands = [
293
+ [any_desc.strip,[any_command_name]],
294
+ [any_desc.strip,[any_command_name,any_command_name]],
295
+ ]
296
+
297
+ @app = TestApp.new
298
+ @app.instance_eval do
299
+ program_desc program_description
300
+ subcommand_option_handling :normal
301
+
302
+ unless omit_options
303
+ flags.each do |(description,arg,flag_names)|
304
+ desc description
305
+ arg_name arg
306
+ flag flag_names
307
+ end
308
+
309
+ switches.each do |(description,switch_names)|
310
+ desc description
311
+ switch switch_names
312
+ end
313
+ end
314
+
315
+ commands.each do |(description,command_names)|
316
+ desc description
317
+ command command_names do |c|
318
+ c.action {}
319
+ end
320
+ end
321
+ end
322
+ }
323
+ end
324
+
325
+ def assert_top_level_help_output
326
+ assert_output_contained(@program_description)
327
+
328
+ @commands.each do |(description,command_names)|
329
+ assert_output_contained(/#{command_names.join(', ')}\s+-\s+#{description}/,"For command #{command_names.join(',')}")
330
+ end
331
+ assert_output_contained(/help\s+-\s+#{@command.description}/)
332
+
333
+ @switches.each do |(description,switch_names)|
334
+ expected_switch_names = switch_names.map { |_| _.length == 1 ? "-#{_}" : "--\\[no-\\]#{_}" }.join(', ')
335
+ assert_output_contained(/#{expected_switch_names}\s+-\s+#{description}/,"For switch #{switch_names.join(',')}")
336
+ end
337
+
338
+ @flags.each do |(description,arg,flag_names)|
339
+ expected_flag_names = flag_names.map { |_| _.length == 1 ? "-#{_}" : "--#{_}" }.join(', ')
340
+ assert_output_contained(/#{expected_flag_names}[ =]#{arg}\s+-\s+#{description}/,"For flag #{flag_names.join(',')}")
341
+ end
342
+
343
+ assert_output_contained('GLOBAL OPTIONS')
344
+ assert_output_contained('COMMANDS')
345
+ assert_output_contained(/\[global options\] command \[command options\] \[arguments\.\.\.\]/)
346
+ end
347
+
348
+ def assert_error_contained(string_or_regexp,desc='')
349
+ string_or_regexp = /#{string_or_regexp}/ if string_or_regexp.kind_of?(String)
350
+ assert_match string_or_regexp,@error.string,desc
351
+ end
352
+
353
+ def assert_output_contained(string_or_regexp,desc='')
354
+ string_or_regexp = /#{string_or_regexp}/ if string_or_regexp.kind_of?(String)
355
+ assert_match string_or_regexp,@output.string,desc
356
+ end
357
+
358
+ def refute_output_contained(string_or_regexp,desc='')
359
+ string_or_regexp = /#{string_or_regexp}/ if string_or_regexp.kind_of?(String)
360
+ assert_no_match string_or_regexp,@output.string,desc
361
+ end
362
+
363
+ def any_option
364
+ ('a'..'z').to_a[@option_index].tap { @option_index += 1 }
365
+ end
366
+
367
+ def any_long_option
368
+ Faker::Lorem.words(10)[rand(10)]
369
+ end
370
+
371
+ def any_arg_name
372
+ any_string :max => 20
373
+ end
374
+
375
+ def any_desc
376
+ Faker::Lorem.words(10).join(' ')[0..30].gsub(/\s*$/,'')
377
+ end
378
+
379
+ def any_command_name
380
+ command_name = Faker::Lorem.words(10)[rand(10)]
381
+ while @command_names_used.include?(command_name)
382
+ command_name = Faker::Lorem.words(10)[rand(10)]
383
+ end
384
+ @command_names_used << command_name
385
+ command_name
386
+ end
387
+ end
@@ -0,0 +1,43 @@
1
+ require 'test_helper'
2
+
3
+ class TC_testOptions < Clean::Test::TestCase
4
+ include TestHelper
5
+
6
+ def test_by_method
7
+ o = GLI::Options.new
8
+ o.name = 'verbose'
9
+ assert_equal 'verbose', o.name
10
+ assert_equal 'verbose', o[:name]
11
+ assert_equal 'verbose', o['name']
12
+ end
13
+
14
+ def test_by_string
15
+ o = GLI::Options.new
16
+ o['name'] = 'verbose'
17
+ assert_equal 'verbose', o.name
18
+ assert_equal 'verbose', o[:name]
19
+ assert_equal 'verbose', o['name']
20
+ end
21
+
22
+ def test_by_symbol
23
+ o = GLI::Options.new
24
+ o[:name] = 'verbose'
25
+ assert_equal 'verbose', o.name
26
+ assert_equal 'verbose', o[:name]
27
+ assert_equal 'verbose', o['name']
28
+ end
29
+
30
+ def test_map_defers_to_underlying_map
31
+ o = GLI::Options.new
32
+ o[:foo] = 'bar'
33
+ o[:blah] = 'crud'
34
+
35
+ result = Hash[o.map { |k,v|
36
+ [k,v.upcase]
37
+ }]
38
+ assert_equal 2,result.size
39
+ assert_equal "BAR",result[:foo]
40
+ assert_equal "CRUD",result[:blah]
41
+ end
42
+
43
+ end
@@ -0,0 +1,104 @@
1
+ require 'test_helper'
2
+ require 'pp'
3
+
4
+ class TC_testSubCommandParsing < Clean::Test::TestCase
5
+ include TestHelper
6
+
7
+ test_that "commands options may clash with globals and it gets sorted out" do
8
+ Given :app_with_subcommands_storing_results
9
+ When {
10
+ @app.run(%w(-f global command1 -f command -s foo))
11
+ }
12
+ Then {
13
+ assert_equal 'command1',@results[:command_name]
14
+ assert_equal 'global', @results[:global_options][:f],'global'
15
+ assert !@results[:global_options][:s]
16
+ assert_equal 'command', @results[:command_options][:f]
17
+ assert @results[:command_options][:s]
18
+ }
19
+ end
20
+
21
+ test_that "in legacy mode, subcommand options all share a namespace" do
22
+ Given :app_with_subcommands_storing_results
23
+ When {
24
+ @app.run(%w(-f global command1 -f command -s subcommand10 -f sub))
25
+ }
26
+ Then {
27
+ with_clue(@results) {
28
+ assert_equal 'subcommand10',@results[:command_name]
29
+ assert_equal 'global', @results[:global_options][:f],'global'
30
+ assert !@results[:global_options][:s]
31
+ assert_equal 'sub', @results[:command_options][:f]
32
+ assert @results[:command_options][:s]
33
+ assert_nil @results[:command_options][GLI::Command::PARENT]
34
+ assert_nil @results[:command_options][GLI::Command::PARENT]
35
+ }
36
+ }
37
+ end
38
+
39
+ test_that "in normal mode, each subcommand has its own namespace" do
40
+ Given :app_with_subcommands_storing_results, :normal
41
+ When {
42
+ @app.run(%w(-f global command1 -f command -s subcommand10 -f sub))
43
+ }
44
+ Then {
45
+ with_clue(@results) {
46
+ assert_equal 'subcommand10',@results[:command_name]
47
+ assert_equal 'global', @results[:global_options][:f],'global'
48
+ assert !@results[:global_options][:s]
49
+ assert_equal 'sub', @results[:command_options][:f]
50
+ assert !@results[:command_options][:s]
51
+ assert_equal 'command',@results[:command_options][GLI::Command::PARENT][:f]
52
+ assert @results[:command_options][GLI::Command::PARENT][:s]
53
+ }
54
+ }
55
+ end
56
+
57
+ private
58
+ def with_clue(message,&block)
59
+ block.call
60
+ rescue Exception
61
+ PP.pp message,dump=""
62
+ puts dump
63
+ raise
64
+ end
65
+
66
+ def app_with_subcommands_storing_results(subcommand_option_handling_strategy = :legacy)
67
+ @results = {}
68
+ @app = CLIApp.new
69
+ @app.subcommand_option_handling subcommand_option_handling_strategy
70
+ @app.flag ['f','flag']
71
+ @app.switch ['s','switch']
72
+
73
+ 2.times do |i|
74
+ @app.command "command#{i}" do |c|
75
+ c.flag ['f','flag']
76
+ c.switch ['s','switch']
77
+ c.action do |global,options,args|
78
+ @results = {
79
+ :command_name => "command#{i}",
80
+ :global_options => global,
81
+ :command_options => options,
82
+ :args => args
83
+ }
84
+ end
85
+
86
+ 2.times do |j|
87
+ c.command "subcommand#{i}#{j}" do |subcommand|
88
+ subcommand.flag ['f','flag']
89
+ subcommand.flag ['foo']
90
+ subcommand.switch ['s','switch']
91
+ subcommand.action do |global,options,args|
92
+ @results = {
93
+ :command_name => "subcommand#{i}#{j}",
94
+ :global_options => global,
95
+ :command_options => options,
96
+ :args => args
97
+ }
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end