Ruby cli: Difference between revisions
From wikinotes
(11 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
Some rough starting points for creating commandline interfaces in ruby.<br> | |||
salt to taste. | |||
= Param Parsing, Raw = | = Param Parsing, Raw = | ||
<blockquote> | <blockquote> | ||
{{ | {{ expand | ||
| no structure | | no structure | ||
| | | | ||
Line 22: | Line 24: | ||
when '-h', '--help' | when '-h', '--help' | ||
helpmsg = <<~HELP | helpmsg = <<~HELP | ||
#{EXECUTABLE} [-h] | #{EXECUTABLE} [-h] [-n NAME] [-a AGE] | ||
DESCRIPTION: | DESCRIPTION: | ||
Line 30: | Line 32: | ||
-n --name: | -n --name: | ||
assign a name | assign a name | ||
-a --age: | |||
assign an age | |||
EXAMPLE: | EXAMPLE: | ||
#{EXECUTABLE} -n my-name | #{EXECUTABLE} -n my-name -a 30 | ||
HELP | HELP | ||
Line 55: | Line 60: | ||
puts("hello, #{name} with age #{age}") | puts("hello, #{name} with age #{age}") | ||
</syntaxhighlight> | |||
}} | |||
{{ expand | |||
| enumerator structure | |||
| | |||
<syntaxhighlight lang="ruby"> | |||
#!/usr/bin/env ruby | |||
EXECUTABLE = File.basename(__FILE__) | |||
class ArgumentIterator | |||
def initialize(argv) | |||
@argv = argv | |||
@index = 0 | |||
end | |||
def shift(n = 1) | |||
n.times.map { next_item } | |||
end | |||
def next_item | |||
val = @argv[@index] | |||
@index += 1 | |||
val | |||
end | |||
def each | |||
Enumerator.new do |enum| | |||
loop do | |||
break if @index >= @argv.count | |||
enum.yield([self, next_item]) | |||
end | |||
end.each { |this, val| yield(this, val) } | |||
end | |||
end | |||
class CommandlineInterface | |||
Args = Struct.new(:name, :age) | |||
def help_msg | |||
<<~HELP | |||
#{EXECUTABLE} [-h] [-n NAME] [-a AGE] | |||
DESCRIPTION: | |||
says hello | |||
PARAMS: | |||
-n --name: | |||
assign a name | |||
-a --age: | |||
assign an age | |||
EXAMPLE: | |||
#{EXECUTABLE} -n my-name -a 30 | |||
HELP | |||
end | |||
def parse_args(argv) | |||
name = "unknown" | |||
age = "unknown" | |||
ArgumentIterator.new(argv).each do |iterator, arg| | |||
case arg | |||
when '-h', '--help' | |||
puts(help_msg) | |||
exit(0) | |||
when '-n', '--name' | |||
name, = iterator.shift | |||
when '-a', '--age' | |||
age, = iterator.shift | |||
else | |||
$stderr.puts("[ERROR] unexpected argument #{arg}") | |||
exit(1) | |||
end | |||
end | |||
Args.new(name, age) | |||
end | |||
end | |||
cli = CommandlineInterface.new | |||
args = cli.parse_args(ARGV) | |||
puts("hello, #{args.name} with age #{args.age}") | |||
</syntaxhighlight> | </syntaxhighlight> | ||
}} | }} | ||
</blockquote><!-- Param Parsing --> | </blockquote><!-- Param Parsing --> | ||
= Optparse = | |||
<blockquote> | |||
Ruby ships also ships with [[ruby optparse]].<br> | |||
It works by defining a DSL for params (ex. <code>opts.on("-n NAME", "--name NAME"</code>), and defining callbacks for each param.<br> | |||
I think it's a bit more complicated than it needs to be. | |||
Example from the docs: | |||
<syntaxhighlight lang="ruby"> | |||
require 'optparse' | |||
options = {} | |||
OptionParser.new do |parser| | |||
parser.on("-r", "--require LIBRARY", | |||
"Require the LIBRARY before executing your script") do |lib| | |||
puts "You required #{lib}!" | |||
end | |||
end.parse! | |||
</syntaxhighlight> | |||
</blockquote><!-- Optparse --> |
Latest revision as of 16:44, 29 October 2022
Some rough starting points for creating commandline interfaces in ruby.
salt to taste.
Param Parsing, Raw
no structure
#!/usr/bin/env ruby EXECUTABLE = File.basename(__FILE__) name = "unknown" age = "unknown" shift = 0 ARGV.count.times do |index| if shift > 0 shift -= 1 next end case ARGV[index] when '-h', '--help' helpmsg = <<~HELP #{EXECUTABLE} [-h] [-n NAME] [-a AGE] DESCRIPTION: says hello PARAMS: -n --name: assign a name -a --age: assign an age EXAMPLE: #{EXECUTABLE} -n my-name -a 30 HELP puts(helpmsg) exit(0) when '-n', '--name' name = ARGV[index+1] shift += 1 when '-a', '--age' age = ARGV[index+1] shift += 1 else puts "error" exit(1) end end puts("hello, #{name} with age #{age}")enumerator structure
#!/usr/bin/env ruby EXECUTABLE = File.basename(__FILE__) class ArgumentIterator def initialize(argv) @argv = argv @index = 0 end def shift(n = 1) n.times.map { next_item } end def next_item val = @argv[@index] @index += 1 val end def each Enumerator.new do |enum| loop do break if @index >= @argv.count enum.yield([self, next_item]) end end.each { |this, val| yield(this, val) } end end class CommandlineInterface Args = Struct.new(:name, :age) def help_msg <<~HELP #{EXECUTABLE} [-h] [-n NAME] [-a AGE] DESCRIPTION: says hello PARAMS: -n --name: assign a name -a --age: assign an age EXAMPLE: #{EXECUTABLE} -n my-name -a 30 HELP end def parse_args(argv) name = "unknown" age = "unknown" ArgumentIterator.new(argv).each do |iterator, arg| case arg when '-h', '--help' puts(help_msg) exit(0) when '-n', '--name' name, = iterator.shift when '-a', '--age' age, = iterator.shift else $stderr.puts("[ERROR] unexpected argument #{arg}") exit(1) end end Args.new(name, age) end end cli = CommandlineInterface.new args = cli.parse_args(ARGV) puts("hello, #{args.name} with age #{args.age}")
Optparse
Ruby ships also ships with ruby optparse.
It works by defining a DSL for params (ex.opts.on("-n NAME", "--name NAME"
), and defining callbacks for each param.
I think it's a bit more complicated than it needs to be.Example from the docs:
require 'optparse' options = {} OptionParser.new do |parser| parser.on("-r", "--require LIBRARY", "Require the LIBRARY before executing your script") do |lib| puts "You required #{lib}!" end end.parse!