rb_splash 1.0.0

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.
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'faraday'
4
+ require 'json'
5
+
6
+ require_relative 'response'
7
+
8
+ module RbSplash
9
+ class HttpClient
10
+ RETRYABLE_ERRORS = [
11
+ Faraday::TimeoutError,
12
+ Faraday::ConnectionFailed,
13
+ Net::OpenTimeout,
14
+ Net::ReadTimeout,
15
+ Net::ProtocolError,
16
+ IOError,
17
+ Errno::ECONNRESET,
18
+ Errno::ECONNREFUSED,
19
+ Errno::ETIMEDOUT
20
+ ].freeze
21
+
22
+ def initialize(headers: {}, timeout: 10_000, retries: 2, retry_delay_ms: 100)
23
+ @headers = headers
24
+ @timeout = timeout
25
+ @retries = retries
26
+ @retry_delay_ms = retry_delay_ms
27
+ end
28
+
29
+ def make_request(url, method, query_parameters: {}, body: nil)
30
+ raise ArgumentError, 'URL required' if url.nil? || url.empty?
31
+
32
+ last_error = nil
33
+
34
+ (0..@retries).each do |attempt|
35
+ return execute_request(url, method, query_parameters, body)
36
+ rescue *RETRYABLE_ERRORS => e
37
+ last_error = e
38
+ sleep(@retry_delay_ms / 1000.0) if @retry_delay_ms.positive? && attempt < @retries
39
+ end
40
+
41
+ raise last_error
42
+ end
43
+
44
+ private
45
+
46
+ def execute_request(url, method, query_parameters, body)
47
+ conn = Faraday.new do |f|
48
+ f.adapter Faraday.default_adapter
49
+ end
50
+
51
+ response = conn.send(method.downcase.to_sym, url) do |req|
52
+ req.headers.merge!(@headers)
53
+ req.params.merge!(query_parameters.transform_keys(&:to_s)) if query_parameters.any?
54
+ req.body = body.to_json if body
55
+ req.options.timeout = @timeout / 1000.0
56
+ end
57
+
58
+ data = response.body.to_s.empty? ? {} : parse_json(response.body)
59
+
60
+ result = Response.new(
61
+ status: response.status,
62
+ status_text: response.reason_phrase,
63
+ data: data
64
+ )
65
+
66
+ unless response.status.between?(200, 299)
67
+ error_message = "HTTP #{response.status}: #{response.reason_phrase}"
68
+ error_message += " - #{response.body}" if response.body && !response.body.empty?
69
+ raise StandardError, error_message
70
+ end
71
+
72
+ result
73
+ end
74
+
75
+ def parse_json(body)
76
+ JSON.parse(body)
77
+ rescue JSON::ParserError
78
+ { raw: body }
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RbSplash
4
+ class Response
5
+ attr_reader :status, :status_text, :data
6
+
7
+ def initialize(status:, status_text:, data:)
8
+ @status = status
9
+ @status_text = status_text
10
+ @data = data
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RbSplash
4
+ module UrlConfig
5
+ API_LOCATION = 'https://api.unsplash.com/'
6
+ BEARER_TOKEN_URL = 'https://unsplash.com/oauth/token'
7
+
8
+ USERS_PUBLIC_PROFILE = 'users/'
9
+ USERS_PORTFOLIO = 'users/:username/portfolio'
10
+ USERS_PHOTOS = 'users/:username/photos'
11
+ USERS_LIKED_PHOTOS = 'users/:username/likes'
12
+ USERS_COLLECTIONS = 'users/:username/collections'
13
+ USERS_STATISTICS = 'users/:username/statistics'
14
+
15
+ LIST_PHOTOS = 'photos'
16
+ LIST_CURATED_PHOTOS = 'photos/curated'
17
+ GET_A_PHOTO = 'photos/:id'
18
+ GET_A_RANDOM_PHOTO = 'photos/random'
19
+ GET_A_PHOTO_STATISTICS = 'photos/:id/statistics'
20
+ GET_A_PHOTO_DOWNLOAD_LINK = 'photos/:id/download'
21
+ UPDATE_A_PHOTO = 'photos/:id'
22
+ LIKE_A_PHOTO = 'photos/:id/like'
23
+ UNLIKE_A_PHOTO = 'photos/:id/like'
24
+
25
+ SEARCH_PHOTOS = 'search/photos'
26
+ SEARCH_COLLECTIONS = 'search/collections'
27
+ SEARCH_USERS = 'search/users'
28
+
29
+ CURRENT_USER_PROFILE = 'me'
30
+ UPDATE_CURRENT_USER_PROFILE = 'me'
31
+
32
+ STATS_TOTALS = 'stats/total'
33
+ STATS_MONTH = 'stats/month'
34
+
35
+ LIST_COLLECTIONS = 'collections'
36
+ LIST_FEATURED_COLLECTIONS = 'collections/featured'
37
+ LIST_CURATED_COLLECTIONS = 'collections/curated'
38
+ GET_COLLECTION = 'collections/:id'
39
+ GET_CURATED_COLLECTION = 'collections/curated/:id'
40
+ GET_COLLECTION_PHOTOS = 'collections/:id/photos'
41
+ GET_CURATED_COLLECTION_PHOTOS = 'collections/curated/:id/photos'
42
+ LIST_RELATED_COLLECTION = 'collections/:id/related'
43
+ CREATE_NEW_COLLECTION = 'collections'
44
+ UPDATE_EXISTING_COLLECTION = 'collections/:id'
45
+ DELETE_COLLECTION = 'collections/:id'
46
+ ADD_PHOTO_TO_COLLECTION = 'collections/:collection_id/add'
47
+ REMOVE_PHOTO_FROM_COLLECTION = 'collections/:collection_id/remove'
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RbSplash
4
+ VERSION = '1.0.0'
5
+ end
@@ -0,0 +1,404 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'digest'
4
+ require 'concurrent/promises'
5
+
6
+ module RbSplash
7
+ class WrapSplashApi
8
+ AVAILABLE_ORDERS = %w[latest oldest popular].freeze
9
+ AVAILABLE_ORIENTATIONS = %w[landscape portrait squarish].freeze
10
+
11
+ def initialize
12
+ @api_location = UrlConfig::API_LOCATION
13
+ @bearer_token_url = UrlConfig::BEARER_TOKEN_URL
14
+ @access_key = ''
15
+ @secret_key = ''
16
+ @redirect_uri = ''
17
+ @code = ''
18
+ @grant_type = 'authorization_code'
19
+ @bearer_token = ''
20
+ @timeout = 10_000
21
+ @retries = 2
22
+ @retry_delay_ms = 100
23
+ @headers = {
24
+ 'Content-type' => 'application/json',
25
+ 'X-Requested-With' => 'WrapSplash'
26
+ }
27
+ end
28
+
29
+ def init(options = {})
30
+ raise WrapSplashError, 'Initialisation parameters required!' unless options.is_a?(Hash) && !options.empty?
31
+
32
+ @timeout = options[:timeout].is_a?(Numeric) && options[:timeout].positive? ? options[:timeout] : 10_000
33
+ @retries = options[:retries].is_a?(Numeric) && options[:retries] >= 0 ? options[:retries] : 2
34
+ raw_timeout = options[:retry_delay_ms]
35
+ valid_timeout = raw_timeout.is_a?(Numeric) && raw_timeout >= 0
36
+ @retry_delay_ms = valid_timeout ? raw_timeout : 100
37
+ @bearer_token = options[:bearer_token] || ''
38
+
39
+ @headers = {
40
+ 'Content-type' => 'application/json',
41
+ 'X-Requested-With' => 'WrapSplash'
42
+ }
43
+
44
+ if options[:bearer_token]
45
+ @headers['Authorization'] = "Bearer #{options[:bearer_token]}"
46
+ @headers['X-WrapSplash-Header'] = compute_hash(options[:bearer_token])
47
+ return
48
+ end
49
+
50
+ @access_key = options[:access_key] || raise(WrapSplashError, 'Access Key missing!')
51
+ @secret_key = options[:secret_key] || raise(WrapSplashError, 'Secret Key missing!')
52
+ @redirect_uri = options[:redirect_uri] || raise(WrapSplashError, 'Redirect URI missing!')
53
+ @code = options[:code] || raise(WrapSplashError, 'Authorization Code missing!')
54
+
55
+ @headers['Authorization'] = "Client-ID #{options[:access_key]}"
56
+ @headers['X-WrapSplash-Header'] = compute_hash(options[:access_key])
57
+ end
58
+
59
+ def generate_bearer_token
60
+ validate_required(@access_key, 'access_key')
61
+ validate_required(@secret_key, 'secret_key')
62
+ validate_required(@redirect_uri, 'redirect_uri')
63
+ validate_required(@code, 'code')
64
+
65
+ result = fetch_url(@bearer_token_url, 'POST', {}, {
66
+ client_id: @access_key,
67
+ client_secret: @secret_key,
68
+ redirect_uri: @redirect_uri,
69
+ code: @code,
70
+ grant_type: @grant_type
71
+ })
72
+
73
+ clear_credentials!
74
+
75
+ result
76
+ end
77
+
78
+ def get_current_user_profile
79
+ fetch_url(@api_location + UrlConfig::CURRENT_USER_PROFILE, 'GET')
80
+ end
81
+
82
+ def update_current_user_profile(username: nil, first_name: nil, last_name: nil, email: nil, url: nil,
83
+ location: nil, bio: nil, instagram_username: nil)
84
+ fetch_url(@api_location + UrlConfig::UPDATE_CURRENT_USER_PROFILE, 'PUT', {
85
+ username: username, first_name: first_name, last_name: last_name,
86
+ email: email, url: url, location: location, bio: bio,
87
+ instagram_username: instagram_username
88
+ })
89
+ end
90
+
91
+ def get_public_profile(username, width: nil, height: nil)
92
+ validate_required(username, 'username')
93
+ fetch_url(@api_location + UrlConfig::USERS_PUBLIC_PROFILE + username, 'GET', { w: width, h: height })
94
+ end
95
+
96
+ def get_user_portfolio(username)
97
+ validate_required(username, 'username')
98
+ fetch_url(@api_location + UrlConfig::USERS_PORTFOLIO.gsub(':username', username), 'GET')
99
+ end
100
+
101
+ def get_user_photos(username, page: 1, per_page: 10, stats: false, resolution: 'days', quantity: 30,
102
+ order_by: 'latest')
103
+ validate_required(username, 'username')
104
+ validate_supported_value(order_by, AVAILABLE_ORDERS, 'order_by')
105
+ fetch_url(@api_location + UrlConfig::USERS_PHOTOS.gsub(':username', username), 'GET', {
106
+ page: page, per_page: per_page, order_by: order_by,
107
+ stats: stats, resolution: resolution, quantity: quantity
108
+ })
109
+ end
110
+
111
+ def get_user_liked_photos(username, page: 1, per_page: 10, order_by: 'latest')
112
+ validate_required(username, 'username')
113
+ validate_supported_value(order_by, AVAILABLE_ORDERS, 'order_by')
114
+ fetch_url(@api_location + UrlConfig::USERS_LIKED_PHOTOS.gsub(':username', username), 'GET', {
115
+ page: page, per_page: per_page, order_by: order_by
116
+ })
117
+ end
118
+
119
+ def get_user_collections(username, page: 1, per_page: 10)
120
+ validate_required(username, 'username')
121
+ fetch_url(@api_location + UrlConfig::USERS_COLLECTIONS.gsub(':username', username), 'GET', {
122
+ page: page, per_page: per_page
123
+ })
124
+ end
125
+
126
+ def get_user_statistics(username, resolution: 'days', quantity: 30)
127
+ validate_required(username, 'username')
128
+ fetch_url(@api_location + UrlConfig::USERS_STATISTICS.gsub(':username', username), 'GET', {
129
+ resolution: resolution, quantity: quantity
130
+ })
131
+ end
132
+
133
+ def list_photos(page: 1, per_page: 10, order_by: 'latest')
134
+ validate_supported_value(order_by, AVAILABLE_ORDERS, 'order_by')
135
+ fetch_url(@api_location + UrlConfig::LIST_PHOTOS, 'GET', {
136
+ page: page, per_page: per_page, order_by: order_by
137
+ })
138
+ end
139
+
140
+ def list_curated_photos(page: 1, per_page: 10, order_by: 'latest')
141
+ validate_supported_value(order_by, AVAILABLE_ORDERS, 'order_by')
142
+ fetch_url(@api_location + UrlConfig::LIST_CURATED_PHOTOS, 'GET', {
143
+ page: page, per_page: per_page, order_by: order_by
144
+ })
145
+ end
146
+
147
+ def get_a_photo(id, width: nil, height: nil, rect: nil)
148
+ validate_required(id, 'id')
149
+ fetch_url(@api_location + UrlConfig::GET_A_PHOTO.gsub(':id', id), 'GET', {
150
+ w: width, h: height, rect: rect
151
+ })
152
+ end
153
+
154
+ alias get_photo get_a_photo
155
+
156
+ def get_a_random_photo(collections: nil, featured: false, username: nil, query: nil, width: nil, height: nil,
157
+ orientation: 'landscape', count: 1)
158
+ validate_supported_value(orientation, AVAILABLE_ORIENTATIONS, 'orientation')
159
+ fetch_url(@api_location + UrlConfig::GET_A_RANDOM_PHOTO, 'GET', {
160
+ collections: collections&.to_s, featured: featured, username: username,
161
+ query: query, width: width, height: height, orientation: orientation, count: count
162
+ })
163
+ end
164
+
165
+ alias get_random_photo get_a_random_photo
166
+
167
+ def get_photo_statistics(id, resolution: 'days', quantity: 30)
168
+ validate_required(id, 'id')
169
+ fetch_url(@api_location + UrlConfig::GET_A_PHOTO_STATISTICS.gsub(':id', id), 'GET', {
170
+ resolution: resolution, quantity: quantity
171
+ })
172
+ end
173
+
174
+ def get_photo_link(id)
175
+ validate_required(id, 'id')
176
+ fetch_url(@api_location + UrlConfig::GET_A_PHOTO_DOWNLOAD_LINK.gsub(':id', id), 'GET')
177
+ end
178
+
179
+ def update_photo(id, location: {}, exif: {})
180
+ validate_required(id, 'id')
181
+ params = {}
182
+ params['location[latitude]'] = location[:latitude] if location[:latitude]
183
+ params['location[longitude]'] = location[:longitude] if location[:longitude]
184
+ params['location[name]'] = location[:name] if location[:name]
185
+ params['location[city]'] = location[:city] if location[:city]
186
+ params['location[country]'] = location[:country] if location[:country]
187
+ params['location[confidential]'] = location[:confidential] if location[:confidential]
188
+ params['exif[make]'] = exif[:make] if exif[:make]
189
+ params['exif[model]'] = exif[:model] if exif[:model]
190
+ params['exif[exposure_time]'] = exif[:exposure_time] if exif[:exposure_time]
191
+ params['exif[aperture_value]'] = exif[:aperture_value] if exif[:aperture_value]
192
+ params['exif[focal_length]'] = exif[:focal_length] if exif[:focal_length]
193
+ params['exif[iso_speed_ratings]'] = exif[:iso_speed_ratings] if exif[:iso_speed_ratings]
194
+ fetch_url(@api_location + UrlConfig::UPDATE_A_PHOTO.gsub(':id', id), 'PUT', params)
195
+ end
196
+
197
+ def like_photo(id)
198
+ validate_required(id, 'id')
199
+ fetch_url(@api_location + UrlConfig::LIKE_A_PHOTO.gsub(':id', id), 'POST')
200
+ end
201
+
202
+ def unlike_photo(id)
203
+ validate_required(id, 'id')
204
+ fetch_url(@api_location + UrlConfig::UNLIKE_A_PHOTO.gsub(':id', id), 'DELETE')
205
+ end
206
+
207
+ def search(query, page: 1, per_page: 10, collections: nil, orientation: nil)
208
+ validate_required(query, 'query')
209
+ validate_supported_value(orientation, AVAILABLE_ORIENTATIONS, 'orientation')
210
+ fetch_url(@api_location + UrlConfig::SEARCH_PHOTOS, 'GET', {
211
+ query: query, page: page, per_page: per_page,
212
+ collections: collections&.to_s, orientation: orientation
213
+ })
214
+ end
215
+
216
+ def search_collections(query, page: 1, per_page: 10)
217
+ validate_required(query, 'query')
218
+ fetch_url(@api_location + UrlConfig::SEARCH_COLLECTIONS, 'GET', {
219
+ query: query, page: page, per_page: per_page
220
+ })
221
+ end
222
+
223
+ def search_users(query, page: 1, per_page: 10)
224
+ validate_required(query, 'query')
225
+ fetch_url(@api_location + UrlConfig::SEARCH_USERS, 'GET', {
226
+ query: query, page: page, per_page: per_page
227
+ })
228
+ end
229
+
230
+ def get_stats_totals
231
+ fetch_url(@api_location + UrlConfig::STATS_TOTALS, 'GET')
232
+ end
233
+
234
+ def get_stats_month
235
+ fetch_url(@api_location + UrlConfig::STATS_MONTH, 'GET')
236
+ end
237
+
238
+ def list_collections(page: 1, per_page: 10)
239
+ fetch_url(@api_location + UrlConfig::LIST_COLLECTIONS, 'GET', {
240
+ page: page, per_page: per_page
241
+ })
242
+ end
243
+
244
+ def list_featured_collections(page: 1, per_page: 10)
245
+ fetch_url(@api_location + UrlConfig::LIST_FEATURED_COLLECTIONS, 'GET', {
246
+ page: page, per_page: per_page
247
+ })
248
+ end
249
+
250
+ def list_curated_collections(page: 1, per_page: 10)
251
+ fetch_url(@api_location + UrlConfig::LIST_CURATED_COLLECTIONS, 'GET', {
252
+ page: page, per_page: per_page
253
+ })
254
+ end
255
+
256
+ def get_collection(id)
257
+ validate_required(id, 'id')
258
+ fetch_url(@api_location + UrlConfig::GET_COLLECTION.gsub(':id', id), 'GET')
259
+ end
260
+
261
+ def get_curated_collection(id)
262
+ validate_required(id, 'id')
263
+ fetch_url(@api_location + UrlConfig::GET_CURATED_COLLECTION.gsub(':id', id), 'GET')
264
+ end
265
+
266
+ def get_collection_photos(id, page: 1, per_page: 10)
267
+ validate_required(id, 'id')
268
+ fetch_url(@api_location + UrlConfig::GET_COLLECTION_PHOTOS.gsub(':id', id), 'GET', {
269
+ page: page, per_page: per_page
270
+ })
271
+ end
272
+
273
+ def get_curated_collection_photos(id, page: 1, per_page: 10)
274
+ validate_required(id, 'id')
275
+ fetch_url(@api_location + UrlConfig::GET_CURATED_COLLECTION_PHOTOS.gsub(':id', id), 'GET', {
276
+ page: page, per_page: per_page
277
+ })
278
+ end
279
+
280
+ def list_related_collections(id)
281
+ validate_required(id, 'id')
282
+ fetch_url(@api_location + UrlConfig::LIST_RELATED_COLLECTION.gsub(':id', id), 'GET')
283
+ end
284
+
285
+ def create_new_collection(title, description: nil, private_collection: false)
286
+ validate_required(title, 'title')
287
+ fetch_url(@api_location + UrlConfig::CREATE_NEW_COLLECTION, 'POST', {
288
+ title: title, description: description, private: private_collection
289
+ })
290
+ end
291
+
292
+ alias create_collection create_new_collection
293
+
294
+ def update_existing_collection(id, title, description: nil, private_collection: false)
295
+ validate_required(id, 'id')
296
+ validate_required(title, 'title')
297
+ fetch_url(@api_location + UrlConfig::UPDATE_EXISTING_COLLECTION.gsub(':id', id), 'PUT', {
298
+ title: title, description: description, private: private_collection
299
+ })
300
+ end
301
+
302
+ alias update_collection update_existing_collection
303
+
304
+ def delete_collection(id)
305
+ validate_required(id, 'id')
306
+ fetch_url(@api_location + UrlConfig::DELETE_COLLECTION.gsub(':id', id), 'DELETE')
307
+ end
308
+
309
+ def add_photo_to_collection(collection_id, photo_id)
310
+ validate_required(collection_id, 'collection_id')
311
+ validate_required(photo_id, 'photo_id')
312
+ fetch_url(@api_location + UrlConfig::ADD_PHOTO_TO_COLLECTION.gsub(':collection_id', collection_id), 'POST', {
313
+ photo_id: photo_id
314
+ })
315
+ end
316
+
317
+ def remove_photo_from_collection(collection_id, photo_id)
318
+ validate_required(collection_id, 'collection_id')
319
+ validate_required(photo_id, 'photo_id')
320
+ url = UrlConfig::REMOVE_PHOTO_FROM_COLLECTION.gsub(':collection_id', collection_id)
321
+ fetch_url(@api_location + url, 'DELETE', { photo_id: photo_id })
322
+ end
323
+
324
+ private
325
+
326
+ def compute_hash(value)
327
+ Digest::SHA256.hexdigest(value)
328
+ end
329
+
330
+ def validate_required(value, field_name)
331
+ return if value && !value.to_s.empty?
332
+
333
+ message = case field_name
334
+ when 'id' then 'Parameter : id is required!'
335
+ when 'query' then 'Parameter : query is missing!'
336
+ else "Parameter : #{field_name} is required and cannot be empty!"
337
+ end
338
+ raise WrapSplashError, message
339
+ end
340
+
341
+ def validate_supported_value(value, allowed_values, field_name)
342
+ return if value.nil?
343
+ return if allowed_values.include?(value)
344
+
345
+ raise WrapSplashError, "Parameter : #{field_name} has an unsupported value!"
346
+ end
347
+
348
+ def build_query_parameters(params)
349
+ params.select { |_, v| !v.nil? && !v.to_s.empty? }
350
+ end
351
+
352
+ def fetch_url(url, method, query_parameters = {}, body = nil)
353
+ Concurrent::Promises.future do
354
+ http = HttpClient.new(
355
+ headers: @headers,
356
+ timeout: @timeout,
357
+ retries: @retries,
358
+ retry_delay_ms: @retry_delay_ms
359
+ )
360
+
361
+ response = http.make_request(url, method, query_parameters: build_query_parameters(query_parameters),
362
+ body: body)
363
+
364
+ if response.status == 204
365
+ { status: 204, status_text: response.status_text, message: 'Content Deleted' }
366
+ elsif response.status == 403
367
+ { status: 403, status_text: response.status_text, message: 'Rate Limit Exceeded' }
368
+ else
369
+ response.data
370
+ end
371
+ end.rescue do |e|
372
+ raise create_wrap_splash_error(e)
373
+ end
374
+ end
375
+
376
+ def create_wrap_splash_error(error)
377
+ return error if error.is_a?(WrapSplashError)
378
+
379
+ status_code = error.respond_to?(:response) && error.response&.dig(:status)
380
+ status_text = error.respond_to?(:response) && error.response&.dig(:status_text)
381
+
382
+ WrapSplashError.new(
383
+ get_error_message(error),
384
+ status_code: status_code,
385
+ status_text: status_text,
386
+ cause: error
387
+ )
388
+ end
389
+
390
+ def get_error_message(error)
391
+ return error.message if error.is_a?(StandardError)
392
+ return error if error.is_a?(String)
393
+
394
+ 'Request failed'
395
+ end
396
+
397
+ def clear_credentials!
398
+ @access_key = nil
399
+ @secret_key = nil
400
+ @redirect_uri = nil
401
+ @code = nil
402
+ end
403
+ end
404
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RbSplash
4
+ class WrapSplashError < StandardError
5
+ attr_reader :status_code, :status_text, :cause_error
6
+
7
+ def initialize(message, status_code: nil, status_text: nil, cause: nil)
8
+ super(message)
9
+ @status_code = status_code
10
+ @status_text = status_text
11
+ @cause_error = cause
12
+ end
13
+ end
14
+ end
data/lib/rb_splash.rb ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'rb_splash/version'
4
+ require_relative 'rb_splash/url_config'
5
+ require_relative 'rb_splash/wrap_splash_error'
6
+ require_relative 'rb_splash/response'
7
+ require_relative 'rb_splash/http_client'
8
+ require_relative 'rb_splash/wrap_splash_api'
9
+
10
+ module RbSplash
11
+ end