Class: Razor::CLI::Navigate

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/razor/cli/navigate.rb

Instance Method Summary collapse

Constructor Details

#initialize(parse, segments) ⇒ Navigate

Returns a new instance of Navigate.



10
11
12
13
14
15
# File 'lib/razor/cli/navigate.rb', line 10

def initialize(parse, segments)
  @parse = parse
  @segments = segments||[]
  @doc = entrypoint
  @doc_url = parse.api_url
end

Instance Method Details

#collectionsObject



25
26
27
# File 'lib/razor/cli/navigate.rb', line 25

def collections
  entrypoint["collections"]
end

#command(name) ⇒ Object



41
42
43
# File 'lib/razor/cli/navigate.rb', line 41

def command(name)
  commands.find { |coll| coll["name"] == name }
end

#command?Boolean

Returns:

  • (Boolean)


45
46
47
# File 'lib/razor/cli/navigate.rb', line 45

def command?
  !! command(@segments.first)
end

#commandsObject



29
30
31
# File 'lib/razor/cli/navigate.rb', line 29

def commands
  entrypoint["commands"]
end

#entrypointObject



21
22
23
# File 'lib/razor/cli/navigate.rb', line 21

def entrypoint
  @entrypoint ||= json_get(@parse.api_url)
end

#extract_commandObject



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/razor/cli/navigate.rb', line 95

def extract_command
  cmd = command(@segments.shift)
  @cmd_url = cmd['id']
  body = {}
  until @segments.empty?
    argument = @segments.shift
    if argument =~ /\A--([a-z-]+)(=(.+))?\Z/
      # `--arg=value` or `--arg value`
      arg, value = [$1, $3]
      value = @segments.shift if value.nil? && @segments[0] !~ /^--/
      if value =~ /\A([a-zA-Z._-]+)=(\S+)?\z/
        # `--arg name=value`
        unless body[arg].nil? or body[arg].is_a?(Hash)
          # Error: `--arg value --arg name=value`
          raise ArgumentError, "Cannot handle mixed types for argument #{arg}"
        end
        # Do not convert, assume the above is the conversion.
        body[arg] = (body[arg].nil? ? {} : body[arg]).merge($1 => $2)
      elsif body[arg].is_a?(Hash)
        # Error: `--arg name=value --arg value`
        raise ArgumentError, "Cannot handle mixed types for argument #{arg}"
      else
        value = convert_arg(cmd["name"], arg, value)
        if body[arg].nil?
          body[arg] = value
        else
          # Either/both `body[arg]` or/and `value` might be an array at this point.
          body[arg] = Array(body[arg]) + Array(value)
        end
      end
    else
      raise ArgumentError, "Unexpected argument #{argument}"
    end
  end

  begin
    body = MultiJson::load(File::read(body["json"])) if body["json"]
  rescue MultiJson::LoadError
    raise Razor::CLI::Error, "File #{body["json"]} is not valid JSON"
  rescue Errno::ENOENT
    raise Razor::CLI::Error, "File #{body["json"]} not found"
  rescue Errno::EACCES
    raise Razor::CLI::Error,
          "Permission to read file #{body["json"]} denied"
  end
  [cmd, body]
end

#get(url, headers = {}) ⇒ Object



188
189
190
191
192
# File 'lib/razor/cli/navigate.rb', line 188

def get(url, headers={})
  response = RestClient.get url.to_s, headers
  print "GET #{url.to_s}\n#{response.body}\n\n" if @parse.dump_response?
  response
end

#get_documentObject



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/razor/cli/navigate.rb', line 51

def get_document
  if @segments.empty?
    entrypoint
  elsif query?
    @doc = collections
    while @segments.any?
      move_to @segments.shift
    end

    # Get the next level if it's a list of objects.
    if @doc.is_a?(Hash) and @doc['items'].is_a?(Array)
      @doc['items'] = @doc['items'].map do |item|
        item.is_a?(Hash) && item.has_key?('id') ? json_get(item['id']) : item
      end
    end
    @doc
  elsif command?
    # @todo lutter 2013-08-16: None of this has any tests, and error
    # handling is heinous at best
    cmd, body = extract_command
    # Ensure that we copy authentication data from our previous URL.
    url = cmd["id"]
    if @doc_url
      url          = URI.parse(url.to_s)
      url.userinfo = @doc_url.userinfo
    end

    if show_command_help?
      json_get(url)
    else
      if body.empty?
        raise Razor::CLI::Error,
              "No arguments for command (did you forget --json ?)"
      end
      result = json_post(url, body)
      # Get actual object from the id.
      result = result.merge(json_get(result['id'])) if result['id']
      result
    end
  else
    raise NavigationError.new(@doc_url, @segments, @doc)
  end
end

#json_get(url, headers = {}) ⇒ Object



194
195
196
197
198
199
200
# File 'lib/razor/cli/navigate.rb', line 194

def json_get(url, headers = {})
  response = get(url,headers.merge(:accept => :json))
  unless response.headers[:content_type] =~ /application\/json/
    raise "Received content type #{response.headers[:content_type]}"
  end
  MultiJson.load(response.body)
end

#json_post(url, body) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
# File 'lib/razor/cli/navigate.rb', line 202

def json_post(url, body)
  headers = {  :accept=>:json, "Content-Type" => :json }
  begin
    response = RestClient.post url.to_s, MultiJson::dump(body), headers
  ensure
    if @parse.dump_response?
      print "POST #{url.to_s}\n#{body}\n-->\n"
      puts (response ? response.body : "ERROR")
    end
  end
  MultiJson::load(response.body)
end

#last_urlObject



17
18
19
# File 'lib/razor/cli/navigate.rb', line 17

def last_url
  @doc_url
end

#move_to(key) ⇒ Object

Raises:



143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/razor/cli/navigate.rb', line 143

def move_to(key)
  if @doc.is_a? Array
    obj = @doc.find {|x| x.is_a?(Hash) and x["name"] == key }
  elsif @doc.is_a?(Hash) && @doc['items'].is_a?(Array)
    obj = @doc['items'].find {|x| x.is_a?(Hash) and x["name"] == key }
  elsif @doc.is_a? Hash
    obj = @doc[key]
  end

  raise NavigationError.new(@doc_url, key, @doc) unless obj

  if obj.is_a?(Hash) && obj["id"]
    url = obj["id"]
    if @doc_url
      url          = URI.parse(url.to_s)
      url.userinfo = @doc_url.userinfo
    end

    @doc = json_get(url)
    @doc_url = url
  elsif obj.is_a?(Hash) && obj['spec']
    @doc = obj
  elsif obj.is_a?(Hash)
    # No spec string; use parent's and remember extra navigation.
    if @doc['+spec'].is_a?(Array)
      # Something's been added.
      @doc['+spec'] << key
    elsif @doc['+spec'].nil? || @doc['+spec'].is_a?(String)
      @doc['+spec'] = [@doc['spec'], key]
    end
    @doc = obj.merge({'+spec' => @doc['+spec']})
  elsif obj.is_a?(Array)
    # No spec string; use parent's and remember extra navigation.
    if @doc['+spec'].is_a?(Array)
      # Something's already been added.
      @doc['+spec'] << key
    elsif @doc['+spec'].nil? || @doc['+spec'].is_a?(String)
      @doc['+spec'] = [@doc['spec'], key]
    end
    @doc = {'+spec' => @doc['+spec'], 'items' => obj}
  else
    @doc = nil
  end
end

#query?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/razor/cli/navigate.rb', line 37

def query?
  collections.any? { |coll| coll["name"] == @segments.first }
end

#server_versionObject



33
34
35
# File 'lib/razor/cli/navigate.rb', line 33

def server_version
  entrypoint.has_key?('version') and entrypoint['version']['server'] or 'Unknown'
end