angus-remote 0.0.1 → 0.0.2
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.
- data/lib/angus-remote.rb +4 -0
- data/lib/angus/remote/builder.rb +204 -0
- data/lib/angus/remote/client.rb +79 -0
- data/lib/angus/remote/exceptions.rb +50 -0
- data/lib/angus/remote/http/multipart.rb +54 -0
- data/lib/angus/remote/http/multipart_methods/multipart_base.rb +36 -0
- data/lib/angus/remote/http/multipart_methods/multipart_post.rb +11 -0
- data/lib/angus/remote/http/multipart_methods/multipart_put.rb +11 -0
- data/lib/angus/remote/http/query_params.rb +53 -0
- data/lib/angus/remote/message.rb +14 -0
- data/lib/angus/remote/proxy_client.rb +58 -0
- data/lib/angus/remote/proxy_client_utils.rb +70 -0
- data/lib/angus/remote/remote_response.rb +44 -0
- data/lib/angus/remote/representation.rb +18 -0
- data/lib/angus/remote/response/builder.rb +308 -0
- data/lib/angus/remote/response/hash.rb +47 -0
- data/lib/angus/remote/response/serializer.rb +43 -0
- data/lib/angus/remote/service_directory.rb +217 -0
- data/lib/angus/remote/utils.rb +119 -0
- data/lib/angus/remote/version.rb +4 -2
- data/lib/angus/unmarshalling.rb +33 -0
- data/spec/angus/remote/builder_spec.rb +105 -0
- data/spec/angus/remote/client_spec.rb +75 -0
- data/spec/angus/remote/http/multipart_methods/multipart_base_spec.rb +36 -0
- data/spec/angus/remote/http/multipart_spec.rb +120 -0
- data/spec/angus/remote/http/query_params_spec.rb +28 -0
- data/spec/angus/remote/proxy_client_utils_spec.rb +102 -0
- data/spec/angus/remote/response/builder_spec.rb +69 -0
- data/spec/angus/remote/service_directory_spec.rb +76 -0
- data/spec/angus/remote/utils_spec.rb +204 -0
- metadata +192 -32
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/README.md +0 -29
- data/Rakefile +0 -1
- data/angus-remote.gemspec +0 -23
- data/lib/angus/remote.rb +0 -7
@@ -0,0 +1,53 @@
|
|
1
|
+
module Http
|
2
|
+
module QueryParams
|
3
|
+
|
4
|
+
# @return <String> This hash as a query string
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# { :name => "Bob",
|
8
|
+
# :address => {
|
9
|
+
# :street => '111 Ruby Ave.',
|
10
|
+
# :city => 'Ruby Central',
|
11
|
+
# :phones => ['111-111-1111', '222-222-2222']
|
12
|
+
# }
|
13
|
+
# }.to_params
|
14
|
+
# #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave."
|
15
|
+
def self.to_params(hash)
|
16
|
+
params = hash.map { |k,v| normalize_param(k,v) }.join
|
17
|
+
params.chop! # trailing &
|
18
|
+
params
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param key<Object> The key for the param.
|
22
|
+
# @param value<Object> The value for the param.
|
23
|
+
#
|
24
|
+
# @return <String> This key value pair as a param
|
25
|
+
#
|
26
|
+
# @example normalize_param(:name, "Bob Jones") #=> "name=Bob%20Jones&"
|
27
|
+
def self.normalize_param(key, value)
|
28
|
+
param = ''
|
29
|
+
stack = []
|
30
|
+
|
31
|
+
if value.is_a?(Array)
|
32
|
+
param << value.map { |element| normalize_param("#{key}[]", element) }.join
|
33
|
+
elsif value.is_a?(Hash)
|
34
|
+
stack << [key,value]
|
35
|
+
else
|
36
|
+
param << "#{key}=#{URI.encode(value.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))}&"
|
37
|
+
end
|
38
|
+
|
39
|
+
stack.each do |parent, hash|
|
40
|
+
hash.each do |k, v|
|
41
|
+
if v.is_a?(Hash)
|
42
|
+
stack << ["#{parent}[#{k}]", v]
|
43
|
+
else
|
44
|
+
param << normalize_param("#{parent}[#{k}]", v)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
param
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'persistent_http'
|
3
|
+
|
4
|
+
require_relative 'exceptions'
|
5
|
+
require_relative 'proxy_client_utils'
|
6
|
+
|
7
|
+
module Angus
|
8
|
+
module Remote
|
9
|
+
|
10
|
+
# A client for service invocation when proxing requests.
|
11
|
+
class ProxyClient
|
12
|
+
|
13
|
+
DEFAULT_TIMEOUT = 10
|
14
|
+
|
15
|
+
def initialize(url, timeout = DEFAULT_TIMEOUT)
|
16
|
+
url = url[0..-2] if url[-1] == '/'
|
17
|
+
|
18
|
+
@connection = PersistentHTTP.new(
|
19
|
+
:pool_size => 4,
|
20
|
+
:pool_timeout => 10,
|
21
|
+
:warn_timeout => 0.25,
|
22
|
+
:force_retry => false,
|
23
|
+
:url => url,
|
24
|
+
|
25
|
+
:read_timeout => timeout,
|
26
|
+
:open_timeout => timeout
|
27
|
+
)
|
28
|
+
|
29
|
+
@api_base_path = @connection.default_path
|
30
|
+
end
|
31
|
+
|
32
|
+
# Makes a request to the service
|
33
|
+
#
|
34
|
+
def make_request(method, path, query, headers = {}, body = nil)
|
35
|
+
full_path = @api_base_path + path
|
36
|
+
|
37
|
+
request = ProxyClientUtils.build_request(method, full_path, query, headers, body)
|
38
|
+
|
39
|
+
begin
|
40
|
+
response = @connection.request(request)
|
41
|
+
|
42
|
+
from_headers = ProxyClientUtils.normalize_headers(
|
43
|
+
ProxyClientUtils.filter_response_headers(response.to_hash)
|
44
|
+
)
|
45
|
+
|
46
|
+
[response.code.to_i, from_headers, [response.body]]
|
47
|
+
rescue Errno::ECONNREFUSED
|
48
|
+
raise RemoteConnectionError.new(self.class.base_uri)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_s
|
53
|
+
"#<#{self.class}:#{object_id}>"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require_relative 'exceptions'
|
5
|
+
require_relative 'http/query_params'
|
6
|
+
|
7
|
+
module Angus
|
8
|
+
module Remote
|
9
|
+
|
10
|
+
module ProxyClientUtils
|
11
|
+
|
12
|
+
ALLOWED_RESPONSE_HEADERS = ['content-type']
|
13
|
+
|
14
|
+
def self.build_request(method, path, query, headers = {}, body = nil)
|
15
|
+
uri = URI(path)
|
16
|
+
uri.query = query
|
17
|
+
|
18
|
+
full_uri = uri.to_s
|
19
|
+
|
20
|
+
request = case method.to_s.downcase
|
21
|
+
when 'get'
|
22
|
+
Net::HTTP::Get.new(full_uri)
|
23
|
+
when 'post'
|
24
|
+
Net::HTTP::Post.new(full_uri)
|
25
|
+
when 'put'
|
26
|
+
Net::HTTP::Put.new(full_uri)
|
27
|
+
when 'delete'
|
28
|
+
Net::HTTP::Delete.new(full_uri)
|
29
|
+
else
|
30
|
+
raise MethodArgumentError.new(method)
|
31
|
+
end
|
32
|
+
|
33
|
+
headers.each do |k, v|
|
34
|
+
request[k] = v
|
35
|
+
end
|
36
|
+
|
37
|
+
request.body = body
|
38
|
+
|
39
|
+
request
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.filter_response_headers(headers)
|
43
|
+
headers.select { |h, v| ALLOWED_RESPONSE_HEADERS.include?(h) }
|
44
|
+
end
|
45
|
+
|
46
|
+
# Converts any header value that is an array to its first value.
|
47
|
+
#
|
48
|
+
# @param [Hash] header
|
49
|
+
#
|
50
|
+
# @return [Hash]
|
51
|
+
#
|
52
|
+
# @example
|
53
|
+
# normalize_headers({'content-type'=>['application/json;charset=utf-8']})
|
54
|
+
#
|
55
|
+
# -> {'content-type'=>'application/json;charset=utf-8'}
|
56
|
+
def self.normalize_headers(headers)
|
57
|
+
normalized = headers.map do |h, v|
|
58
|
+
if v.is_a?(Array)
|
59
|
+
[h, v.first]
|
60
|
+
else
|
61
|
+
[h, v]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
Hash[normalized]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'response/hash'
|
2
|
+
|
3
|
+
module Angus
|
4
|
+
module Remote
|
5
|
+
|
6
|
+
# A service's response
|
7
|
+
#
|
8
|
+
# Acts as an array to store information at HTTP level, like the status_code
|
9
|
+
class RemoteResponse
|
10
|
+
include Angus::Remote::Response::Hash
|
11
|
+
|
12
|
+
attr_accessor :status
|
13
|
+
attr_accessor :status_code
|
14
|
+
attr_accessor :messages
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@http_response_info = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(key, value)
|
21
|
+
@http_response_info[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](key)
|
25
|
+
@http_response_info[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"#<#{self.class}:#{object_id}>"
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_hash
|
33
|
+
{
|
34
|
+
:http_status_code => @http_response_info[:status_code],
|
35
|
+
:body => @http_response_info[:body],
|
36
|
+
:service_name => @http_response_info[:service_name],
|
37
|
+
:operation_name => @http_response_info[:operation_name],
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'response/hash'
|
2
|
+
|
3
|
+
module Angus
|
4
|
+
module Remote
|
5
|
+
|
6
|
+
class Representation
|
7
|
+
include Angus::Remote::Response::Hash
|
8
|
+
|
9
|
+
attr_accessor :elements
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@http_response_info = {}
|
13
|
+
@elements = {}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,308 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
require 'date'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
require_relative '../message'
|
6
|
+
require_relative '../remote_response'
|
7
|
+
|
8
|
+
require_relative 'hash'
|
9
|
+
|
10
|
+
require_relative '../service_directory'
|
11
|
+
|
12
|
+
|
13
|
+
# TODO: move to another gem and possibly change its name
|
14
|
+
require_relative '../../unmarshalling'
|
15
|
+
|
16
|
+
module Angus
|
17
|
+
module Remote
|
18
|
+
module Response
|
19
|
+
|
20
|
+
module Builder
|
21
|
+
|
22
|
+
# Builds a Response
|
23
|
+
#
|
24
|
+
# The r parameter should contain in the body, encoded as json, the values / objects
|
25
|
+
# specified in the operation response metadata
|
26
|
+
#
|
27
|
+
# @param [Integer] status_code HTTP status_code
|
28
|
+
# @param body [String] HTTP body
|
29
|
+
# @param service_name [String] Name of the service that the response belongs to
|
30
|
+
# @param version [String] Version of the service that the response belongs to
|
31
|
+
# @param operation_namespace [String] Namespace of the operation that the response belongs to
|
32
|
+
# @param operation_name [String] Name of the operation that the response belongs to
|
33
|
+
#
|
34
|
+
# @return A Response object that responds to the methods:
|
35
|
+
# - status
|
36
|
+
# - messages
|
37
|
+
#
|
38
|
+
# Also, provides one method for each value / object / array returned
|
39
|
+
def self.build(status_code, body, service_code_name, version, operation_namespace,
|
40
|
+
operation_code_name)
|
41
|
+
service_definition = Angus::Remote::ServiceDirectory.service_definition(
|
42
|
+
service_code_name, version
|
43
|
+
)
|
44
|
+
|
45
|
+
representations = service_definition.representations
|
46
|
+
glossary = service_definition.glossary
|
47
|
+
|
48
|
+
operation_definition = service_definition.operation_definition(operation_namespace,
|
49
|
+
operation_code_name)
|
50
|
+
|
51
|
+
json_response = JSON(body)
|
52
|
+
|
53
|
+
response_class = build_response_class(operation_definition.name)
|
54
|
+
|
55
|
+
response = response_class.new
|
56
|
+
|
57
|
+
# TODO use constants
|
58
|
+
response[:status_code] = status_code
|
59
|
+
response[:body] = body
|
60
|
+
response[:service_code_name] = service_code_name
|
61
|
+
response[:service_version] = version
|
62
|
+
response[:operation_namespace] = operation_namespace
|
63
|
+
response[:operation_code_name] = operation_code_name
|
64
|
+
|
65
|
+
response.status = json_response['status']
|
66
|
+
response.messages = self.build_messages(json_response['messages'])
|
67
|
+
|
68
|
+
representations_hash = self.representations_hash(representations)
|
69
|
+
glossary_terms_hash = glossary.terms_hash
|
70
|
+
|
71
|
+
operation_definition.response_elements.each do |element|
|
72
|
+
self.build_response_method(json_response, response_class, response,
|
73
|
+
representations_hash, glossary_terms_hash, element)
|
74
|
+
end
|
75
|
+
|
76
|
+
response
|
77
|
+
end
|
78
|
+
|
79
|
+
# Builds the methods for each value / object / array
|
80
|
+
#
|
81
|
+
# The r parameter should contain in the body, encoded as json, the values / objects
|
82
|
+
# specified in the operation response metadata
|
83
|
+
def self.build_response_method(json_response, response_class, response,
|
84
|
+
representations_hash, glossary_terms_hash, element)
|
85
|
+
if (json_response.has_key?(element.name))
|
86
|
+
hash_value = json_response[element.name]
|
87
|
+
elsif (element.required == false)
|
88
|
+
hash_value = element.default
|
89
|
+
else
|
90
|
+
return
|
91
|
+
end
|
92
|
+
|
93
|
+
object_value = nil
|
94
|
+
|
95
|
+
if element.type && representations_hash.include?(element.type)
|
96
|
+
object_value = self.build_from_representation(hash_value, element.type,
|
97
|
+
representations_hash, glossary_terms_hash)
|
98
|
+
elsif element.elements_type
|
99
|
+
object_value = self.build_collection_from_representation(hash_value,
|
100
|
+
element.elements_type,
|
101
|
+
representations_hash,
|
102
|
+
glossary_terms_hash)
|
103
|
+
elsif element.type && element.type.to_sym == :variable
|
104
|
+
object_value = self.build_from_variable_fields(hash_value)
|
105
|
+
elsif element.type
|
106
|
+
begin
|
107
|
+
object_value = Angus::Unmarshalling.unmarshal_scalar(hash_value,
|
108
|
+
element.type.to_sym)
|
109
|
+
rescue ArgumentError
|
110
|
+
object_value = nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Don't apply the glossary to response elements
|
115
|
+
response.elements[element.name] = object_value
|
116
|
+
|
117
|
+
# Instead, apply the glossary to method names
|
118
|
+
getter_method_name = self.apply_glossary(element.name, glossary_terms_hash)
|
119
|
+
|
120
|
+
response_class.send :define_method, getter_method_name do
|
121
|
+
object_value
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Builds a Response based on a service's response
|
126
|
+
#
|
127
|
+
# The remote_response parameter should contain in the body,
|
128
|
+
# encoded as json, the values / objects
|
129
|
+
# specified in the operation response metadata.
|
130
|
+
#
|
131
|
+
# @param [Http] remote_response HTTP response object, must respond to methods :body and :code
|
132
|
+
# @param [String] service_name Name of the invoked service
|
133
|
+
# @param version [String] Version of the invoked service
|
134
|
+
# @param operation_namespace [String] Namespace of the invoked operation
|
135
|
+
# @param operation_name [String] Name of the invoked operation
|
136
|
+
#
|
137
|
+
# @return (see #build)
|
138
|
+
def self.build_from_remote_response(remote_response, service_code_name, version,
|
139
|
+
operation_namespace, operation_code_name)
|
140
|
+
|
141
|
+
status_code = remote_response.code
|
142
|
+
body = remote_response.body
|
143
|
+
|
144
|
+
self.build(status_code, body, service_code_name, version, operation_namespace,
|
145
|
+
operation_code_name)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Searches for a short name in the glossary and returns the corresponding long name
|
149
|
+
#
|
150
|
+
# If name is not a short name, returns the name
|
151
|
+
#
|
152
|
+
# @param [String] name
|
153
|
+
# @param [Hash<String, GlossaryTerm>] glossary_terms_hash, where keys are short names
|
154
|
+
#
|
155
|
+
# @return long name
|
156
|
+
def self.apply_glossary(name, glossary_terms_hash)
|
157
|
+
if glossary_terms_hash.include?(name)
|
158
|
+
name = glossary_terms_hash[name].long_name
|
159
|
+
end
|
160
|
+
|
161
|
+
return name
|
162
|
+
end
|
163
|
+
|
164
|
+
# Build a response class for the operation
|
165
|
+
#
|
166
|
+
# @param [String] operation_name the name of the operation
|
167
|
+
#
|
168
|
+
# @return [Class] A class client, that inherits from {Angus::Remote::Response}
|
169
|
+
def self.build_response_class(operation_name)
|
170
|
+
response_class = Class.new(Angus::Remote::RemoteResponse)
|
171
|
+
response_class.class_eval <<-END
|
172
|
+
def self.name
|
173
|
+
"#<Response_#{operation_name.gsub(' ', '_')}>"
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.to_s
|
177
|
+
name
|
178
|
+
end
|
179
|
+
END
|
180
|
+
|
181
|
+
response_class
|
182
|
+
end
|
183
|
+
|
184
|
+
# Receives an array of messages and returns an array of Message objects
|
185
|
+
def self.build_messages(messages)
|
186
|
+
messages ||= []
|
187
|
+
|
188
|
+
messages.map do |m|
|
189
|
+
message = Angus::Remote::Message.new
|
190
|
+
message.description = m['dsc']
|
191
|
+
message.key = m['key']
|
192
|
+
message.level = m['level']
|
193
|
+
|
194
|
+
message
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# Receives a hash, a type and an array of representations and
|
199
|
+
# build an object that has one method for each attribute of the type.
|
200
|
+
def self.build_from_representation(hash_value, type, representations, glossary_terms_hash)
|
201
|
+
return nil if hash_value.nil?
|
202
|
+
|
203
|
+
representation_class = Class.new do
|
204
|
+
include Angus::Remote::Response::Hash
|
205
|
+
end
|
206
|
+
|
207
|
+
representation_object = representation_class.new
|
208
|
+
|
209
|
+
if representations.include?(type)
|
210
|
+
representation = representations[type]
|
211
|
+
return nil if representation.nil?
|
212
|
+
representation.fields.each do |field|
|
213
|
+
field_raw_value = hash_value[field.name]
|
214
|
+
field_value = nil
|
215
|
+
unless field_raw_value.nil? && field.required == false
|
216
|
+
if field.type && representations.include?(field.type)
|
217
|
+
field_value = self.build_from_representation(field_raw_value, field.type,
|
218
|
+
representations,
|
219
|
+
glossary_terms_hash)
|
220
|
+
elsif field.elements_type
|
221
|
+
field_value = self.build_collection_from_representation(field_raw_value,
|
222
|
+
field.elements_type,
|
223
|
+
representations,
|
224
|
+
glossary_terms_hash)
|
225
|
+
elsif field.type && field.type.to_sym == :variable
|
226
|
+
field_value = self.build_from_variable_fields(field_raw_value)
|
227
|
+
elsif field.type
|
228
|
+
field_value = Angus::Unmarshalling.unmarshal_scalar(field_raw_value,
|
229
|
+
field.type.to_sym)
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Don't apply the glossary to response elements
|
234
|
+
representation_object.elements[field.name] = field_value
|
235
|
+
|
236
|
+
# Instead, apply the glossary to method names
|
237
|
+
getter_method_name = self.apply_glossary(field.name, glossary_terms_hash)
|
238
|
+
|
239
|
+
representation_class.send :define_method, field.name.to_sym do
|
240
|
+
field_value
|
241
|
+
end
|
242
|
+
end
|
243
|
+
else
|
244
|
+
if type.to_sym == :variable
|
245
|
+
representation_object = self.build_from_variable_fields(hash_value)
|
246
|
+
else
|
247
|
+
begin
|
248
|
+
representation_object = Angus::Unmarshalling.unmarshal_scalar(hash_value,
|
249
|
+
type.to_sym)
|
250
|
+
rescue ArgumentError
|
251
|
+
representation_object = nil
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
return representation_object
|
258
|
+
end
|
259
|
+
|
260
|
+
# Builds an array of objects that corresponds to the received type
|
261
|
+
def self.build_collection_from_representation(value_array, type, representations,
|
262
|
+
glossary_terms_hash)
|
263
|
+
collection = []
|
264
|
+
|
265
|
+
value_array.each do |raw_value|
|
266
|
+
collection << build_from_representation(raw_value, type, representations,
|
267
|
+
glossary_terms_hash)
|
268
|
+
end
|
269
|
+
|
270
|
+
collection
|
271
|
+
end
|
272
|
+
|
273
|
+
# Builds an object from variable fields
|
274
|
+
def self.build_from_variable_fields(variable_fields_hash)
|
275
|
+
|
276
|
+
return nil if variable_fields_hash.nil?
|
277
|
+
|
278
|
+
representation_class = Class.new do
|
279
|
+
include Angus::Remote::Response::Hash
|
280
|
+
end
|
281
|
+
|
282
|
+
representation_object = representation_class.new
|
283
|
+
|
284
|
+
variable_fields_hash.each do |key_name, field_value|
|
285
|
+
representation_object.elements[key_name] = field_value
|
286
|
+
representation_class.send :define_method, key_name.to_sym do
|
287
|
+
field_value
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
representation_object
|
292
|
+
|
293
|
+
end
|
294
|
+
|
295
|
+
# Receives an array of representations and returns a hash of representations where
|
296
|
+
# the keys are the representation's names and the values are the representations
|
297
|
+
def self.representations_hash(representations)
|
298
|
+
hash = {}
|
299
|
+
representations.each do |representation|
|
300
|
+
hash[representation.name] = representation
|
301
|
+
end
|
302
|
+
hash
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
end
|
307
|
+
end
|
308
|
+
end
|