mixlib-cli 1.5.0 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/NOTICE +6 -7
- data/README.md +109 -0
- data/Rakefile +19 -9
- data/lib/mixlib/cli.rb +67 -17
- data/lib/mixlib/cli/version.rb +1 -2
- data/mixlib-cli.gemspec +27 -0
- data/spec/mixlib/cli_spec.rb +91 -17
- data/spec/spec_helper.rb +9 -3
- metadata +40 -24
- data/README.rdoc +0 -84
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d2d8c52004fea1ccbbacc8cc9eb27c90319169a7
|
4
|
+
data.tar.gz: 02c491e6efbd0311e961fabdfa5104cac182f906
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0ebca3acd4ff265dc86b78ad542b2400260167345d6d05334359e2e4e575160d26ccaa905e42cc36e8eaecf373ed5f7b6eafc6d0f0e72c8dd9541d6749e4cda
|
7
|
+
data.tar.gz: 08c9482a936d10feea1f968effa75beba3f7f0911fa63dbf16755da7d0f674df9f64622f2941050ea7a16ed71efd4b963b7715956b819f67362469668b0d7d71
|
data/Gemfile
ADDED
data/NOTICE
CHANGED
@@ -1,27 +1,26 @@
|
|
1
1
|
Mixin::CLI NOTICE
|
2
2
|
=================
|
3
3
|
|
4
|
-
Developed at
|
4
|
+
Developed at Chef (http://www.chef.io).
|
5
5
|
|
6
|
-
|
6
|
+
|
7
|
+
* Copyright 2009-2016, Chef Software, Inc. <legal@chef.io>
|
7
8
|
|
8
9
|
Mixin::CLI incorporates code from Chef. The Chef notice file follows:
|
9
10
|
|
10
11
|
Chef NOTICE
|
11
12
|
===========
|
12
13
|
|
13
|
-
Developed at
|
14
|
+
Developed at Chef (http://www.chef.io).
|
14
15
|
|
15
16
|
Contributors and Copyright holders:
|
16
17
|
|
17
|
-
* Copyright 2008, Adam Jacob <adam@
|
18
|
+
* Copyright 2008, Adam Jacob <adam@chef.io>
|
18
19
|
* Copyright 2008, Arjuna Christensen <aj@hjksolutions.com>
|
19
20
|
* Copyright 2008, Bryan McLellan <btm@loftninjas.org>
|
20
21
|
* Copyright 2008, Ezra Zygmuntowicz <ezra@engineyard.com>
|
21
22
|
* Copyright 2009, Sean Cribbs <seancribbs@gmail.com>
|
22
|
-
* Copyright 2009, Christopher Brown <cb@
|
23
|
+
* Copyright 2009, Christopher Brown <cb@chef.io>
|
23
24
|
* Copyright 2009, Thom May <thom@clearairturbulence.org>
|
24
25
|
|
25
26
|
Chef incorporates code modified from Open4 (http://www.codeforpeople.com/lib/ruby/open4/), which was written by Ara T. Howard.
|
26
|
-
|
27
|
-
Chef incorporates code modified from Merb (http://www.merbivore.com), which is Copyright (c) 2008 Engine Yard.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Mixlib::CLI
|
2
|
+
|
3
|
+
[![Build Status Master](https://travis-ci.org/chef/mixlib-cli.svg?branch=master)](https://travis-ci.org/chef/mixlib-cli) [![Gem Version](https://badge.fury.io/rb/mixlib-cli.svg)](https://badge.fury.io/rb/mixlib-cli)
|
4
|
+
|
5
|
+
Mixlib::CLI provides a class-based command line option parsing object, like the one used in Chef, Ohai and Relish. To use in your project:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require 'rubygems'
|
9
|
+
require 'mixlib/cli'
|
10
|
+
|
11
|
+
class MyCLI
|
12
|
+
include Mixlib::CLI
|
13
|
+
|
14
|
+
option :config_file,
|
15
|
+
:short => "-c CONFIG",
|
16
|
+
:long => "--config CONFIG",
|
17
|
+
:default => 'config.rb',
|
18
|
+
:description => "The configuration file to use"
|
19
|
+
|
20
|
+
option :log_level,
|
21
|
+
:short => "-l LEVEL",
|
22
|
+
:long => "--log_level LEVEL",
|
23
|
+
:description => "Set the log level (debug, info, warn, error, fatal)",
|
24
|
+
:required => true,
|
25
|
+
:in => ['debug', 'info', 'warn', 'error', 'fatal'],
|
26
|
+
:proc => Proc.new { |l| l.to_sym }
|
27
|
+
|
28
|
+
option :help,
|
29
|
+
:short => "-h",
|
30
|
+
:long => "--help",
|
31
|
+
:description => "Show this message",
|
32
|
+
:on => :tail,
|
33
|
+
:boolean => true,
|
34
|
+
:show_options => true,
|
35
|
+
:exit => 0
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
# ARGV = [ '-c', 'foo.rb', '-l', 'debug' ]
|
40
|
+
cli = MyCLI.new
|
41
|
+
cli.parse_options
|
42
|
+
cli.config[:config_file] # 'foo.rb'
|
43
|
+
cli.config[:log_level] # :debug
|
44
|
+
```
|
45
|
+
|
46
|
+
If you are using this in conjunction with Mixlib::Config, you can do something like this (building on the above definition):
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
class MyConfig
|
50
|
+
extend(Mixlib::Config)
|
51
|
+
|
52
|
+
log_level :info
|
53
|
+
config_file "default.rb"
|
54
|
+
end
|
55
|
+
|
56
|
+
class MyCLI
|
57
|
+
def run(argv=ARGV)
|
58
|
+
parse_options(argv)
|
59
|
+
MyConfig.merge!(config)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
c = MyCLI.new
|
64
|
+
# ARGV = [ '-l', 'debug' ]
|
65
|
+
c.run
|
66
|
+
MyConfig[:log_level] # :debug
|
67
|
+
```
|
68
|
+
|
69
|
+
Available arguments to 'option':
|
70
|
+
|
71
|
+
- `:short`: The short option, just like from optparse. Example: "-l LEVEL"
|
72
|
+
- `:long`: The long option, just like from optparse. Example: "--level LEVEL"
|
73
|
+
- `:description`: The description for this item, just like from optparse.
|
74
|
+
- `:default`: A default value for this option
|
75
|
+
- `:required`: Prints a message informing the user of the missing requirement, and exits. Default is false.
|
76
|
+
- `:on`: Set to :tail to appear at the end, or `:head`: to appear at the top.
|
77
|
+
- `:boolean:`: If this option takes no arguments, set this to true.
|
78
|
+
- `:show_options`: If you want the option list printed when this option is called, set this to true.
|
79
|
+
- `:exit`: Exit your program with the exit code when this option is specified. Example: 0
|
80
|
+
- `:proc`: If set, the configuration value will be set to the return value of this proc.
|
81
|
+
- `:in`: An array containing the list of accepted values
|
82
|
+
|
83
|
+
If you need access to the leftover options that aren't captured in the config, you can get at them through +cli_arguments+ (referring to the above definition of MyCLI).
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
# ARGV = [ '-c', 'foo.rb', '-l', 'debug', 'file1', 'file2', 'file3' ]
|
87
|
+
cli = MyCLI.new
|
88
|
+
cli.parse_options
|
89
|
+
cli.cli_arguments # [ 'file1', 'file2', 'file3' ]
|
90
|
+
```
|
91
|
+
|
92
|
+
## LICENSE:
|
93
|
+
|
94
|
+
- Copyright:: Copyright (c) 2008-2016 Chef Software, Inc.
|
95
|
+
- License:: Apache License, Version 2.0
|
96
|
+
|
97
|
+
```text
|
98
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
99
|
+
you may not use this file except in compliance with the License.
|
100
|
+
You may obtain a copy of the License at
|
101
|
+
|
102
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
103
|
+
|
104
|
+
Unless required by applicable law or agreed to in writing, software
|
105
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
106
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
107
|
+
See the License for the specific language governing permissions and
|
108
|
+
limitations under the License.
|
109
|
+
```
|
data/Rakefile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "bundler"
|
2
|
+
require "rubygems"
|
3
|
+
require "rubygems/package_task"
|
4
|
+
require "rdoc/task"
|
5
|
+
require "rspec/core/rake_task"
|
6
6
|
|
7
7
|
Bundler::GemHelper.install_tasks
|
8
8
|
|
@@ -10,14 +10,24 @@ task :default => :spec
|
|
10
10
|
|
11
11
|
desc "Run specs"
|
12
12
|
RSpec::Core::RakeTask.new(:spec) do |spec|
|
13
|
-
spec.pattern =
|
13
|
+
spec.pattern = "spec/**/*_spec.rb"
|
14
14
|
end
|
15
15
|
|
16
16
|
gem_spec = eval(File.read("mixlib-cli.gemspec"))
|
17
17
|
|
18
18
|
RDoc::Task.new do |rdoc|
|
19
|
-
rdoc.rdoc_dir =
|
19
|
+
rdoc.rdoc_dir = "rdoc"
|
20
20
|
rdoc.title = "mixlib-cli #{gem_spec.version}"
|
21
|
-
rdoc.rdoc_files.include(
|
22
|
-
rdoc.rdoc_files.include(
|
21
|
+
rdoc.rdoc_files.include("README*")
|
22
|
+
rdoc.rdoc_files.include("lib/**/*.rb")
|
23
|
+
end
|
24
|
+
|
25
|
+
begin
|
26
|
+
require "chefstyle"
|
27
|
+
require "rubocop/rake_task"
|
28
|
+
RuboCop::RakeTask.new(:style) do |task|
|
29
|
+
task.options += ["--display-cop-names", "--no-color"]
|
30
|
+
end
|
31
|
+
rescue LoadError
|
32
|
+
puts "chefstyle/rubocop is not available. gem install chefstyle to do style checking."
|
23
33
|
end
|
data/lib/mixlib/cli.rb
CHANGED
@@ -16,7 +16,7 @@
|
|
16
16
|
# limitations under the License.
|
17
17
|
#
|
18
18
|
|
19
|
-
require
|
19
|
+
require "optparse"
|
20
20
|
|
21
21
|
module Mixlib
|
22
22
|
|
@@ -38,8 +38,46 @@ module Mixlib
|
|
38
38
|
# #parse_options. After calling this method, the attribute #config will
|
39
39
|
# contain a hash of `:option_name => value` pairs.
|
40
40
|
module CLI
|
41
|
-
module ClassMethods
|
42
41
|
|
42
|
+
module InheritMethods
|
43
|
+
def inherited(receiver)
|
44
|
+
receiver.options = deep_dup(self.options)
|
45
|
+
receiver.extend(Mixlib::CLI::InheritMethods)
|
46
|
+
end
|
47
|
+
|
48
|
+
# object:: Instance to clone
|
49
|
+
# This method will return a "deep clone" of the provided
|
50
|
+
# `object`. If the provided `object` is an enumerable type the
|
51
|
+
# contents will be iterated and cloned as well.
|
52
|
+
def deep_dup(object)
|
53
|
+
cloned_object = object.respond_to?(:dup) ? object.dup : object
|
54
|
+
if cloned_object.kind_of?(Enumerable)
|
55
|
+
if cloned_object.kind_of?(Hash)
|
56
|
+
new_hash = cloned_object.class.new
|
57
|
+
cloned_object.each do |key, value|
|
58
|
+
cloned_key = deep_dup(key)
|
59
|
+
cloned_value = deep_dup(value)
|
60
|
+
new_hash[cloned_key] = cloned_value
|
61
|
+
end
|
62
|
+
cloned_object.replace(new_hash)
|
63
|
+
else
|
64
|
+
cloned_object.map! do |shallow_instance|
|
65
|
+
deep_dup(shallow_instance)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
cloned_object
|
70
|
+
rescue TypeError
|
71
|
+
# Symbol will happily provide a `#dup` method even though
|
72
|
+
# attempts to clone it will result in an exception (atoms!).
|
73
|
+
# So if we run into an issue of TypeErrors, just return the
|
74
|
+
# original object as we gave our "best effort"
|
75
|
+
object
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
module ClassMethods
|
43
81
|
# When this setting is set to +true+, default values supplied to the
|
44
82
|
# mixlib-cli DSL will be stored in a separate Hash
|
45
83
|
def use_separate_default_options(true_or_false)
|
@@ -47,7 +85,7 @@ module Mixlib
|
|
47
85
|
end
|
48
86
|
|
49
87
|
def use_separate_defaults?
|
50
|
-
@separate_default_options
|
88
|
+
@separate_default_options ||= false
|
51
89
|
end
|
52
90
|
|
53
91
|
# Add a command line option.
|
@@ -92,7 +130,7 @@ module Mixlib
|
|
92
130
|
#
|
93
131
|
# === Returns
|
94
132
|
# @banner<String>:: The current banner
|
95
|
-
def banner(bstring=nil)
|
133
|
+
def banner(bstring = nil)
|
96
134
|
if bstring
|
97
135
|
@banner = bstring
|
98
136
|
else
|
@@ -149,7 +187,7 @@ module Mixlib
|
|
149
187
|
@opt_parser = nil
|
150
188
|
|
151
189
|
# Set the banner
|
152
|
-
@banner
|
190
|
+
@banner = self.class.banner
|
153
191
|
|
154
192
|
# Dupe the class options for this instance
|
155
193
|
klass_options = self.class.options
|
@@ -170,6 +208,7 @@ module Mixlib
|
|
170
208
|
config_opts[:proc] ||= nil
|
171
209
|
config_opts[:show_options] ||= false
|
172
210
|
config_opts[:exit] ||= nil
|
211
|
+
config_opts[:in] ||= nil
|
173
212
|
|
174
213
|
if config_opts.has_key?(:default)
|
175
214
|
defaults_container[config_key] = config_opts[:default]
|
@@ -186,7 +225,7 @@ module Mixlib
|
|
186
225
|
#
|
187
226
|
# === Returns
|
188
227
|
# argv<Array>:: Returns any un-parsed elements.
|
189
|
-
def parse_options(argv=ARGV)
|
228
|
+
def parse_options(argv = ARGV)
|
190
229
|
argv = argv.dup
|
191
230
|
opt_parser.parse!(argv)
|
192
231
|
|
@@ -198,13 +237,23 @@ module Mixlib
|
|
198
237
|
puts @opt_parser
|
199
238
|
exit 2
|
200
239
|
end
|
240
|
+
if opt_value[:in]
|
241
|
+
unless opt_value[:in].kind_of?(Array)
|
242
|
+
raise(ArgumentError, "Options config key :in must receive an Array")
|
243
|
+
end
|
244
|
+
if !opt_value[:in].include?(config[opt_key])
|
245
|
+
reqarg = opt_value[:short] || opt_value[:long]
|
246
|
+
puts "#{reqarg}: #{config[opt_key]} is not included in the list ['#{opt_value[:in].join("', '")}'] "
|
247
|
+
puts @opt_parser
|
248
|
+
exit 2
|
249
|
+
end
|
250
|
+
end
|
201
251
|
end
|
202
252
|
|
203
253
|
@cli_arguments = argv
|
204
254
|
argv
|
205
255
|
end
|
206
256
|
|
207
|
-
|
208
257
|
# The option parser generated from the mixlib-cli DSL. +opt_parser+ can be
|
209
258
|
# used to print a help message including the banner and any CLI options via
|
210
259
|
# `puts opt_parser`.
|
@@ -220,15 +269,15 @@ module Mixlib
|
|
220
269
|
opt_args = build_option_arguments(opt_val)
|
221
270
|
|
222
271
|
opt_method = case opt_val[:on]
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
272
|
+
when :on
|
273
|
+
:on
|
274
|
+
when :tail
|
275
|
+
:on_tail
|
276
|
+
when :head
|
277
|
+
:on_head
|
278
|
+
else
|
279
|
+
raise ArgumentError, "You must pass :on, :tail, or :head to :on"
|
280
|
+
end
|
232
281
|
|
233
282
|
parse_block =
|
234
283
|
Proc.new() do |c|
|
@@ -250,10 +299,10 @@ module Mixlib
|
|
250
299
|
|
251
300
|
arguments << opt_setting[:short] if opt_setting.has_key?(:short)
|
252
301
|
arguments << opt_setting[:long] if opt_setting.has_key?(:long)
|
253
|
-
|
254
302
|
if opt_setting.has_key?(:description)
|
255
303
|
description = opt_setting[:description]
|
256
304
|
description << " (required)" if opt_setting[:required]
|
305
|
+
description << " (included in ['#{opt_setting[:in].join("', '")}'])" if opt_setting[:in]
|
257
306
|
arguments << description
|
258
307
|
end
|
259
308
|
|
@@ -262,6 +311,7 @@ module Mixlib
|
|
262
311
|
|
263
312
|
def self.included(receiver)
|
264
313
|
receiver.extend(Mixlib::CLI::ClassMethods)
|
314
|
+
receiver.extend(Mixlib::CLI::InheritMethods)
|
265
315
|
end
|
266
316
|
|
267
317
|
end
|
data/lib/mixlib/cli/version.rb
CHANGED
data/mixlib-cli.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + "/lib")
|
2
|
+
require "mixlib/cli/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "mixlib-cli"
|
6
|
+
s.version = Mixlib::CLI::VERSION
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.has_rdoc = true
|
9
|
+
s.extra_rdoc_files = ["README.md", "LICENSE", "NOTICE"]
|
10
|
+
s.summary = "A simple mixin for CLI interfaces, including option parsing"
|
11
|
+
s.description = s.summary
|
12
|
+
s.author = "Chef Software, Inc."
|
13
|
+
s.email = "info@chef.io"
|
14
|
+
s.homepage = "https://www.chef.io"
|
15
|
+
s.license = "Apache-2.0"
|
16
|
+
|
17
|
+
# Uncomment this to add a dependency
|
18
|
+
#s.add_dependency "mixlib-log"
|
19
|
+
s.add_development_dependency "rake", "< 11.0"
|
20
|
+
s.add_development_dependency "rspec", "~> 2.14"
|
21
|
+
s.add_development_dependency "rdoc"
|
22
|
+
s.add_development_dependency "chefstyle", "~> 0.3"
|
23
|
+
|
24
|
+
s.require_path = "lib"
|
25
|
+
s.files = %w{LICENSE README.md Gemfile Rakefile NOTICE} + Dir.glob("*.gemspec") +
|
26
|
+
Dir.glob("{lib,spec}/**/*", File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
|
27
|
+
end
|
data/spec/mixlib/cli_spec.rb
CHANGED
@@ -27,21 +27,21 @@ describe Mixlib::CLI do
|
|
27
27
|
describe "class method" do
|
28
28
|
describe "option" do
|
29
29
|
it "should allow you to set a config option with a hash" do
|
30
|
-
TestCLI.option(:config_file, :short =>
|
30
|
+
TestCLI.option(:config_file, :short => "-c CONFIG").should == { :short => "-c CONFIG" }
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
describe "options" do
|
35
35
|
it "should return the current options hash" do
|
36
|
-
TestCLI.option(:config_file, :short =>
|
37
|
-
TestCLI.options.should == { :config_file => { :short =>
|
36
|
+
TestCLI.option(:config_file, :short => "-c CONFIG")
|
37
|
+
TestCLI.options.should == { :config_file => { :short => "-c CONFIG" } }
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
describe "options=" do
|
42
42
|
it "should allow you to set the full options with a single hash" do
|
43
|
-
TestCLI.options = { :config_file => { :short =>
|
44
|
-
TestCLI.options.should == { :config_file => { :short =>
|
43
|
+
TestCLI.options = { :config_file => { :short => "-c CONFIG" } }
|
44
|
+
TestCLI.options.should == { :config_file => { :short => "-c CONFIG" } }
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
@@ -79,8 +79,9 @@ describe Mixlib::CLI do
|
|
79
79
|
:required => false,
|
80
80
|
:proc => nil,
|
81
81
|
:show_options => false,
|
82
|
-
:exit => nil
|
83
|
-
|
82
|
+
:exit => nil,
|
83
|
+
:in => nil,
|
84
|
+
},
|
84
85
|
}
|
85
86
|
end
|
86
87
|
|
@@ -134,8 +135,8 @@ describe Mixlib::CLI do
|
|
134
135
|
it "should set the corresponding config value for non-boolean arguments" do
|
135
136
|
TestCLI.option(:config_file, :short => "-c CONFIG")
|
136
137
|
@cli = TestCLI.new
|
137
|
-
@cli.parse_options([
|
138
|
-
@cli.config[:config_file].should ==
|
138
|
+
@cli.parse_options([ "-c", "foo.rb" ])
|
139
|
+
@cli.config[:config_file].should == "foo.rb"
|
139
140
|
end
|
140
141
|
|
141
142
|
it "should set the corresponding config value according to a supplied proc" do
|
@@ -151,14 +152,14 @@ describe Mixlib::CLI do
|
|
151
152
|
it "should set the corresponding config value to true for boolean arguments" do
|
152
153
|
TestCLI.option(:i_am_boolean, :short => "-i", :boolean => true)
|
153
154
|
@cli = TestCLI.new
|
154
|
-
@cli.parse_options([
|
155
|
+
@cli.parse_options([ "-i" ])
|
155
156
|
@cli.config[:i_am_boolean].should == true
|
156
157
|
end
|
157
158
|
|
158
159
|
it "should set the corresponding config value to false when a boolean is prefixed with --no" do
|
159
160
|
TestCLI.option(:i_am_boolean, :long => "--[no-]bool", :boolean => true)
|
160
161
|
@cli = TestCLI.new
|
161
|
-
@cli.parse_options([
|
162
|
+
@cli.parse_options([ "--no-bool" ])
|
162
163
|
@cli.config[:i_am_boolean].should == false
|
163
164
|
end
|
164
165
|
|
@@ -174,6 +175,32 @@ describe Mixlib::CLI do
|
|
174
175
|
lambda { @cli.parse_options([]) }.should raise_error(SystemExit)
|
175
176
|
end
|
176
177
|
|
178
|
+
it "should exit if option is not included in the list" do
|
179
|
+
TestCLI.option(:inclusion, :short => "-i val", :in => %w{one two})
|
180
|
+
@cli = TestCLI.new
|
181
|
+
lambda { @cli.parse_options(["-i", "three"]) }.should raise_error(SystemExit)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should raise ArgumentError if options key :in is not an array" do
|
185
|
+
TestCLI.option(:inclusion, :short => "-i val", :in => "foo")
|
186
|
+
@cli = TestCLI.new
|
187
|
+
lambda { @cli.parse_options(["-i", "three"]) }.should raise_error(ArgumentError)
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should not exit if option is included in the list" do
|
191
|
+
TestCLI.option(:inclusion, :short => "-i val", :in => %w{one two})
|
192
|
+
@cli = TestCLI.new
|
193
|
+
@cli.parse_options(["-i", "one"])
|
194
|
+
@cli.config[:inclusion].should == "one"
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should change description if :in key is specified" do
|
198
|
+
TestCLI.option(:inclusion, :short => "-i val", :in => %w{one two}, :description => "desc")
|
199
|
+
@cli = TestCLI.new
|
200
|
+
@cli.parse_options(["-i", "one"])
|
201
|
+
@cli.options[:inclusion][:description].should == "desc (included in ['one', 'two'])"
|
202
|
+
end
|
203
|
+
|
177
204
|
it "should not exit if a required option is specified" do
|
178
205
|
TestCLI.option(:require_me, :short => "-r", :boolean => true, :required => true)
|
179
206
|
@cli = TestCLI.new
|
@@ -199,17 +226,17 @@ describe Mixlib::CLI do
|
|
199
226
|
TestCLI.option(:config_file, :short => "-c CONFIG")
|
200
227
|
@cli = TestCLI.new
|
201
228
|
argv_old = ARGV.dup
|
202
|
-
ARGV.replace [
|
229
|
+
ARGV.replace ["-c", "foo.rb"]
|
203
230
|
@cli.parse_options()
|
204
|
-
ARGV.should == [
|
231
|
+
ARGV.should == ["-c", "foo.rb"]
|
205
232
|
ARGV.replace argv_old
|
206
233
|
end
|
207
234
|
|
208
235
|
it "should preserve and return any un-parsed elements" do
|
209
236
|
TestCLI.option(:party, :short => "-p LOCATION")
|
210
237
|
@cli = TestCLI.new
|
211
|
-
@cli.parse_options([
|
212
|
-
@cli.cli_arguments.should ==
|
238
|
+
@cli.parse_options([ "easy", "-p", "opscode", "hard" ]).should == %w{easy hard}
|
239
|
+
@cli.cli_arguments.should == %w{easy hard}
|
213
240
|
end
|
214
241
|
end
|
215
242
|
end
|
@@ -228,15 +255,62 @@ describe Mixlib::CLI do
|
|
228
255
|
end
|
229
256
|
|
230
257
|
it "sets parsed values on the `config` hash" do
|
231
|
-
@cli.parse_options(%w
|
258
|
+
@cli.parse_options(%w{-D not-default})
|
232
259
|
@cli.default_config[:defaulter].should == "this is the default"
|
233
260
|
@cli.config[:defaulter].should == "not-default"
|
234
261
|
end
|
235
262
|
|
236
263
|
end
|
237
264
|
|
238
|
-
|
265
|
+
context "when subclassed" do
|
266
|
+
before do
|
267
|
+
TestCLI.options = { :arg1 => { :boolean => true } }
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should retain previously defined options from parent" do
|
271
|
+
class T1 < TestCLI
|
272
|
+
option :arg2, :boolean => true
|
273
|
+
end
|
274
|
+
T1.options[:arg1].should be_a(Hash)
|
275
|
+
T1.options[:arg2].should be_a(Hash)
|
276
|
+
TestCLI.options[:arg2].should be_nil
|
277
|
+
end
|
278
|
+
|
279
|
+
it "should not be able to modify parent classes options" do
|
280
|
+
class T2 < TestCLI
|
281
|
+
option :arg2, :boolean => true
|
282
|
+
end
|
283
|
+
T2.options[:arg1][:boolean] = false
|
284
|
+
T2.options[:arg1][:boolean].should be_false
|
285
|
+
TestCLI.options[:arg1][:boolean].should be_true
|
286
|
+
end
|
287
|
+
|
288
|
+
it "should pass its options onto child" do
|
289
|
+
class T3 < TestCLI
|
290
|
+
option :arg2, :boolean => true
|
291
|
+
end
|
292
|
+
class T4 < T3
|
293
|
+
option :arg3, :boolean => true
|
294
|
+
end
|
295
|
+
3.times do |i|
|
296
|
+
T4.options["arg#{i + 1}".to_sym].should be_a(Hash)
|
297
|
+
end
|
298
|
+
end
|
239
299
|
|
300
|
+
it "should also work with an option that's an array" do
|
301
|
+
class T5 < TestCLI
|
302
|
+
option :arg2, :default => []
|
303
|
+
end
|
304
|
+
|
305
|
+
class T6 < T5
|
306
|
+
end
|
307
|
+
|
308
|
+
T6.options[:arg2].should be_a(Hash)
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
240
314
|
|
241
315
|
# option :config_file,
|
242
316
|
# :short => "-c CONFIG",
|
data/spec/spec_helper.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
-
$TESTING=true
|
2
|
-
$:.push File.join(File.dirname(__FILE__),
|
1
|
+
$TESTING = true
|
2
|
+
$:.push File.join(File.dirname(__FILE__), "..", "lib")
|
3
3
|
|
4
|
-
require
|
4
|
+
require "mixlib/cli"
|
5
5
|
|
6
6
|
class TestCLI
|
7
7
|
include Mixlib::CLI
|
8
8
|
end
|
9
9
|
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.filter_run :focus => true
|
12
|
+
config.run_all_when_everything_filtered = true
|
13
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
14
|
+
config.warnings = true
|
15
|
+
end
|
metadata
CHANGED
@@ -1,76 +1,93 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mixlib-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
7
|
+
- Chef Software, Inc.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-05-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "<"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '11.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - "<"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '11.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '2.14'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '2.14'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rdoc
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: chefstyle
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.3'
|
55
69
|
description: A simple mixin for CLI interfaces, including option parsing
|
56
|
-
email: info@
|
70
|
+
email: info@chef.io
|
57
71
|
executables: []
|
58
72
|
extensions: []
|
59
73
|
extra_rdoc_files:
|
60
|
-
- README.
|
74
|
+
- README.md
|
61
75
|
- LICENSE
|
62
76
|
- NOTICE
|
63
77
|
files:
|
78
|
+
- Gemfile
|
64
79
|
- LICENSE
|
65
|
-
- README.rdoc
|
66
|
-
- Rakefile
|
67
80
|
- NOTICE
|
68
|
-
-
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
69
83
|
- lib/mixlib/cli.rb
|
84
|
+
- lib/mixlib/cli/version.rb
|
85
|
+
- mixlib-cli.gemspec
|
70
86
|
- spec/mixlib/cli_spec.rb
|
71
87
|
- spec/spec_helper.rb
|
72
|
-
homepage:
|
73
|
-
licenses:
|
88
|
+
homepage: https://www.chef.io
|
89
|
+
licenses:
|
90
|
+
- Apache-2.0
|
74
91
|
metadata: {}
|
75
92
|
post_install_message:
|
76
93
|
rdoc_options: []
|
@@ -78,19 +95,18 @@ require_paths:
|
|
78
95
|
- lib
|
79
96
|
required_ruby_version: !ruby/object:Gem::Requirement
|
80
97
|
requirements:
|
81
|
-
- -
|
98
|
+
- - ">="
|
82
99
|
- !ruby/object:Gem::Version
|
83
100
|
version: '0'
|
84
101
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
102
|
requirements:
|
86
|
-
- -
|
103
|
+
- - ">="
|
87
104
|
- !ruby/object:Gem::Version
|
88
105
|
version: '0'
|
89
106
|
requirements: []
|
90
107
|
rubyforge_project:
|
91
|
-
rubygems_version: 2.
|
108
|
+
rubygems_version: 2.4.5.1
|
92
109
|
signing_key:
|
93
110
|
specification_version: 4
|
94
111
|
summary: A simple mixin for CLI interfaces, including option parsing
|
95
112
|
test_files: []
|
96
|
-
has_rdoc: true
|
data/README.rdoc
DELETED
@@ -1,84 +0,0 @@
|
|
1
|
-
== Mixlib::CLI
|
2
|
-
|
3
|
-
Mixlib::CLI provides a class-based command line option parsing object, like the one used in Chef, Ohai and Relish. To use in your project:
|
4
|
-
|
5
|
-
require 'rubygems'
|
6
|
-
require 'mixlib/cli'
|
7
|
-
|
8
|
-
class MyCLI
|
9
|
-
include Mixlib::CLI
|
10
|
-
|
11
|
-
option :config_file,
|
12
|
-
:short => "-c CONFIG",
|
13
|
-
:long => "--config CONFIG",
|
14
|
-
:default => 'config.rb',
|
15
|
-
:description => "The configuration file to use"
|
16
|
-
|
17
|
-
option :log_level,
|
18
|
-
:short => "-l LEVEL",
|
19
|
-
:long => "--log_level LEVEL",
|
20
|
-
:description => "Set the log level (debug, info, warn, error, fatal)",
|
21
|
-
:required => true,
|
22
|
-
:proc => Proc.new { |l| l.to_sym }
|
23
|
-
|
24
|
-
option :help,
|
25
|
-
:short => "-h",
|
26
|
-
:long => "--help",
|
27
|
-
:description => "Show this message",
|
28
|
-
:on => :tail,
|
29
|
-
:boolean => true,
|
30
|
-
:show_options => true,
|
31
|
-
:exit => 0
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
# ARGV = [ '-c', 'foo.rb', '-l', 'debug' ]
|
36
|
-
cli = MyCLI.new
|
37
|
-
cli.parse_options
|
38
|
-
cli.config[:config_file] # 'foo.rb'
|
39
|
-
cli.config[:log_level] # :debug
|
40
|
-
|
41
|
-
If you are using this in conjunction with Mixlib::Config, you can do something like this (building on the above definition):
|
42
|
-
|
43
|
-
class MyConfig
|
44
|
-
extend(Mixlib::Config)
|
45
|
-
|
46
|
-
log_level :info
|
47
|
-
config_file "default.rb"
|
48
|
-
end
|
49
|
-
|
50
|
-
class MyCLI
|
51
|
-
def run(argv=ARGV)
|
52
|
-
parse_options(argv)
|
53
|
-
MyConfig.merge!(config)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
c = MyCLI.new
|
58
|
-
# ARGV = [ '-l', 'debug' ]
|
59
|
-
c.run
|
60
|
-
MyConfig[:log_level] # :debug
|
61
|
-
|
62
|
-
Available arguments to 'option':
|
63
|
-
|
64
|
-
:short:: The short option, just like from optparse. Example: "-l LEVEL"
|
65
|
-
:long:: The long option, just like from optparse. Example: "--level LEVEL"
|
66
|
-
:description:: The description for this item, just like from optparse.
|
67
|
-
:default:: A default value for this option
|
68
|
-
:required:: Prints a message informing the user of the missing requirement, and exits. Default is false.
|
69
|
-
:on:: Set to :tail to appear at the end, or :head to appear at the top.
|
70
|
-
:boolean:: If this option takes no arguments, set this to true.
|
71
|
-
:show_options:: If you want the option list printed when this option is called, set this to true.
|
72
|
-
:exit:: Exit your program with the exit code when this option is specified. Example: 0
|
73
|
-
:proc:: If set, the configuration value will be set to the return value of this proc.
|
74
|
-
|
75
|
-
=== New in 1.2.2
|
76
|
-
|
77
|
-
:required works, and we now support Ruby-style boolean option negation
|
78
|
-
(e.g. '--no-cookie' will set 'cookie' to false if the option is boolean)
|
79
|
-
|
80
|
-
=== New in 1.2.0
|
81
|
-
|
82
|
-
We no longer destructively manipulate ARGV.
|
83
|
-
|
84
|
-
Have fun!
|