├── .gitignore ├── CONTRIBUTING ├── LICENSE ├── README.md ├── Rakefile ├── clap.gemspec ├── lib └── clap.rb └── test └── clap_test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /pkg 2 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | This code tries to solve a particular problem with a very simple 2 | implementation. We try to keep the code to a minimum while making 3 | it as clear as possible. The design is very likely finished, and 4 | if some feature is missing it is possible that it was left out on 5 | purpose. That said, new usage patterns may arise, and when that 6 | happens we are ready to adapt if necessary. 7 | 8 | A good first step for contributing is to meet us on IRC and discuss 9 | ideas. We spend a lot of time on #lesscode at freenode, always ready 10 | to talk about code and simplicity. If connecting to IRC is not an 11 | option, you can create an issue explaining the proposed change and 12 | a use case. We pay a lot of attention to use cases, because our 13 | goal is to keep the code base simple. Usually the result of a 14 | conversation is the creation of a different tool. 15 | 16 | Please don't start the conversation with a pull request. The code 17 | should come at last, and even though it may help to convey an idea, 18 | more often than not it draws the attention to a particular 19 | implementation. 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010 Michel Martens 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Clap 2 | ==== 3 | 4 | Command line argument parsing for simple applications. 5 | 6 | Description 7 | ----------- 8 | 9 | Clap is a small library that can be bundled with your command line 10 | application. It covers the simple case of executing code based on the 11 | flags or parameters passed. 12 | 13 | Usage 14 | ----- 15 | 16 | Using Clap is simple: just pass `ARGV` and a hash of flags, and it 17 | will extract the arguments as needed. 18 | 19 | ``` ruby 20 | Clap.run ARGV, 21 | "-a" => lambda { |param| ... }, 22 | "-b" => lambda { ... } 23 | ``` 24 | 25 | To better illustrate the usage, in the following examples `ARGV` is 26 | replaced by an array of strings. 27 | 28 | If you want your command line application to require a file or display 29 | a version number, you can configure it like this: 30 | 31 | ``` ruby 32 | Clap.run %w(-r foo -v), 33 | "-r" => lambda { |file| require file }, 34 | "-v" => lambda { puts VERSION } 35 | ``` 36 | 37 | This will detect the `-r` or `-v` flags and act accordingly. Note that 38 | it will also read the necessary number of parameters for each flag 39 | based on the arity of the passed lambda. 40 | 41 | Another example, for an application that takes a `-v` flag and also a 42 | list of files: 43 | 44 | ``` ruby 45 | files = Clap.run %w(-v foo bar), 46 | "-v" => lambda { puts VERSION } 47 | 48 | files == %w(foo bar) 49 | ``` 50 | 51 | Using methods instead of lambdas 52 | -------------------------------- 53 | 54 | If you prefer to group the options in a module or class, you can still 55 | attach the methods to command line flags: 56 | 57 | ``` ruby 58 | class MyApp 59 | module CLI 60 | def self.version 61 | puts VERSION 62 | end 63 | 64 | def self.help(command) 65 | puts HELP[command] 66 | end 67 | end 68 | end 69 | 70 | Clap.run %w(-v -h foo), 71 | "-v" => MyApp::CLI.method(:version), 72 | "-h" => MyApp::CLI.method(:help) 73 | ``` 74 | 75 | When in doubt, check the tests for the different use cases. 76 | 77 | Installation 78 | ------------ 79 | 80 | $ gem install clap 81 | 82 | License 83 | ------- 84 | 85 | Copyright (c) 2010 Michel Martens 86 | 87 | Permission is hereby granted, free of charge, to any person 88 | obtaining a copy of this software and associated documentation 89 | files (the "Software"), to deal in the Software without 90 | restriction, including without limitation the rights to use, 91 | copy, modify, merge, publish, distribute, sublicense, and/or sell 92 | copies of the Software, and to permit persons to whom the 93 | Software is furnished to do so, subject to the following 94 | conditions: 95 | 96 | The above copyright notice and this permission notice shall be 97 | included in all copies or substantial portions of the Software. 98 | 99 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 100 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 101 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 102 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 103 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 104 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 105 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 106 | OTHER DEALINGS IN THE SOFTWARE. 107 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | task :test do 2 | require "cutest" 3 | Cutest.run(Dir["test/*.rb"]) 4 | end 5 | 6 | task :default => :test 7 | -------------------------------------------------------------------------------- /clap.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = "clap" 3 | s.version = "1.0.0" 4 | s.summary = "Command line argument parsing for simple applications." 5 | s.description = "Clap is a small library that can be bundled with your command line application. It covers the simple case of executing code based on the flags or parameters passed." 6 | s.authors = ["Michel Martens"] 7 | s.email = ["michel@soveran.com"] 8 | s.homepage = "http://github.com/soveran/clap" 9 | s.files = Dir[ "LICENSE", "README.md", "Rakefile", "lib/**/*.rb", "*.gemspec", "test/**/*.rb" ] 10 | s.add_development_dependency "cutest" 11 | end 12 | -------------------------------------------------------------------------------- /lib/clap.rb: -------------------------------------------------------------------------------- 1 | class Clap 2 | attr :argv 3 | attr :opts 4 | 5 | def self.run(args, opts) 6 | new(args, opts).run 7 | end 8 | 9 | def initialize(argv, opts) 10 | @argv = argv.dup 11 | @opts = opts 12 | end 13 | 14 | def run 15 | args = [] 16 | 17 | while argv.any? 18 | 19 | item = argv.shift 20 | flag = opts[item] 21 | 22 | if flag 23 | 24 | # Work around lambda semantics in 1.8.7. 25 | arity = [flag.arity, 0].max 26 | 27 | # Raise if there are not enough parameters 28 | # available for the flag. 29 | if argv.size < arity 30 | raise ArgumentError 31 | end 32 | 33 | # Call the lambda with N items from argv, 34 | # where N is the lambda's arity. 35 | flag.call(*argv.shift(arity)) 36 | else 37 | 38 | # Collect the items that don't correspond to 39 | # flags. 40 | args << item 41 | end 42 | end 43 | 44 | args 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /test/clap_test.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path("../lib/clap", File.dirname(__FILE__)) 2 | 3 | test "flag with one argument" do 4 | result = Clap.run %w(-x y), "-x" => lambda { |flag| assert flag == "y" } 5 | assert result == [] 6 | end 7 | 8 | test "flag with more than one argument" do 9 | result = Clap.run %w(-x y z), "-x" => lambda { |y, z| assert [y, z] == %w(y z) } 10 | assert result == [] 11 | end 12 | 13 | test "flag with wrong number of arguments" do 14 | assert_raise(ArgumentError) do 15 | Clap.run %w(-x), "-x" => lambda { |flag| } 16 | end 17 | end 18 | 19 | test "extract flags with parameters" do 20 | result = Clap.run %w(a b -x y c), "-x" => lambda { |flag| assert flag == "y" } 21 | assert result == %w(a b c) 22 | end 23 | 24 | test "extract flags with zero arity" do 25 | result = Clap.run %w(a b -x c), "-x" => lambda { || } 26 | assert result == %w(a b c) 27 | end 28 | 29 | test "extract flags with no parameters" do 30 | result = Clap.run %w(a b -x c), "-x" => lambda {} 31 | assert result == %w(a b c) 32 | end 33 | 34 | test "use a method instead of a lambda" do 35 | class Foo 36 | def self.bar(flag) 37 | assert flag == "y" 38 | end 39 | end 40 | 41 | result = Clap.run %w(a b -x y c), "-x" => Foo.method(:bar) 42 | assert result == %w(a b c) 43 | end 44 | --------------------------------------------------------------------------------