rbcli 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +60 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +28 -0
- data/LICENSE.txt +21 -0
- data/README.md +207 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/defaults.yml +4 -0
- data/examples/mytool +70 -0
- data/exe/rbcli +30 -0
- data/lib/rbcli/configurate.rb +91 -0
- data/lib/rbcli/engine/command.rb +179 -0
- data/lib/rbcli/engine/parser.rb +68 -0
- data/lib/rbcli/util/config.rb +140 -0
- data/lib/rbcli/util/hash_deep_symbolize.rb +28 -0
- data/lib/rbcli/util/logging.rb +73 -0
- data/lib/rbcli/util/string_colorize.rb +25 -0
- data/lib/rbcli/util.rb +4 -0
- data/lib/rbcli/version.rb +3 -0
- data/lib/rbcli.rb +11 -0
- data/rbcli.gemspec +42 -0
- metadata +153 -0
@@ -0,0 +1,179 @@
|
|
1
|
+
class Rbcli::Command
|
2
|
+
|
3
|
+
#include InheritableTraits
|
4
|
+
#traits :description
|
5
|
+
|
6
|
+
@commands = {}
|
7
|
+
|
8
|
+
def self.inherited subklass
|
9
|
+
@commands[subklass.name.downcase] = subklass.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.add_command name, klass
|
13
|
+
@commands[name.downcase] = klass.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.commands
|
17
|
+
@commands
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Interface Functions
|
22
|
+
##
|
23
|
+
def self.description desc; @desc = desc end
|
24
|
+
def description; self.class.instance_variable_get :@desc end
|
25
|
+
|
26
|
+
def self.usage usage; @usage = usage end
|
27
|
+
def usage; self.class.instance_variable_get :@usage end
|
28
|
+
|
29
|
+
def self.action █ @action = block end
|
30
|
+
def action; self.class.instance_variable_get :@action end
|
31
|
+
|
32
|
+
def self.parameter name, description, type: :boolean, default: nil, required: false
|
33
|
+
@paramlist ||= {}
|
34
|
+
@paramlist[name.to_sym] = {
|
35
|
+
description: description,
|
36
|
+
type: type,
|
37
|
+
default: default,
|
38
|
+
required: required
|
39
|
+
}
|
40
|
+
end
|
41
|
+
def paramlist; self.class.instance_variable_get :@paramlist end
|
42
|
+
|
43
|
+
def self.config_defaults filename
|
44
|
+
Rbcli::Config::add_defaults filename
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.config_default *params
|
48
|
+
Rbcli::Config::add_default *params
|
49
|
+
end
|
50
|
+
|
51
|
+
##
|
52
|
+
# END Interface Functions
|
53
|
+
##
|
54
|
+
|
55
|
+
##
|
56
|
+
# Run a given command
|
57
|
+
##
|
58
|
+
def self.runcmd cmd, local_params, cliopts
|
59
|
+
args = local_params.delete :args
|
60
|
+
params = local_params
|
61
|
+
global_opts = cliopts
|
62
|
+
config = Rbcli::config
|
63
|
+
|
64
|
+
@commands[cmd].action.call params, args, global_opts, config
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Returns all descriptions for display in CLI help
|
69
|
+
##
|
70
|
+
def self.descriptions indent_size, justification
|
71
|
+
#descmap = @commands.map { |name, klass| [name, klass.description] }.to_h
|
72
|
+
@commands.map do |name, cmdobj|
|
73
|
+
desc = ''
|
74
|
+
indent_size.times { desc << ' ' }
|
75
|
+
desc << name.ljust(justification)
|
76
|
+
desc << cmdobj.description
|
77
|
+
end.join("\n")
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# This method reads the parameters provided by the class and parses them from the CLI
|
82
|
+
##
|
83
|
+
def parseopts *args
|
84
|
+
params = paramlist
|
85
|
+
command_name = self.class.name.split('::')[-1].downcase
|
86
|
+
command_desc = description
|
87
|
+
command_usage = usage
|
88
|
+
optx = Trollop::options do
|
89
|
+
data = Rbcli.configuration
|
90
|
+
banner <<-EOS
|
91
|
+
#{data[:description]}
|
92
|
+
Selected Command:
|
93
|
+
#{command_name.ljust(21)}#{command_desc}
|
94
|
+
|
95
|
+
Usage:
|
96
|
+
#{data[:scriptname]} [options] #{command_name} [parameters]
|
97
|
+
|
98
|
+
#{command_usage}
|
99
|
+
|
100
|
+
Command-specific Parameters:
|
101
|
+
EOS
|
102
|
+
params.each do |name, opts|
|
103
|
+
opt name, opts[:description], type: opts[:type], default: opts[:default], required: opts[:required]
|
104
|
+
end if params.is_a? Hash
|
105
|
+
end
|
106
|
+
optx[:args] = ARGV
|
107
|
+
optx
|
108
|
+
end
|
109
|
+
|
110
|
+
##
|
111
|
+
# Inject metadata into response
|
112
|
+
##
|
113
|
+
# def self.wrap_metadata resp
|
114
|
+
# {
|
115
|
+
# meta: {
|
116
|
+
# status: 'ok',
|
117
|
+
# timestamp: (Time.now.to_f * 1000).floor
|
118
|
+
# },
|
119
|
+
# response: resp
|
120
|
+
# }.deep_stringify!
|
121
|
+
# end
|
122
|
+
|
123
|
+
####
|
124
|
+
### DEPRECATED
|
125
|
+
####
|
126
|
+
# Now we automatically pull in the plugins and register them as commands.
|
127
|
+
# Note that filenames must be the same as the class name and are case
|
128
|
+
# sensitive. Only one class per file.
|
129
|
+
##
|
130
|
+
# This is commented out as this functionality is deprecated. Instead we rely on subclassing to
|
131
|
+
# add the commands.
|
132
|
+
###
|
133
|
+
# Dir.glob("#{File.dirname(__FILE__)}/commands/*.rb") do |f|
|
134
|
+
# Rbcli::log.debug {"Loading CLI command #{f.split('commands/')[1].split('.')[0]}"}
|
135
|
+
# require f
|
136
|
+
# klassname = "Rbcli::Command::#{f.match(/.*\/([^\/]+)\.rb$/i)[1].capitalize}"
|
137
|
+
# klass = Object.const_get(klassname)
|
138
|
+
# klass.send :include, Rbcli::Command
|
139
|
+
# self.add_command klassname.split('::')[-1], klass
|
140
|
+
# end
|
141
|
+
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
# module InheritableTraits
|
146
|
+
#
|
147
|
+
# def self.included(base)
|
148
|
+
# base.extend ClassMethods
|
149
|
+
# end
|
150
|
+
#
|
151
|
+
# module ClassMethods
|
152
|
+
# def traits(*attrs)
|
153
|
+
# @traits ||= []
|
154
|
+
# @traits += attrs
|
155
|
+
# attrs.each do |attr|
|
156
|
+
# class_eval %{
|
157
|
+
# def self.#{attr}(string = nil)
|
158
|
+
# @#{attr} = string || @#{attr}
|
159
|
+
# end
|
160
|
+
# def self.#{attr}=(string = nil)
|
161
|
+
# #{attr}(string)
|
162
|
+
# end
|
163
|
+
# }
|
164
|
+
# end
|
165
|
+
# @traits
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# def inherited(subclass)
|
169
|
+
# (["traits"] + traits).each do |t|
|
170
|
+
# ivar = "@#{t}"
|
171
|
+
# subclass.instance_variable_set(
|
172
|
+
# ivar,
|
173
|
+
# instance_variable_get(ivar)
|
174
|
+
# )
|
175
|
+
# end
|
176
|
+
# end
|
177
|
+
# end
|
178
|
+
#
|
179
|
+
# end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'trollop'
|
2
|
+
|
3
|
+
module Rbcli::Parser
|
4
|
+
|
5
|
+
@cliopts = nil
|
6
|
+
|
7
|
+
def self.parse
|
8
|
+
@cliopts = Trollop::options do
|
9
|
+
data = Rbcli.configuration
|
10
|
+
version "#{data[:scriptname]} version: #{data[:version]}"
|
11
|
+
banner <<-EOS
|
12
|
+
#{data[:description]}
|
13
|
+
For more information on individual commands, run `#{data[:scriptname]} <command> -h`.
|
14
|
+
|
15
|
+
Usage:
|
16
|
+
#{data[:scriptname]} [options] command [parameters]
|
17
|
+
|
18
|
+
Commands:
|
19
|
+
#{Rbcli::Command.descriptions 6, 21}
|
20
|
+
|
21
|
+
[options]:
|
22
|
+
EOS
|
23
|
+
data[:options].each do |name, opts|
|
24
|
+
opt name.to_sym, opts[:description], type: opts[:type], default: opts[:default]
|
25
|
+
end
|
26
|
+
opt :json_output, 'Output result in machine-friendly JSON format', :type => :boolean, :default => false if data[:allow_json]
|
27
|
+
opt :config_file, 'Specify a config file manually', :type => :string, :default => data[:config_userfile]
|
28
|
+
opt :generate_config, 'Generate a new config file' #defaults to false
|
29
|
+
stop_on Rbcli::Command.commands.keys
|
30
|
+
end
|
31
|
+
|
32
|
+
@cmd = [ARGV.shift] # get the subcommand
|
33
|
+
if @cliopts[:generate_config]
|
34
|
+
Rbcli::Config::generate_userconf @cliopts[:config_file]
|
35
|
+
puts "User config generated at #{@cliopts[:config_file]} using default values."
|
36
|
+
elsif @cmd[0].nil?
|
37
|
+
if Rbcli.configuration[:default_action].nil?
|
38
|
+
Trollop::educate
|
39
|
+
else
|
40
|
+
Rbcli.configuration[:default_action].call @cliopts
|
41
|
+
end
|
42
|
+
elsif Rbcli::Command.commands.key? @cmd[0]
|
43
|
+
@cmd << Rbcli::Command.commands[@cmd[0]].parseopts
|
44
|
+
|
45
|
+
Rbcli.configuration[:pre_hook].call @cliopts unless Rbcli.configuration[:pre_hook].nil?
|
46
|
+
Rbcli::Command.runcmd(@cmd.shift, @cmd[0], @cliopts)
|
47
|
+
Rbcli.configuration[:post_hook].call @cliopts unless Rbcli.configuration[:pre_hook].nil?
|
48
|
+
else
|
49
|
+
Trollop::die "Unknown subcommand #{@cmd[0].inspect}"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.opts
|
55
|
+
@cliopts
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.cmd
|
59
|
+
@cmd
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
module Rbcli
|
65
|
+
def self.parse
|
66
|
+
Rbcli::Parser::parse
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
####
|
2
|
+
# Config Module
|
3
|
+
####
|
4
|
+
# The config module manages two distinct sets of config: one is the user's, and one is the application's default.
|
5
|
+
# This allows you to set default values for your configuration files, and can use the default values to generate a
|
6
|
+
# new user config file at any time by writing them to a file.
|
7
|
+
#
|
8
|
+
# Usage
|
9
|
+
#
|
10
|
+
# Rbcli::config[:key]
|
11
|
+
# Provides access to config file hash values under :key.
|
12
|
+
# Note the lowercase 'c' in config, which is different from the rest of the functions below.
|
13
|
+
#
|
14
|
+
# Rbcli::Config::set_file(filename, autoload:true, merge_defaults: false)
|
15
|
+
# This function allows you to set the path for the user's config file (eg: /etc/myscript/config.yml).
|
16
|
+
# autoload will load the file at the same time
|
17
|
+
# merge_defaults will fill in missing values in the user's config with default ones
|
18
|
+
#
|
19
|
+
# Rbcli::Config::add_defaults(filename)
|
20
|
+
# This function loads the contents of a YAML or JSON file into the default config. Used for custom configuration.
|
21
|
+
#
|
22
|
+
# Rbcli::Config::load
|
23
|
+
# This forces a reload of the config file.
|
24
|
+
#
|
25
|
+
# Rbcli::Config::generate_userconf
|
26
|
+
# This writes the config defaults to the filename set using the set_file command.
|
27
|
+
####
|
28
|
+
|
29
|
+
require 'yaml'
|
30
|
+
require 'fileutils'
|
31
|
+
require 'deep_merge'
|
32
|
+
|
33
|
+
module Rbcli
|
34
|
+
def self.config
|
35
|
+
Rbcli::Config::config
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module Rbcli::Config
|
40
|
+
|
41
|
+
@config = nil
|
42
|
+
@config_file = nil
|
43
|
+
@config_defaults = nil
|
44
|
+
@merge_defaults = false
|
45
|
+
@categorized_defaults = nil
|
46
|
+
@loaded = false
|
47
|
+
|
48
|
+
def self.set_userfile filename, merge_defaults: false, required: false
|
49
|
+
@config_file = filename
|
50
|
+
@merge_defaults = merge_defaults
|
51
|
+
@userfile_required = required
|
52
|
+
@loaded = false
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.add_categorized_defaults name, description, config
|
56
|
+
@categorized_defaults ||= {}
|
57
|
+
@categorized_defaults[name.to_sym] = {
|
58
|
+
description: description,
|
59
|
+
config: config
|
60
|
+
}
|
61
|
+
|
62
|
+
@config_defaults ||= {}
|
63
|
+
@config_defaults[name.to_sym] = {}
|
64
|
+
config.each do |k, v|
|
65
|
+
@config_defaults[name.to_sym][k.to_sym] = v[:value]
|
66
|
+
end
|
67
|
+
@loaded = false
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.add_default name, description: nil, value: nil
|
71
|
+
@config_individual_lines ||= []
|
72
|
+
text = "#{name.to_s}: #{value}".ljust(30) + " # #{description}"
|
73
|
+
@config_individual_lines.push text unless @config_individual_lines.include? text
|
74
|
+
@config_defaults[name.to_sym] = value
|
75
|
+
@loaded = false
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.add_defaults filename=nil, text: nil
|
79
|
+
return unless filename and File.exists? filename
|
80
|
+
@config_text ||= ''
|
81
|
+
@config_text += "\n" unless @config_text.empty?
|
82
|
+
File.readlines(filename).each do |line|
|
83
|
+
if (line.start_with? '---' or line.start_with? '...')
|
84
|
+
@config_text << "\n\n"
|
85
|
+
else
|
86
|
+
@config_text << line unless @config_text.include? line
|
87
|
+
end
|
88
|
+
end if filename and File.exists? filename
|
89
|
+
@config_text << "\n\n" << text if text
|
90
|
+
|
91
|
+
@config_defaults ||= {}
|
92
|
+
@config_defaults.deep_merge! YAML::load(@config_text).deep_symbolize!
|
93
|
+
@loaded = false
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.load
|
97
|
+
if (! @config_file.nil?) and File.exists? @config_file
|
98
|
+
@config = YAML::load(File.read(@config_file)).deep_symbolize!
|
99
|
+
@config.deep_merge! @config_defaults if @merge_defaults
|
100
|
+
elsif @userfile_required
|
101
|
+
puts "User's config file not found at #{@config_file}. Please run this tool with the -g option to generate it."
|
102
|
+
exit 1
|
103
|
+
else
|
104
|
+
@config = @config_defaults
|
105
|
+
end
|
106
|
+
@loaded = true
|
107
|
+
@config
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.config
|
111
|
+
self.load unless @loaded
|
112
|
+
(@config.nil?) ? @config_defaults : @config
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.generate_userconf filename
|
116
|
+
filepath = "#{(filename) ? filename : "#{Dir.pwd}/config.yml"}"
|
117
|
+
File.write filepath, @config_text
|
118
|
+
File.open(filepath, 'a') do |f|
|
119
|
+
f.puts "# Individual Settings"
|
120
|
+
@config_individual_lines.each { |l| f.puts l }
|
121
|
+
end if @config_individual_lines
|
122
|
+
|
123
|
+
|
124
|
+
if @categorized_defaults
|
125
|
+
text = ''
|
126
|
+
@categorized_defaults.each do |name, opts|
|
127
|
+
text += "\n# #{opts[:description]}\n"
|
128
|
+
text += "#{name.to_s}:\n"
|
129
|
+
opts[:config].each do |opt, v|
|
130
|
+
text += " #{opt.to_s}: #{v[:value]}".ljust(30) + " # #{v[:description]}\n"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
File.open(filepath, 'a') do |f|
|
134
|
+
f.puts text
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
##
|
2
|
+
# Functions to convert hash keys to all symbols or all strings
|
3
|
+
##
|
4
|
+
class Hash
|
5
|
+
def deep_symbolize! hsh = nil
|
6
|
+
hsh ||= self
|
7
|
+
hsh.keys.each do |k|
|
8
|
+
if k.is_a? String
|
9
|
+
hsh[k.to_sym] = hsh[k]
|
10
|
+
hsh.delete k
|
11
|
+
end
|
12
|
+
deep_symbolize! hsh[k.to_sym] if hsh[k.to_sym].is_a? Hash
|
13
|
+
end
|
14
|
+
hsh
|
15
|
+
end
|
16
|
+
|
17
|
+
def deep_stringify! hsh = nil
|
18
|
+
hsh ||= self
|
19
|
+
hsh.keys.each do |k|
|
20
|
+
if k.is_a? Symbol
|
21
|
+
hsh[k.to_s] = hsh[k]
|
22
|
+
hsh.delete k
|
23
|
+
end
|
24
|
+
deep_stringify! hsh[k.to_s] if hsh[k.to_s].is_a? Hash
|
25
|
+
end
|
26
|
+
hsh
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
####
|
2
|
+
# Logging Module
|
3
|
+
####
|
4
|
+
# The logging module automatically initializes and formats the Ruby logger, and makes it available for the application.
|
5
|
+
# Note that all of the built-in log commands are available.
|
6
|
+
#
|
7
|
+
# Additionally, a convenience function Rbcli::debug is available, which does not log, but prints an object.to_s
|
8
|
+
# in red so that it is easily identifiable in the coutput.
|
9
|
+
#
|
10
|
+
# Usage
|
11
|
+
#
|
12
|
+
# Rbcli::log.info {'Some Message'}
|
13
|
+
#
|
14
|
+
# Rbcli::debug myobj
|
15
|
+
#
|
16
|
+
####
|
17
|
+
|
18
|
+
require 'logger'
|
19
|
+
require 'colorize'
|
20
|
+
|
21
|
+
module Rbcli::Logger
|
22
|
+
|
23
|
+
@default_level = 'info'
|
24
|
+
@default_target = 'stderr'
|
25
|
+
|
26
|
+
def self.save_defaults level: nil, target: nil
|
27
|
+
@default_level = level if level
|
28
|
+
@default_target = target if target
|
29
|
+
|
30
|
+
Rbcli::Config::add_categorized_defaults :logger, 'Log Settings', {
|
31
|
+
log_level: {
|
32
|
+
description: '0-5, or DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN',
|
33
|
+
value: @default_level || 'info'
|
34
|
+
},
|
35
|
+
log_target: {
|
36
|
+
description: 'STDOUT, STDERR, or a file path',
|
37
|
+
value: @default_target || 'stderr'
|
38
|
+
}
|
39
|
+
}
|
40
|
+
end
|
41
|
+
self.save_defaults
|
42
|
+
|
43
|
+
|
44
|
+
if Rbcli::config[:logger][:log_target].downcase == 'stdout'
|
45
|
+
target = STDOUT
|
46
|
+
elsif Rbcli::config[:logger][:log_target].downcase == 'stderr'
|
47
|
+
target = STDERR
|
48
|
+
else
|
49
|
+
target = Rbcli::config[:logger][:log_target]
|
50
|
+
end
|
51
|
+
@logger = Logger.new(target)
|
52
|
+
@logger.level = Rbcli::config[:logger][:log_level]
|
53
|
+
|
54
|
+
original_formatter = Logger::Formatter.new
|
55
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
56
|
+
original_formatter.call(severity, datetime, progname || caller_locations[3].path.split('/')[-1], msg.dump)
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.log
|
60
|
+
@logger
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
module Rbcli
|
66
|
+
def self.log
|
67
|
+
Rbcli::Logger::log
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.debug obj
|
71
|
+
puts obj.to_s.red
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class String
|
2
|
+
def black; "\e[30m#{self}\e[0m" end
|
3
|
+
def red; "\e[31m#{self}\e[0m" end
|
4
|
+
def green; "\e[32m#{self}\e[0m" end
|
5
|
+
def brown; "\e[33m#{self}\e[0m" end
|
6
|
+
def blue; "\e[34m#{self}\e[0m" end
|
7
|
+
def magenta; "\e[35m#{self}\e[0m" end
|
8
|
+
def cyan; "\e[36m#{self}\e[0m" end
|
9
|
+
def gray; "\e[37m#{self}\e[0m" end
|
10
|
+
|
11
|
+
def bg_black; "\e[40m#{self}\e[0m" end
|
12
|
+
def bg_red; "\e[41m#{self}\e[0m" end
|
13
|
+
def bg_green; "\e[42m#{self}\e[0m" end
|
14
|
+
def bg_brown; "\e[43m#{self}\e[0m" end
|
15
|
+
def bg_blue; "\e[44m#{self}\e[0m" end
|
16
|
+
def bg_magenta; "\e[45m#{self}\e[0m" end
|
17
|
+
def bg_cyan; "\e[46m#{self}\e[0m" end
|
18
|
+
def bg_gray; "\e[47m#{self}\e[0m" end
|
19
|
+
|
20
|
+
def bold; "\e[1m#{self}\e[22m" end
|
21
|
+
def italic; "\e[3m#{self}\e[23m" end
|
22
|
+
def underline; "\e[4m#{self}\e[24m" end
|
23
|
+
def blink; "\e[5m#{self}\e[25m" end
|
24
|
+
def reverse_color; "\e[7m#{self}\e[27m" end
|
25
|
+
end
|
data/lib/rbcli/util.rb
ADDED
data/lib/rbcli.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
lib = File.expand_path('../../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
module Rbcli end # Empty module declaration required to declare submodules freely
|
5
|
+
require "rbcli/version"
|
6
|
+
|
7
|
+
require "rbcli/util"
|
8
|
+
require "rbcli/configurate"
|
9
|
+
|
10
|
+
require "rbcli/engine/command"
|
11
|
+
require "rbcli/engine/parser"
|
data/rbcli.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "rbcli/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'rbcli'
|
8
|
+
spec.version = Rbcli::VERSION
|
9
|
+
spec.authors = ['Andrew Khoury']
|
10
|
+
spec.email = ['akhoury@live.com']
|
11
|
+
|
12
|
+
spec.summary = %q{A CLI Framework for Ruby}
|
13
|
+
spec.description = %q{RBCli is a framework to quickly develop command-line tools.}
|
14
|
+
spec.homepage = 'https://github.com/akhoury6/rbcli'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
# if spec.respond_to?(:metadata)
|
20
|
+
# spec.metadata["allowed_push_host"] = "http://mygemserver.com"
|
21
|
+
# else
|
22
|
+
# raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
+
# "public gem pushes."
|
24
|
+
# end
|
25
|
+
|
26
|
+
# Specify which files should be added to the gem when it is released.
|
27
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
28
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
29
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
30
|
+
end
|
31
|
+
spec.bindir = 'exe'
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ['lib']
|
34
|
+
|
35
|
+
spec.add_development_dependency 'bundler', '~> 1.16'
|
36
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
37
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
38
|
+
|
39
|
+
spec.add_dependency 'colorize', '~> 0.8'
|
40
|
+
spec.add_dependency 'deep_merge', '~> 1.2'
|
41
|
+
spec.add_dependency 'trollop', '~> 2.1'
|
42
|
+
end
|