rbcli 0.1.0
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 +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
|