kommand 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e728a399b1bbe6ae3294871c2f3186f6e866c675
4
+ data.tar.gz: 692bbc295236b95010345f8638aae5ed036506f4
5
+ SHA512:
6
+ metadata.gz: 2fb412fdc3e080cbc595c7c455fcba65fb68cef6de77c5c7f58b7f45228552cdfeabf2f95a7591b082f8eef4fd94136278ed9eb69edb2ce1655f18396bf84e4f
7
+ data.tar.gz: 841eb474194955c825122df2a6d97871563f456403c9e0bd60e3f1bf90b6e4cfca50411f378b6f8133b8db8067f6ccaaf82ab37c834d98097ce69fd604cc003d
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ *.swp
23
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Mark Rebec
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Kommand
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'kommand'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install kommand
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/kommand/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/kommand ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Kommand
4
+ #
5
+ $:.unshift File.expand_path("../../lib", __FILE__)
6
+
7
+ require 'kommand/kli'
8
+
9
+ Kommand::KLI.start(*ARGV)
data/kommand.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'kommand/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "kommand"
8
+ spec.version = Kommand::VERSION
9
+ spec.authors = ["Mark Rebec"]
10
+ spec.email = ["mark@markrebec.com"]
11
+ spec.summary = %q{Simple object-oriented interface for building CLI commands with subcommands.}
12
+ spec.description = %q{Simple object-oriented interface for building CLI commands with subcommands.}
13
+ spec.homepage = "https://github.com/markrebec/kommand"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "activesupport"
22
+ spec.add_dependency "inkjet"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,116 @@
1
+ require 'active_support/inflector'
2
+ require 'kommand'
3
+ require 'kommand/scripts'
4
+ require 'kommand/commands'
5
+
6
+ module Kommand
7
+ class CLI
8
+ include Scripts::Script
9
+
10
+ def self.inherited(sub)
11
+ sub.send :valid_argument, Scripts::Argument.new("-v, --verbose", :valid => [], :summary => "Output additional information from command executions to STDOUT")
12
+ sub.send :valid_argument, Scripts::Argument.new("-d, --debug", :valid => [], :summary => "Output full backtraces for exceptions and errors")
13
+ end
14
+
15
+ valid_argument Scripts::Argument.new("-v, --verbose", :valid => [], :summary => "Output additional information from command executions to STDOUT")
16
+ valid_argument Scripts::Argument.new("-d, --debug", :valid => [], :summary => "Output full backtraces for exceptions and errors")
17
+
18
+ def self.verbose?
19
+ user_arguments.map(&:key).include?("-v")
20
+ end
21
+
22
+ def self.debug?
23
+ user_arguments.map(&:key).include?("-d")
24
+ end
25
+
26
+ def self.exec(cmd)
27
+ if verbose?
28
+ system cmd
29
+ else
30
+ `#{cmd}`
31
+ end
32
+ end
33
+
34
+ def self.add_arguments(*args)
35
+ keep = []
36
+ args.each_with_index do |arg,a|
37
+ if Commands::exists?(arg)
38
+ begin
39
+ @command = Commands::command(arg)
40
+ @command.set_arguments(*args.slice(a+1,args.length-a))
41
+ rescue Scripts::InvalidArgument => e
42
+ puts e.message
43
+ Commands::command(arg).usage
44
+ exit 1
45
+ end
46
+ break
47
+ end
48
+
49
+ keep << arg
50
+ end
51
+ super(*keep)
52
+ end
53
+
54
+ def self.binary=(bin)
55
+ @binary = bin
56
+ end
57
+
58
+ def self.binary
59
+ @binary ||= Kommand.kommand
60
+ end
61
+
62
+ def self.command_name
63
+ binary
64
+ end
65
+
66
+ def self.version=(ver)
67
+ @version = ver
68
+ end
69
+
70
+ def self.version
71
+ @version ||= VERSION
72
+ end
73
+
74
+ def self.usage
75
+ puts "#{binary} v#{version}"
76
+ puts
77
+ puts "usage: #{binary} #{valid_arguments.to_s} <command> [<args>]"
78
+ unless valid_arguments.empty?
79
+ puts
80
+ puts "Arguments:"
81
+ puts valid_arguments.to_help
82
+ end
83
+ puts
84
+ puts "The available #{binary} commands are:"
85
+
86
+ Commands::commands.each do |cmd|
87
+ print " %-#{Commands::commands.sort { |a,b| a.command_name.length <=> b.command_name.length }.last.command_name.length + 2}s" % cmd.command_name
88
+ puts "# #{cmd.command_summary}"
89
+ end
90
+
91
+ puts
92
+ puts "See `#{binary} help <command>` for more information on a specific command."
93
+ end
94
+
95
+ def self.start(*args)
96
+ args = args[0] if args.length == 1 && args.first.is_a?(Array)
97
+ begin
98
+ set_arguments(*args)
99
+ rescue Scripts::InvalidArgument => e
100
+ puts e.message
101
+ return
102
+ rescue Exception => e
103
+ usage
104
+ return
105
+ end
106
+
107
+ if @command.nil?
108
+ usage
109
+ return
110
+ end
111
+
112
+ @command.run
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,90 @@
1
+ module Kommand
2
+ module Commands
3
+ module Command
4
+ def self.included(base)
5
+ Commands::commands << base # Keep track of all commands
6
+
7
+ base.send :include, Scripts::Script
8
+ base.send :extend, ClassMethods
9
+ base.send :include, InstanceMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def command_name(n=nil)
14
+ @command_name = n unless n.nil?
15
+ return @command_name unless @command_name.nil?
16
+ self.name.underscore.split("/").last
17
+ end
18
+
19
+ def command_summary(summary=nil)
20
+ @command_summary = summary unless summary.nil?
21
+ @command_summary
22
+ end
23
+ alias_method :summary, :command_summary
24
+
25
+ def usage
26
+ puts "usage: #{::Kommand.kommand} #{command_name} #{valid_arguments.to_s}"
27
+ end
28
+
29
+ def run
30
+ begin
31
+ @command ||= new
32
+ before_hooks.each { |block| @command.instance_eval(&block) }
33
+ @command.run
34
+ after_hooks.each { |block| @command.instance_eval(&block) }
35
+ rescue Exception => e
36
+ puts e.message
37
+ puts e.backtrace if ::Kommand::CLI.debug?
38
+ @command.usage if e.is_a?(Scripts::InvalidArgument)
39
+ return
40
+ end
41
+ end
42
+
43
+ def append_after_hook(&block)
44
+ @after_hooks ||= []
45
+ @after_hooks << block
46
+ end
47
+ alias_method :after_hook, :append_after_hook
48
+
49
+ def prepend_after_hook(&block)
50
+ @after_hooks ||= []
51
+ @after_hooks.unshift block
52
+ end
53
+
54
+ def after_hooks
55
+ @after_hooks ||= []
56
+ @after_hooks
57
+ end
58
+
59
+ def append_before_hook(&block)
60
+ @before_hooks ||= []
61
+ @before_hooks << block
62
+ end
63
+ alias_method :before_hook, :append_before_hook
64
+
65
+ def prepend_before_hook(&block)
66
+ @before_hooks ||= []
67
+ @before_hooks.unshift block
68
+ end
69
+
70
+ def before_hooks
71
+ @before_hooks ||= []
72
+ @before_hooks
73
+ end
74
+
75
+ def to_arg
76
+ Scripts::Argument.new(command_name, :summary => command_summary)
77
+ end
78
+ end
79
+
80
+ module InstanceMethods
81
+ %w(command_name command_summary usage).each do |method|
82
+ define_method method do |*args|
83
+ self.class.send method, *args
84
+ end
85
+ end
86
+ end
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,45 @@
1
+ module Kommand
2
+ module Commands
3
+ class Help
4
+ include Command
5
+
6
+ command_summary "Provides help and usage examples"
7
+
8
+ valid_arguments *Commands::commands.map(&:to_arg)
9
+ validate_arguments false
10
+
11
+ def self.usage
12
+ puts <<USAGE
13
+ usage: #{::Kommand.kommand} #{command_name} <command>
14
+
15
+ The available commands are:
16
+ USAGE
17
+
18
+ Commands::commands.select { |cmd| cmd != self}.each do |cmd|
19
+ print " %-#{Commands::commands.sort { |a,b| a.command_name.length <=> b.command_name.length }.last.command_name.length + 2}s" % cmd.command_name
20
+ puts "# #{cmd.command_summary}"
21
+ end
22
+ end
23
+
24
+ def run
25
+ if arguments.empty?
26
+ usage
27
+ return
28
+ end
29
+
30
+ begin
31
+ cmd = Commands::commands.select { |cmd| cmd.command_name == arguments.first.key.underscore }.first
32
+ raise if cmd.nil?
33
+
34
+ puts cmd.command_summary
35
+ puts
36
+ print " "
37
+ cmd.usage
38
+ rescue
39
+ puts "Invalid Command: #{arguments.first.key.underscore}"
40
+ usage
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ module Kommand
2
+ module Commands
3
+ def self.commands
4
+ @commands ||= []
5
+ end
6
+
7
+ def self.exists?(cmd)
8
+ commands.map(&:command_name).include?(cmd.underscore.to_s)
9
+ end
10
+
11
+ def self.command(cmd)
12
+ raise "Command does not exist: #{cmd}" unless exists?(cmd)
13
+ commands.select { |command| command.command_name == cmd.underscore.to_s }.first
14
+ end
15
+ end
16
+ end
17
+
18
+ require 'kommand/commands/command'
19
+ require 'kommand/commands/help'
@@ -0,0 +1,6 @@
1
+ require 'kommand/cli'
2
+
3
+ module Kommand
4
+ class KLI < CLI
5
+ end
6
+ end
@@ -0,0 +1,40 @@
1
+ module Kommand
2
+ module Scripts
3
+ class Argument
4
+ attr_reader :value, :valid, :summary
5
+
6
+ def value=(val)
7
+ raise "Invalid value for `#{key}` argument: '#{val}'" if (!@valid.nil? && !@valid.include?(val)) && (!val.nil? && !val.empty?)
8
+ @value = val
9
+ end
10
+
11
+ def key
12
+ @keys.is_a?(Array) ? @keys[0] : @keys
13
+ end
14
+
15
+ def keys
16
+ @keys.is_a?(Array) ? @keys : [@keys]
17
+ end
18
+
19
+ def name
20
+ keys.sort { |a,b| a.length <=> b.length }.last.gsub(/^--/, '')
21
+ end
22
+
23
+ protected
24
+
25
+ def initialize(keys, *args)
26
+ @keys = (keys.is_a?(String) && keys.match(/,?\s/) ? keys.gsub(/,?\s+/, " ").split(" ") : keys)
27
+
28
+ val = args.slice!(0) if %w(String Symbol Integer).include?(args[0].class.name)
29
+
30
+ if args.length > 0 && args[0].is_a?(Hash)
31
+ opts = args.slice!(0)
32
+ @valid = (opts[:valid].is_a?(Array) ? opts[:valid].map(&:to_s) : [opts[:valid].to_s]) if opts.has_key?(:valid)
33
+ @summary = opts[:summary] if opts.has_key?(:summary)
34
+ end
35
+
36
+ self.value = val
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,28 @@
1
+ module Kommand
2
+ module Scripts
3
+ class Arguments < Array
4
+
5
+ def to_s
6
+ map do |arg|
7
+ #if arg.valid.nil? || arg.valid.empty?
8
+ "[#{arg.keys.join(", ")}]"
9
+ #else
10
+ # "[#{arg.keys.join(", ")} = (#{arg.valid.join("|")})]"
11
+ #end
12
+ end.join(" ")
13
+ end
14
+
15
+ def to_help
16
+ map do |arg|
17
+ " #{"%-#{sort { |a,b| a.keys.join(", ").length <=> b.keys.join(", ").length }.last.keys.join(", ").length + 2}s" % arg.keys.join(", ")}# #{arg.summary}"
18
+ end.join("\n")
19
+ end
20
+
21
+ protected
22
+
23
+ def initialize
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ module Kommand
2
+ module Scripts
3
+ class InvalidArgument < Exception
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,108 @@
1
+ # TODO implement OptionParser
2
+ module Kommand
3
+ module Scripts
4
+ module Script
5
+ def self.included(base)
6
+ base.send :extend, ClassMethods
7
+ base.send :include, InstanceMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def run
12
+ @script ||= new
13
+ raise "You must define a `run` method for your script." unless @script.respond_to?(:run)
14
+ @script.run
15
+ end
16
+
17
+ def validate_arguments(val=nil)
18
+ @validate_arguments = val
19
+ end
20
+
21
+ def validate_arguments?
22
+ @validate_arguments = true if @validate_arguments.nil?
23
+ @validate_arguments
24
+ end
25
+
26
+ def valid_argument(arg)
27
+ @valid_args ||= Arguments.new
28
+ @valid_args << begin
29
+ if arg.is_a?(Argument)
30
+ arg
31
+ elsif arg.is_a?(Hash)
32
+ Argument.new(arg.keys.first.to_s, arg.values.first)
33
+ elsif arg.is_a?(Array)
34
+ Argument.new(arg[0].to_s, (arg.length > 1 ? arg[1] : []))
35
+ else
36
+ Argument.new(arg.to_s)
37
+ end
38
+ end
39
+ @valid_args.last
40
+ end
41
+
42
+ def valid_arguments(*args)
43
+ @valid_args ||= Arguments.new
44
+ return @valid_args if args.empty?
45
+
46
+ args.each { |arg| valid_argument(arg) }
47
+ @valid_args
48
+ end
49
+
50
+ def arguments(*args)
51
+ add_arguments(*args)
52
+ end
53
+
54
+ def user_arguments
55
+ arguments
56
+ end
57
+
58
+ def set_arguments(*args)
59
+ @arguments = Arguments.new
60
+ add_arguments(*args)
61
+ end
62
+
63
+ def add_arguments(*args)
64
+ @arguments ||= Arguments.new
65
+ args.each_with_index do |arg,a|
66
+ argk, argv = *parse_arg(arg)
67
+
68
+ if !argument_flag?(arg) && !valid_argument?(argk) && (a > 0 && argument_flag?(args[a-1]))
69
+ @arguments.last.value = arg
70
+ next
71
+ end
72
+
73
+ raise InvalidArgument, "Invalid Argument: #{arg}" if validate_arguments? && !valid_argument?(argk)
74
+ @arguments << argument_object(argk)
75
+ @arguments.last.value = argv unless argv.empty?
76
+ end
77
+ @arguments
78
+ end
79
+
80
+ def parse_arg(arg)
81
+ arga = arg.split("=")
82
+ [arga.slice!(0), arga.join("=")]
83
+ end
84
+
85
+ def valid_argument?(key)
86
+ valid_arguments.map(&:keys).flatten.include?(key)
87
+ end
88
+
89
+ def argument_flag?(arg)
90
+ arg.match(/\A(-)+[a-z0-9\-]=?.*\Z/i)
91
+ end
92
+
93
+ def argument_object(key)
94
+ valid_arguments.select { |varg| varg.keys.include?(key) }.first || Argument.new(key)
95
+ end
96
+ end
97
+
98
+ module InstanceMethods
99
+ %w(arguments valid_arguments).each do |method|
100
+ define_method method do |*args|
101
+ self.class.send method, *args
102
+ end
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,4 @@
1
+ require 'kommand/scripts/invalid_argument'
2
+ require 'kommand/scripts/argument'
3
+ require 'kommand/scripts/arguments'
4
+ require 'kommand/scripts/script'
@@ -0,0 +1,3 @@
1
+ module Kommand
2
+ VERSION = "0.0.1"
3
+ end
data/lib/kommand.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "kommand/version"
2
+
3
+ module Kommand
4
+ def self.kommand
5
+ File.basename($0)
6
+ end
7
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kommand
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mark Rebec
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: inkjet
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Simple object-oriented interface for building CLI commands with subcommands.
70
+ email:
71
+ - mark@markrebec.com
72
+ executables:
73
+ - kommand
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - Gemfile
79
+ - LICENSE.txt
80
+ - README.md
81
+ - Rakefile
82
+ - bin/kommand
83
+ - kommand.gemspec
84
+ - lib/kommand.rb
85
+ - lib/kommand/cli.rb
86
+ - lib/kommand/commands.rb
87
+ - lib/kommand/commands/command.rb
88
+ - lib/kommand/commands/help.rb
89
+ - lib/kommand/kli.rb
90
+ - lib/kommand/scripts.rb
91
+ - lib/kommand/scripts/argument.rb
92
+ - lib/kommand/scripts/arguments.rb
93
+ - lib/kommand/scripts/invalid_argument.rb
94
+ - lib/kommand/scripts/script.rb
95
+ - lib/kommand/version.rb
96
+ homepage: https://github.com/markrebec/kommand
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubyforge_project:
116
+ rubygems_version: 2.2.2
117
+ signing_key:
118
+ specification_version: 4
119
+ summary: Simple object-oriented interface for building CLI commands with subcommands.
120
+ test_files: []