aviator 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/.coveralls.yml +1 -0
  2. data/.gitignore +6 -1
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +12 -0
  6. data/Gemfile +13 -0
  7. data/Guardfile +6 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +151 -2
  10. data/Rakefile +8 -0
  11. data/aviator.gemspec +14 -1
  12. data/bin/aviator +110 -0
  13. data/lib/aviator/core.rb +9 -0
  14. data/lib/aviator/core/request.rb +229 -0
  15. data/lib/aviator/core/response.rb +33 -0
  16. data/lib/aviator/core/service.rb +203 -0
  17. data/lib/aviator/core/session.rb +187 -0
  18. data/lib/aviator/openstack/compute/v2/public/list_images.rb +49 -0
  19. data/lib/aviator/openstack/identity/v2/admin/create_tenant.rb +42 -0
  20. data/lib/aviator/openstack/identity/v2/admin/list_tenants.rb +43 -0
  21. data/lib/aviator/openstack/identity/v2/public/create_token.rb +61 -0
  22. data/lib/aviator/openstack/identity/v2/public/list_tenants.rb +44 -0
  23. data/lib/aviator/version.rb +1 -1
  24. data/test/aviator/core/request_test.rb +342 -0
  25. data/test/aviator/core/service_test.rb +158 -0
  26. data/test/aviator/core/session_test.rb +201 -0
  27. data/test/aviator/openstack/compute/v2/public/list_images_test.rb +179 -0
  28. data/test/aviator/openstack/identity/v2/admin/create_tenant_test.rb +151 -0
  29. data/test/aviator/openstack/identity/v2/public/create_token_test.rb +159 -0
  30. data/test/cassettes/core/service/i_default_session_data_/sets_the_service_s_default_session_data.yml +63 -0
  31. data/test/cassettes/core/service/i_request/accepts_an_endpoint_type_option_for_selecting_a_specific_request.yml +140 -0
  32. data/test/cassettes/core/service/i_request/can_find_the_correct_request_based_on_bootstrapped_session_data.yml +63 -0
  33. data/test/cassettes/core/service/i_request/can_find_the_correct_request_based_on_non-bootstrapped_session_data.yml +97 -0
  34. data/test/cassettes/core/service/i_request/can_find_the_correct_request_if_api_version_is_not_defined_but_can_be_inferred_from_host_uri.yml +63 -0
  35. data/test/cassettes/core/service/i_request/uses_the_default_session_data_if_session_data_is_not_provided.yml +97 -0
  36. data/test/cassettes/core/session/c_load/creates_a_new_instance_from_the_given_session_dump.yml +63 -0
  37. data/test/cassettes/core/session/c_load/uses_the_loaded_auth_info_for_its_services.yml +63 -0
  38. data/test/cassettes/core/session/c_new/directs_log_entries_to_the_given_log_file.yml +63 -0
  39. data/test/cassettes/core/session/i_authenticate/authenticates_against_the_auth_service_indicated_in_the_config_file.yml +63 -0
  40. data/test/cassettes/core/session/i_authenticate/authenticates_against_the_auth_service_using_the_credentials_in_the_given_block.yml +38 -0
  41. data/test/cassettes/core/session/i_authenticate/raises_an_AuthenticationError_when_authentication_fails.yml +35 -0
  42. data/test/cassettes/core/session/i_authenticate/updates_the_session_data_of_its_service_objects.yml +123 -0
  43. data/test/cassettes/core/session/i_dump/serializes_the_session_data_for_caching.yml +63 -0
  44. data/test/cassettes/core/session/i_validate/returns_false_if_session_is_no_longer_valid.yml +97 -0
  45. data/test/cassettes/core/session/i_validate/returns_true_if_session_is_still_valid.yml +98 -0
  46. data/test/cassettes/core/session/i_xxx_service/returns_an_instance_of_the_indicated_service.yml +63 -0
  47. data/test/cassettes/openstack/compute/v2/public/list_images/leads_to_a_valid_response_when_no_parameters_are_provided.yml +108 -0
  48. data/test/cassettes/openstack/compute/v2/public/list_images/leads_to_a_valid_response_when_parameters_are_invalid.yml +96 -0
  49. data/test/cassettes/openstack/compute/v2/public/list_images/leads_to_a_valid_response_when_parameters_are_valid.yml +103 -0
  50. data/test/cassettes/openstack/compute/v2/public/list_images/returns_the_correct_value_for_body.yml +63 -0
  51. data/test/cassettes/openstack/compute/v2/public/list_images/returns_the_correct_value_for_body_.yml +63 -0
  52. data/test/cassettes/openstack/compute/v2/public/list_images/returns_the_correct_value_for_headers.yml +63 -0
  53. data/test/cassettes/openstack/compute/v2/public/list_images/returns_the_correct_value_for_headers_.yml +63 -0
  54. data/test/cassettes/openstack/compute/v2/public/list_images/returns_the_correct_value_for_url.yml +63 -0
  55. data/test/cassettes/openstack/compute/v2/public/list_images/returns_the_correct_value_for_url_.yml +63 -0
  56. data/test/cassettes/openstack/identity/v2/admin/create_tenant/leads_to_a_valid_response_when_params_are_invalid.yml +97 -0
  57. data/test/cassettes/openstack/identity/v2/admin/create_tenant/leads_to_a_valid_response_when_params_are_valid.yml +97 -0
  58. data/test/cassettes/openstack/identity/v2/admin/create_tenant/leads_to_a_valid_response_when_provided_with_invalid_params.yml +97 -0
  59. data/test/cassettes/openstack/identity/v2/public/create_token/leads_to_a_valid_response_when_parameters_are_invalid.yml +35 -0
  60. data/test/cassettes/openstack/identity/v2/public/create_token/leads_to_a_valid_response_when_parameters_are_valid.yml +38 -0
  61. data/test/cassettes/openstack/identity/v2/public/create_token/leads_to_a_valid_response_when_provided_with_a_token.yml +98 -0
  62. data/test/environment.yml.example +22 -0
  63. data/test/environment.yml.travis-ci +24 -0
  64. data/test/support/openstack_request_test_helper.rb +57 -0
  65. data/test/support/test_base_class.rb +39 -0
  66. data/test/support/test_environment.rb +37 -0
  67. data/test/support/test_reporter.rb +45 -0
  68. data/test/support/vcr_setup.rb +41 -0
  69. data/test/test_helper.rb +35 -0
  70. data/tmp/.gitignore +0 -0
  71. metadata +310 -8
  72. data/lib/aviator.rb +0 -5
@@ -0,0 +1 @@
1
+ service_name: travis-ci
data/.gitignore CHANGED
@@ -14,4 +14,9 @@ rdoc
14
14
  spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
- tmp
17
+ tmp/*.*
18
+ !tmp/.gitignore
19
+ .DS_Store
20
+ test/environment.yml
21
+ vcr.log
22
+
@@ -0,0 +1 @@
1
+ aviator
@@ -0,0 +1 @@
1
+ ruby-1.9.3-p448
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ branches:
5
+ only:
6
+ - master
7
+ - develop
8
+ - release
9
+ bundler_args: --without development
10
+ script:
11
+ - cp test/environment.yml.travis-ci test/environment.yml
12
+ - bundle exec rake
data/Gemfile CHANGED
@@ -2,3 +2,16 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in aviator.gemspec
4
4
  gemspec
5
+
6
+ # Putting these gems in the test group so that
7
+ # we can tell travis-ci not to build any of the
8
+ # development gems. Makes the build run faster.
9
+ group :test do
10
+ gem 'rake'
11
+ gem 'simplecov', '~> 0.7.0'
12
+ gem 'coveralls', '~> 0.6.0'
13
+ gem 'json', '~> 1.7.0'
14
+ gem 'minitest', '~> 4.7.0'
15
+ gem 'minitest-reporters', '~> 0.14.20'
16
+ gem 'vcr', '~> 2.5.0'
17
+ end
@@ -0,0 +1,6 @@
1
+ guard 'minitest' do
2
+ watch(%r|^lib/aviator\.rb|) { "test" }
3
+ watch(%r|^test/test_helper\.rb|) { "test" }
4
+ watch(%r|^lib/aviator/(.*)\.rb|) { |m| "test/aviator/#{m[1]}_test.rb" }
5
+ watch(%r|^test/aviator/.*_test\.rb|) # Run the matched file
6
+ end
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,6 +1,12 @@
1
1
  # Aviator
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/relaxdiego/aviator.png?branch=master)](https://travis-ci.org/relaxdiego/aviator)
4
+ [![Coverage Status](https://coveralls.io/repos/relaxdiego/aviator/badge.png?branch=master)](https://coveralls.io/r/relaxdiego/aviator?branch=master)
5
+ [![Code Climate](https://codeclimate.com/github/relaxdiego/aviator.png)](https://codeclimate.com/github/relaxdiego/aviator)
6
+
7
+
8
+ A lightweight library for communicating with the OpenStack API.
9
+
4
10
 
5
11
  ## Installation
6
12
 
@@ -18,8 +24,151 @@ Or install it yourself as:
18
24
 
19
25
  ## Usage
20
26
 
21
- TODO: Write usage instructions here
27
+ ```ruby
28
+ require 'aviator'
29
+
30
+ # Create a new session. See 'Configuration' below for the config file format.
31
+ session = Aviator::Session.new(
32
+ config_file: 'path/to/aviator.yml',
33
+ environment: :production,
34
+ log_file: 'path/to/aviator.log'
35
+ )
36
+
37
+ # Authenticate against the auth service specified in :config_file. If no
38
+ # credentials are available in the config file, this line will throw an error.
39
+ session.authenticate
40
+
41
+ # You can re-authenticate anytime. Note that this creates a new token in the
42
+ # underlying environment while the old token is discarded by the Session object.
43
+ # Be aware of this fact as it might unnecessarily generate too many tokens.
44
+ #
45
+ # Notice how you can override the credentials in the config file. Also note that
46
+ # the keys used below (:username, :password, :tenantName) match the name as
47
+ # indicated in the official OpenStack documentation.
48
+ session.authenticate do |credentials|
49
+ credentials[:username] = myusername
50
+ credentials[:password] = mypassword
51
+ credentials[:tenantName] = tenantName
52
+ end
53
+
54
+ # Serialize the session information for caching. The output is in plaintext JSON which
55
+ # contains sensitive information and you are responsible for securing this data.
56
+ str = session.dump
57
+
58
+ # Create a new Session object from a session dump. This DOES NOT create a new token.
59
+ # If you employed any form of encryption on the string, make sure to decrypt it first!
60
+ session = Aviator::Session.load(str)
61
+
62
+ # Depending on how old the loaded session dump is, the auth_info may already be expired.
63
+ # Check if it's still current by calling Session#validate and reauthenticate as needed.
64
+ #
65
+ # IMPORTANT: The validator must be defined in the config file and it must refer to the
66
+ # name of a request that is known to Aviator. See 'Configuration' below for examples
67
+ session.authenticate unless session.validate
68
+
69
+ # If you want the newly created session to log its output, make sure to indicate it on load
70
+ session = Aviator::Session.load(str, log_file: 'path/to/aviator.log')
71
+
72
+ # Get a handle to the Identity Service.
73
+ keystone = session.identity_service
74
+
75
+ # Create a new tenant
76
+ response = keystone.request(:create_tenant) do |params|
77
+ params[:name] = 'Project'
78
+ params[:description] = 'My Project'
79
+ params[:enabled] = true
80
+ end
81
+
82
+ # Aviator uses parameter names as defined in the official OpenStack API doc. You can
83
+ # also access the params via dot notation (e.g. params.description) or by using a string
84
+ # for a hash key (e.g. params['description']). However, keep in mind that OpenStack
85
+ # parameters that have dashes and other characters that are not valid for method names
86
+ # and symbols can only be expressed as strings. E.g. params['changes-since']
87
+
88
+
89
+ # Be explicit about the endpoint type. Useful in those rare instances when
90
+ # the same request name means differently depending on the endpoint type.
91
+ # For example, in OpenStack, :list_tenants will return only the tenants the
92
+ # user is a member of in the public endpoint whereas the admin endpoint will
93
+ # return all tenants in the system.
94
+ response = keystone.request(:list_tenants, endpoint_type: 'admin')
95
+ ```
96
+
97
+ ## Configuration
98
+
99
+ The configuration file is a simple YAML file with one or more environment definitions.
100
+
101
+ ```
102
+ production:
103
+ provider: openstack
104
+ auth_service:
105
+ name: identity
106
+ host_uri: http://my.openstackenv.org:5000
107
+ request: create_token
108
+ validator: list_tenants # Request to make for validating the session
109
+ api_version: v2 # Optional if version is indicated in host_uri
110
+ auth_credentials:
111
+ username: admin
112
+ password: mypassword
113
+ tenantName: myproject
114
+
115
+ development_1:
116
+ provider: openstack
117
+ auth_service:
118
+ name: identity
119
+ host_uri: http://devstack:5000/v2.0
120
+ request: create_token
121
+ validator: list_tenants
122
+ auth_credentials:
123
+ tokenId: 2c963f5512d067b24fdc312707c80c7a6d3d261b
124
+ tenantName: admin
125
+
126
+ development_2:
127
+ provider: openstack
128
+ auth_service:
129
+ name: identity
130
+ host_uri: http://devstack:5000/v2.0
131
+ request: create_token
132
+ validator: list_tenants
133
+ auth_credentials:
134
+ username: admin
135
+ password: mypassword
136
+ tenantName: myproject
137
+ ```
138
+
139
+ A note on the validator: it can be any request as long as
140
+
141
+ 1. It is defined in Aviator
142
+ 1. Does not require any parameters
143
+ 1. It returns an HTTP status 200 or 203 to indicate auth info validity.
144
+ 1. It returns any other HTTP status to indicate that the auth info is invalid.
145
+
146
+ ## CLI tools
147
+
148
+ List available providers. Includes only OpenStack for now.
149
+
150
+ ```bash
151
+ $ aviator describe
152
+ ```
153
+
154
+ List available services for OpenStack.
155
+
156
+ ```bash
157
+ $ aviator describe openstack
158
+ ```
159
+
160
+ List available requests for Keystone
161
+
162
+ ```bash
163
+ $ aviator describe openstack identity
164
+ ```
165
+
166
+ Describe Keystone's create_tenant request
22
167
 
168
+ ```bash
169
+ $ aviator describe openstack identity v2 admin create_tenant
170
+ ```
171
+
23
172
  ## Contributing
24
173
 
25
174
  1. Fork it
data/Rakefile CHANGED
@@ -1 +1,9 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.pattern = "test/aviator/**/*_test.rb"
6
+ t.libs.push 'test'
7
+ end
8
+
9
+ task :default => :test
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["mmaglana@gmail.com"]
11
11
  spec.description = %q{ Lightweight Ruby bindings for the OpenStack API }
12
12
  spec.summary = %q{ Lightweight Ruby bindings for the OpenStack API }
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/relaxdiego/aviator"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -18,6 +18,19 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency 'faraday', '~> 0.8.0'
22
+ spec.add_dependency 'activesupport', '~> 4.0.0'
23
+ spec.add_dependency 'thor', '~> 0.18.1'
24
+
21
25
  spec.add_development_dependency "bundler", "~> 1.3"
22
26
  spec.add_development_dependency "rake"
27
+ spec.add_development_dependency 'rb-fsevent', '~> 0.9.0'
28
+ spec.add_development_dependency 'guard', '~> 1.8.0'
29
+ spec.add_development_dependency 'guard-rake', '~> 0.0.0'
30
+ spec.add_development_dependency 'guard-minitest', '~> 0.5.0'
31
+ spec.add_development_dependency 'ruby_gntp', '~> 0.3.0'
32
+ spec.add_development_dependency 'debugger', '~> 1.6.0'
33
+ spec.add_development_dependency 'pry', '~> 0.9.0'
34
+ spec.add_development_dependency 'yard', '~> 0.8.0'
35
+ spec.add_development_dependency 'redcarpet', '~> 2.3.0'
23
36
  end
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'thor'
5
+ require 'aviator/core'
6
+
7
+ module Aviator
8
+ module CLI
9
+
10
+ class Main < Thor
11
+
12
+ desc 'describe [PROVIDER] [SERVICE] [API_VERSION ENDPOINT_TYPE REQUEST_NAME]', 'Describes various parts of Aviator.'
13
+ def describe(provider=nil, service=nil, api_version=nil, endpoint_type=nil, request=nil)
14
+ if request
15
+ describe_request provider, service, api_version, endpoint_type, request
16
+ elsif service
17
+ describe_service provider, service
18
+ elsif provider
19
+ describe_provider provider
20
+ else
21
+ list_providers
22
+ end
23
+ end
24
+
25
+
26
+ private
27
+
28
+
29
+ def describe_provider(provider)
30
+ puts "Available services from #{ provider }"
31
+
32
+ Dir[Pathname.new(__FILE__).join('..', '..', 'lib', 'aviator', provider, '**')].each do |d|
33
+ puts " #{ Pathname.new(d).basename }"
34
+ end
35
+ end
36
+
37
+
38
+ def describe_request(provider, service, api_version, endpoint_type, request_name)
39
+ endpoints = Service.new(provider: provider, service: service).requests[api_version.to_sym]
40
+ raise "Invalid API version #{ api_version }" unless endpoints
41
+
42
+ requests = endpoints[endpoint_type.to_sym]
43
+ raise "Invalid endpoint type #{ endpoint_type }" unless requests
44
+
45
+ request = requests[request_name.to_sym]
46
+ raise "Could not find request named #{ request_name }. Try a different api version or endpoint" unless request
47
+
48
+ puts "Request: #{ request_name }"
49
+
50
+ params = []
51
+
52
+ request.optional_params.each do |param|
53
+ params << [param, :optional]
54
+ end
55
+
56
+ request.required_params.each do |param|
57
+ params << [param, :required]
58
+ end
59
+
60
+ params.sort! { |a,b| a[0].to_s <=> b[0].to_s }
61
+
62
+ puts "\nParameters:"
63
+ params.each do |param_desc|
64
+ puts " (#{ param_desc[1] }) #{ param_desc[0] }"
65
+ end
66
+
67
+ puts "\nSample Code:"
68
+ print " session.#{ service }_service.request(:#{ request_name }, endpoint_type: '#{ endpoint_type }')"
69
+ if params
70
+ puts " do |params|"
71
+ params.each do |pair|
72
+ puts " params['#{ pair[0] }'] = val"
73
+ end
74
+ puts " end"
75
+ end
76
+
77
+ puts "\nLinks:"
78
+ request.links.each do |link|
79
+ puts " #{ link[:rel] }:"
80
+ puts " #{ link[:href] }\n"
81
+ end
82
+ end
83
+
84
+
85
+ def describe_service(provider, service)
86
+ puts "Available requests for #{ provider } #{ service }:"
87
+
88
+ Service.new(provider: provider, service: service).requests.each do |api_version, endpoints|
89
+ endpoints.each do |endpoint_type, requests|
90
+ requests.each do |request_name, request_obj|
91
+ puts " #{ api_version} #{ endpoint_type } #{ request_name }"
92
+ end
93
+ puts ""
94
+ end
95
+ end
96
+ end
97
+
98
+
99
+ def list_providers
100
+ puts "Available providers:"
101
+ puts " openstack"
102
+ end
103
+
104
+ end
105
+
106
+
107
+ end
108
+ end
109
+
110
+ Aviator::CLI::Main.start(ARGV)
@@ -0,0 +1,9 @@
1
+ require 'json'
2
+ require 'active_support/inflector'
3
+ require 'faraday'
4
+
5
+ require "aviator/version"
6
+ require "aviator/core/request"
7
+ require "aviator/core/response"
8
+ require "aviator/core/service"
9
+ require "aviator/core/session"
@@ -0,0 +1,229 @@
1
+ module Aviator
2
+
3
+ class Request
4
+
5
+ class ApiVersionNotDefinedError < StandardError
6
+ def initialize
7
+ super "api_version is not defined."
8
+ end
9
+ end
10
+
11
+ class EndpointTypeNotDefinedError < StandardError
12
+ def initialize
13
+ super "endpoint_type is not defined."
14
+ end
15
+ end
16
+
17
+ class PathNotDefinedError < StandardError
18
+ def initialize
19
+ super "path is not defined."
20
+ end
21
+ end
22
+
23
+
24
+ def initialize(session_data=nil)
25
+ @session_data = session_data
26
+
27
+ params = self.class.params_class.new if self.class.params_class
28
+
29
+ if params
30
+ yield(params) if block_given?
31
+ validate_params(params)
32
+ end
33
+
34
+ @params = params
35
+ end
36
+
37
+
38
+ def anonymous?
39
+ self.class.anonymous?
40
+ end
41
+
42
+
43
+ def api_version
44
+ self.class.api_version
45
+ end
46
+
47
+
48
+ def body?
49
+ self.class.body?
50
+ end
51
+
52
+
53
+ def endpoint_type
54
+ self.class.endpoint_type
55
+ end
56
+
57
+
58
+ def headers?
59
+ self.class.headers?
60
+ end
61
+
62
+
63
+ def http_method
64
+ self.class.http_method
65
+ end
66
+
67
+
68
+ def links
69
+ self.class.links
70
+ end
71
+
72
+
73
+ def optional_params
74
+ self.class.optional_params
75
+ end
76
+
77
+
78
+ def params
79
+ @params.dup
80
+ end
81
+
82
+
83
+ def querystring?
84
+ self.class.querystring?
85
+ end
86
+
87
+
88
+ def required_params
89
+ self.class.required_params
90
+ end
91
+
92
+
93
+ def session_data
94
+ @session_data
95
+ end
96
+
97
+
98
+ def session_data?
99
+ !session_data.nil?
100
+ end
101
+
102
+
103
+ def url?
104
+ self.class.url?
105
+ end
106
+
107
+
108
+ private
109
+
110
+
111
+ def validate_params(params)
112
+ required_params = self.class.required_params
113
+
114
+ required_params.each do |name|
115
+ raise ArgumentError.new("Missing parameter #{ name }.") if params.send(name).nil?
116
+ end
117
+ end
118
+
119
+
120
+ # NOTE that, because we are defining the following as class methods, when they
121
+ # are called, all 'instance' variables are actually defined in the descendant class,
122
+ # not in the instance/object. This is by design since we want to keep these attributes
123
+ # within the class and because they don't change between instances anyway.
124
+ class << self
125
+
126
+ def anonymous
127
+ @anonymous = true
128
+ end
129
+
130
+
131
+ def anonymous?
132
+ @anonymous == true
133
+ end
134
+
135
+
136
+ def api_version(value=nil)
137
+ if value
138
+ @api_version = value
139
+ else
140
+ @api_version
141
+ end
142
+ end
143
+
144
+
145
+ def body?
146
+ instance_methods.include? :body
147
+ end
148
+
149
+
150
+ def endpoint_type(value=nil)
151
+ if value
152
+ @endpoint_type = value
153
+ else
154
+ @endpoint_type
155
+ end
156
+ end
157
+
158
+
159
+ def headers?
160
+ instance_methods.include? :headers
161
+ end
162
+
163
+
164
+ def http_method(value=nil)
165
+ if value
166
+ @http_method = value
167
+ else
168
+ @http_method
169
+ end
170
+ end
171
+
172
+
173
+ def link_to(rel, href)
174
+ links << { rel: rel, href: href }
175
+ end
176
+
177
+
178
+ def links
179
+ @links ||= []
180
+ end
181
+
182
+
183
+ def params_class
184
+ all_params = required_params + optional_params
185
+
186
+ if all_params.length > 0
187
+ @params_class ||= Struct.new(*all_params)
188
+ end
189
+
190
+ @params_class
191
+ end
192
+
193
+
194
+ def optional_params
195
+ @optional_params ||= []
196
+ end
197
+
198
+
199
+ def querystring?
200
+ instance_methods.include? :querystring
201
+ end
202
+
203
+
204
+ def required_params
205
+ @required_params ||= []
206
+ end
207
+
208
+
209
+ def url?
210
+ instance_methods.include? :url
211
+ end
212
+
213
+
214
+ private
215
+
216
+ def required_param(param_name)
217
+ required_params << param_name unless required_params.include?(param_name)
218
+ end
219
+
220
+
221
+ def optional_param(param_name)
222
+ optional_params << param_name unless optional_params.include?(param_name)
223
+ end
224
+
225
+ end
226
+
227
+ end
228
+
229
+ end