def request(service_name, request_name, opts={}, &block)
      service = send("#{service_name.to_s}_service")
      response = service.request(request_name, opts, &block)
      response.to_hash
    end
def request(service_name, request_name, opts={}, &block)
      service = send("#{service_name.to_s}_service")
      response = service.request(request_name, opts, &block)
      response.to_hash
    end
Calls the given request of the given service. An example call might look like:

  session.request :compute_service, :create_server do |p|
    p.name       = "My Server"
    p.image_ref  = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29"
    p.flavor_ref = "fa283da1-59a5-4245-8569-b6eadf69f10b"
  end

 Note that you can also treat the block's argument like a hash with the attribute
 names as the keys. For example, we can rewrite the above as:

  session.request :compute_service, :create_server do |p|
    p[:name]       = "My Server"
    p[:image_ref]  = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29"
    p[:flavor_ref] = "fa283da1-59a5-4245-8569-b6eadf69f10b"
  end

 Keys can be symbols or strings.

 You may also provide parameters as an argument instead of a block. This is
 especially useful when mocking Aviator as it's easier to specify ordinary
 argument expectations over blocks. Further rewriting the example above,
 we end up with:

  session.request :compute_service, :create_server, :params => {
    :name       => "My Server",
    :image_ref  => "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29",
    :flavor_ref => "fa283da1-59a5-4245-8569-b6eadf69f10b"
  }

 If both <tt>:params</tt> and a block are provided, the values in <tt>:params</tt>
 will be used and the block ignored.

 <b>Return Value</b>

 The return value will be an instance of Hashish, a lightweight replacement for
 activesupport's HashWithIndifferentAccess, with the following structure:

   {
     :status => 200,
     :headers => {
       'X-Auth-Token' => 'd9186f45ce5446eaa0adc9def1c46f5f',
       'Content-Type' => 'application/json'
     },
     :body => {
       :some_key => :some_value
     }
   }

 Note that the members in <tt>:headers</tt> and <tt>:body</tt> will vary depending
 on the provider and the request that was made.

 ---

 <b>Request Options</b>

 You can further customize how the method behaves by providing one or more
 options to the call. For example, assuming you are using the <tt>openstack</tt>
 provider, the following will call the <tt>:create_server</tt> request of the
 v1 API of <tt>:compute_service</tt>.

  session.request :compute_service, :create_server, :api_version => v1, :params => params

 The available options vary depending on the provider. See the documentation
 on the provider's Provider class for more information (e.g. Aviator::Openstack::Provider)