Module: RightApi::Helper

Included in:
Client, Resource, ResourceDetail, Resources
Defined in:
lib/right_api_client/helper.rb

Overview

Methods shared by the Client, Resource and Resources.

Constant Summary collapse

INCONSISTENT_RESOURCE_TYPES =

Some resource_types are not the same as the last thing in the URL, put these here to ensure consistency

{
  'current_instance' => 'instance',
  'data'  => 'monitoring_metric_data',
  'setting'  => 'multi_cloud_image_setting'
}
RESOURCE_SPECIAL_ACTIONS =

Some RightApi::Resources have methods that operate on the resource type itself and not on a particular one (ie: without specifying an id). Place these here:

{
  'instances' => {:multi_terminate => 'do_post', :multi_run_executable => 'do_post'},
  'inputs'    => {:multi_update    => 'do_put'},
  'tags'      => {:by_tag          => 'do_post', :by_resource => 'do_post', :multi_add => 'do_post', :multi_delete =>'do_post'},
  'backups'   => {:cleanup         => 'do_post'},
  'runnable_bindings' => {:multi_update => 'do_put'},

}
INSTANCE_FACING_RESOURCES =

List of resources that are available as instance-facing calls

[:backups, :live_tasks, :volumes, :volume_attachments, :volume_snapshots, :volume_types, :tags]

Instance Method Summary collapse

Instance Method Details

#add_id_and_params_to_path(original_path, params = {}) ⇒ Object

Helper method that adds filters and other parameters to the path Normally you would just pass a hash of query params to RestClient, but unfortunately it only takes them as a hash, and for filtering we need to pass multiple parameters with the same key. The result is that we have to build up the query string manually. This does not modify the original_path but will change the params



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/right_api_client/helper.rb', line 124

def add_id_and_params_to_path(original_path, params = {})
  path = original_path.dup

  path += "/#{params.delete(:id)}" if has_id(params)
  filters = params.delete(:filter)
  params_string = params.map{|k,v| "#{k.to_s}=#{CGI::escape(v.to_s)}" }.join('&')
  if filters && filters.any?
    path += "?filter[]=" + filters.map{|f| CGI::escape(f) }.join('&filter[]=')
    path += "&#{params_string}"
  else
    path += "?#{params_string}"
  end

  # If present, remove ? and & at end of path
  path.chomp!('&')
  path.chomp!('?')
  path
end

#api_methodsObject

Helper method that returns all api methods available to a client or resource



32
33
34
# File 'lib/right_api_client/helper.rb', line 32

def api_methods
  self.methods(false)
end

#define_instance_method(meth, &blk) ⇒ Object

Helper used to add methods to classes dynamically



25
26
27
28
29
# File 'lib/right_api_client/helper.rb', line 25

def define_instance_method(meth, &blk)
  (class << self; self; end).module_eval do
    define_method(meth, &blk)
  end
end

#fix_array_of_hashes(args, top_level = true) ⇒ Object

rest client does not post params correctly for all the keys whose values are arrays of hashes



212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/right_api_client/helper.rb', line 212

def fix_array_of_hashes(args, top_level = true)

  if args.is_a?(Array)

    #recursively fix each element of the array
    #
    args.collect{|a| fix_array_of_hashes(a, false)}
  elsif args.is_a?(Hash)

    args.inject({}) do |res, (k, v)|
      key = k
      if v.is_a?(Array) && !v.empty? && v.first.is_a?(Hash)
        if top_level
          # signal to Rails that this really is an array
          key = k.to_s + '[]'
          value = fix_array_of_hashes(v, false)
        else
          # signal to Rails that this really is an array
          value = {'' => fix_array_of_hashes(v, false)}
        end
      else
        value = fix_array_of_hashes(v, false)
      end
      res[key] = value
      res
    end
  else

    args
  end
end

This will modify links



182
183
184
185
186
187
188
# File 'lib/right_api_client/helper.rb', line 182

def get_and_delete_href_from_links(links)
  if links
    self_link = links.detect{|link| link["rel"] == "self"}
    return links.delete(self_link)["href"] if self_link
  end
  return nil
end

#get_associated_resources(client, links, associations) ⇒ Object

Helper method that creates instance methods out of the associated resources from links Some resources have many links with the same rel. We want to capture all these href in the same method, returning an array



39
40
41
42
43
44
45
46
47
48
49
50
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/right_api_client/helper.rb', line 39

def get_associated_resources(client, links, associations)
  # First go through the links and group the rels together
  rels = {}
  links.each do |link|
    if rels[link['rel'].to_sym]  # if we have already seen this rel attribute
      rels[link['rel'].to_sym] << link['href']
    else
      rels[link['rel'].to_sym] = [link['href']]
    end
  end

  # Note: hrefs will be an array, even if there is only one link with that rel
  rels.each do |rel,hrefs|
    # Add the link to the associations set if present. This is to accommodate ResourceDetail objects
    associations << rel if associations != nil

    # Create methods so that the link can be followed
    define_instance_method(rel) do |*args|
      if hrefs.size == 1 # Only one link for the specific rel attribute
        if has_id(*args) || is_singular?(rel)
          # User wants a single resource. Either doing a show, update, delete...
          # get the resource_type
          # Special case: calling .data you don't want a resources object back
          # but rather all its details since you cannot do a show
          return RightApi::ResourceDetail.new(
            client, *client.send(:do_get, hrefs.first, *args)
          ) if rel == :data

          if is_singular?(rel)
            # Then the href will be: /resource_type/:id
            resource_type = get_singular(hrefs.first.split('/')[-2])
          else
            # Else the href will be: /resource_type
            resource_type = get_singular(hrefs.first.split('/')[-1])
          end
          path = add_id_and_params_to_path(hrefs.first, *args)
          RightApi::Resource.process(client, resource_type, path)
        else
          # Returns the class of this resource
          resource_type = hrefs.first.split('/')[-1]
          path = add_id_and_params_to_path(hrefs.first, *args)
          RightApi::Resources.new(client, path, resource_type)
        end
      else
        # There were multiple links with the same relation name
        # This occurs in tags.by_resource
        resources = []
        if has_id(*args) || is_singular?(rel)
          hrefs.each do |href|
            # User wants a single resource. Either doing a show, update, delete...
            if is_singular?(rel)
              resource_type = get_singular(href.split('/')[-2])
            else
              resource_type = get_singular(href.split('/')[-1])
            end
            path = add_id_and_params_to_path(href, *args)
            resources << RightApi::Resource.process(client, resource_type, path)
          end
        else
          hrefs.each do |href|
            # Returns the class of this resource
            resource_type = href.split('/')[-1]
            path = add_id_and_params_to_path(href, *args)
            resources << RightApi::Resources.new(client, path, resource_type)
          end
        end
        # return the array of resource objects
        resources
      end
    end
  end
end

Does not modify links



173
174
175
176
177
178
179
# File 'lib/right_api_client/helper.rb', line 173

def get_href_from_links(links)
  if links
    self_link = links.detect{|link| link["rel"] == "self"}
    return self_link["href"] if self_link
  end
  return nil
end

#get_singular(obj) ⇒ Object

Will not change obj



205
206
207
# File 'lib/right_api_client/helper.rb', line 205

def get_singular(obj)
  simple_singularize(obj.to_s.downcase)
end

#has_id(params = {}) ⇒ Object

Helper method that checks whether params contains a key :id



114
115
116
# File 'lib/right_api_client/helper.rb', line 114

def has_id(params = {})
  params.has_key?(:id)
end

#insert_in_path(path, term) ⇒ Object

Helper method that inserts the given term at the correct place in the path If there are parameters in the path then insert it before them. Will not change path.



146
147
148
149
150
151
152
153
# File 'lib/right_api_client/helper.rb', line 146

def insert_in_path(path, term)
  if path.index('?')
    # sub returns a copy of path
    new_path = path.sub('?', "/#{term}?")
  else
    new_path = "#{path}/#{term}"
  end
end

#is_singular?(str) ⇒ Boolean

Helper method that checks whether the string is singular

Returns:

  • (Boolean)


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/right_api_client/helper.rb', line 156

def is_singular?(str)
  test_str = str.to_s
  return true if ['data'].include?(test_str)

  case test_str
  when "audit_entry"
    return true
  when "ip_address"
    return true
  when "process"
    return true
  else
    (test_str)[-1, 1] != 's' # use legacy syntax for Ruby 1.8.7
  end
end

#simple_singularize(word) ⇒ Object

HACK: instead of pulling in activesupport gem, just hardcode some words



191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/right_api_client/helper.rb', line 191

def simple_singularize(word)
  case word
  when "audit_entries"
    "audit_entry"
  when "ip_addresses"
    "ip_address"
  when "processes"
    "process"
  else
    word.chop
  end
end