slop-4.5.0/0000755000175000017500000000000013133607775012345 5ustar uwabamiuwabamislop-4.5.0/Rakefile0000644000175000017500000000110613133607775014010 0ustar uwabamiuwabamibegin require 'bundler/gem_tasks' rescue LoadError end require 'rake/testtask' Rake::TestTask.new do |t| t.libs << 'test' t.test_files = Dir['test/*_test.rb'] end # begin # require 'rdoc/task' # # requires sdoc and horo gems # RDoc::Task.new do |rdoc| # rdoc.title = 'Slop API Documentation' # rdoc.rdoc_dir = 'doc' # rdoc.options << '-f' << 'sdoc' # rdoc.options << '-T' << 'rails' # rdoc.options << '-e' << 'UTF-8' # rdoc.options << '-g' # rdoc.rdoc_files.include('lib/**/*.rb') # end # rescue LoadError # end task :default => :test slop-4.5.0/Gemfile0000644000175000017500000000004613133607775013640 0ustar uwabamiuwabamisource "https://rubygems.org" gemspecslop-4.5.0/.travis.yml0000644000175000017500000000033713133607775014461 0ustar uwabamiuwabamicache: bundler before_install: - gem install bundler rvm: - 2.0.0 - 2.1 - 2.2 - 2.3.4 - 2.4.1 - jruby-9.1.8.0 - jruby-head - ruby-head notifications: email: on_success: change on_failure: always slop-4.5.0/lib/0000755000175000017500000000000013133607775013113 5ustar uwabamiuwabamislop-4.5.0/lib/slop/0000755000175000017500000000000013133607775014070 5ustar uwabamiuwabamislop-4.5.0/lib/slop/result.rb0000644000175000017500000000471313133607775015740 0ustar uwabamiuwabamimodule Slop # This class encapsulates a Parser and Options pair. The idea is that # the Options class shouldn't have to deal with what happens when options # are parsed, and the Parser shouldn't have to deal with the state of # options once parsing is complete. This keeps the API really simple; A # Parser parses, Options handles options, and this class handles the # result of those actions. This class contains the important most used # methods. class Result attr_reader :parser, :options def initialize(parser) @parser = parser @options = parser.options end # Returns an options value, nil if the option does not exist. def [](flag) (o = option(flag)) && o.value end alias get [] # Set the value for an option. Raises an ArgumentError if the option # does not exist. def []=(flag, value) if o = option(flag) o.value = value else raise ArgumentError, "no option with flag `#{flag}'" end end alias set []= # Returns an Option if it exists. Ignores any prefixed hyphens. def option(flag) cleaned = -> (f) do key = f.to_s.sub(/\A--?/, '') key = key.tr '-', '_' if parser.config[:underscore_flags] key.to_sym end options.find do |o| o.flags.any? { |f| cleaned.(f) == cleaned.(flag) } end end def method_missing(name, *args, &block) if respond_to_missing?(name) (o = option(name.to_s.chomp("?"))) && used_options.include?(o) else super end end def respond_to_missing?(name, include_private = false) name.to_s.end_with?("?") || super end # Returns an Array of Option instances that were used. def used_options parser.used_options end # Returns an Array of Option instances that were not used. def unused_options parser.unused_options end # Example: # # opts = Slop.parse do |o| # o.string '--host' # o.int '-p' # end # # # ruby run.rb connect --host 123 helo # opts.arguments #=> ["connect", "helo"] # # Returns an Array of String arguments that were not parsed. def arguments parser.arguments end alias args arguments # Returns a hash with option key => value. def to_hash Hash[options.reject(&:null?).map { |o| [o.key, o.value] }] end alias to_h to_hash def to_s(**opts) options.to_s(**opts) end end end slop-4.5.0/lib/slop/parser.rb0000644000175000017500000001046613133607775015720 0ustar uwabamiuwabamimodule Slop class Parser # Our Options instance. attr_reader :options # A Hash of configuration options. attr_reader :config # Returns an Array of String arguments that were not parsed. attr_reader :arguments def initialize(options, **config) @options = options @config = config reset end # Reset the parser, useful to use the same instance to parse a second # time without duplicating state. def reset @arguments = [] @options.each(&:reset) self end # Traverse `strings` and process options one by one. Anything after # `--` is ignored. If a flag includes a equals (=) it will be split # so that `flag, argument = s.split('=')`. # # The `call` method will be executed immediately for each option found. # Once all options have been executed, any found options will have # the `finish` method called on them. # # Returns a Slop::Result. def parse(strings) reset # reset before every parse # ignore everything after "--" strings, ignored_args = partition(strings) pairs = strings.each_cons(2).to_a # this ensures we still support the last string being a flag, # otherwise it'll only be used as an argument. pairs << [strings.last, nil] @arguments = strings.dup pairs.each_with_index do |pair, idx| flag, arg = pair break if !flag # support `foo=bar` orig_flag = flag.dup orig_arg = arg if flag.include?("=") flag, arg = flag.split("=") end if opt = try_process(flag, arg) # since the option was parsed, we remove it from our # arguments (plus the arg if necessary) # delete argument first while we can find its index. if opt.expects_argument? # if we consumed the argument, remove the next pair if orig_arg == opt.value.to_s pairs.delete_at(idx + 1) end arguments.each_with_index do |argument, i| if argument == orig_flag && !orig_flag.include?("=") arguments.delete_at(i + 1) end end end arguments.delete(orig_flag) end end @arguments += ignored_args Result.new(self).tap do |result| used_options.each { |o| o.finish(result) } end end # Returns an Array of Option instances that were used. def used_options options.select { |o| o.count > 0 } end # Returns an Array of Option instances that were not used. def unused_options options.to_a - used_options end private # We've found an option, process and return it def process(option, arg) option.ensure_call(arg) option end # Try and find an option to process def try_process(flag, arg) if option = matching_option(flag) process(option, arg) elsif flag.start_with?("--no-") && option = matching_option(flag.sub("no-", "")) process(option, false) elsif flag =~ /\A-[^-]{2,}/ try_process_smashed_arg(flag) || try_process_grouped_flags(flag, arg) else if flag.start_with?("-") && !suppress_errors? raise UnknownOption.new("unknown option `#{flag}'", "#{flag}") end end end # try and process a flag with a "smashed" argument, e.g. # -nFoo or -i5 def try_process_smashed_arg(flag) option = matching_option(flag[0, 2]) if option && option.expects_argument? process(option, flag[2..-1]) end end # try and process as a set of grouped short flags. drop(1) removes # the prefixed -, then we add them back to each flag separately. def try_process_grouped_flags(flag, arg) flags = flag.split("").drop(1).map { |f| "-#{f}" } last = flags.pop flags.each { |f| try_process(f, nil) } try_process(last, arg) # send the argument to the last flag end def suppress_errors? config[:suppress_errors] end def matching_option(flag) options.find { |o| o.flags.include?(flag) } end def partition(strings) if strings.include?("--") partition_idx = strings.index("--") [strings[0..partition_idx-1], strings[partition_idx+1..-1]] else [strings, []] end end end end slop-4.5.0/lib/slop/options.rb0000644000175000017500000000674613133607775016125 0ustar uwabamiuwabamimodule Slop class Options include Enumerable DEFAULT_CONFIG = { suppress_errors: false, type: "null", banner: true, underscore_flags: true, } # The Array of Option instances we've created. attr_reader :options # An Array of separators used for the help text. attr_reader :separators # Our Parser instance. attr_reader :parser # A Hash of configuration options. attr_reader :config # The String banner prefixed to the help string. attr_accessor :banner def initialize(**config) @options = [] @separators = [] @banner = config[:banner].is_a?(String) ? config[:banner] : config.fetch(:banner, "usage: #{$0} [options]") @config = DEFAULT_CONFIG.merge(config) @parser = Parser.new(self, @config) yield self if block_given? end # Add a new option. This method is an alias for adding a NullOption # (i.e an option with an ignored return value). # # Example: # # opts = Slop.parse do |o| # o.on '--version' do # puts Slop::VERSION # end # end # # opts.to_hash #=> {} # # Returns the newly created Option subclass. def on(*flags, **config, &block) desc = flags.pop unless flags.last.start_with?('-') config = self.config.merge(config) klass = Slop.string_to_option_class(config[:type].to_s) option = klass.new(flags, desc, config, &block) add_option option end # Add a separator between options. Used when displaying # the help text. def separator(string) if separators[options.size] separators.last << "\n#{string}" else separators[options.size] = string end end # Sugar to avoid `options.parser.parse(x)`. def parse(strings) parser.parse(strings) end # Implements the Enumerable interface. def each(&block) options.each(&block) end # Handle custom option types. Will fall back to raising an # exception if an option is not defined. def method_missing(name, *args, **config, &block) if respond_to_missing?(name) config[:type] = name on(*args, config, &block) else super end end def respond_to_missing?(name, include_private = false) Slop.option_defined?(name) || super end # Return a copy of our options Array. def to_a options.dup end # Returns the help text for this options. Used by Result#to_s. def to_s(prefix: " " * 4) str = config[:banner] ? "#{banner}\n" : "" len = longest_flag_length options.select(&:help?).each_with_index.sort_by{ |o,i| [o.tail, i] }.each do |opt, i| # use the index to fetch an associated separator if sep = separators[i] str << "#{sep}\n" end str << "#{prefix}#{opt.to_s(offset: len)}\n" end str end private def longest_flag_length (o = longest_option) && o.flag.length || 0 end def longest_option options.max { |a, b| a.flag.length <=> b.flag.length } end def add_option(option) options.each do |o| flags = o.flags & option.flags # Raise an error if we found an existing option with the same # flags. I can't immediately see a use case for this.. if flags.any? raise ArgumentError, "duplicate flags: #{flags}" end end options << option option end end end slop-4.5.0/lib/slop/types.rb0000644000175000017500000000374613133607775015573 0ustar uwabamiuwabamimodule Slop # Cast the option argument to a String. class StringOption < Option def call(value) value.to_s end end # Cast the option argument to true or false. # Override default_value to default to false instead of nil. # This option type does not expect an argument. However, the API # supports value being passed. This is to ensure it can capture # an explicit false value class BoolOption < Option attr_accessor :explicit_value def call(value) self.explicit_value = value !force_false? end def value if force_false? false else super end end def force_false? explicit_value == false end def default_value config[:default] || false end def expects_argument? false end end BooleanOption = BoolOption # Cast the option argument to an Integer. class IntegerOption < Option def call(value) value =~ /\A-?\d+\z/ && value.to_i end end IntOption = IntegerOption # Cast the option argument to a Float. class FloatOption < Option def call(value) # TODO: scientific notation, etc. value =~ /\A-?\d*\.*\d+\z/ && value.to_f end end # Collect multiple items into a single Array. Support # arguments separated by commas or multiple occurences. class ArrayOption < Option def call(value) @value ||= [] if delimiter @value.concat value.split(delimiter, limit) else @value << value end end def default_value config[:default] || [] end def delimiter config.fetch(:delimiter, ",") end def limit config[:limit] || 0 end end # Cast the option argument to a Regexp. class RegexpOption < Option def call(value) Regexp.new(value) end end # An option that discards the return value, inherits from Bool # since it does not expect an argument. class NullOption < BoolOption def null? true end end end slop-4.5.0/lib/slop/option.rb0000644000175000017500000000716413133607775015735 0ustar uwabamiuwabamimodule Slop class Option DEFAULT_CONFIG = { help: true, tail: false, underscore_flags: true, } # An Array of flags this option matches. attr_reader :flags # A custom description used for the help text. attr_reader :desc # A Hash of configuration options. attr_reader :config # An Integer count for the total times this option # has been executed. attr_reader :count # A custom proc that yields the option value when # it's executed. attr_reader :block # The end value for this option. attr_writer :value def initialize(flags, desc, **config, &block) @flags = flags @desc = desc @config = DEFAULT_CONFIG.merge(config) @block = block reset end # Reset the option count and value. Used when calling .reset # on the Parser. def reset @value = nil @count = 0 end # Since `call()` can be used/overriden in subclasses, this # method is used to do general tasks like increment count. This # ensures you don't *have* to call `super` when overriding `call()`. # It's used in the Parser. def ensure_call(value) @count += 1 if value.nil? && expects_argument? if default_value @value = default_value elsif !suppress_errors? raise Slop::MissingArgument.new("missing argument for #{flag}", flags) end else @value = call(value) end block.call(@value) if block.respond_to?(:call) end # This method is called immediately when an option is found. # Override it in sub-classes. def call(_value) raise NotImplementedError, "you must override the `call' method for option #{self.class}" end # By default this method does nothing. It's called when all options # have been parsed and allows you to mutate the `@value` attribute # according to other options. def finish(_result) end # Override this if this option type does not expect an argument # (i.e a boolean option type). def expects_argument? true end # Override this if you want to ignore the return value for an option # (i.e so Result#to_hash does not include it). def null? false end # Returns the value for this option. Falls back to the default (or nil). def value @value || default_value end # Returns the default value for this option (default is nil). def default_value config[:default] end # Returns true if we should ignore errors that cause exceptions to be raised. def suppress_errors? config[:suppress_errors] end # Returns all flags joined by a comma. Used by the help string. def flag flags.join(", ") end # Returns the last key as a symbol. Used in Options.to_hash. def key key = config[:key] || flags.last.sub(/\A--?/, '') key = key.tr '-', '_' if underscore_flags? key.to_sym end # Returns true if this option should be displayed with dashes transformed into underscores. def underscore_flags? config[:underscore_flags] end # Returns true if this option should be displayed in help text. def help? config[:help] end # Returns true if this option should be added to the tail of the help text. def tail? config[:tail] end # Returns 1 if this option should be added to the tail of the help text. # Used for sorting. def tail tail? ? 1 : -1 end # Returns the help text for this option (flags and description). def to_s(offset: 0) "%-#{offset}s %s" % [flag, desc] end end end slop-4.5.0/lib/slop/error.rb0000644000175000017500000000144313133607775015550 0ustar uwabamiuwabamimodule Slop # Base error class. class Error < StandardError end # Raised when calling `call` on Slop::Option (this # method must be overriden in subclasses) class NotImplementedError < Error end # Raised when an option that expects an argument is # executed without one. Suppress with the `suppress_errors` # config option. class MissingArgument < Error attr_reader :flags # Get all the flags that matches # the option with the missing argument def initialize(msg, flags) super(msg) @flags = flags end end # Raised when an unknown option is parsed. Suppress # with the `suppress_errors` config option. class UnknownOption < Error attr_reader :flag def initialize(msg, flag) super(msg) @flag = flag end end end slop-4.5.0/lib/slop.rb0000644000175000017500000000311513133607775014415 0ustar uwabamiuwabamirequire 'slop/option' require 'slop/options' require 'slop/parser' require 'slop/result' require 'slop/types' require 'slop/error' module Slop VERSION = '4.5.0' # Parse an array of options (defaults to ARGV). Accepts an # optional hash of configuration options and block. # # Example: # # opts = Slop.parse(["-host", "localhost"]) do |o| # o.string '-host', 'a hostname', default: '0.0.0.0' # end # opts.to_hash #=> { host: 'localhost' } # # Returns a Slop::Result. def self.parse(items = ARGV, **config, &block) Options.new(config, &block).parse(items) end # Example: # # Slop.option_defined?(:string) #=> true # Slop.option_defined?(:omg) #=> false # # Returns true if an option is defined. def self.option_defined?(name) const_defined?(string_to_option(name.to_s)) rescue NameError # If a NameError is raised, it wasn't a valid constant name, # and thus couldn't have been defined. false end # Example: # # Slop.string_to_option("string") #=> "StringOption" # Slop.string_to_option("some_thing") #=> "SomeThingOption" # # Returns a camel-cased class looking string with Option suffix. def self.string_to_option(s) s.gsub(/(?:^|_)([a-z])/) { $1.capitalize } + "Option" end # Example: # # Slop.string_to_option_class("string") #=> Slop::StringOption # Slop.string_to_option_class("foo") #=> uninitialized constant FooOption # # Returns the full qualified option class. Uses `#string_to_option`. def self.string_to_option_class(s) const_get(string_to_option(s)) end end slop-4.5.0/slop.gemspec0000644000175000017500000000117713133607775014675 0ustar uwabamiuwabami$:.unshift './lib' require 'slop' Gem::Specification.new do |s| s.name = 'slop' s.version = Slop::VERSION s.summary = 'Simple Lightweight Option Parsing' s.description = 'A DSL for gathering options and parsing command line flags' s.author = 'Lee Jarvis' s.email = 'ljjarvis@gmail.com' s.homepage = 'http://github.com/leejarvis/slop' s.files = `git ls-files`.split("\n") s.test_files = `git ls-files -- test/*`.split("\n") s.license = 'MIT' s.required_ruby_version = '>= 2.0.0' s.add_development_dependency 'rake' s.add_development_dependency 'minitest', '~> 5.0.0' end slop-4.5.0/test/0000755000175000017500000000000013133607775013324 5ustar uwabamiuwabamislop-4.5.0/test/types_test.rb0000644000175000017500000000647313133607775016066 0ustar uwabamiuwabamirequire 'test_helper' describe Slop::BoolOption do before do @options = Slop::Options.new @verbose = @options.bool "--verbose" @quiet = @options.bool "--quiet" @inversed = @options.bool "--inversed", default: true @bloc = @options.bool("--bloc"){|val| (@bloc_val ||= []) << val} @result = @options.parse %w(--verbose --no-inversed --bloc --no-bloc) end it "returns true if used" do assert_equal true, @result[:verbose] end it "returns false if not used" do assert_equal false, @result[:quiet] end it "can be inversed via --no- prefix" do assert_equal false, @result[:inversed] end it "will invert the value passed to &block via --no- prefix" do assert_equal [true, false], @bloc_val end end describe Slop::IntegerOption do before do @options = Slop::Options.new @age = @options.integer "--age" @result = @options.parse %w(--age 20) end it "returns the value as an integer" do assert_equal 20, @result[:age] end it "returns nil for non-numbers by default" do @result.parser.parse %w(--age hello) assert_nil @result[:age] end end describe Slop::FloatOption do before do @options = Slop::Options.new @apr = @options.float "--apr" @apr_value = 2.9 @result = @options.parse %W(--apr #{@apr_value}) end it "returns the value as a float" do assert_equal @apr_value, @result[:apr] end it "returns nil for non-numbers by default" do @result.parser.parse %w(--apr hello) assert_nil @result[:apr] end end describe Slop::ArrayOption do before do @options = Slop::Options.new @files = @options.array "--files" @multi = @options.array "-M", delimiter: nil @delim = @options.array "-d", delimiter: ":" @limit = @options.array "-l", limit: 2 @result = @options.parse %w(--files foo.txt,bar.rb) end it "defaults to []" do assert_equal [], @result[:d] end it "parses comma separated args" do assert_equal %w(foo.txt bar.rb), @result[:files] end it "collects multiple option values" do @result.parser.parse %w(--files foo.txt --files bar.rb) assert_equal %w(foo.txt bar.rb), @result[:files] end it "collects multiple option values with no delimiter" do @result.parser.parse %w(-M foo,bar -M bar,qux) assert_equal %w(foo,bar bar,qux), @result[:M] end it "can use a custom delimiter" do @result.parser.parse %w(-d foo.txt:bar.rb) assert_equal %w(foo.txt bar.rb), @result[:d] end it "can use a custom limit" do @result.parser.parse %w(-l foo,bar,baz) assert_equal ["foo", "bar,baz"], @result[:l] end end describe Slop::NullOption do before do @options = Slop::Options.new @version = @options.null('--version') @result = @options.parse %w(--version) end it 'has a return value of true' do assert_equal true, @result[:version] end it 'is not included in to_hash' do assert_equal({}, @result.to_hash) end end describe Slop::RegexpOption do before do @options = Slop::Options.new @exclude = @options.regexp "--exclude" @exclude_value = "redirect|news" @result = @options.parse %W(--exclude #{@exclude_value}) end it "returns the value as a Regexp" do assert_equal Regexp.new(@exclude_value), @result[:exclude] end end slop-4.5.0/test/error_test.rb0000644000175000017500000000220713133607775016042 0ustar uwabamiuwabamirequire 'test_helper' # All raised errors tested here describe Slop::MissingArgument do it "raises when an argument is missing" do opts = Slop::Options.new opts.string "-n", "--name" assert_raises(Slop::MissingArgument) { opts.parse %w(--name) } #Assert returns the argument question begin opts.parse %w(--name) rescue Slop::MissingArgument => e assert_equal(e.flags, ["-n", "--name"]) end end it "does not raise when errors are suppressed" do opts = Slop::Options.new(suppress_errors: true) opts.string "-n", "--name" opts.parse %w(--name) end end describe Slop::UnknownOption do it "raises when an option is unknown" do opts = Slop::Options.new opts.string "-n", "--name" assert_raises(Slop::UnknownOption) { opts.parse %w(--foo) } #Assert returns the unknown option in question begin opts.parse %w(--foo) rescue Slop::UnknownOption => e assert_equal(e.flag, "--foo") end end it "does not raise when errors are suppressed" do opts = Slop::Options.new(suppress_errors: true) opts.string "-n", "--name" opts.parse %w(--foo) end end slop-4.5.0/test/options_test.rb0000644000175000017500000000511513133607775016405 0ustar uwabamiuwabamirequire 'test_helper' describe Slop::Options do before do @options = Slop::Options.new end describe "#on" do it "defaults to null type" do assert_kind_of Slop::NullOption, @options.on("--foo") end it "accepts custom types" do module Slop; class FooOption < Option; end; end assert_kind_of Slop::FooOption, @options.on("--foo", type: :foo) end it "adds multiple flags" do option = @options.on("-f", "-F", "--foo") assert_equal %w(-f -F --foo), option.flags end it "accepts a trailing description" do option = @options.on("--foo", "fooey") assert_equal "fooey", option.desc end it "adds the option" do option = @options.on("--foo") assert_equal [option], @options.to_a end it "raises an error when a duplicate flag is used" do @options.on("--foo") assert_raises(ArgumentError) { @options.on("--foo") } end end describe "#method_missing" do it "uses the method name as an option type" do option = @options.string("--name") assert_kind_of Slop::StringOption, option end it "raises if a type doesn't exist" do assert_raises(NoMethodError) { @options.unknown } end end describe "#respond_to?" do it "handles custom types" do module Slop; class BarOption < Option; end; end assert @options.respond_to?(:bar) end end describe "#to_s" do it "is prefixed with the default banner" do assert_match(/^usage/, @options.to_s) end it "aligns option strings" do @options.on "-f", "--foo", "fooey" @options.on "-s", "short" assert_match(/^ -f, --foo fooey/, @options.to_s) assert_match(/^ -s short/, @options.to_s) end it "can use a custom prefix" do @options.on "-f", "--foo" assert_match(/^ -f, --foo/, @options.to_s(prefix: " ")) end it "ignores options with help: false" do @options.on "-x", "something", help: false refute_match(/something/, @options.to_s) end it "adds 'tail' options to the bottom of the help text" do @options.on "-h", "--help", tail: true @options.on "-f", "--foo" assert_match(/^ -h, --help/, @options.to_s.lines.last) end end describe "custom banner" do it "is prefixed with defined banner" do @options_config = Slop::Options.new({banner: "custom banner"}) assert_match(/^custom banner/, @options_config.to_s) end it "banner is disabled" do @options_config = Slop::Options.new({banner: false}) assert_match("", @options_config.to_s) end end end slop-4.5.0/test/option_test.rb0000644000175000017500000000164513133607775016226 0ustar uwabamiuwabamirequire 'test_helper' describe Slop::Option do def option(*args) Slop::Option.new(*args) end describe "#flag" do it "returns the flags joined by a comma" do assert_equal "-f, --bar", option(%w(-f --bar), nil).flag assert_equal "--bar", option(%w(--bar), nil).flag end end describe "#key" do it "uses the last flag and strips trailing hyphens" do assert_equal :foo, option(%w(-f --foo), nil).key end it "converts dashes to underscores to make multi-word options symbol-friendly" do assert_equal :foo_bar, option(%w(-f --foo-bar), nil).key end it "when specified, it won't convert dashes to underscores to make multi-word options symbol-friendly" do assert_equal :'foo-bar', option(%w(-f --foo-bar), nil, underscore_flags: false).key end it "can be overridden" do assert_equal :bar, option(%w(-f --foo), nil, key: "bar").key end end end slop-4.5.0/test/test_helper.rb0000644000175000017500000000011713133607775016166 0ustar uwabamiuwabami$VERBOSE = true require 'slop' require 'minitest/autorun' require 'stringio' slop-4.5.0/test/result_test.rb0000644000175000017500000000576413133607775016242 0ustar uwabamiuwabamirequire 'test_helper' module Slop class ReverseEverythingOption < BoolOption def finish(result) result.used_options.grep(Slop::StringOption).each do |opt| opt.value = opt.value.reverse end end end end describe Slop::Result do before do @options = Slop::Options.new @verbose = @options.bool "-v", "--verbose" @name = @options.string "--name" @unused = @options.string "--unused" @long_option = @options.string "--long-option" @result = @options.parse %w(foo -v --name lee --long-option bar argument) end it "increments option count" do # test this here so it's more "full stack" assert_equal 1, @verbose.count assert_equal 1, @long_option.count @result.parser.parse %w(-v --verbose) assert_equal 2, @verbose.count end it "handles default values" do @options.string("--foo", default: "bar") @result.parser.parse %w() assert_equal "bar", @result[:foo] @result.parser.parse %w(--foo) assert_equal "bar", @result[:foo] end it "handles custom finishing" do @options.string "--foo" @options.reverse_everything "-r" @result.parser.parse %w(-r --name lee --foo bar) assert_equal %w(eel rab), @result.to_hash.values_at(:name, :foo) end it "yields arguments to option blocks" do output = nil @options.string("--foo") { |v| output = v } @result.parser.parse %w(--foo bar) assert_equal output, "bar" end describe "#[]" do it "returns an options value" do assert_equal "lee", @result["name"] assert_equal "lee", @result[:name] assert_equal "lee", @result["--name"] assert_equal "bar", @result["long_option"] assert_equal "bar", @result[:long_option] assert_equal "bar", @result["--long-option"] end end describe "#[]=" do it "sets an options value" do assert_equal "lee", @result["name"] @result["name"] = "bob" assert_equal "bob", @result[:name] end it "raises if an option isn't found" do assert_raises ArgumentError do @result["zomg"] = "something" end end end describe "#method_missing" do it "checks if options have been used" do assert_equal true, @result.verbose? assert_equal false, @result.unused? assert_equal true, @result.long_option? end end describe "#option" do it "returns an option by flag" do assert_equal @verbose, @result.option("--verbose") assert_equal @verbose, @result.option("-v") assert_equal @long_option, @result.option("--long-option") end it "ignores prefixed hyphens" do assert_equal @verbose, @result.option("verbose") assert_equal @verbose, @result.option("-v") end it "returns nil if nothing is found" do assert_nil @result.option("foo") end end describe "#to_hash" do it "returns option keys and values" do assert_equal({ verbose: true, name: "lee", unused: nil, long_option: "bar" }, @result.to_hash) end end end slop-4.5.0/test/parser_test.rb0000644000175000017500000000610013133607775016201 0ustar uwabamiuwabamirequire 'test_helper' describe Slop::Parser do before do @options = Slop::Options.new @verbose = @options.bool "-v", "--verbose" @name = @options.string "-n", "--name" @unused = @options.string "--unused" @parser = Slop::Parser.new(@options) @result = @parser.parse %w(foo -v --name lee argument) end it "ignores everything after --" do @parser.parse %w(-v -- -v --name lee) assert_equal [@verbose], @parser.used_options assert_equal ["-v", "--name", "lee"], @parser.arguments end it "parses flag=argument" do @options.integer "-p", "--port" @result.parser.parse %w(--name=bob -p=123) assert_equal "bob", @result[:name] assert_equal 123, @result[:port] end it "parses arg with leading -" do @options.string "-t", "--text" @result.parser.parse %w(--name=bob --text --sometext) assert_equal "bob", @result[:name] assert_equal "--sometext", @result[:text] end it "parses negative integer" do @options.integer "-p", "--port" @result.parser.parse %w(--name=bob --port -123) assert_equal "bob", @result[:name] assert_equal(-123, @result[:port]) end it "parses negative float" do @options.float "-m", "--multiple" @result.parser.parse %w(--name=bob -m -123.987) assert_equal "bob", @result[:name] assert_equal(-123.987, @result[:multiple]) end describe "parsing grouped short flags" do before do @options.bool "-q", "--quiet" end it "parses boolean flags" do @result.parser.parse %w(-qv) assert_equal true, @result.quiet? assert_equal true, @result.verbose? end it "sends the argument to the last flag" do @result.parser.parse %w(-qvn foo) assert_equal "foo", @result[:name] end it "doesn't screw up single hyphen long options" do @options.string "-host" @result.parser.parse %w(-host localhost) assert_equal "localhost", @result[:host] end end describe "short flags with arguments" do before do @options.integer "-i" @options.string "-s" end it "parses the argument" do @result.parser.parse %w(-i5 -sfoo) assert_equal 5, @result[:i] assert_equal "foo", @result[:s] end end describe "#used_options" do it "returns all options that were parsed" do assert_equal [@verbose, @name], @parser.used_options end end describe "#unused_options" do it "returns all options that were not parsed" do assert_equal [@unused], @parser.unused_options end end describe "#arguments" do it "returns all unparsed arguments" do assert_equal %w(foo argument), @parser.arguments end it "does not return --" do @parser.parse %w(-v -- --name lee) assert_equal %w(--name lee), @parser.arguments end it "correctly removes the option argument" do @parser.parse %w(lee --name lee lee) assert_equal %w(lee lee), @parser.arguments end it "correctly removes options that use =" do @parser.parse %w(lee --name=lee lee) assert_equal %w(lee lee), @parser.arguments end end end slop-4.5.0/test/slop_test.rb0000644000175000017500000000065013133607775015666 0ustar uwabamiuwabamirequire "test_helper" describe Slop do describe ".option_defined?" do it "handles bad constant names" do assert_equal false, Slop.option_defined?("Foo?Bar") end it "returns false if the option is not defined" do assert_equal false, Slop.option_defined?("FooBar") end it "returns true if the option is defined" do assert_equal true, Slop.option_defined?("String") end end end slop-4.5.0/LICENSE0000644000175000017500000000203113133607775013346 0ustar uwabamiuwabamiCopyright (c) Lee Jarvis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. slop-4.5.0/CHANGELOG.md0000644000175000017500000000446513133607775014167 0ustar uwabamiuwabamiChangelog ========= v4.5.0 (2017-05-22) ------------------- Features: * Added config option to avoid translating flags-with-dashes into underscores. #206 (@lbriais) v4.4.3 (2017-05-02) ------------------- Bug fixes: * Ruby 2.0.0 support broken in v4.4.2 v4.4.2 (2017-04-29) ------------------- Bug fixes: * Fix support for parsing -x5 or -nfoo. #199 * Fix removing arguments after `--`. #194 v4.4.1 (2016-08-21) ------------------- Bug fixes: * Handle bad constant names in `Slop.option_defined?`. #198 (Ellen Marie Dash) v4.4.0 (2016-08-15) ------------------- Features * Support parsing arguments prefixed with dashes. #192 (Andrew Clemons) Bug fixes: * Retain sort order inside tail sort. #193 (Caio Chassot) v4.3.0 (2016-03-19) ------------------- Features * Allow disabling array delimiter. #189 (Mike Pastore) * Allow passing custom banner as config. #191 (Philip Rees) v4.2.1 (2015-11-25) ------------------- Features: * Better handling of option names with multiple words. #169 (Tim Rogers) Minor enhancements: * add ARGF notes to Arguments (README). #173 (Rick Hull) Bug fixes: * Fix arguments removed with option arguments. #182 (Naoki Mizuno) * Fix bug where true is passed to BoolOption block regardless of --no- prefix. #184 (Ben Brady) * only raise MissingArgument if not `default_value`. #163 (Ben Brady) v4.2.0 (2015-04-18) ------------------- Features: * Support for Regexp option type #167 (Laurent Arnoud) * Support prefixed `--no-` for explicitly setting boolean options to `false` #168 * Better handling of flags with multiple words #169 (Tim Rogers) v4.1.0 (2015-04-18) ------------------- Features: * Support for FloatOption #156 (Rick Hull) * Support for `limit` config to ArrayOption. * Support for `tail` config to add options to the bottom of the help text. * Add explicit setter (#[]=) to Result class. #162 * Implement flag gettings for UnknownOption and MissingArgument error classes. #165 (sigurdsvela) Minor enhancements: * Reset parser every time `parse` is called. Bug fixes: * Remove "--" from unprocessed arguments #157 (David Rodríguez). v4.0.0 (2014-12-27) ------------------- Features: * Rebuilt from the ground up. See the v3 changelog for all existing changes: https://github.com/leejarvis/slop/blob/v3/CHANGES.md slop-4.5.0/README.md0000644000175000017500000002120713133607775013626 0ustar uwabamiuwabamiSlop ==== Slop is a simple option parser with an easy to remember syntax and friendly API. Version 4 of Slop is aimed at Ruby 2.0 or later. Please use [Version 3](https://github.com/leejarvis/slop/tree/v3) for Ruby 1.9 support. [![Build Status](https://travis-ci.org/leejarvis/slop.svg?branch=master)](http://travis-ci.org/leejarvis/slop) Installation ------------ gem install slop Usage ----- ```ruby opts = Slop.parse do |o| o.string '-h', '--host', 'a hostname' o.integer '--port', 'custom port', default: 80 o.bool '-v', '--verbose', 'enable verbose mode' o.bool '-q', '--quiet', 'suppress output (quiet mode)' o.bool '-c', '--check-ssl-certificate', 'check SSL certificate for host' o.on '--version', 'print the version' do puts Slop::VERSION exit end end ARGV #=> -v --host 192.168.0.1 --check-ssl-certificate opts[:host] #=> 192.168.0.1 opts.verbose? #=> true opts.quiet? #=> false opts.check_ssl_certificate? #=> true opts.to_hash #=> { host: "192.168.0.1", port: 80, verbose: true, quiet: false, check_ssl_certificate: true } ``` Option types ------------ Built in Option types are as follows: ```ruby o.string #=> Slop::StringOption, expects an argument o.bool #=> Slop::BoolOption, no argument, aliased to BooleanOption o.integer #=> Slop::IntegerOption, expects an argument, aliased to IntOption o.float #=> Slop::FloatOption, expects an argument o.array #=> Slop::ArrayOption, expects an argument o.regexp #=> Slop::RegexpOption, expects an argument o.null #=> Slop::NullOption, no argument and ignored from `to_hash` o.on #=> alias for o.null ``` You can see all built in types in `slop/types.rb`. Suggestions or pull requests for more types are welcome. Advanced Usage -------------- This example is really just to describe how the underlying API works. It's not necessarily the best way to do it. ```ruby opts = Slop::Options.new opts.banner = "usage: connect [options] ..." opts.separator "" opts.separator "Connection options:" opts.string "-H", "--hostname", "a hostname" opts.int "-p", "--port", "a port", default: 80 opts.separator "" opts.separator "Extra options:" opts.array "--files", "a list of files to import" opts.bool "-v", "--verbose", "enable verbose mode", default: true parser = Slop::Parser.new(opts) result = parser.parse(["--hostname", "192.168.0.1", "--no-verbose"]) result.to_hash #=> { hostname: "192.168.0.1", port: 80, # files: [], verbose: false } puts opts # prints out help ``` Arguments --------- It's common to want to retrieve an array of arguments that were not processed by the parser (i.e options or consumed arguments). You can do that with the `Result#arguments` method: ```ruby args = %w(connect --host google.com GET) opts = Slop.parse args do |o| o.string '--host' end p opts.arguments #=> ["connect", "GET"] # also aliased to `args` ``` This is particularly useful when writing scripts with `ARGF`: ```ruby opts = Slop.parse do |blah| # ... end # make sure sloptions aren't consumed by ARGF ARGV.replace opts.arguments ARGF.each { |line| # ... } ``` Arrays ------ Slop has a built in `ArrayOption` for handling array values: ```ruby opts = Slop.parse do |o| # the delimiter defaults to ',' o.array '--files', 'a list of files', delimiter: ',' end # both of these will return o[:files] as ["foo.txt", "bar.rb"]: # --files foo.txt,bar.rb # --files foo.txt --files bar.rb ``` If you want to disable the built-in string-splitting, set the delimiter to `nil`. Custom option types ------------------- Slop uses option type classes for every new option added. They default to the `NullOption`. When you type `o.array` Slop looks for an option called `Slop::ArrayOption`. This class must contain at least 1 method, `call`. This method is executed at parse time, and the return value of this method is used for the option value. We can use this to build custom option types: ```ruby module Slop class PathOption < Option def call(value) Pathname.new(value) end end end opts = Slop.parse %w(--path ~/) do |o| o.path '--path', 'a custom path name' end p opts[:path] #=> # ``` Custom options can also implement a `finish` method. This method by default does nothing, but it's executed once *all* options have been parsed. This allows us to go back and mutate state without having to rely on options being parsed in a particular order. Here's an example: ```ruby module Slop class FilesOption < ArrayOption def finish(opts) if opts.expand? self.value = value.map { |f| File.expand_path(f) } end end end end opts = Slop.parse %w(--files foo.txt,bar.rb -e) do |o| o.files '--files', 'an array of files' o.bool '-e', '--expand', 'if used, list of files will be expanded' end p opts[:files] #=> ["/full/path/foo.txt", "/full/path/bar.rb"] ``` Errors ------ Slop will raise errors for the following: * An option used without an argument when it expects one: `Slop::MissingArgument` * An option used that Slop doesn't know about: `Slop::UnknownOption` These errors inherit from `Slop::Error`, so you can rescue them all. Alternatively you can suppress these errors with the `suppress_errors` config option: ```ruby opts = Slop.parse suppress_errors: true do o.string '-name' end # or per option: opts = Slop.parse do o.string '-host', suppress_errors: true o.int '-port' end ``` Printing help ------------- The return value of `Slop.parse` is a `Slop::Result` which provides a nice help string to display your options. Just `puts opts` or call `opts.to_s`: ```ruby opts = Slop.parse do |o| o.string '-h', '--host', 'hostname' o.int '-p', '--port', 'port (default: 80)', default: 80 o.string '--username' o.separator '' o.separator 'other options:' o.bool '--quiet', 'suppress output' o.on '-v', '--version' do puts "1.1.1" end end puts opts ``` Output: ``` % ruby run.rb usage: run.rb [options] -h, --host hostname -p, --port port (default: 80) --username other options: --quiet suppress output -v, --version ``` This method takes an optional `prefix` value, which defaults to `" " * 4`: ``` puts opts.to_s(prefix: " ") ``` It'll deal with aligning your descriptions according to the longest option flag. Here's an example of adding your own help option: ```ruby o.on '--help' do puts o exit end ``` Commands -------- As of version 4, Slop does not have built in support for git-style subcommands. You can use version 3 of Slop (see `v3` branch). I also expect there to be some external libraries released soon that wrap around Slop to provide support for this feature. I'll update this document when that happens. Upgrading from version 3 ------------------------ Slop v4 is completely non-backwards compatible. The code has been rewritten from the ground up. If you're already using version 3 you *have* to update your code to use version 4. Here's an overview of the more fundamental changes: #### No more `instance_eval` Before: ```ruby Slop.parse do on 'v', 'version' do puts VERSION end end ``` After: ```ruby Slop.parse do |o| o.on '-v', '--version' do puts VERSION end end ``` #### No more `as` for option types Instead, the type is declared in the method call. Before: ```ruby on 'port=', as: Integer ``` After: ```ruby o.int '--port' # or integer ``` See the custom types section of the document. #### No more trailing `=` Instead, the "does this option expect an argument" question is answered by the option type (i.e `on` and `bool` options do not expect arguments, all others do. They handle type conversion, too. #### Hyphens are required This was a hard decision to make, but you must provide prefixed hyphens when declaring your flags. This makes the underlying code much nicer and much less ambiguous, which leads to less error prone code. It also means you can easily support single hyphen prefix for a long flag, i.e `-hostname` which you could not do before. It also provides a hidden feature, which is infinity flag aliases: `o.string '-f', '-x', '--foo', '--bar', 'this is insane'` #### Strict is now on by default v3 had a `strict` option. v4 has no such option, and to suppress errors you can instead provide the `suppress_errors: true` option to Slop. #### No more parse! Where v3 has both `Slop.parse` and `Slop.parse!`, v4 only has `parse`. The former was used to decide whether Slop should or should not mutate the original args (usually ARGV). This is almost never what you want, and it can lead to confusion. Instead, `Slop::Result` provides an `arguments` methods: ```ruby opts = Slop.parse do |o| o.string '--hostname', '...' end # ARGV is "hello --hostname foo bar" p opts.arguments #=> ["hello", "bar"] ```