naranya_ecm-sdk 0.0.42 → 0.0.43
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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.rspec +3 -0
- data/Gemfile +1 -2
- data/lib/aasm/persistence/rest_persistence.rb +11 -6
- data/lib/naranya_ecm-sdk.rb +4 -65
- data/lib/naranya_ecm-sdk/version.rb +1 -1
- data/lib/naranya_ecm/models/media_resource.rb +1 -1
- data/lib/naranya_ecm/models/notification.rb +2 -2
- data/lib/naranya_ecm/rest/errors.rb +16 -3
- data/lib/naranya_ecm/rest/finder_methods.rb +4 -4
- data/lib/naranya_ecm/rest/model.rb +87 -19
- data/lib/naranya_ecm/rest/persistence.rb +234 -46
- data/lib/naranya_ecm/rest/relation.rb +15 -5
- data/lib/naranya_ecm/search/results.rb +19 -17
- data/lib/ncontent-sdk-testing.rb +13 -0
- data/lib/ncontent-sdk.rb +85 -0
- data/lib/ncontent/sdk/config.rb +75 -0
- data/lib/ncontent/sdk/faraday_middleware.rb +4 -0
- data/lib/ncontent/sdk/faraday_middleware/required_response_format.rb +14 -0
- data/lib/ncontent/sdk/faraday_middleware/response_parser.rb +35 -0
- data/lib/ncontent/sdk/faraday_middleware/rest_api_call_benchmark.rb +49 -0
- data/lib/ncontent/sdk/railtie.rb +59 -0
- data/lib/ncontent/sdk/rest_client.rb +131 -0
- data/lib/ncontent/sdk/testing/server_mock.rb +316 -0
- data/naranya_ecm-sdk.gemspec +24 -10
- metadata +85 -68
- data/lib/naranya_ecm/rest/client.rb +0 -92
- data/spec/models/category_spec.rb +0 -16
- data/spec/models/content_spec.rb +0 -20
- data/spec/models/content_version_spec.rb +0 -7
- data/spec/models/download_authorization.rb +0 -7
- data/spec/models/media_spec.rb +0 -7
- data/spec/models/module_spec.rb +0 -18
- data/spec/spec_helper.rb +0 -47
- data/spec/support/naranya_ecms_shared_specs.rb +0 -21
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
require 'ncontent/sdk/faraday_middleware'
|
3
|
+
|
4
|
+
module NContent
|
5
|
+
|
6
|
+
module SDK
|
7
|
+
|
8
|
+
class RESTClient
|
9
|
+
|
10
|
+
CLIENT_TOKEN_CACHE_KEY = "ncontent/api_client/client_token".freeze
|
11
|
+
|
12
|
+
class << self
|
13
|
+
delegate :config, :logger, :cache, to: NContent::SDK
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the thread's OAuth2 client instance.
|
17
|
+
#
|
18
|
+
# In multi-thread environments, each thread will have it's own client
|
19
|
+
# instance object - since it's saved as a @instance_variable - but
|
20
|
+
# shouldn't be a problem since the mutable data is actually the
|
21
|
+
# client_token (see self.client_token).
|
22
|
+
def self.instance
|
23
|
+
@instance ||= OAuth2::Client.new(
|
24
|
+
config.api_key, config.api_secret, site: config.api_host
|
25
|
+
) do |faraday|
|
26
|
+
### Oauth2 Client (Faraday) builder:
|
27
|
+
|
28
|
+
faraday.request :url_encoded # them posts...
|
29
|
+
|
30
|
+
faraday.response :logger, logger
|
31
|
+
|
32
|
+
faraday.use NContent::SDK::FaradayMiddleware::RESTAPICallBenchmark
|
33
|
+
|
34
|
+
faraday.use NContent::SDK::FaradayMiddleware::ResponseParser
|
35
|
+
|
36
|
+
if defined?(Patron)
|
37
|
+
faraday.adapter :patron # Prefer patron if exists
|
38
|
+
else
|
39
|
+
faraday.adapter Faraday.default_adapter # make requests with Net::HTTP
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns a client_token initialized from cache.
|
45
|
+
#
|
46
|
+
# In multi-thread environments, each thread will have it's own
|
47
|
+
# client_token object - since it's saved as a @instance_variable -, but
|
48
|
+
# all of them should have the same token data - since it's initialized
|
49
|
+
# from cache (We're assuming a thread-safe cache such as redis gem).
|
50
|
+
def self.client_token
|
51
|
+
@client_token ||= begin
|
52
|
+
cached_token_data = cache.read CLIENT_TOKEN_CACHE_KEY
|
53
|
+
if cached_token_data.present?
|
54
|
+
OAuth2::AccessToken.from_hash instance, cached_token_data
|
55
|
+
else
|
56
|
+
new_token = instance.client_credentials.get_token
|
57
|
+
cache.write CLIENT_TOKEN_CACHE_KEY, new_token.to_hash
|
58
|
+
new_token
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Clears the thread's token object. If called with 'true', it also
|
64
|
+
# clears the token data from the cache.
|
65
|
+
def self.clear_client_token!(clear_from_cache = false)
|
66
|
+
cache.delete CLIENT_TOKEN_CACHE_KEY if clear_from_cache
|
67
|
+
@client_token = nil
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Make a request to the API:
|
72
|
+
#
|
73
|
+
# @param [Symbol] verb the HTTP request method
|
74
|
+
# @param [String] path the HTTP URL path of the request
|
75
|
+
# @param [Hash] opts the options to make the request with
|
76
|
+
def self.request(verb, path=nil, opts = {}, &block)
|
77
|
+
|
78
|
+
cleared_cached_token_data = false
|
79
|
+
|
80
|
+
begin
|
81
|
+
|
82
|
+
# If we beforehand know that the current token expired then clear the
|
83
|
+
# token object from the current thread. We'll not clear it from the
|
84
|
+
# cache store here, as maybe another thread has already updated the
|
85
|
+
# cached token data:
|
86
|
+
clear_client_token! if client_token.expired?
|
87
|
+
|
88
|
+
client_token.request(verb, path, opts) do |req|
|
89
|
+
req.options.timeout = config.api_call_timeout
|
90
|
+
req.options.open_timeout = config.api_call_open_timeout
|
91
|
+
yield req if block_given?
|
92
|
+
end
|
93
|
+
|
94
|
+
rescue OAuth2::Error => error
|
95
|
+
|
96
|
+
if error.response.status == 401 && !cleared_cached_token_data
|
97
|
+
# Here the cached token data is stale, so we'll force the cached
|
98
|
+
# token data to be cleared:
|
99
|
+
cleared_cached_token_data = clear_client_token!(true)
|
100
|
+
retry
|
101
|
+
else
|
102
|
+
::NaranyaEcm::Rest::RestError.raise_by_failed_response(error.response)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.get(path=nil, opts = {}, &block)
|
108
|
+
request(:get, path, opts, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
def self.post(path=nil, opts = {}, &block)
|
112
|
+
request(:post, path, opts, &block)
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.put(path=nil, opts = {}, &block)
|
116
|
+
request(:put, path, opts, &block)
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.patch(path=nil, opts = {}, &block)
|
120
|
+
request(:patch, path, opts, &block)
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.delete(path=nil, opts = {}, &block)
|
124
|
+
request(:delete, path, opts, &block)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'bson'
|
3
|
+
|
4
|
+
module NContent
|
5
|
+
module SDK
|
6
|
+
module Testing
|
7
|
+
|
8
|
+
##
|
9
|
+
# Clase que simula el servicio de nContent:
|
10
|
+
# Ver https://robots.thoughtbot.com/how-to-stub-external-services-in-tests
|
11
|
+
class ServerMock < Sinatra::Base
|
12
|
+
|
13
|
+
class ValidationError < StandardError
|
14
|
+
attr_reader :errors
|
15
|
+
def initialize(errors = {})
|
16
|
+
@errors = errors.collect({}) do |hsh, keyval|
|
17
|
+
key, val = keyval
|
18
|
+
hsh[key] = [] unless hsh[key].is_a? Array
|
19
|
+
hsh[key] << val
|
20
|
+
hsh
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
delegate :config, to: :class
|
26
|
+
|
27
|
+
class << self
|
28
|
+
delegate :config, to: NContent::SDK
|
29
|
+
end
|
30
|
+
|
31
|
+
COLLECTION_NAMES = %w(
|
32
|
+
categories content_versions contents download_authorizations
|
33
|
+
media_processes media_profiles media_resources
|
34
|
+
).freeze
|
35
|
+
|
36
|
+
RESOURCE_TYPES = COLLECTION_NAMES.map(&:singularize).freeze
|
37
|
+
|
38
|
+
def self.get_blank_collection_set
|
39
|
+
COLLECTION_NAMES.inject({}) do |hash, collection_name|
|
40
|
+
hash[collection_name] = {}
|
41
|
+
hash
|
42
|
+
end.with_indifferent_access
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.clear_collections!
|
46
|
+
@collections = nil
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.collections
|
50
|
+
@collections ||= get_blank_collection_set
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.method_missing(method_name, *args, &block)
|
54
|
+
if COLLECTION_NAMES.include? method_name.to_s
|
55
|
+
|
56
|
+
# Create the method:
|
57
|
+
define_singleton_method method_name do
|
58
|
+
collections[method_name.to_s]
|
59
|
+
end
|
60
|
+
|
61
|
+
# Call the newly defined method:
|
62
|
+
self.send method_name, *args
|
63
|
+
elsif method_name =~ /\Aget_(\w+)\z/ && RESOURCE_TYPES.include?($1)
|
64
|
+
|
65
|
+
# Create the method:
|
66
|
+
define_singleton_method method_name do |resource_id|
|
67
|
+
get_resource $1, resource_id
|
68
|
+
end
|
69
|
+
|
70
|
+
# Call the newly defined method:
|
71
|
+
self.send method_name, *args
|
72
|
+
elsif method_name =~ /\A(create|update|upsert)_(\w+)\z/ && RESOURCE_TYPES.include?($2)
|
73
|
+
|
74
|
+
# Create the methods:
|
75
|
+
%w(create update upsert).each do |method_prefix|
|
76
|
+
new_method_name = "#{method_prefix}_#{$2}".to_sym
|
77
|
+
define_singleton_method new_method_name do |*args|
|
78
|
+
upsert_resource $2.pluralize, *args
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Call the newly defined method:
|
83
|
+
self.send method_name, *args
|
84
|
+
else
|
85
|
+
super # You *must* call super if you don't handle the
|
86
|
+
# method, otherwise you'll mess up Ruby's method
|
87
|
+
# lookup.
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.upsert_resource(collection_name, given_resource_attributes, resource_id = nil)
|
92
|
+
# Ignore the ID:
|
93
|
+
given_resource_attributes.delete 'id'
|
94
|
+
|
95
|
+
invalid_attributes = given_resource_attributes.select do |k, v|
|
96
|
+
v =~ /invalid/i
|
97
|
+
end
|
98
|
+
|
99
|
+
raise ValidationError, invalid_attributes.collect {} do |h, kv|
|
100
|
+
k, v = kv;
|
101
|
+
h[k] = ['is invalid']
|
102
|
+
h
|
103
|
+
end if invalid_attributes.any?
|
104
|
+
|
105
|
+
if resource_id.present? && collections[collection_name].key?(resource_id)
|
106
|
+
collections[collection_name][resource_id].merge! given_resource_attributes
|
107
|
+
else
|
108
|
+
# Caso especial:
|
109
|
+
if collection_name == 'contents'
|
110
|
+
given_resource_attributes.reverse_merge "lifecycle_state" => 'draft'
|
111
|
+
|
112
|
+
# Generar iconos y screenshots en caso de que sea Game:
|
113
|
+
if given_resource_attributes['type'] == "Game"
|
114
|
+
icon = self.upsert_media_resource(
|
115
|
+
roles: ["icon"],
|
116
|
+
downloadable_url: "http://test-bucket.s3.amazonaws.com/icons/original/#{resource_id}.jpg",
|
117
|
+
type: "image/jpg",
|
118
|
+
access_type: "public",
|
119
|
+
parent_document_id: resource_id,
|
120
|
+
parent_document_type: "Content"
|
121
|
+
)
|
122
|
+
|
123
|
+
%w(120w 150w 300w).each do |processed_role|
|
124
|
+
self.upsert_media_resource(
|
125
|
+
roles: ["icon", "processed", "v2", processed_role],
|
126
|
+
downloadable_url: "http://test-bucket.s3.amazonaws.com/icons/#{processed_role}/#{resource_id}.jpg",
|
127
|
+
type: "image/jpg",
|
128
|
+
access_type: "public",
|
129
|
+
parent_document_id: icon[:id],
|
130
|
+
parent_document_type: "MediaResource"
|
131
|
+
)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
resource_id = (BSON::ObjectId.new).to_s
|
138
|
+
collections[collection_name][resource_id] = { id: resource_id }.merge(
|
139
|
+
given_resource_attributes
|
140
|
+
).with_indifferent_access
|
141
|
+
end
|
142
|
+
|
143
|
+
collections[collection_name][resource_id]
|
144
|
+
end
|
145
|
+
|
146
|
+
# Éste método es útil para llamar "stub_request", usando el host+port configurado por ENV["NARANYA_ECM_SITE"]
|
147
|
+
def self.url_matcher
|
148
|
+
@url_matcher ||= begin
|
149
|
+
site_url = URI config.api_host
|
150
|
+
pattern_string = site_url.host
|
151
|
+
pattern_string += ":#{site_url.port}" unless site_url.port == 80
|
152
|
+
Regexp.new pattern_string, "i"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.get_resource(resource_type, resource_id)
|
157
|
+
collection_name = resource_type.pluralize
|
158
|
+
requested_resource = self.collections[collection_name.to_s].fetch resource_id, nil
|
159
|
+
|
160
|
+
# Traerse los MR's:
|
161
|
+
requested_resource[:media_resources] = self.media_resources.values.select do |mr|
|
162
|
+
mr[:parent_document_type] == "Content" && mr[:parent_document_id] == resource_id
|
163
|
+
end.map do |mr|
|
164
|
+
mr[:media_resources] = self.media_resources.values.select do |c_mr|
|
165
|
+
c_mr[:parent_document_type] == "MediaResource" && c_mr[:parent_document_id] == mr[:id]
|
166
|
+
end
|
167
|
+
mr
|
168
|
+
end if requested_resource.present? && collection_name == 'contents'
|
169
|
+
|
170
|
+
requested_resource
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.get_resource_headers(collection_name, resource_id)
|
174
|
+
raise "no collection name given" unless collection_name.present?
|
175
|
+
raise "no resource id given" unless resource_id.present?
|
176
|
+
|
177
|
+
headers = {}
|
178
|
+
headers = {
|
179
|
+
"X-Frame-Options" => "SAMEORIGIN",
|
180
|
+
"X-Xss-Protection" => "1; mode=block",
|
181
|
+
"X-Content-Type-Options" => "nosniff",
|
182
|
+
"Location" => "http://ecm.naranya.net:5000/#{collection_name}/#{resource_id}",
|
183
|
+
"Content-Type" => "application/json; charset=utf-8",
|
184
|
+
"Vary" => "Accept-Encoding",
|
185
|
+
"Etag" => '"a547f3ead872de01928f79724390aba4"',
|
186
|
+
"Cache-Control" => "max-age=0, private, must-revalidate",
|
187
|
+
"Set-Cookie" => "request_method=POST; path=/",
|
188
|
+
"X-Request-Id" => "a6463225-df54-450d-b571-7068f3c96364",
|
189
|
+
"X-Runtime" => "'0.241093'",
|
190
|
+
"Transfer-Encoding" => "chunked"
|
191
|
+
} if self.collections[collection_name].key? resource_id
|
192
|
+
end
|
193
|
+
|
194
|
+
delegate :collections, :get_resource, :get_resource_headers,
|
195
|
+
:upsert_resource, to: :class
|
196
|
+
|
197
|
+
# Servicio de token de oauth:
|
198
|
+
# Responderá con un token "fake" de prueba...
|
199
|
+
post "/oauth/token" do
|
200
|
+
case params[:grant_type]
|
201
|
+
when "client_credentials"
|
202
|
+
status 201
|
203
|
+
|
204
|
+
headers \
|
205
|
+
"X-Frame-Options" => "SAMEORIGIN",
|
206
|
+
"X-XSS-Protection" => "1; mode=block",
|
207
|
+
"X-Content-Type-Options" => "nosniff",
|
208
|
+
"Cache-Control" => "no-store",
|
209
|
+
"Pragma" => "no-cache",
|
210
|
+
"Content-Type" => "application/json; charset=utf-8",
|
211
|
+
"Vary" => "Accept-Encoding",
|
212
|
+
"ETag" => '"75e236bc0e47293b0bfbb7a5d16a06c3"',
|
213
|
+
"X-Request-Id" => "f4d38d78-84b9-4c41-8943-cf2c6f519061",
|
214
|
+
"X-Runtime" => "0.015009",
|
215
|
+
"Transfer-Encoding" => "chunked"
|
216
|
+
|
217
|
+
body ActiveSupport::JSON.encode(
|
218
|
+
access_token: "NContentClientTestAccessTokenA",
|
219
|
+
refresh_token: "NContentClientTestRefreshToken",
|
220
|
+
token_type: "bearer",
|
221
|
+
expires_in: 7200
|
222
|
+
)
|
223
|
+
else
|
224
|
+
status 401
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
get '/:collection_name.json' do
|
230
|
+
status 200
|
231
|
+
|
232
|
+
headers \
|
233
|
+
"X-Frame-Options" => "SAMEORIGIN",
|
234
|
+
"X-Xss-Protection" => "1; mode=block",
|
235
|
+
"X-Content-Type-Options" => "nosniff",
|
236
|
+
"Content-Type" => "application/json; charset=utf-8",
|
237
|
+
"Vary" => "Accept-Encoding",
|
238
|
+
"Etag" => '"d751713988987e9331980363e24189ce"',
|
239
|
+
"Cache-Control" => "max-age=0, private, must-revalidate",
|
240
|
+
"Set-Cookie" => "request_method=GET; path=/",
|
241
|
+
"X-Request-Id" => "4fe9e39f-2b2d-400f-9da7-0b9ad611ce26",
|
242
|
+
"X-Runtime" => "'0.019181'",
|
243
|
+
"Transfer-Encoding" => "chunked"
|
244
|
+
|
245
|
+
body ActiveSupport::JSON.encode collections[params[:collection_name]].values
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
post "/:collection_name.json" do
|
250
|
+
collection_name = params[:collection_name]
|
251
|
+
params = ActiveSupport::JSON.decode request.body.read
|
252
|
+
attributes = params[collection_name.singularize]
|
253
|
+
|
254
|
+
if attributes.present?
|
255
|
+
begin
|
256
|
+
resource = upsert_resource collection_name, attributes
|
257
|
+
status 201
|
258
|
+
headers get_resource_headers collection_name, resource[:id]
|
259
|
+
body ActiveSupport::JSON.encode resource
|
260
|
+
rescue ValidationError => e
|
261
|
+
status 422
|
262
|
+
body ActiveSupport::JSON.encode e.errors
|
263
|
+
end
|
264
|
+
else
|
265
|
+
status 422
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
get "/:collection_name/:id.json" do
|
271
|
+
resource = get_resource params[:collection_name], params[:id]
|
272
|
+
if resource.present?
|
273
|
+
status 201
|
274
|
+
headers get_resource_headers params[:collection_name], resource[:id]
|
275
|
+
body ActiveSupport::JSON.encode resource
|
276
|
+
else
|
277
|
+
status 404
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
put '/:collection_name/:id.json' do
|
282
|
+
|
283
|
+
collection_name = params[:collection_name]
|
284
|
+
resource_id = params[:id]
|
285
|
+
|
286
|
+
if collection_name != 'download_authorizations' and resource = get_resource(collection_name, resource_id)
|
287
|
+
|
288
|
+
params = ActiveSupport::JSON.decode(request.body.read)
|
289
|
+
|
290
|
+
if attributes = params[collection_name.singularize]
|
291
|
+
begin
|
292
|
+
resource = upsert_resource collection_name, attributes, resource_id
|
293
|
+
status 200
|
294
|
+
headers get_resource_headers collection_name, resource[:id]
|
295
|
+
body ActiveSupport::JSON.encode resource
|
296
|
+
rescue ValidationError => e
|
297
|
+
status 422
|
298
|
+
body ActiveSupport::JSON.encode e.errors
|
299
|
+
end
|
300
|
+
else
|
301
|
+
status 422
|
302
|
+
end
|
303
|
+
|
304
|
+
else
|
305
|
+
status 404
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
get // do
|
310
|
+
byebug
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
data/naranya_ecm-sdk.gemspec
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
|
5
4
|
require "naranya_ecm-sdk/version"
|
6
5
|
|
7
6
|
Gem::Specification.new do |spec|
|
@@ -9,26 +8,41 @@ Gem::Specification.new do |spec|
|
|
9
8
|
spec.version = NaranyaEcm::VERSION
|
10
9
|
spec.authors = ["Roberto Quintanilla"]
|
11
10
|
spec.email = ["roberto.quintanilla@naranya.com"]
|
11
|
+
|
12
12
|
spec.summary = %q{Cliente Ruby de NaranyaEcm}
|
13
13
|
spec.description = %q{Cliente Ruby de NaranyaEcm para aplicaciones cliente.}
|
14
14
|
spec.homepage = "http://naranya.com"
|
15
15
|
spec.license = "MIT"
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
|
18
|
+
# delete this section to allow pushing this gem to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
23
|
+
end
|
24
|
+
|
25
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.bindir = "exe"
|
20
28
|
spec.require_paths = ["lib"]
|
21
29
|
|
22
30
|
spec.add_dependency "activesupport", "~> 4.0", ">= 4.0.5"
|
23
31
|
spec.add_dependency "activemodel", "~> 4.0", ">= 4.0.5"
|
24
|
-
|
32
|
+
|
33
|
+
spec.add_dependency "oauth2", "~> 1.0"
|
34
|
+
# which uses Faraday as it's client... we get to choose which HTTP driver to use!
|
35
|
+
|
25
36
|
spec.add_dependency "aasm", "~> 3.2", ">= 3.2.1"
|
26
37
|
spec.add_dependency "fog-core", "1.25.0"
|
27
38
|
spec.add_dependency "fog", "~> 1.22", ">= 1.22.1"
|
28
39
|
|
29
|
-
spec.add_development_dependency "bundler",
|
30
|
-
spec.add_development_dependency "rake",
|
31
|
-
spec.add_development_dependency "
|
32
|
-
spec.add_development_dependency "
|
33
|
-
spec.add_development_dependency "
|
40
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
41
|
+
spec.add_development_dependency "rake", "~> 10.3"
|
42
|
+
spec.add_development_dependency "factory_girl", "~> 4.5"
|
43
|
+
spec.add_development_dependency "rspec", "~> 3.2"
|
44
|
+
spec.add_development_dependency "sinatra", "~> 1.4"
|
45
|
+
spec.add_development_dependency "bson", "~> 3.0"
|
46
|
+
|
47
|
+
spec.add_development_dependency "webmock", "~> 1.18"
|
34
48
|
end
|