kommand 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []