razor-client 1.1.0 → 1.2.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.
- data/NEWS.md +13 -0
- data/bin/razor +3 -2
- data/lib/razor/cli/command.rb +41 -36
- data/lib/razor/cli/format.rb +28 -13
- data/lib/razor/cli/navigate.rb +9 -1
- data/lib/razor/cli/parse.rb +42 -21
- data/lib/razor/cli/table_format.rb +1 -1
- data/lib/razor/cli/version.rb +1 -1
- data/spec/cli/command_spec.rb +96 -0
- data/spec/cli/navigate_spec.rb +25 -0
- data/spec/cli/parse_spec.rb +11 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/argument_formatting/should_allow_single-dash_with_single_character_flag.yml +203 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/argument_formatting/should_not_allow_double-dash_with_single_character_flag.yml +133 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/argument_formatting/should_not_allow_single-dash_with_multiple_character_flag.yml +133 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/positional_arguments/should_allow_the_use_of_positional_arguments.yml +681 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/positional_arguments/should_fail_with_too_many_positional_arguments.yml +133 -0
- metadata +12 -2
data/NEWS.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Razor Client Release Notes
|
|
2
2
|
|
|
3
|
+
## 1.2.0 - 2016-03-08
|
|
4
|
+
|
|
5
|
+
* BUGFIX: Razor client version will be reported even if the Razor server is
|
|
6
|
+
unreachable.
|
|
7
|
+
* BUGFIX: Fixed insecure flag when supplied in addition to a server URL.
|
|
8
|
+
* NEW: Added positional argument support, when supplied by the server. See
|
|
9
|
+
`razor <command> --help` for details on usage.
|
|
10
|
+
* NEW: Added USAGE section to the command's help, which will include positional
|
|
11
|
+
arguments, if any exist.
|
|
12
|
+
* IMPROVEMENT: Proper short form argument style is now followed.
|
|
13
|
+
Single-character arguments now require a single dash, e.g. `-c`.
|
|
14
|
+
* IMPROVEMENT: Error messaging for SSL issues has been improved.
|
|
15
|
+
|
|
3
16
|
## 1.1.0 - 2015-11-12
|
|
4
17
|
|
|
5
18
|
* IMPROVEMENT: By default, `razor` will point to port 8150.
|
data/bin/razor
CHANGED
data/lib/razor/cli/command.rb
CHANGED
|
@@ -1,54 +1,60 @@
|
|
|
1
1
|
class Razor::CLI::Command
|
|
2
|
-
def initialize(parse, navigate,
|
|
3
|
-
@
|
|
2
|
+
def initialize(parse, navigate, command, segments, cmd_url)
|
|
3
|
+
@dump_response = parse && parse.dump_response?
|
|
4
|
+
@show_command_help = parse && parse.show_command_help?
|
|
4
5
|
@navigate = navigate
|
|
5
|
-
@
|
|
6
|
+
@command = command
|
|
7
|
+
@cmd_schema = command ? command['schema'] : nil
|
|
8
|
+
@cmd_url = cmd_url
|
|
6
9
|
@segments = segments
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
def run
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
# Ensure that we copy authentication data from our previous URL.
|
|
14
|
-
url = URI.parse(cmd["id"])
|
|
15
|
-
if @doc_resource
|
|
16
|
-
url = URI.parse(url.to_s)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
if @parse.show_command_help?
|
|
20
|
-
@navigate.json_get(url)
|
|
13
|
+
body = extract_command
|
|
14
|
+
if @show_command_help
|
|
15
|
+
@command
|
|
21
16
|
else
|
|
22
17
|
if body.empty?
|
|
23
18
|
raise Razor::CLI::Error,
|
|
24
19
|
"No arguments for command (did you forget --json ?)"
|
|
25
20
|
end
|
|
26
|
-
result = @navigate.json_post(
|
|
21
|
+
result = @navigate.json_post(@cmd_url, body)
|
|
27
22
|
# Get actual object from the id.
|
|
28
23
|
result = result.merge(@navigate.json_get(URI.parse(result['id']))) if result['id']
|
|
29
24
|
result
|
|
30
25
|
end
|
|
31
26
|
end
|
|
32
27
|
|
|
33
|
-
def command(name)
|
|
34
|
-
@command ||= @commands.find { |coll| coll["name"] == name }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
28
|
def extract_command
|
|
38
|
-
cmd = command(@segments.shift)
|
|
39
|
-
@cmd_url = URI.parse(cmd['id'])
|
|
40
|
-
@cmd_schema = cmd_schema(@cmd_url)
|
|
41
29
|
body = {}
|
|
30
|
+
pos_index = 0
|
|
42
31
|
until @segments.empty?
|
|
43
32
|
argument = @segments.shift
|
|
44
|
-
if argument =~ /\A--([a-z-]
|
|
45
|
-
|
|
46
|
-
arg
|
|
33
|
+
if argument =~ /\A--([a-z-]{2,})(=(.+))?\Z/ or
|
|
34
|
+
argument =~ /\A-([a-z])(=(.+))?\Z/
|
|
35
|
+
# `--arg=value`/`--arg value`
|
|
36
|
+
# `-a=value`/`-a value`
|
|
37
|
+
arg_name, value = [$1, $3]
|
|
47
38
|
value = @segments.shift if value.nil? && @segments[0] !~ /^--/
|
|
48
|
-
|
|
49
|
-
body[
|
|
39
|
+
arg_name = self.class.resolve_alias(arg_name, @cmd_schema)
|
|
40
|
+
body[arg_name] = self.class.convert_arg(arg_name, value, body[arg_name], @cmd_schema)
|
|
41
|
+
elsif argument =~ /\A-([a-z-]{2,})(=(.+))?\Z/ and
|
|
42
|
+
@cmd_schema[self.class.resolve_alias($1, @cmd_schema)]
|
|
43
|
+
# Short form, should be long; offer suggestion
|
|
44
|
+
raise ArgumentError, "Unexpected argument #{argument} (did you mean --#{$1}?)"
|
|
45
|
+
elsif argument =~ /\A--([a-z])(=(.+))?\Z/ and
|
|
46
|
+
@cmd_schema[self.class.resolve_alias($1, @cmd_schema)]
|
|
47
|
+
# Long form, should be short; offer suggestion
|
|
48
|
+
raise ArgumentError, "Unexpected argument #{argument} (did you mean -#{$1}?)"
|
|
50
49
|
else
|
|
51
|
-
|
|
50
|
+
# This may be a positional argument.
|
|
51
|
+
arg_name = positional_argument(@cmd_schema, pos_index)
|
|
52
|
+
if arg_name
|
|
53
|
+
body[arg_name] = self.class.convert_arg(arg_name, argument, body[arg_name], @cmd_schema)
|
|
54
|
+
pos_index += 1
|
|
55
|
+
else
|
|
56
|
+
raise ArgumentError, "Unexpected argument #{argument}"
|
|
57
|
+
end
|
|
52
58
|
end
|
|
53
59
|
end
|
|
54
60
|
|
|
@@ -62,15 +68,14 @@ class Razor::CLI::Command
|
|
|
62
68
|
raise Razor::CLI::Error,
|
|
63
69
|
"Permission to read file #{body["json"]} denied"
|
|
64
70
|
end
|
|
65
|
-
|
|
71
|
+
body
|
|
66
72
|
end
|
|
67
73
|
|
|
68
|
-
def cmd_schema
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
end
|
|
74
|
+
def positional_argument(cmd_schema, pos_index)
|
|
75
|
+
# Find a matching position and return its argument name.
|
|
76
|
+
cmd_schema && cmd_schema.select do |_, schema|
|
|
77
|
+
schema['position'] == pos_index
|
|
78
|
+
end.keys.first
|
|
74
79
|
end
|
|
75
80
|
|
|
76
81
|
def self.arg_type(arg_name, cmd_schema)
|
|
@@ -94,7 +99,7 @@ class Razor::CLI::Command
|
|
|
94
99
|
argument_type = arg_type(arg_name, cmd_schema)
|
|
95
100
|
|
|
96
101
|
# This might be helpful, since there's no other method for debug-level logging on the client.
|
|
97
|
-
puts "Formatting argument #{arg_name} with value #{value} as #{argument_type}\n" if @
|
|
102
|
+
puts "Formatting argument #{arg_name} with value #{value} as #{argument_type}\n" if @dump_response
|
|
98
103
|
|
|
99
104
|
case argument_type
|
|
100
105
|
when "array"
|
data/lib/razor/cli/format.rb
CHANGED
|
@@ -65,33 +65,48 @@ module Razor::CLI
|
|
|
65
65
|
def format_command_help(doc, show_api_help)
|
|
66
66
|
item = doc.items.first
|
|
67
67
|
raise Razor::CLI::Error, 'Could not find help for that entry' unless item.has_key?('help')
|
|
68
|
-
if
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
if item['help'].has_key?('examples')
|
|
69
|
+
if show_api_help && item['help']['examples'].has_key?('api')
|
|
70
|
+
format_composed_help(item, item['help']['examples']['api']).chomp
|
|
71
|
+
else
|
|
72
|
+
format_composed_help(item).chomp
|
|
73
|
+
end
|
|
72
74
|
else
|
|
73
75
|
format_full_help(item['help']).chomp
|
|
74
76
|
end
|
|
75
77
|
end
|
|
76
78
|
|
|
77
|
-
def
|
|
79
|
+
def positional_args_usage(object)
|
|
80
|
+
object['schema'].map do |k, v|
|
|
81
|
+
[v['position'], k] if v.has_key?('position')
|
|
82
|
+
end.compact.sort.map(&:last).
|
|
83
|
+
map {|attr| "[#{attr.gsub('_', '-')}] " }.join.strip
|
|
84
|
+
end
|
|
85
|
+
def format_composed_help(object, examples = object['help']['examples']['cli'])
|
|
86
|
+
help_obj = object['help']
|
|
78
87
|
ret = ''
|
|
79
|
-
ret = ret + <<-
|
|
88
|
+
ret = ret + <<-USAGE
|
|
89
|
+
# USAGE
|
|
90
|
+
|
|
91
|
+
razor #{object['name']} #{positional_args_usage(object)} <flags>
|
|
92
|
+
|
|
93
|
+
USAGE
|
|
94
|
+
ret = ret + <<-SYNOPSIS if help_obj.has_key?('summary')
|
|
80
95
|
# SYNOPSIS
|
|
81
|
-
#{
|
|
96
|
+
#{help_obj['summary']}
|
|
82
97
|
|
|
83
98
|
SYNOPSIS
|
|
84
|
-
ret = ret + <<-DESCRIPTION if
|
|
99
|
+
ret = ret + <<-DESCRIPTION if help_obj.has_key?('description')
|
|
85
100
|
# DESCRIPTION
|
|
86
|
-
#{
|
|
101
|
+
#{help_obj['description']}
|
|
87
102
|
|
|
88
|
-
#{
|
|
103
|
+
#{help_obj['schema']}
|
|
89
104
|
DESCRIPTION
|
|
90
|
-
ret = ret + <<-RETURNS if
|
|
105
|
+
ret = ret + <<-RETURNS if help_obj.has_key?('returns')
|
|
91
106
|
# RETURNS
|
|
92
|
-
#{
|
|
107
|
+
#{help_obj['returns'].gsub(/^/, ' ')}
|
|
93
108
|
RETURNS
|
|
94
|
-
ret = ret + <<-EXAMPLES if
|
|
109
|
+
ret = ret + <<-EXAMPLES if examples
|
|
95
110
|
# EXAMPLES
|
|
96
111
|
|
|
97
112
|
#{examples.gsub(/^/, ' ')}
|
data/lib/razor/cli/navigate.rb
CHANGED
|
@@ -93,7 +93,15 @@ module Razor::CLI
|
|
|
93
93
|
elsif query?
|
|
94
94
|
Razor::CLI::Query.new(@parse, self, collections, @segments).run
|
|
95
95
|
elsif command?
|
|
96
|
-
|
|
96
|
+
cmd = @segments.shift
|
|
97
|
+
command = commands.find { |coll| coll["name"] == cmd }
|
|
98
|
+
cmd_url = URI.parse(command['id'])
|
|
99
|
+
# Ensure that we copy authentication data from our previous URL.
|
|
100
|
+
if @doc_resource
|
|
101
|
+
cmd_url = URI.parse(cmd_url.to_s)
|
|
102
|
+
end
|
|
103
|
+
command = json_get(cmd_url)
|
|
104
|
+
Razor::CLI::Command.new(@parse, self, command, @segments, cmd_url).run
|
|
97
105
|
else
|
|
98
106
|
raise NavigationError.new(@doc_resource, @segments, @doc)
|
|
99
107
|
end
|
data/lib/razor/cli/parse.rb
CHANGED
|
@@ -63,22 +63,19 @@ module Razor::CLI
|
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def version
|
|
66
|
+
server_version = '(unknown)'
|
|
67
|
+
error = ''
|
|
66
68
|
begin
|
|
67
|
-
|
|
68
|
-
Razor Server version: #{navigate.server_version}
|
|
69
|
-
Razor Client version: #{Razor::CLI::VERSION}
|
|
70
|
-
VERSION
|
|
69
|
+
server_version = navigate.server_version
|
|
71
70
|
rescue RestClient::Unauthorized
|
|
72
|
-
|
|
73
|
-
Error: Credentials are required to connect to the server at #{@api_url}"
|
|
74
|
-
UNAUTH
|
|
75
|
-
exit 1
|
|
71
|
+
error = "Error: Credentials are required to connect to the server at #{@api_url}."
|
|
76
72
|
rescue
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
73
|
+
error = "Error: Could not connect to the server at #{@api_url}."
|
|
74
|
+
ensure
|
|
75
|
+
return [(<<-OUTPUT + "\n" + error).rstrip, error != '' ? 1 : 0]
|
|
76
|
+
Razor Server version: #{server_version}
|
|
77
|
+
Razor Client version: #{Razor::CLI::VERSION}
|
|
78
|
+
OUTPUT
|
|
82
79
|
end
|
|
83
80
|
end
|
|
84
81
|
|
|
@@ -105,10 +102,23 @@ HELP
|
|
|
105
102
|
Error: Credentials are required to connect to the server at #{@api_url}"
|
|
106
103
|
UNAUTH
|
|
107
104
|
exit = 1
|
|
108
|
-
rescue
|
|
105
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
|
106
|
+
puts "Error: Could not connect to the server at #{@api_url}"
|
|
107
|
+
puts " #{e}\n"
|
|
108
|
+
die
|
|
109
|
+
rescue RestClient::SSLCertificateNotVerified
|
|
110
|
+
puts "Error: SSL certificate could not be verified against known CA certificates."
|
|
111
|
+
puts " To turn off verification, use the -k or --insecure option."
|
|
112
|
+
die
|
|
113
|
+
rescue OpenSSL::SSL::SSLError => e
|
|
114
|
+
# Occurs in case of e.g. certificate mismatch (FQDN vs. hostname)
|
|
115
|
+
puts "Error: SSL certificate error from server at #{@api_url}"
|
|
116
|
+
puts " #{e}"
|
|
117
|
+
die
|
|
118
|
+
rescue => e
|
|
109
119
|
output << <<-ERR
|
|
110
|
-
Error:
|
|
111
|
-
|
|
120
|
+
Error: Unknown error occurred while connecting to server at #{@api_url}:
|
|
121
|
+
#{e}
|
|
112
122
|
ERR
|
|
113
123
|
exit = 1
|
|
114
124
|
end
|
|
@@ -143,23 +153,34 @@ ERR
|
|
|
143
153
|
# The format can be determined from later segments.
|
|
144
154
|
attr_accessor :format, :stripped_args, :ssl_ca_file
|
|
145
155
|
|
|
156
|
+
LINUX_PEM_FILE = '/etc/puppetlabs/puppet/ssl/certs/ca.pem'
|
|
157
|
+
WIN_PEM_FILE = 'C:\ProgramData\PuppetLabs\puppet\etc\ssl\certs\ca.pem'
|
|
146
158
|
def initialize(args)
|
|
147
159
|
parse_and_set_api_url(ENV["RAZOR_API"] || DEFAULT_RAZOR_API, :env)
|
|
148
160
|
@args = args.dup
|
|
149
161
|
# To be populated externally.
|
|
150
162
|
@stripped_args = []
|
|
151
163
|
@format = 'short'
|
|
164
|
+
@verify_ssl = true
|
|
165
|
+
env_pem_file = ENV['RAZOR_CA_FILE']
|
|
152
166
|
# If this is set, it should actually exist.
|
|
153
|
-
if
|
|
154
|
-
raise Razor::CLI::InvalidCAFileError.new(
|
|
167
|
+
if env_pem_file && !File.exists?(env_pem_file)
|
|
168
|
+
raise Razor::CLI::InvalidCAFileError.new(env_pem_file)
|
|
169
|
+
end
|
|
170
|
+
pem_file_locations = [env_pem_file, LINUX_PEM_FILE, WIN_PEM_FILE]
|
|
171
|
+
pem_file_locations.each do |file|
|
|
172
|
+
if file && File.exists?(file)
|
|
173
|
+
@ssl_ca_file = file
|
|
174
|
+
break
|
|
175
|
+
end
|
|
155
176
|
end
|
|
156
|
-
ca_file = ENV["RAZOR_CA_FILE"]
|
|
157
|
-
@ssl_ca_file = ca_file if ca_file && File.exists?(ca_file)
|
|
158
177
|
@args = get_optparse.order(@args)
|
|
159
178
|
|
|
160
179
|
# Localhost won't match the server's certificate; no verification required.
|
|
161
180
|
# This needs to happen after get_optparse so `-k` and `-u` can take effect.
|
|
162
|
-
|
|
181
|
+
if @api_url.hostname == 'localhost'
|
|
182
|
+
@verify_ssl = false
|
|
183
|
+
end
|
|
163
184
|
|
|
164
185
|
@args = set_help_vars(@args)
|
|
165
186
|
if @args == ['version'] or @show_version
|
|
@@ -54,7 +54,7 @@ class Razor::CLI::TableFormat
|
|
|
54
54
|
def average_width(headings)
|
|
55
55
|
# The 3 here = 2 for width gap + 1 for the column separator.
|
|
56
56
|
# The 1 is for the last separator.
|
|
57
|
-
console_width = `stty size | cut -d ' ' -f 2`
|
|
57
|
+
console_width = `stty size | cut -d ' ' -f 2 2>/dev/null`
|
|
58
58
|
if console_width.nil? || console_width.to_i <= 0
|
|
59
59
|
console_width = 80
|
|
60
60
|
end
|
data/lib/razor/cli/version.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Razor
|
|
|
18
18
|
#
|
|
19
19
|
# The next line is the one that our packaging tools modify, so please make
|
|
20
20
|
# sure that any change to it is discussed and agreed first.
|
|
21
|
-
version = '1.
|
|
21
|
+
version = '1.2.0'
|
|
22
22
|
|
|
23
23
|
if version == "DEVELOPMENT"
|
|
24
24
|
root = File.expand_path("../../..", File.dirname(__FILE__))
|
data/spec/cli/command_spec.rb
CHANGED
|
@@ -63,4 +63,100 @@ describe Razor::CLI::Command do
|
|
|
63
63
|
result.should == 'abc'
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
|
+
|
|
67
|
+
context "extract_command" do
|
|
68
|
+
|
|
69
|
+
def extract(schema, run_array)
|
|
70
|
+
c = Razor::CLI::Command.new(nil, nil, schema, run_array, nil)
|
|
71
|
+
c.extract_command
|
|
72
|
+
end
|
|
73
|
+
context "flag length" do
|
|
74
|
+
|
|
75
|
+
it "fails with a single dash for long flags" do
|
|
76
|
+
expect{extract({'schema' => {'name' => {'type' => 'array'}}}, ['-name', 'abc'])}.
|
|
77
|
+
to raise_error(ArgumentError, 'Unexpected argument -name (did you mean --name?)')
|
|
78
|
+
end
|
|
79
|
+
it "fails with a double dash for short flags" do
|
|
80
|
+
expect{extract({'schema' => {'n' => {'type' => 'array'}}}, ['--n', 'abc'])}.
|
|
81
|
+
to raise_error(ArgumentError, 'Unexpected argument --n (did you mean -n?)')
|
|
82
|
+
end
|
|
83
|
+
it "fails with a double dash for short flags if argument does not exist" do
|
|
84
|
+
c = Razor::CLI::Command.new(nil, nil, {'schema' => {}},
|
|
85
|
+
['--n', 'abc'], '/foobar')
|
|
86
|
+
expect{extract({'schema' => {}}, ['--n', 'abc'])}.
|
|
87
|
+
to raise_error(ArgumentError, 'Unexpected argument --n')
|
|
88
|
+
end
|
|
89
|
+
it "succeeds with a double dash for long flags" do
|
|
90
|
+
extract({'schema' => {'name' => {'type' => 'array'}}},
|
|
91
|
+
['--name', 'abc'])['name'].should == ['abc']
|
|
92
|
+
end
|
|
93
|
+
it "succeeds with a single dash for short flags" do
|
|
94
|
+
c = Razor::CLI::Command.new(nil, nil, {'schema' => {'n' => {'type' => 'array'}}},
|
|
95
|
+
['-n', 'abc'], nil)
|
|
96
|
+
extract({'schema' => {'n' => {'type' => 'array'}}}, ['-n', 'abc'])['n'].should == ['abc']
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context "positional arguments" do
|
|
101
|
+
let(:schema) do
|
|
102
|
+
{'schema' => {'n' => {'position' => 1},
|
|
103
|
+
'o' => {'position' => 0}}}
|
|
104
|
+
end
|
|
105
|
+
it "fails without a command schema" do
|
|
106
|
+
expect{extract(nil, ['123'])}.
|
|
107
|
+
to raise_error(ArgumentError, 'Unexpected argument 123')
|
|
108
|
+
end
|
|
109
|
+
it "fails if no positional arguments exist for a command" do
|
|
110
|
+
expect{extract({'schema' => {'n' => {}}}, ['abc'])}.
|
|
111
|
+
to raise_error(ArgumentError, 'Unexpected argument abc')
|
|
112
|
+
end
|
|
113
|
+
it "succeeds if no position is supplied" do
|
|
114
|
+
extract({'schema' => {'n' => {'position' => 0}}}, ['-n', '123'])['n'].
|
|
115
|
+
should == '123'
|
|
116
|
+
end
|
|
117
|
+
it "succeeds if position exists and is supplied" do
|
|
118
|
+
extract({'schema' => {'n' => {'position' => 0}}}, ['123'])['n'].
|
|
119
|
+
should == '123'
|
|
120
|
+
end
|
|
121
|
+
it "succeeds if multiple positions exist and are supplied" do
|
|
122
|
+
body = extract(schema, ['123', '456'])
|
|
123
|
+
body['o'].should == '123'
|
|
124
|
+
body['n'].should == '456'
|
|
125
|
+
end
|
|
126
|
+
it "fails if too many positions are supplied" do
|
|
127
|
+
expect{extract(schema, ['123', '456', '789'])}.
|
|
128
|
+
to raise_error(ArgumentError, 'Unexpected argument 789')
|
|
129
|
+
end
|
|
130
|
+
it "succeeds if multiple positions exist and one is supplied" do
|
|
131
|
+
body = extract(schema, ['123'])
|
|
132
|
+
body['o'].should == '123'
|
|
133
|
+
body['n'].should == nil
|
|
134
|
+
end
|
|
135
|
+
it "succeeds with a combination of positional and flags" do
|
|
136
|
+
body = extract(schema, ['123', '-n', '456'])
|
|
137
|
+
body['o'].should == '123'
|
|
138
|
+
body['n'].should == '456'
|
|
139
|
+
end
|
|
140
|
+
it "prefers the later between positional and flags" do
|
|
141
|
+
body = extract(schema, ['123', '-o', '456'])
|
|
142
|
+
body['o'].should == '456'
|
|
143
|
+
body = extract(schema, ['-o', '456', '123'])
|
|
144
|
+
body['o'].should == '123'
|
|
145
|
+
end
|
|
146
|
+
it "correctly sets datatypes" do
|
|
147
|
+
schema =
|
|
148
|
+
{'schema' => {'n' => {'type' => 'array', 'position' => 0},
|
|
149
|
+
'o' => {'type' => 'number', 'position' => 1},
|
|
150
|
+
'w' => {'type' => 'boolean', 'position' => 2},
|
|
151
|
+
'a' => {'type' => 'object', 'position' => 3},
|
|
152
|
+
'i' => {'type' => 'object', 'position' => 4}}}
|
|
153
|
+
body = extract(schema, ['arr', '123', 'true', '{}', 'abc=123'])
|
|
154
|
+
body['n'].should == ['arr']
|
|
155
|
+
body['o'].should == 123
|
|
156
|
+
body['w'].should == true
|
|
157
|
+
body['a'].should == {}
|
|
158
|
+
body['i'].should == {'abc' => '123'}
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
66
162
|
end
|