helix 0.0.4.3.pre → 0.0.4.4.pre
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/helix/base.rb +3 -2
- data/lib/helix/builds_urls.rb +67 -0
- data/lib/helix/config.rb +9 -206
- data/lib/helix/has_signatures.rb +84 -0
- data/lib/helix/library.rb +11 -0
- data/lib/helix/paginates.rb +91 -0
- data/spec/base_spec.rb +5 -0
- data/spec/config_spec.rb +0 -28
- data/spec/library_spec.rb +1 -1
- data/spec/paginates_spec.rb +51 -0
- metadata +6 -2
data/lib/helix/base.rb
CHANGED
@@ -137,8 +137,8 @@ module Helix
|
|
137
137
|
base_url_opts = {content_type: (opts[:content_type] || :json)}
|
138
138
|
url = memo_cfg.build_url(base_url_opts.merge(guid: self.guid, resource_label: plural_resource_label))
|
139
139
|
# We allow opts[:sig_type] for internal negative testing only.
|
140
|
-
raw_attrs
|
141
|
-
@attributes
|
140
|
+
raw_attrs = memo_cfg.get_response(url, {sig_type: :view}.merge(opts))
|
141
|
+
@attributes = massage_raw_attrs(raw_attrs)
|
142
142
|
self
|
143
143
|
end
|
144
144
|
alias_method :reload, :load
|
@@ -166,6 +166,7 @@ module Helix
|
|
166
166
|
private
|
167
167
|
|
168
168
|
def massage_raw_attrs(raw_attrs)
|
169
|
+
return raw_attrs['site'] if raw_attrs.respond_to?(:has_key?) && raw_attrs.has_key?('site')
|
169
170
|
# FIXME: Albums JSON output is embedded as the only member of an Array.
|
170
171
|
proper_hash = raw_attrs.respond_to?(:has_key?) && raw_attrs.has_key?(guid_name)
|
171
172
|
proper_hash ? raw_attrs : raw_attrs.first
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Helix
|
2
|
+
|
3
|
+
module BuildsUrls
|
4
|
+
|
5
|
+
unless defined?(self::SCOPES)
|
6
|
+
SCOPES = [:reseller, :company, :library]
|
7
|
+
end
|
8
|
+
|
9
|
+
# Creates additional URL stubbing that can be used in conjuction
|
10
|
+
# with the base_url to create RESTful URLs
|
11
|
+
#
|
12
|
+
# @param [String] base_url the base part of the URL to be used
|
13
|
+
# @param [Hash] opts a hash of options for building URL additions
|
14
|
+
# @return [String] The full RESTful URL string object
|
15
|
+
def add_sub_urls(base_url, opts)
|
16
|
+
guid, action, format = [:guid, :action, :formats].map { |sub| opts[sub] }
|
17
|
+
url = sub_url_scoping(base_url, opts)
|
18
|
+
url += "/#{guid}" if guid
|
19
|
+
url += "/formats/#{format}" if format
|
20
|
+
url += "/#{action}" if action
|
21
|
+
return url if opts[:content_type].blank?
|
22
|
+
"#{url}.#{opts[:content_type]}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates a full RESTful URL to be used for HTTP requests.
|
26
|
+
#
|
27
|
+
# @param [Hash] opts a hash of options for building URL
|
28
|
+
# @return [String] The full RESTful URL string object
|
29
|
+
def build_url(opts={})
|
30
|
+
opts[:content_type] ||= :xml
|
31
|
+
opts[:resource_label] ||= :videos
|
32
|
+
base_url = get_base_url(opts)
|
33
|
+
url = add_sub_urls(base_url, opts)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Creates the base url with information collected from credentials.
|
37
|
+
#
|
38
|
+
# @param [Hash] opts a hash of options for building URL
|
39
|
+
# @return [String] The base RESTful URL string object
|
40
|
+
def get_base_url(opts)
|
41
|
+
creds = credentials
|
42
|
+
base_url = creds[:site]
|
43
|
+
return base_url if opts[:guid] || opts[:action] == :create_many
|
44
|
+
reseller, company, library = SCOPES.map { |scope| creds[scope] }
|
45
|
+
base_url += "/resellers/#{reseller}" if reseller
|
46
|
+
if company
|
47
|
+
base_url += "/companies/#{company}"
|
48
|
+
base_url += "/libraries/#{library}" if library
|
49
|
+
end
|
50
|
+
base_url
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def sub_url_scoping(base_url, opts)
|
56
|
+
resource_label = opts[:resource_label]
|
57
|
+
if resource_label == 'libraries' and base_url !~ /companies/
|
58
|
+
co_id = opts[:company] || credentials[:company]
|
59
|
+
raise "No company to scope to: #{credentials}" if co_id.nil?
|
60
|
+
resource_label = "companies/#{co_id}/libraries"
|
61
|
+
end
|
62
|
+
"#{base_url}/#{resource_label}"
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/helix/config.rb
CHANGED
@@ -2,26 +2,27 @@ require 'helix/video'
|
|
2
2
|
require 'helix/track'
|
3
3
|
require 'helix/album'
|
4
4
|
require 'helix/image'
|
5
|
+
require 'helix/builds_urls'
|
6
|
+
require 'helix/has_signatures'
|
7
|
+
require 'helix/paginates'
|
5
8
|
require 'singleton'
|
6
9
|
|
7
10
|
module Helix
|
8
11
|
|
9
12
|
class Config
|
10
13
|
|
14
|
+
include BuildsUrls
|
15
|
+
include HasSignatures
|
16
|
+
include Paginates
|
11
17
|
include Singleton
|
12
18
|
|
13
19
|
unless defined?(self::DEFAULT_FILENAME)
|
14
20
|
DEFAULT_FILENAME = './helix.yml'
|
15
|
-
ITEMS_PER_PAGE = 100
|
16
|
-
SCOPES = [:reseller, :company, :library]
|
17
|
-
SIG_DURATION = 1200 # in minutes
|
18
|
-
STARTING_PAGE = 1
|
19
|
-
TIME_OFFSET = 1000 * 60 # 1000 minutes, lower to give some margin of error
|
20
|
-
VALID_SIG_TYPES = [ :ingest, :update, :view ]
|
21
21
|
end
|
22
22
|
|
23
|
-
attr_accessor :credentials
|
24
|
-
attr_reader :response
|
23
|
+
attr_accessor :credentials # local
|
24
|
+
attr_reader :response # in Paginates
|
25
|
+
attr_reader :signature_for, :signature_expiration_for # in HasSignatures
|
25
26
|
|
26
27
|
# Creates a singleton of itself, setting the config
|
27
28
|
# to a specified YAML file. If no file is specified the default
|
@@ -42,122 +43,6 @@ module Helix
|
|
42
43
|
config
|
43
44
|
end
|
44
45
|
|
45
|
-
# Creates additional URL stubbing that can be used in conjuction
|
46
|
-
# with the base_url to create RESTful URLs
|
47
|
-
#
|
48
|
-
# @param [String] base_url the base part of the URL to be used
|
49
|
-
# @param [Hash] opts a hash of options for building URL additions
|
50
|
-
# @return [String] The full RESTful URL string object
|
51
|
-
def add_sub_urls(base_url, opts)
|
52
|
-
guid, action, format = [:guid, :action, :formats].map { |sub| opts[sub] }
|
53
|
-
url = sub_url_scoping(base_url, opts)
|
54
|
-
url += "/#{guid}" if guid
|
55
|
-
url += "/formats/#{format}" if format
|
56
|
-
url += "/#{action}" if action
|
57
|
-
return url if opts[:content_type].blank?
|
58
|
-
"#{url}.#{opts[:content_type]}"
|
59
|
-
end
|
60
|
-
|
61
|
-
# Creates a full RESTful URL to be used for HTTP requests.
|
62
|
-
#
|
63
|
-
# @param [Hash] opts a hash of options for building URL
|
64
|
-
# @return [String] The full RESTful URL string object
|
65
|
-
def build_url(opts={})
|
66
|
-
opts[:content_type] ||= :xml
|
67
|
-
opts[:resource_label] ||= :videos
|
68
|
-
base_url = get_base_url(opts)
|
69
|
-
url = add_sub_urls(base_url, opts)
|
70
|
-
end
|
71
|
-
|
72
|
-
def clear_signatures!
|
73
|
-
@signature_for = {}
|
74
|
-
@signature_expiration_for = {}
|
75
|
-
end
|
76
|
-
|
77
|
-
# Makes aggregated calls to get_response with pagination
|
78
|
-
# folding/injecting/accumulating the results into a single output set.
|
79
|
-
#
|
80
|
-
# @param [String] url the base part of the URL to be used
|
81
|
-
# @param [String] plural_resource_label: "videos", "tracks", etc.
|
82
|
-
# @param [Hash] original_opts a hash of options for building URL additions
|
83
|
-
# @return [Array] The accumulated attribute Hashes for ORM instances
|
84
|
-
def get_aggregated_data_sets(url, plural_resource_label, original_opts={})
|
85
|
-
data_sets, page, per_page = [], STARTING_PAGE
|
86
|
-
begin
|
87
|
-
aggregation_opts = {page: page, per_page: ITEMS_PER_PAGE}.merge(original_opts)
|
88
|
-
raw_response = get_response(url, {sig_type: :view}.merge(aggregation_opts))
|
89
|
-
data_set = raw_response[plural_resource_label]
|
90
|
-
data_sets += data_set if data_set
|
91
|
-
page += 1
|
92
|
-
end until last_page?
|
93
|
-
data_sets
|
94
|
-
end
|
95
|
-
|
96
|
-
# Creates the base url with information collected from credentials.
|
97
|
-
#
|
98
|
-
# @param [Hash] opts a hash of options for building URL
|
99
|
-
# @return [String] The base RESTful URL string object
|
100
|
-
def get_base_url(opts)
|
101
|
-
creds = credentials
|
102
|
-
base_url = creds[:site]
|
103
|
-
return base_url if opts[:guid] || opts[:action] == :create_many
|
104
|
-
reseller, company, library = SCOPES.map { |scope| creds[scope] }
|
105
|
-
base_url += "/resellers/#{reseller}" if reseller
|
106
|
-
if company
|
107
|
-
base_url += "/companies/#{company}"
|
108
|
-
base_url += "/libraries/#{library}" if library
|
109
|
-
end
|
110
|
-
base_url
|
111
|
-
end
|
112
|
-
|
113
|
-
# Creates additional URL stubbing that can be used in conjuction
|
114
|
-
# with the base_url to create RESTful URLs
|
115
|
-
#
|
116
|
-
# @param [String] url the base part of the URL to be used
|
117
|
-
# @param [Hash] original_opts a hash of options for building URL additions
|
118
|
-
# @return [String] The full RESTful URL string object
|
119
|
-
def get_response(url, original_opts={})
|
120
|
-
opts = massage_custom_fields_in(original_opts)
|
121
|
-
sig_type = opts.delete(:sig_type)
|
122
|
-
params = opts.merge(signature: signature(sig_type, opts))
|
123
|
-
begin
|
124
|
-
@response = RestClient.get(url, params: params)
|
125
|
-
rescue RestClient::InternalServerError => e
|
126
|
-
raise NetworkError, "Unable to access url #{url} with params #{params}"
|
127
|
-
end
|
128
|
-
parse_response_by_url_format(@response, url)
|
129
|
-
end
|
130
|
-
|
131
|
-
# Reports whether the most recent response's headers have a true :is_last_page value
|
132
|
-
#
|
133
|
-
# @return [Boolean] As above. Returns false if no such header is found,
|
134
|
-
# or if there is an explictly false value.
|
135
|
-
def last_page?
|
136
|
-
return false unless @response
|
137
|
-
return false unless @response.headers
|
138
|
-
return true unless @response.headers.has_key?(:is_last_page)
|
139
|
-
@response.headers[:is_last_page] == "true"
|
140
|
-
end
|
141
|
-
|
142
|
-
# Fetches the signature for a specific license key.
|
143
|
-
#
|
144
|
-
# @param [Symbol] sig_type The type of signature required for calls.
|
145
|
-
# @param [Hash] opts allows you to overide contributor and license_id
|
146
|
-
# @return [String] The signature needed to pass around for calls.
|
147
|
-
def signature(sig_type, opts={})
|
148
|
-
prepare_signature_memoization
|
149
|
-
memo_sig = existing_sig_for(sig_type)
|
150
|
-
return memo_sig if memo_sig
|
151
|
-
unless VALID_SIG_TYPES.include?(sig_type)
|
152
|
-
raise ArgumentError, error_message_for(sig_type)
|
153
|
-
end
|
154
|
-
|
155
|
-
lk = license_key
|
156
|
-
@signature_expiration_for[lk][sig_type] = Time.now + TIME_OFFSET
|
157
|
-
new_sig_url = url_for(sig_type, opts)
|
158
|
-
@signature_for[lk][sig_type] = RestClient.get(new_sig_url)
|
159
|
-
end
|
160
|
-
|
161
46
|
def proxy
|
162
47
|
if @credentials[:proxy_uri]
|
163
48
|
protocol, uri = @credentials[:proxy_uri].split "://"
|
@@ -172,88 +57,6 @@ module Helix
|
|
172
57
|
end
|
173
58
|
end
|
174
59
|
|
175
|
-
private
|
176
|
-
|
177
|
-
def sub_url_scoping(base_url, opts)
|
178
|
-
resource_label = opts[:resource_label]
|
179
|
-
if resource_label == 'libraries' and base_url !~ /companies/
|
180
|
-
co_id = opts[:company] || credentials[:company]
|
181
|
-
raise "No company to scope to: #{credentials}" if co_id.nil?
|
182
|
-
resource_label = "companies/#{co_id}/libraries"
|
183
|
-
end
|
184
|
-
"#{base_url}/#{resource_label}"
|
185
|
-
end
|
186
|
-
|
187
|
-
def error_message_for(sig_type)
|
188
|
-
"I don't understand '#{sig_type}'. Please give me one of :ingest, :update, or :view."
|
189
|
-
end
|
190
|
-
|
191
|
-
def existing_sig_for(sig_type)
|
192
|
-
return if sig_expired_for?(sig_type)
|
193
|
-
@signature_for[license_key][sig_type]
|
194
|
-
end
|
195
|
-
|
196
|
-
def get_contributor_library_company(opts)
|
197
|
-
sig_param_labels = [:contributor, :library, :company]
|
198
|
-
scoping_proc = lambda { |key| opts[key] || credentials[key] }
|
199
|
-
contributor, library, company = sig_param_labels.map(&scoping_proc)
|
200
|
-
contributor ||= 'helix_default_contributor'
|
201
|
-
[contributor, library, company]
|
202
|
-
end
|
203
|
-
|
204
|
-
def license_key
|
205
|
-
@credentials[:license_key]
|
206
|
-
end
|
207
|
-
|
208
|
-
def massage_custom_fields_in(opts)
|
209
|
-
return opts.clone unless opts.has_key?(:custom_fields)
|
210
|
-
cf_opts = opts.delete(:custom_fields)
|
211
|
-
cf_opts.inject(opts.clone) do |memo,pair|
|
212
|
-
k,v = pair
|
213
|
-
memo.merge("custom_fields[#{k}]" => v)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
def parse_response_by_url_format(response, url)
|
218
|
-
### FIXME: This is ugly. Clean it up.
|
219
|
-
if url =~ /json/
|
220
|
-
JSON.parse(response)
|
221
|
-
elsif url =~ /xml/
|
222
|
-
#TODO: Cleanup Nori and response gsub.
|
223
|
-
Nori.parser = :nokogiri
|
224
|
-
xml = response.gsub(/<custom-fields type='array'>/, '<custom-fields type=\'hash\'>')
|
225
|
-
Nori.parse(xml)
|
226
|
-
elsif url =~ /csv/
|
227
|
-
response
|
228
|
-
else
|
229
|
-
raise "Could not parse #{url}"
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
def prepare_signature_memoization
|
234
|
-
lk = license_key
|
235
|
-
@signature_for ||= {}
|
236
|
-
@signature_expiration_for ||= {}
|
237
|
-
@signature_for[lk] ||= {}
|
238
|
-
@signature_expiration_for[lk] ||= {}
|
239
|
-
end
|
240
|
-
|
241
|
-
def sig_expired_for?(sig_type)
|
242
|
-
expires_at = @signature_expiration_for[license_key][sig_type]
|
243
|
-
return true if expires_at.nil?
|
244
|
-
expires_at <= Time.now
|
245
|
-
end
|
246
|
-
|
247
|
-
def url_for(sig_type, opts={})
|
248
|
-
contributor, library, company = get_contributor_library_company(opts)
|
249
|
-
url = "#{credentials[:site]}/api/#{sig_type}_key?"
|
250
|
-
url += "licenseKey=#{credentials[:license_key]}&duration=#{SIG_DURATION}"
|
251
|
-
url += "&contributor=#{contributor}" if sig_type == :ingest
|
252
|
-
url += "&library_id=#{library}" if library
|
253
|
-
url += "&company_id=#{company}" if company
|
254
|
-
url
|
255
|
-
end
|
256
|
-
|
257
60
|
end
|
258
61
|
|
259
62
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Helix
|
2
|
+
|
3
|
+
module HasSignatures
|
4
|
+
|
5
|
+
unless defined?(self::VALID_SIG_TYPES)
|
6
|
+
SIG_DURATION = 1200 # in minutes
|
7
|
+
TIME_OFFSET = 1000 * 60 # 1000 minutes, lower to give some margin of error
|
8
|
+
VALID_SIG_TYPES = [ :ingest, :update, :view ]
|
9
|
+
end
|
10
|
+
|
11
|
+
def clear_signatures!
|
12
|
+
@signature_for = {}
|
13
|
+
@signature_expiration_for = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
# Fetches the signature for a specific license key.
|
17
|
+
#
|
18
|
+
# @param [Symbol] sig_type The type of signature required for calls.
|
19
|
+
# @param [Hash] opts allows you to overide contributor and license_id
|
20
|
+
# @return [String] The signature needed to pass around for calls.
|
21
|
+
def signature(sig_type, opts={})
|
22
|
+
prepare_signature_memoization
|
23
|
+
memo_sig = existing_sig_for(sig_type)
|
24
|
+
return memo_sig if memo_sig
|
25
|
+
unless VALID_SIG_TYPES.include?(sig_type)
|
26
|
+
raise ArgumentError, error_message_for(sig_type)
|
27
|
+
end
|
28
|
+
|
29
|
+
lk = license_key
|
30
|
+
@signature_expiration_for[lk][sig_type] = Time.now + TIME_OFFSET
|
31
|
+
new_sig_url = signature_url_for(sig_type, opts)
|
32
|
+
@signature_for[lk][sig_type] = RestClient.get(new_sig_url)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def error_message_for(sig_type)
|
38
|
+
"I don't understand '#{sig_type}'. Please give me one of :ingest, :update, or :view."
|
39
|
+
end
|
40
|
+
|
41
|
+
def existing_sig_for(sig_type)
|
42
|
+
return if sig_expired_for?(sig_type)
|
43
|
+
@signature_for[license_key][sig_type]
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_contributor_library_company(opts)
|
47
|
+
sig_param_labels = [:contributor, :library, :company]
|
48
|
+
scoping_proc = lambda { |key| opts[key] || credentials[key] }
|
49
|
+
contributor, library, company = sig_param_labels.map(&scoping_proc)
|
50
|
+
contributor ||= 'helix_default_contributor'
|
51
|
+
[contributor, library, company]
|
52
|
+
end
|
53
|
+
|
54
|
+
def license_key
|
55
|
+
@credentials[:license_key]
|
56
|
+
end
|
57
|
+
|
58
|
+
def prepare_signature_memoization
|
59
|
+
lk = license_key
|
60
|
+
@signature_for ||= {}
|
61
|
+
@signature_expiration_for ||= {}
|
62
|
+
@signature_for[lk] ||= {}
|
63
|
+
@signature_expiration_for[lk] ||= {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def sig_expired_for?(sig_type)
|
67
|
+
expires_at = @signature_expiration_for[license_key][sig_type]
|
68
|
+
return true if expires_at.nil?
|
69
|
+
expires_at <= Time.now
|
70
|
+
end
|
71
|
+
|
72
|
+
def signature_url_for(sig_type, opts={})
|
73
|
+
contributor, library, company = get_contributor_library_company(opts)
|
74
|
+
url = "#{credentials[:site]}/api/#{sig_type}_key?"
|
75
|
+
url += "licenseKey=#{credentials[:license_key]}&duration=#{SIG_DURATION}"
|
76
|
+
url += "&contributor=#{contributor}" if sig_type == :ingest
|
77
|
+
url += "&library_id=#{library}" if library
|
78
|
+
url += "&company_id=#{company}" if company
|
79
|
+
url
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/helix/library.rb
CHANGED
@@ -13,6 +13,16 @@ module Helix
|
|
13
13
|
super(nickname, opts.merge(content_type: :xml))
|
14
14
|
end
|
15
15
|
|
16
|
+
# Creates a string that associates to the class id.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# Helix::Library.guid_name #=> "name"
|
20
|
+
#
|
21
|
+
# @return [String] The guid name for a specific class.
|
22
|
+
def self.guid_name
|
23
|
+
"name"
|
24
|
+
end
|
25
|
+
|
16
26
|
# The class name, to be used by supporting classes. Such as Config which uses
|
17
27
|
# this method as a way to build URLs.
|
18
28
|
#
|
@@ -33,6 +43,7 @@ module Helix
|
|
33
43
|
"libraries"
|
34
44
|
end
|
35
45
|
|
46
|
+
#TODO: Revisit and document.
|
36
47
|
def self.known_attributes
|
37
48
|
[:player_profile, :ingest_profile, :secure_stream_callback_url, :hooks_attributes]
|
38
49
|
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Helix
|
2
|
+
|
3
|
+
module Paginates
|
4
|
+
|
5
|
+
unless defined?(self::STARTING_PAGE)
|
6
|
+
ITEMS_PER_PAGE = 100
|
7
|
+
STARTING_PAGE = 1
|
8
|
+
end
|
9
|
+
|
10
|
+
# Makes aggregated calls to get_response with pagination
|
11
|
+
# folding/injecting/accumulating the results into a single output set.
|
12
|
+
#
|
13
|
+
# @param [String] url the base part of the URL to be used
|
14
|
+
# @param [String] plural_resource_label: "videos", "tracks", etc.
|
15
|
+
# @param [Hash] original_opts a hash of options for building URL additions
|
16
|
+
# @return [Array] The accumulated attribute Hashes for ORM instances
|
17
|
+
def get_aggregated_data_sets(url, plural_resource_label, original_opts={})
|
18
|
+
data_sets, page, per_page = [], STARTING_PAGE
|
19
|
+
begin
|
20
|
+
aggregation_opts = {page: page, per_page: ITEMS_PER_PAGE}.merge(original_opts)
|
21
|
+
raw_response = get_response(url, {sig_type: :view}.merge(aggregation_opts))
|
22
|
+
data_set = raw_response[plural_resource_label]
|
23
|
+
data_sets += data_set if data_set
|
24
|
+
page += 1
|
25
|
+
end until last_page? || specific_page_requested?(original_opts)
|
26
|
+
data_sets
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates additional URL stubbing that can be used in conjuction
|
30
|
+
# with the base_url to create RESTful URLs
|
31
|
+
#
|
32
|
+
# @param [String] url the base part of the URL to be used
|
33
|
+
# @param [Hash] original_opts a hash of options for building URL additions
|
34
|
+
# @return [String] The full RESTful URL string object
|
35
|
+
def get_response(url, original_opts={})
|
36
|
+
opts = massage_custom_fields_in(original_opts)
|
37
|
+
sig_type = opts.delete(:sig_type)
|
38
|
+
params = opts.merge(signature: signature(sig_type, opts))
|
39
|
+
begin
|
40
|
+
@response = RestClient.get(url, params: params)
|
41
|
+
rescue RestClient::InternalServerError => e
|
42
|
+
raise NetworkError, "Unable to access url #{url} with params #{params}"
|
43
|
+
end
|
44
|
+
parse_response_by_url_format(@response, url)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Reports whether the most recent response's headers have a true :is_last_page value
|
50
|
+
#
|
51
|
+
# @return [Boolean] As above. Returns false if no such header is found,
|
52
|
+
# or if there is an explictly false value.
|
53
|
+
def last_page?
|
54
|
+
return false unless @response
|
55
|
+
return false unless @response.headers
|
56
|
+
return true unless @response.headers.has_key?(:is_last_page)
|
57
|
+
@response.headers[:is_last_page] == "true"
|
58
|
+
end
|
59
|
+
|
60
|
+
def massage_custom_fields_in(opts)
|
61
|
+
return opts.clone unless opts.has_key?(:custom_fields)
|
62
|
+
cf_opts = opts.delete(:custom_fields)
|
63
|
+
cf_opts.inject(opts.clone) do |memo,pair|
|
64
|
+
k,v = pair
|
65
|
+
memo.merge("custom_fields[#{k}]" => v)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def specific_page_requested?(original_opts)
|
70
|
+
original_opts.has_key?(:page)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_response_by_url_format(response, url)
|
74
|
+
### FIXME: This is ugly. Clean it up.
|
75
|
+
if url =~ /json/
|
76
|
+
JSON.parse(response)
|
77
|
+
elsif url =~ /xml/
|
78
|
+
#TODO: Cleanup Nori and response gsub.
|
79
|
+
Nori.parser = :nokogiri
|
80
|
+
xml = response.gsub(/<custom-fields type='array'>/, '<custom-fields type=\'hash\'>')
|
81
|
+
Nori.parse(xml)
|
82
|
+
elsif url =~ /csv/
|
83
|
+
response
|
84
|
+
else
|
85
|
+
raise "Could not parse #{url}"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
data/spec/base_spec.rb
CHANGED
@@ -289,6 +289,11 @@ describe Helix::Base do
|
|
289
289
|
subject { obj.send(meth, raw_attrs) }
|
290
290
|
it { should eq(nil) }
|
291
291
|
end
|
292
|
+
context "when given {'site' => :site_contents}" do
|
293
|
+
let(:raw_attrs) { {'site' => :site_contents} }
|
294
|
+
subject { obj.send(meth, raw_attrs) }
|
295
|
+
it { should eq(:site_contents) }
|
296
|
+
end
|
292
297
|
context "when given { guid_name => :the_val }" do
|
293
298
|
let(:raw_attrs) { { guid_name => :the_val } }
|
294
299
|
subject { obj.send(meth, raw_attrs) }
|
data/spec/config_spec.rb
CHANGED
@@ -336,34 +336,6 @@ describe Helix::Config do
|
|
336
336
|
end
|
337
337
|
end
|
338
338
|
|
339
|
-
describe "#get_aggregated_data_sets" do
|
340
|
-
let(:meth) { :get_aggregated_data_sets }
|
341
|
-
subject { obj.method(meth) }
|
342
|
-
its(:arity) { should eq(-3) }
|
343
|
-
context "when called" do
|
344
|
-
let(:opts) { {opts_key1: :opts_val1, per_page: 99} }
|
345
|
-
let(:label) { :videos }
|
346
|
-
before(:each) do
|
347
|
-
obj.stub(:signature) { :the_sig }
|
348
|
-
end
|
349
|
-
subject { obj.send(meth, :a_url, label, opts) }
|
350
|
-
it "should successively call RestClient.get with the opts arg merged with pagination info and return the parsed results" do
|
351
|
-
base_opts = {opts_key1: :opts_val1, per_page: 99, signature: :the_sig}
|
352
|
-
opts1 = {params: base_opts.merge(page: 1)}
|
353
|
-
opts2 = {params: base_opts.merge(page: 2)}
|
354
|
-
opts3 = {params: base_opts.merge(page: 3)}
|
355
|
-
non_final_response = double(String, headers: {is_last_page: 'false'})
|
356
|
-
final_response = double(String, headers: {is_last_page: 'true'})
|
357
|
-
RestClient.should_receive(:get).with(:a_url, opts1) { non_final_response }
|
358
|
-
RestClient.should_receive(:get).with(:a_url, opts2) { non_final_response }
|
359
|
-
RestClient.should_receive(:get).with(:a_url, opts3) { final_response }
|
360
|
-
obj.stub(:parse_response_by_url_format).with(non_final_response, :a_url) { {label => [:non_final]} }
|
361
|
-
obj.stub(:parse_response_by_url_format).with(final_response, :a_url) { {label => [:final]} }
|
362
|
-
expect(obj.send(meth, :a_url, label, opts)).to eq([:non_final, :non_final, :final])
|
363
|
-
end
|
364
|
-
end
|
365
|
-
end
|
366
|
-
|
367
339
|
describe "#get_response" do
|
368
340
|
let(:meth) { :get_response }
|
369
341
|
subject { obj.method(meth) }
|
data/spec/library_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Helix::Library do
|
|
10
10
|
mods.each { |mod| its(:ancestors) { should include(mod) } }
|
11
11
|
its(:ancestors) { should_not include(Helix::Media) }
|
12
12
|
|
13
|
-
its(:guid_name) { should eq('
|
13
|
+
its(:guid_name) { should eq('name') }
|
14
14
|
its(:resource_label_sym) { should be(:library) }
|
15
15
|
its(:plural_resource_label) { should eq('libraries') }
|
16
16
|
[:find, :create, :all, :find_all, :where].each do |crud_call|
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'helix'
|
3
|
+
|
4
|
+
describe Helix::Paginates do
|
5
|
+
|
6
|
+
class DummyClass;end
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
@klass = DummyClass.new
|
10
|
+
@klass.extend(Helix::Paginates)
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
describe "#get_aggregated_data_sets" do
|
15
|
+
let(:meth) { :get_aggregated_data_sets }
|
16
|
+
subject { @klass.method(meth) }
|
17
|
+
its(:arity) { should eq(-3) }
|
18
|
+
context "when called" do
|
19
|
+
let(:opts) { {opts_key1: :opts_val1, per_page: 99} }
|
20
|
+
let(:label) { :videos }
|
21
|
+
let(:base_opts) { {opts_key1: :opts_val1, per_page: 99, signature: :the_sig} }
|
22
|
+
let(:opts1) { {params: base_opts.merge(page: 1)} }
|
23
|
+
let(:opts2) { {params: base_opts.merge(page: 2)} }
|
24
|
+
let(:opts3) { {params: base_opts.merge(page: 3)} }
|
25
|
+
before(:each) { @klass.stub(:signature) { :the_sig } }
|
26
|
+
subject { @klass.send(meth, :a_url, label, opts) }
|
27
|
+
it "should successively call RestClient.get with the opts arg merged with pagination info and return the parsed results" do
|
28
|
+
non_final_response = double(String, headers: {is_last_page: 'false'})
|
29
|
+
final_response = double(String, headers: {is_last_page: 'true'})
|
30
|
+
RestClient.should_receive(:get).with(:a_url, opts1) { non_final_response }
|
31
|
+
RestClient.should_receive(:get).with(:a_url, opts2) { non_final_response }
|
32
|
+
RestClient.should_receive(:get).with(:a_url, opts3) { final_response }
|
33
|
+
@klass.stub(:parse_response_by_url_format).with(non_final_response, :a_url) { {label => [:non_final]} }
|
34
|
+
@klass.stub(:parse_response_by_url_format).with(final_response, :a_url) { {label => [:final]} }
|
35
|
+
expect(@klass.send(meth, :a_url, label, opts)).to eq([:non_final, :non_final, :final])
|
36
|
+
end
|
37
|
+
|
38
|
+
context "when a page param is passed in." do
|
39
|
+
let(:opts) { {opts_key1: :opts_val1, page: 1} }
|
40
|
+
it "should only return one response" do
|
41
|
+
base_opts = {opts_key1: :opts_val1, per_page: 100, signature: :the_sig}
|
42
|
+
opts1 = {params: base_opts.merge(page: 1)}
|
43
|
+
non_final_response = double(String, headers: {is_last_page: 'false'})
|
44
|
+
RestClient.should_receive(:get).once { non_final_response }
|
45
|
+
@klass.stub(:parse_response_by_url_format).with(non_final_response, :a_url) { {label => [:non_final]} }
|
46
|
+
@klass.send(meth, :a_url, label, opts)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: helix
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.4.
|
4
|
+
version: 0.0.4.4.pre
|
5
5
|
prerelease: 8
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-09-
|
12
|
+
date: 2013-09-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: json
|
@@ -69,15 +69,18 @@ files:
|
|
69
69
|
- lib/helix/album.rb
|
70
70
|
- lib/helix/audio_playlist.rb
|
71
71
|
- lib/helix/base.rb
|
72
|
+
- lib/helix/builds_urls.rb
|
72
73
|
- lib/helix/config.rb
|
73
74
|
- lib/helix/document.rb
|
74
75
|
- lib/helix/durationed.rb
|
75
76
|
- lib/helix/exceptions.rb
|
77
|
+
- lib/helix/has_signatures.rb
|
76
78
|
- lib/helix/hash_ext.rb
|
77
79
|
- lib/helix/image.rb
|
78
80
|
- lib/helix/library.rb
|
79
81
|
- lib/helix/media.rb
|
80
82
|
- lib/helix/object_ext.rb
|
83
|
+
- lib/helix/paginates.rb
|
81
84
|
- lib/helix/playlist.rb
|
82
85
|
- lib/helix/restful.rb
|
83
86
|
- lib/helix/statistics.rb
|
@@ -98,6 +101,7 @@ files:
|
|
98
101
|
- spec/image_spec.rb
|
99
102
|
- spec/library_spec.rb
|
100
103
|
- spec/media_spec.rb
|
104
|
+
- spec/paginates_spec.rb
|
101
105
|
- spec/playlist_spec.rb
|
102
106
|
- spec/spec_helper.rb
|
103
107
|
- spec/statistics_spec.rb
|