pe-razor-client 0.14.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 +7 -0
- data/.yardopts +2 -0
- data/Gemfile +35 -0
- data/Gemfile.lock +53 -0
- data/LICENSE +15 -0
- data/README.md +23 -0
- data/Rakefile +37 -0
- data/bin/razor +61 -0
- data/lib/razor.rb +1 -0
- data/lib/razor/cli.rb +34 -0
- data/lib/razor/cli/format.rb +76 -0
- data/lib/razor/cli/navigate.rb +177 -0
- data/lib/razor/cli/navigate.yaml +28 -0
- data/lib/razor/cli/parse.rb +86 -0
- data/pe-razor-client.gemspec +32 -0
- data/spec/cli/navigate_spec.rb +52 -0
- data/spec/cli/parse_spec.rb +76 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_a_single_item_path/.yml +69 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_an_invalid_path/.yml +36 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_authentication/should_preserve_that_across_navigation.yml +102 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_authentication/should_supply_that_to_the_API_service.yml +36 -0
- data/spec/fixtures/vcr/Razor_CLI_Navigate/with_no_path/.yml +36 -0
- data/spec/fixtures/vcr/Razor_CLI_Parse/_new/_help/.yml +36 -0
- data/spec/fixtures/vcr/Razor_CLI_Parse/_new/_help/should_print_a_list_of_known_endpoints.yml +36 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/vcr_library.rb +8 -0
- metadata +167 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56d3c2b6b7151fc0b1e41bc7b6761b9e7bc46b04
|
4
|
+
data.tar.gz: 28c812344e73fefc6a6634c9688e302afefaa716
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8261b52410c1685770bb406d68698d541c1e986c6b249b21d9cbda8255763a130de0808f21e021228388978482cf9b3c1da6fdf6c226edaf5ce2b4697e49ab34
|
7
|
+
data.tar.gz: 37f1d1535ddcb8d12a405548912dbfcec7a1cdea73b39d39e1df0310ee181ef706e4b08420f4159c1d5f7fa516514d54514c92bc753b7c2d72fd1aff2558b20c
|
data/.gitignore
ADDED
data/.yardopts
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# mime-types is a dependency of rest-client. We need to explicitly depend
|
4
|
+
# on it and pin its version to make sure this works with Ruby 1.8.7
|
5
|
+
gem 'mime-types', '< 2.0'
|
6
|
+
gem 'rest-client'
|
7
|
+
gem 'terminal-table'
|
8
|
+
|
9
|
+
group :doc do
|
10
|
+
gem 'yard'
|
11
|
+
gem 'kramdown'
|
12
|
+
end
|
13
|
+
|
14
|
+
# This group will be excluded by default in `torquebox archive`
|
15
|
+
group :test do
|
16
|
+
gem 'rack-test'
|
17
|
+
gem 'rspec', '~> 2.13.0'
|
18
|
+
gem 'rspec-core', '~> 2.13.1'
|
19
|
+
gem 'rspec-expectations', '~> 2.13.0'
|
20
|
+
gem 'rspec-mocks', '~> 2.13.1'
|
21
|
+
gem 'simplecov'
|
22
|
+
gem 'webmock'
|
23
|
+
gem 'vcr'
|
24
|
+
end
|
25
|
+
|
26
|
+
group :development do
|
27
|
+
gem 'rake'
|
28
|
+
end
|
29
|
+
|
30
|
+
# This allows you to create `Gemfile.local` and have it loaded automatically;
|
31
|
+
# the purpose of this is to allow you to put additional development gems
|
32
|
+
# somewhere convenient without having to constantly mess with this file.
|
33
|
+
#
|
34
|
+
# Gemfile.local is in the .gitignore file; do not check one in!
|
35
|
+
eval(File.read(File.dirname(__FILE__) + '/Gemfile.local'), binding) rescue nil
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.3.3)
|
5
|
+
crack (0.3.2)
|
6
|
+
diff-lcs (1.2.4)
|
7
|
+
kramdown (1.1.0)
|
8
|
+
mime-types (1.24)
|
9
|
+
multi_json (1.7.9)
|
10
|
+
rack (1.5.2)
|
11
|
+
rack-test (0.6.2)
|
12
|
+
rack (>= 1.0)
|
13
|
+
rake (10.1.0)
|
14
|
+
rest-client (1.6.7)
|
15
|
+
mime-types (>= 1.16)
|
16
|
+
rspec (2.13.0)
|
17
|
+
rspec-core (~> 2.13.0)
|
18
|
+
rspec-expectations (~> 2.13.0)
|
19
|
+
rspec-mocks (~> 2.13.0)
|
20
|
+
rspec-core (2.13.1)
|
21
|
+
rspec-expectations (2.13.0)
|
22
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
23
|
+
rspec-mocks (2.13.1)
|
24
|
+
simplecov (0.7.1)
|
25
|
+
multi_json (~> 1.0)
|
26
|
+
simplecov-html (~> 0.7.1)
|
27
|
+
simplecov-html (0.7.1)
|
28
|
+
terminal-table (1.4.5)
|
29
|
+
vcr (2.5.0)
|
30
|
+
webmock (1.9.3)
|
31
|
+
addressable (>= 2.2.7)
|
32
|
+
crack (>= 0.3.2)
|
33
|
+
yard (0.8.7)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
java
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
kramdown
|
41
|
+
mime-types (< 2.0)
|
42
|
+
rack-test
|
43
|
+
rake
|
44
|
+
rest-client
|
45
|
+
rspec (~> 2.13.0)
|
46
|
+
rspec-core (~> 2.13.1)
|
47
|
+
rspec-expectations (~> 2.13.0)
|
48
|
+
rspec-mocks (~> 2.13.1)
|
49
|
+
simplecov
|
50
|
+
terminal-table
|
51
|
+
vcr
|
52
|
+
webmock
|
53
|
+
yard
|
data/LICENSE
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
Razor
|
2
|
+
|
3
|
+
Copyright 2013, 2014 Puppet Labs Inc
|
4
|
+
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
you may not use this file except in compliance with the License.
|
7
|
+
You may obtain a copy of the License at
|
8
|
+
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
See the License for the specific language governing permissions and
|
15
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Razor client
|
2
|
+
|
3
|
+
This code is still in development mode; that means that we might make
|
4
|
+
backwards incompatible changes, especially to the database schema which
|
5
|
+
would force you to rebuild all the machines that Razor is managing. Razor
|
6
|
+
will become stable RSN.
|
7
|
+
|
8
|
+
This is the command line client for the [Razor
|
9
|
+
server](https://github.com/puppetlabs/razor-server) Please have a look at
|
10
|
+
the Wiki over there for details, in particular, the [Getting
|
11
|
+
Started](https://github.com/puppetlabs/razor-server/wiki/Getting-started)
|
12
|
+
page contains instructions about installation and setup of the client.
|
13
|
+
|
14
|
+
## Getting in touch
|
15
|
+
|
16
|
+
* bug/issue tracker: [RAZOR project in JIRA](https://tickets.puppetlabs.com/browse/RAZOR)
|
17
|
+
* on IRC: `#puppet-razor` on [freenode](http://freenode.net/)
|
18
|
+
* mailing list: [puppet-razor@googlegroups.com](http://groups.google.com/group/puppet-razor)
|
19
|
+
|
20
|
+
## License
|
21
|
+
|
22
|
+
Razor is distributed under the Apache 2.0 license.
|
23
|
+
See [the LICENSE file](LICENSE) for full details.
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require "bundler/gem_tasks"
|
3
|
+
|
4
|
+
# Needed to make the client work on Ruby 1.8.7
|
5
|
+
unless Kernel.respond_to?(:require_relative)
|
6
|
+
module Kernel
|
7
|
+
def require_relative(path)
|
8
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
require_relative 'spec/vcr_library'
|
14
|
+
|
15
|
+
namespace :bundler do
|
16
|
+
task :setup do
|
17
|
+
require 'bundler/setup'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :spec do
|
22
|
+
require 'rspec/core'
|
23
|
+
require 'rspec/core/rake_task'
|
24
|
+
|
25
|
+
desc <<EOS
|
26
|
+
Run all specs. Set VCR_RECORD to 'all' to rerecord and to 'new_episodes'
|
27
|
+
to record new tests. Tapes are in #{VCR_LIBRARY}
|
28
|
+
EOS
|
29
|
+
RSpec::Core::RakeTask.new(:all => :"bundler:setup") do |t|
|
30
|
+
t.pattern = 'spec/**/*_spec.rb'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "Erase all VCR recordings"
|
35
|
+
task :"vcr:erase" do
|
36
|
+
erase_vcr_library
|
37
|
+
end
|
data/bin/razor
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Needed to make the client work on Ruby 1.8.7
|
4
|
+
unless Kernel.respond_to?(:require_relative)
|
5
|
+
module Kernel
|
6
|
+
def require_relative(path)
|
7
|
+
require File.join(File.dirname(caller[0]), path.to_str)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'rubygems'
|
13
|
+
require_relative "../lib/razor/cli"
|
14
|
+
|
15
|
+
include Razor::CLI::Format
|
16
|
+
|
17
|
+
def die(message = nil)
|
18
|
+
puts "Error: #{message}" if message
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
|
22
|
+
begin
|
23
|
+
parse = Razor::CLI::Parse.new(ARGV)
|
24
|
+
rescue Razor::CLI::InvalidURIError => e
|
25
|
+
die e.message
|
26
|
+
rescue OptionParser::InvalidOption => e
|
27
|
+
die e.message + "\nTry 'razor --help' for more information"
|
28
|
+
end
|
29
|
+
|
30
|
+
if parse.show_help?
|
31
|
+
puts parse.help
|
32
|
+
exit 0
|
33
|
+
end
|
34
|
+
|
35
|
+
begin
|
36
|
+
document = parse.navigate.get_document
|
37
|
+
url = parse.navigate.last_url
|
38
|
+
puts "From #{url}:\n\n#{format_document document}\n\n"
|
39
|
+
rescue Razor::CLI::Error => e
|
40
|
+
die "#{e}\n#{parse.help}\n\n"
|
41
|
+
rescue SocketError, Errno::ECONNREFUSED => e
|
42
|
+
puts "Error: Could not connect to the server at #{parse.api_url}"
|
43
|
+
puts " #{e}\n"
|
44
|
+
die
|
45
|
+
rescue RestClient::Exception => e
|
46
|
+
r = e.response
|
47
|
+
puts "Error from doing #{r.args[:method].to_s.upcase} #{r.args[:url]}"
|
48
|
+
puts e.message
|
49
|
+
begin
|
50
|
+
body = MultiJson::load(r.body)
|
51
|
+
puts body.delete("details") if body["details"]
|
52
|
+
unless body.empty?
|
53
|
+
puts format_document(body)
|
54
|
+
end
|
55
|
+
rescue => e
|
56
|
+
# Ignore errors here; our best efforts at telling the user more about
|
57
|
+
# what happened has failed. Just dump the response
|
58
|
+
puts r.body
|
59
|
+
end
|
60
|
+
die
|
61
|
+
end
|
data/lib/razor.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require_relative 'razor/cli'
|
data/lib/razor/cli.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Razor
|
2
|
+
module CLI
|
3
|
+
class Error < RuntimeError; end
|
4
|
+
|
5
|
+
class NavigationError < Error
|
6
|
+
def initialize(url, key, doc)
|
7
|
+
@key = key; @doc = doc
|
8
|
+
if key.is_a?(Array)
|
9
|
+
super "Could not navigate to '#{key.join(" ")}' from #{url}"
|
10
|
+
else
|
11
|
+
super "Could not find entry '#{key}' in document at #{url}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class InvalidURIError < Error
|
17
|
+
def initialize(url, type)
|
18
|
+
case type
|
19
|
+
when :env
|
20
|
+
super "URL '#{url}' in ENV variable RAZOR_API is not valid"
|
21
|
+
when :opts
|
22
|
+
super "URL '#{url}' provided by -U or --url is not valid"
|
23
|
+
else
|
24
|
+
super "URL '#{url}' is not valid"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
require_relative 'cli/navigate'
|
33
|
+
require_relative 'cli/parse'
|
34
|
+
require_relative 'cli/format'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'terminal-table'
|
2
|
+
|
3
|
+
module Razor::CLI
|
4
|
+
module Format
|
5
|
+
PriorityKeys = %w[ id name ]
|
6
|
+
SpecNames = {
|
7
|
+
"/spec/object/policy" => "Policy",
|
8
|
+
"/spec/object/tag" => "Tag",
|
9
|
+
"/spec/object/reference" => "reference"
|
10
|
+
}
|
11
|
+
|
12
|
+
def self.spec_name(spec)
|
13
|
+
path = spec && URI.parse(spec).path
|
14
|
+
SpecNames[path] || path
|
15
|
+
rescue => e
|
16
|
+
spec
|
17
|
+
end
|
18
|
+
|
19
|
+
def format_document(doc)
|
20
|
+
case doc
|
21
|
+
when Array then format_objects(doc)
|
22
|
+
when Hash then format_object(doc)
|
23
|
+
else doc.to_s
|
24
|
+
end.chomp
|
25
|
+
end
|
26
|
+
|
27
|
+
# We assume that all collections are homogenous
|
28
|
+
def format_objects(objects, indent = 0)
|
29
|
+
objects.map do |obj|
|
30
|
+
obj.is_a?(Hash) ? format_object(obj, indent) : ' '*indent + obj.inspect
|
31
|
+
end.join "\n\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
def format_reference_object(ref, indent = 0)
|
35
|
+
output = ' '* indent + "#{ref['name']} => #{ref['id'].to_s.ljust 4}"
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def format_object(object, indent = 0)
|
40
|
+
if object.keys == ["id", "name"]
|
41
|
+
format_reference_object(object, indent)
|
42
|
+
else
|
43
|
+
format_default_object(object, indent)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def format_default_object(object, indent = 0 )
|
48
|
+
fields = (PriorityKeys & object.keys) + (object.keys - PriorityKeys)
|
49
|
+
key_indent = indent + fields.map {|f| f.length}.max
|
50
|
+
output = ""
|
51
|
+
fields.map do |f|
|
52
|
+
value = object[f]
|
53
|
+
output = "#{f.rjust key_indent + 2}: "
|
54
|
+
output << case value
|
55
|
+
when Hash
|
56
|
+
if value.empty?
|
57
|
+
"{}"
|
58
|
+
else
|
59
|
+
"\n" + format_object(value, key_indent + 4).rstrip
|
60
|
+
end
|
61
|
+
when Array
|
62
|
+
if value.all? { |v| v.is_a?(String) }
|
63
|
+
"[" + value.map(&:inspect).join(",") + "]"
|
64
|
+
else
|
65
|
+
"[\n" + format_objects(value, key_indent + 6) + ("\n"+' '*(key_indent+4)+"]")
|
66
|
+
end
|
67
|
+
else
|
68
|
+
case f
|
69
|
+
when "spec" then "\"#{Format.spec_name(value)}\""
|
70
|
+
else value.inspect
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end.join "\n"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Razor::CLI
|
6
|
+
class Navigate
|
7
|
+
|
8
|
+
def initialize(parse, segments)
|
9
|
+
@parse = parse
|
10
|
+
@segments = segments||[]
|
11
|
+
@doc = entrypoint
|
12
|
+
@doc_url = parse.api_url
|
13
|
+
end
|
14
|
+
|
15
|
+
def last_url
|
16
|
+
@doc_url
|
17
|
+
end
|
18
|
+
|
19
|
+
def entrypoint
|
20
|
+
@entrypoint ||= json_get(@parse.api_url)
|
21
|
+
end
|
22
|
+
|
23
|
+
def collections
|
24
|
+
entrypoint["collections"]
|
25
|
+
end
|
26
|
+
|
27
|
+
def commands
|
28
|
+
entrypoint["commands"]
|
29
|
+
end
|
30
|
+
|
31
|
+
def query?
|
32
|
+
collections.any? { |coll| coll["name"] == @segments.first }
|
33
|
+
end
|
34
|
+
|
35
|
+
def command(name)
|
36
|
+
commands.find { |coll| coll["name"] == name }
|
37
|
+
end
|
38
|
+
|
39
|
+
def command?
|
40
|
+
!! command(@segments.first)
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_document
|
44
|
+
if @segments.empty?
|
45
|
+
entrypoint
|
46
|
+
elsif query?
|
47
|
+
@doc = collections
|
48
|
+
while @segments.any?
|
49
|
+
move_to @segments.shift
|
50
|
+
end
|
51
|
+
@doc
|
52
|
+
elsif command?
|
53
|
+
# @todo lutter 2013-08-16: None of this has any tests, and error
|
54
|
+
# handling is heinous at best
|
55
|
+
cmd, body = extract_command
|
56
|
+
if body.empty?
|
57
|
+
raise Razor::CLI::Error,
|
58
|
+
"No arguments for command (did you forget --json ?)"
|
59
|
+
end
|
60
|
+
# Ensure that we copy authentication data from our previous URL.
|
61
|
+
url = cmd["id"]
|
62
|
+
if @doc_url
|
63
|
+
url = URI.parse(url.to_s)
|
64
|
+
url.userinfo = @doc_url.userinfo
|
65
|
+
end
|
66
|
+
|
67
|
+
json_post(url, body)
|
68
|
+
else
|
69
|
+
raise NavigationError.new(@doc_url, @segments, @doc)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def extract_command
|
74
|
+
cmd = command(@segments.shift)
|
75
|
+
body = {}
|
76
|
+
until @segments.empty?
|
77
|
+
if @segments.shift =~ /\A--([a-z-]+)(=(\S+))?\Z/
|
78
|
+
arg, value = [$1, $3]
|
79
|
+
value = @segments.shift if value.nil? && @segments[0] !~ /^--/
|
80
|
+
body[arg] = convert_arg(cmd["name"], arg, value)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
begin
|
85
|
+
body = MultiJson::load(File::read(body["json"])) if body["json"]
|
86
|
+
rescue MultiJson::LoadError
|
87
|
+
raise Razor::CLI::Error, "File #{body["json"]} is not valid JSON"
|
88
|
+
rescue Errno::ENOENT
|
89
|
+
raise Razor::CLI::Error, "File #{body["json"]} not found"
|
90
|
+
rescue Errno::EACCES
|
91
|
+
raise Razor::CLI::Error,
|
92
|
+
"Permission to read file #{body["json"]} denied"
|
93
|
+
end
|
94
|
+
[cmd, body]
|
95
|
+
end
|
96
|
+
|
97
|
+
def move_to(key)
|
98
|
+
key = key.to_i if key.to_i.to_s == key
|
99
|
+
if @doc.is_a? Array
|
100
|
+
obj = @doc.find {|x| x.is_a?(Hash) and x["name"] == key }
|
101
|
+
elsif @doc.is_a? Hash
|
102
|
+
obj = @doc[key]
|
103
|
+
end
|
104
|
+
|
105
|
+
raise NavigationError.new(@doc_url, key, @doc) unless obj
|
106
|
+
|
107
|
+
if obj.is_a?(Hash) && obj["id"]
|
108
|
+
url = obj["id"]
|
109
|
+
if @doc_url
|
110
|
+
url = URI.parse(url.to_s)
|
111
|
+
url.userinfo = @doc_url.userinfo
|
112
|
+
end
|
113
|
+
|
114
|
+
@doc = json_get(url)
|
115
|
+
# strip the wrapper around collections
|
116
|
+
if @doc.is_a? Hash and @doc["items"].is_a? Array
|
117
|
+
@doc = @doc["items"]
|
118
|
+
end
|
119
|
+
@doc_url = url
|
120
|
+
elsif obj.is_a? Hash
|
121
|
+
@doc = obj
|
122
|
+
else
|
123
|
+
@doc = nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def get(url, headers={})
|
128
|
+
response = RestClient.get url.to_s, headers
|
129
|
+
print "GET #{url.to_s}\n#{response.body}\n\n" if @parse.dump_response?
|
130
|
+
response
|
131
|
+
end
|
132
|
+
|
133
|
+
def json_get(url, headers = {})
|
134
|
+
response = get(url,headers.merge(:accept => :json))
|
135
|
+
unless response.headers[:content_type] =~ /application\/json/
|
136
|
+
raise "Received content type #{response.headers[:content_type]}"
|
137
|
+
end
|
138
|
+
MultiJson.load(response.body)
|
139
|
+
end
|
140
|
+
|
141
|
+
def json_post(url, body)
|
142
|
+
headers = { :accept=>:json, "Content-Type" => :json }
|
143
|
+
begin
|
144
|
+
response = RestClient.post url.to_s, MultiJson::dump(body), headers
|
145
|
+
ensure
|
146
|
+
if @parse.dump_response?
|
147
|
+
print "POST #{url.to_s}\n#{body}\n-->\n"
|
148
|
+
puts (response ? response.body : "ERROR")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
MultiJson::load(response.body)
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
def self.annotations
|
156
|
+
@@annotations ||=
|
157
|
+
YAML::load_file(File::join(File::dirname(__FILE__), "navigate.yaml"))
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.arg_type(cmd_name, arg_name)
|
161
|
+
cmd = annotations["commands"][cmd_name]
|
162
|
+
cmd && cmd["args"][arg_name]
|
163
|
+
end
|
164
|
+
|
165
|
+
def convert_arg(cmd_name, arg_name, value)
|
166
|
+
value = nil if value == "null"
|
167
|
+
case self.class.arg_type(cmd_name, arg_name)
|
168
|
+
when "json"
|
169
|
+
MultiJson::load(value)
|
170
|
+
when "boolean"
|
171
|
+
["true", nil].include?(value)
|
172
|
+
else
|
173
|
+
value
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|