cloudsight 0.0.3 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 88263f76dbd9b938a6196193e5f9d2695ad28c29
4
- data.tar.gz: 195421c20284a46e5e8967026958f8a779a4e377
2
+ SHA256:
3
+ metadata.gz: 8b27c9ad341947fd8365b93eeca9202c44bc6997cc153171e45528e0a4f7553e
4
+ data.tar.gz: c4a7a7de5c7b9704925edbab211097e675802937ea3d71070ddd10624c54dfe9
5
5
  SHA512:
6
- metadata.gz: a0526368cef6a2cd9c8cfdb4b4c3f9ae99f1e7628198b051bce03dcbe1db6dbedc0570c606861bc7886983760310f362152fe77a07e77595c09c31e160b238f5
7
- data.tar.gz: 5f841aa7c29d5da09d398119a1af5402d780b3362b348dd6433ea5e2a47849812ec6c1ae1ee83f5e29e849ef9c23274abf8121510fbc985fb0baa9b88de462ad
6
+ metadata.gz: 575f5503cee38dfd89d8f58cae1a04ee9ba994d6b0dd03f7ebdf9ee917e8c3923a40c66ffd4ceb7b6221dc4cef6bf4cc5645c14d0f2c5efab8011454418d1ed5
7
+ data.tar.gz: 439fb02ed6c5164ca146d76150832729c348260337b918205bcb753fa1220aa0fbc3f9ed9652baf596f2fc35918caf5ab1d966215d7d88078b6af7507a87ad41
@@ -0,0 +1,35 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ Gemfile.lock
30
+ .ruby-version
31
+ .ruby-gemset
32
+ .rspec_status
33
+
34
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
35
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
@@ -0,0 +1 @@
1
+ ruby 2.7.1
@@ -0,0 +1,20 @@
1
+ language: ruby
2
+ cache: bundler
3
+
4
+ script:
5
+ - bundle exec rspec
6
+
7
+ branches:
8
+ only:
9
+ - master
10
+
11
+ before_install:
12
+ - gem update --system
13
+ - gem update bundler
14
+
15
+ rvm:
16
+ - 2.3.0
17
+ - 2.4.0
18
+ - 2.5.0
19
+ - 2.6.0
20
+ - 2.7.0
data/README.md CHANGED
@@ -5,8 +5,8 @@ A simple CloudSight API Client
5
5
 
6
6
  | Project | Gem Release |
7
7
  |------------------------ | ----------------- |
8
- | gem name | gem-release |
9
- | version | [![Gem Version](https://badge.fury.io/rb/gem-release.png)](http://badge.fury.io/rb/gem-release) |
8
+ | gem name | cloudsight |
9
+ | version | [![Gem Version](https://badge.fury.io/rb/cloudsight.svg)](https://badge.fury.io/rb/cloudsight)
10
10
  | continuous integration | [![Build Status](https://secure.travis-ci.org/cloudsight/cloudsight-ruby.png?branch=master)](https://travis-ci.org/cloudsight/cloudsight-ruby) |
11
11
 
12
12
  Installation
@@ -51,25 +51,25 @@ Usage
51
51
  Send the image request using a file:
52
52
 
53
53
  ```ruby
54
- requestData = Cloudsight::Request.send(locale: 'en', file: File.open('image.jpg'))
54
+ request_data = Cloudsight::Request.send(locale: 'en', file: File.open('image.jpg'))
55
55
  ```
56
56
 
57
57
  Or, you can send the image request using a URL:
58
58
 
59
59
  ```ruby
60
- requestData = Cloudsight::Request.send(locale: 'en', url: 'http://www.google.com/images/srpr/logo11w.png')
60
+ request_data = Cloudsight::Request.send(locale: 'en', url: 'http://www.google.com/images/srpr/logo11w.png')
61
61
  ```
62
62
 
63
63
  Then, use the token to retrieve the response:
64
64
 
65
65
  ```ruby
66
- responseData = Cloudsight::Response.get(requestData['token'])
66
+ response_data = Cloudsight::Response.get(request_data['token'])
67
67
  ```
68
68
 
69
69
  You can also use the `retrieve` method which will poll for the response for you:
70
70
 
71
71
  ```ruby
72
- Cloudsight::Response.retrieve(requestData['token']) do |responseData|
73
- p responseData
72
+ Cloudsight::Response.retrieve(request_data['token']) do |response_data|
73
+ p response_data
74
74
  end
75
75
  ```
@@ -0,0 +1,13 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |t|
7
+ t.fail_on_error = false
8
+ end
9
+
10
+ task :default => :spec
11
+ rescue LoadError
12
+ # no rspec available
13
+ end
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "cloudsight"
5
+ require "pry"
6
+
7
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -6,30 +6,29 @@ require 'cloudsight/version'
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'cloudsight'
8
8
  s.version = Cloudsight::VERSION
9
- s.date = '2015-11-05'
10
9
  s.summary = "CloudSight API Client"
11
10
  s.description = "A simple CloudSight API Client for Image Recognition"
12
- s.authors = ['Brad Folkens']
13
- s.email = 'brad@cloudsightapi.com'
11
+ s.authors = ['Brad Folkens', 'Jack McCallum', 'Chris Weilemann']
12
+ s.email = 'oss@cloudsight.ai'
14
13
  s.homepage = 'http://github.com/cloudsight/cloudsight-ruby'
15
14
  s.license = 'MIT'
16
15
  s.platform = Gem::Platform::RUBY
17
16
 
18
- s.files = [
19
- 'lib/cloudsight.rb',
20
- 'Gemfile',
21
- 'Gemfile.lock',
22
- 'MIT-LICENSE',
23
- 'README.md',
24
- 'cloudsight.gemspec'
25
- ]
17
+ s.files = `git ls-files`.split($/)
18
+ s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
19
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
+
26
21
  s.require_paths = [%q{lib}]
27
22
 
28
- s.required_ruby_version = Gem::Requirement.new('>= 1.9.1')
23
+ s.required_ruby_version = Gem::Requirement.new('>= 2.1')
29
24
 
30
- s.add_dependency 'json'
31
- s.add_dependency 'rest-client', '~>1.6'
25
+ s.add_dependency 'json', '~> 2.1'
26
+ s.add_dependency 'rest-client', '~> 2.0'
32
27
 
33
- s.add_development_dependency 'bundler', '~> 1.6'
34
- s.add_development_dependency 'rake'
28
+ s.add_development_dependency 'bundler', '~> 2.0'
29
+ s.add_development_dependency 'rake', '~> 12.0'
30
+ s.add_development_dependency 'rspec', '~> 3.6'
31
+ s.add_development_dependency 'pry', '~> 0.10'
32
+ s.add_development_dependency 'webmock', '~> 3.0'
33
+ s.add_development_dependency 'simple_oauth', '~> 0.3'
35
34
  end
@@ -1,139 +1,37 @@
1
1
  require 'rubygems'
2
2
  require 'rest-client'
3
3
  begin
4
- require 'simple_oauth'
5
- rescue LoadError => err
6
- # Tolerate not having this unless it's actually configured
4
+ require 'simple_oauth'
5
+ rescue LoadError
6
+ # Tolerate not having this unless it's actually configured
7
7
  end
8
8
  require 'json'
9
9
 
10
10
  module Cloudsight
11
- BASE_URL = 'https://api.cloudsight.ai'
11
+ BASE_URL = 'https://api.cloudsight.ai'
12
12
 
13
- class << self
14
- def oauth_options=(val)
15
- raise RuntimeError.new("Could not load the simple_oauth gem. Install it with `gem install simple_oauth`.") unless defined?(SimpleOAuth::Header)
13
+ class << self
14
+ FIELDS = %w(api_key oauth_options base_url)
15
+ attr_accessor(*FIELDS)
16
16
 
17
- val = val.inject({}) {|memo, (k, v)| memo[k.to_sym] = v; memo }
18
- @@oauth_options = val
19
- end
17
+ def oauth_options=(val)
18
+ raise RuntimeError.new(
19
+ "Could not load the simple_oauth gem. Install it with `gem install simple_oauth`."
20
+ ) unless defined?(SimpleOAuth::Header)
20
21
 
21
- def api_key=(val)
22
- @@api_key = val
23
- RestClient.add_before_execution_proc do |req, params|
24
- req.add_field 'Authorization', "CloudSight #{val}"
25
- end
26
- end
22
+ val = val.inject({}) {|memo, (k, v)| memo[k.to_sym] = v; memo }
23
+ @oauth_options = val
24
+ end
27
25
 
28
- def api_key
29
- @@api_key if defined?(@@api_key)
30
- end
26
+ def base_url
27
+ @base_url ||= BASE_URL
28
+ end
29
+ end
31
30
 
32
- def oauth_options
33
- @@oauth_options if defined?(@@oauth_options)
34
- end
31
+ require 'cloudsight/api'
32
+ require 'cloudsight/request'
33
+ require 'cloudsight/response'
35
34
 
36
- def base_url=(val)
37
- @@base_url = val
38
- end
39
-
40
- def base_url
41
- @@base_url ||= BASE_URL
42
- end
43
- end
44
-
45
- class Util
46
- def self.wrap_request &block
47
- RestClient.reset_before_execution_procs
48
- RestClient.add_before_execution_proc do |req, params|
49
- if params[:payload]
50
- filtered_payload = params[:payload].dup
51
- filtered_payload.delete('image_request[image]')
52
- end
53
-
54
- oauth = SimpleOAuth::Header.new(params[:method], params[:url], filtered_payload, Cloudsight.oauth_options || {})
55
- req.add_field 'Authorization', oauth.to_s
56
- end
57
-
58
- begin
59
- retval = yield
60
- rescue RestClient::Exception => e
61
- retval = e.response
62
- end
63
-
64
- RestClient.reset_before_execution_procs
65
-
66
- return retval
67
- end
68
- end
69
-
70
- class Request
71
- def self.send(options = {})
72
- raise RuntimeError.new("Need to define either oauth_options or api_key") unless Cloudsight.api_key || Cloudsight.oauth_options
73
- url = "#{Cloudsight::base_url}/image_requests"
74
-
75
- params = {}
76
- [:locale, :language, :latitude, :longitude, :altitude, :device_id, :ttl].each do |attr|
77
- params["image_request[#{attr}]"] = options[attr] if options.has_key?(attr)
78
- end
79
-
80
- if options[:focus]
81
- params['focus[x]'] = options[:focus][:x]
82
- params['focus[y]'] = options[:focus][:y]
83
- end
84
-
85
- params['image_request[remote_image_url]'] = options[:url] if options.has_key?(:url)
86
- params['image_request[image]'] = options[:file] if options.has_key?(:file)
87
-
88
- response = Util.wrap_request { RestClient.post(url, params) }
89
- data = JSON.parse(response.body)
90
- raise ResponseException.new(data['error']) if data['error']
91
- raise UnexpectedResponseException.new(response.body) unless data['token']
92
-
93
- data
94
- end
95
-
96
- def self.repost(token, options = {})
97
- url = "#{Cloudsight::base_url}/image_requests/#{token}/repost"
98
-
99
- response = Util.wrap_request { RestClient.post(url, options) }
100
- return true if response.code == 200 and response.body.to_s.strip.empty?
101
-
102
- data = JSON.parse(response.body)
103
- raise ResponseException.new(data['error']) if data['error']
104
- raise UnexpectedResponseException.new(response.body) unless data['token']
105
-
106
- data
107
- end
108
- end
109
-
110
- class Response
111
- def self.get(token, options = {})
112
- url = "#{Cloudsight::base_url}/image_responses/#{token}"
113
-
114
- response = Util.wrap_request { RestClient.get(url) }
115
- data = JSON.parse(response.body)
116
- raise ResponseException.new(data['error']) if data['error']
117
- raise UnexpectedResponseException.new(response.body) unless data['status']
118
-
119
- data
120
- end
121
-
122
- def self.retrieve(token, options = {})
123
- options = { poll_wait: 1 }.merge(options)
124
-
125
- data = nil
126
- loop do
127
- sleep options[:poll_wait]
128
- data = Cloudsight::Response.get(token, options)
129
- yield data if block_given?
130
- break if data['status'] != 'not completed' and data['status'] != 'in progress'
131
- end
132
-
133
- data
134
- end
135
- end
136
-
137
- class ResponseException < Exception; end
138
- class UnexpectedResponseException < Exception; end
35
+ class ResponseException < Exception; end
36
+ class UnexpectedResponseException < Exception; end
139
37
  end
@@ -0,0 +1,32 @@
1
+ module Cloudsight
2
+ class Api
3
+ class << self
4
+ def post(url, params, headers = {})
5
+ headers['Authorization'] = authorization_header(:post, url, params)
6
+ RestClient.post(url, params, headers)
7
+ rescue RestClient::Exception => e
8
+ e.response
9
+ end
10
+
11
+ def get(url, headers = {})
12
+ headers['Authorization'] = authorization_header(:get, url)
13
+ RestClient.get(url, headers)
14
+ rescue RestClient::Exception => e
15
+ e.response
16
+ end
17
+
18
+ def authorization_header(http_method, url, params = {})
19
+ if Cloudsight.api_key
20
+ "CloudSight #{Cloudsight.api_key}"
21
+ else
22
+ # Exclude image file when generating OAuth header
23
+ filtered_payload = params.dup
24
+ filtered_payload.delete('image_request[image]')
25
+
26
+ oauth = SimpleOAuth::Header.new(http_method, url, filtered_payload, Cloudsight.oauth_options || {})
27
+ oauth.to_s
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ module Cloudsight
2
+ class Request
3
+ class << self
4
+ def send(options = {})
5
+ raise RuntimeError.new("Need to define either oauth_options or api_key") unless Cloudsight.api_key || Cloudsight.oauth_options
6
+ url = "#{Cloudsight::base_url}/v1/images"
7
+
8
+ params = construct_params(options)
9
+ response = Api.post(url, params)
10
+ data = JSON.parse(response.body)
11
+ raise ResponseException.new(data['error']) if data['error']
12
+ raise UnexpectedResponseException.new(response.body) unless data['token']
13
+
14
+ data
15
+
16
+ rescue JSON::ParserError
17
+ raise UnexpectedResponseException.new(response.body)
18
+ end
19
+
20
+ def repost(token, options = {})
21
+ url = "#{Cloudsight::base_url}/v1/images/#{token}/repost"
22
+
23
+ response = Api.post(url, options)
24
+ return true if response.code == 200 and response.body.to_s.strip.empty?
25
+
26
+ data = JSON.parse(response.body)
27
+ raise ResponseException.new(data['error']) if data['error']
28
+ raise UnexpectedResponseException.new(response.body) unless data['token']
29
+
30
+ data
31
+
32
+ rescue JSON::ParserError
33
+ raise UnexpectedResponseException.new(response.body)
34
+ end
35
+
36
+ def construct_params(options)
37
+ params = {}
38
+ [:locale, :language, :latitude, :longitude, :altitude, :device_id, :ttl, :focus_x, :focus_y].each do |attr|
39
+ params[attr.to_s] = options[attr] if options.has_key?(attr)
40
+ end
41
+
42
+ if options[:focus]
43
+ params['focus_x'] = options[:focus][:x]
44
+ params['focus_y'] = options[:focus][:y]
45
+ end
46
+
47
+ params['remote_image_url'] = options[:url] if options.has_key?(:url)
48
+ params['image'] = options[:file] if options.has_key?(:file)
49
+ params
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,33 @@
1
+ module Cloudsight
2
+ class Response
3
+ class << self
4
+ def get(token, options = {})
5
+ url = "#{Cloudsight::base_url}/v1/images/#{token}"
6
+
7
+ response = Api.get(url)
8
+ data = JSON.parse(response.body)
9
+ raise ResponseException.new(data['error']) if data['error']
10
+ raise UnexpectedResponseException.new(response.body) unless data['status']
11
+
12
+ data
13
+
14
+ rescue JSON::ParserError
15
+ raise UnexpectedResponseException.new(response.body)
16
+ end
17
+
18
+ def retrieve(token, options = {})
19
+ options = { poll_wait: 1 }.merge(options)
20
+
21
+ data = nil
22
+ loop do
23
+ sleep options[:poll_wait]
24
+ data = Cloudsight::Response.get(token, options)
25
+ yield data if block_given?
26
+ break if data['status'] != 'not completed' and data['status'] != 'in progress'
27
+ end
28
+
29
+ data
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module Cloudsight
2
+ VERSION = "0.1.1"
3
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+ require 'simple_oauth'
3
+
4
+ RSpec.describe Cloudsight::Api do
5
+
6
+ describe '#authorization_header' do
7
+ context 'with an api_key' do
8
+ it 'returns the proper header' do
9
+ Cloudsight.api_key = 'test_api_key'
10
+ header = described_class.authorization_header(:get, 'test')
11
+ expect(header).to eq 'CloudSight test_api_key'
12
+ end
13
+ end
14
+
15
+ context 'with simple oauth' do
16
+ it 'returns the proper header' do
17
+ Cloudsight.oauth_options = {
18
+ consumer_key: 'test_consumer_key',
19
+ consumer_secret: 'test_consumer_secret'
20
+ }
21
+
22
+ header = described_class.authorization_header(:get, 'https://example.com', { image_request: {} })
23
+ expect(header).to match(/OAuth oauth_consumer_key=/)
24
+ end
25
+ end
26
+ end
27
+
28
+ describe '#post' do
29
+ let(:url) { 'https://example.com' }
30
+
31
+ it 'should post with the correct params' do
32
+ allow(described_class).to receive(:authorization_header).and_return("CloudSight test_api_key")
33
+
34
+ expect(RestClient).to receive(:post).with(
35
+ url, {}, {"Authorization"=>"CloudSight test_api_key"}
36
+ )
37
+
38
+ described_class.post(url, {})
39
+ end
40
+
41
+ it 'should return the response if there is one' do
42
+ allow(described_class).to receive(:authorization_header).and_return("CloudSight test_api_key")
43
+
44
+ allow(RestClient).to receive(:post).with(
45
+ url, {}, {"Authorization"=>"CloudSight test_api_key"}
46
+ ).and_raise(RestClient::Exception)
47
+
48
+ expect { described_class.post(url, {}) }.to_not raise_error
49
+ end
50
+ end
51
+
52
+ describe '#get' do
53
+ let(:url) { 'https://example.com' }
54
+
55
+ it 'should post with the correct params' do
56
+ allow(described_class).to receive(:authorization_header).and_return("CloudSight test_api_key")
57
+
58
+ expect(RestClient).to receive(:get).with(
59
+ url, {"Authorization"=>"CloudSight test_api_key"}
60
+ )
61
+
62
+ described_class.get(url, {})
63
+ end
64
+
65
+ it 'should return the response if there is one' do
66
+ allow(described_class).to receive(:authorization_header).and_return("CloudSight test_api_key")
67
+
68
+ allow(RestClient).to receive(:get).with(
69
+ url, {"Authorization"=>"CloudSight test_api_key"}
70
+ ).and_raise(RestClient::Exception)
71
+
72
+ expect { described_class.get(url, {}) }.to_not raise_error
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Cloudsight::Request do
4
+
5
+ before(:each) do
6
+ Cloudsight.api_key = 'test_api_key'
7
+ end
8
+
9
+ describe '#construct_params' do
10
+ let(:params) do
11
+ {
12
+ locale: 'en',
13
+ language: 'en',
14
+ latitude: '5',
15
+ longitude: '5',
16
+ altitude: '5',
17
+ device_id: '5',
18
+ ttl: '5',
19
+ url: 'test_url',
20
+ file: 'test_file',
21
+ focus: {
22
+ x: '5',
23
+ y: '5'
24
+ }
25
+ }
26
+ end
27
+
28
+ it 'correctly constructs the params' do
29
+ options = described_class.construct_params(params)
30
+ expect(options).to eq(
31
+ {
32
+ 'locale' => 'en',
33
+ 'language' => 'en',
34
+ 'latitude' => '5',
35
+ 'longitude' => '5',
36
+ 'altitude' => '5',
37
+ 'device_id' => '5',
38
+ 'ttl' => '5',
39
+ 'remote_image_url' => 'test_url',
40
+ 'image' => 'test_file',
41
+ 'focus_x' => '5',
42
+ 'focus_y' => '5'
43
+ }
44
+ )
45
+ end
46
+ end
47
+
48
+ describe '#send' do
49
+ let(:params) { { locale: 'en', url: 'test_url' } }
50
+
51
+ it 'returns the proper result' do
52
+ stub_post(
53
+ path: '/v1/images',
54
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
55
+ response: fixture_file('image_request.json')
56
+ )
57
+
58
+ response = described_class.send(params)
59
+
60
+ expect(response["token"]).to eq "sample_token"
61
+ expect(response["url"]).to eq "https://example.com/image.jpg"
62
+ expect(response["status"]).to eq "not completed"
63
+ end
64
+
65
+ it 'responds correctly to a response exception error' do
66
+ stub_post(
67
+ path: '/v1/images',
68
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
69
+ response: fixture_file('error_response.json')
70
+ )
71
+
72
+ expect { described_class.send(params) }.to raise_error Cloudsight::ResponseException
73
+ end
74
+
75
+ it 'responds correctly to an unexpected response' do
76
+ stub_post(
77
+ path: '/v1/images',
78
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
79
+ response: fixture_file('unexpected_response.json')
80
+ )
81
+
82
+ expect { described_class.send(params) }.to raise_error Cloudsight::UnexpectedResponseException
83
+ end
84
+
85
+ it 'responds correctly to an invalid JSON response' do
86
+ stub_post(
87
+ path: '/v1/images',
88
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
89
+ response: fixture_file('invalid_json.json')
90
+ )
91
+
92
+ expect { described_class.send(params) }.to raise_error Cloudsight::UnexpectedResponseException
93
+ end
94
+ end
95
+
96
+ describe '#repost' do
97
+ let(:params) { { locale: 'en', remote_image_url: 'test_url' } }
98
+
99
+ it 'returns the proper result' do
100
+ stub_post(
101
+ path: '/v1/images/sample_token/repost',
102
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
103
+ response: fixture_file('image_request.json')
104
+ )
105
+
106
+ response = described_class.repost('sample_token', params)
107
+
108
+ expect(response["token"]).to eq "sample_token"
109
+ expect(response["url"]).to eq "https://example.com/image.jpg"
110
+ expect(response["status"]).to eq "not completed"
111
+ end
112
+
113
+ it 'responds correctly to a response exception error' do
114
+ stub_post(
115
+ path: '/v1/images/sample_token/repost',
116
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
117
+ response: fixture_file('error_response.json')
118
+ )
119
+
120
+ expect { described_class.repost('sample_token', params) }.to raise_error Cloudsight::ResponseException
121
+ end
122
+
123
+ it 'responds correctly to an unexpected response' do
124
+ stub_post(
125
+ path: '/v1/images/sample_token/repost',
126
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
127
+ response: fixture_file('unexpected_response.json')
128
+ )
129
+
130
+ expect { described_class.repost('sample_token', params) }.to raise_error Cloudsight::UnexpectedResponseException
131
+ end
132
+
133
+ it 'responds correctly to an invalid JSON response' do
134
+ stub_post(
135
+ path: '/v1/images/sample_token/repost',
136
+ body: { "locale" => "en", "remote_image_url" => "test_url" },
137
+ response: fixture_file('invalid_json.json')
138
+ )
139
+
140
+ expect { described_class.repost('sample_token', params) }.to raise_error Cloudsight::UnexpectedResponseException
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Cloudsight::Response do
4
+ before(:each) do
5
+ Cloudsight.api_key = 'test_api_key'
6
+ end
7
+
8
+ describe '#get' do
9
+ it 'returns the proper result' do
10
+ stub_get(
11
+ path: '/v1/images/sample_token',
12
+ response: fixture_file('completed_response.json')
13
+ )
14
+
15
+ response = described_class.get('sample_token')
16
+
17
+ expect(response["token"]).to eq "sample_token"
18
+ expect(response["url"]).to eq "http://www.example.com/your_headphones_image.jpg"
19
+ expect(response["status"]).to eq "completed"
20
+ end
21
+
22
+ it 'responds correctly to a response exception error' do
23
+ stub_get(
24
+ path: '/v1/images/sample_token',
25
+ response: fixture_file('error_response.json')
26
+ )
27
+
28
+ expect { described_class.get('sample_token') }.to raise_error Cloudsight::ResponseException
29
+ end
30
+
31
+ it 'responds correctly to an unexpected response' do
32
+ stub_get(
33
+ path: '/v1/images/sample_token',
34
+ response: fixture_file('unexpected_response.json')
35
+ )
36
+
37
+ expect { described_class.get('sample_token') }.to raise_error Cloudsight::UnexpectedResponseException
38
+ end
39
+
40
+ it 'responds correctly to an invalid JSON response' do
41
+ stub_get(
42
+ path: '/v1/images/sample_token',
43
+ response: fixture_file('invalid_json.json')
44
+ )
45
+
46
+ expect { described_class.get('sample_token') }.to raise_error Cloudsight::UnexpectedResponseException
47
+ end
48
+ end
49
+
50
+ describe '#retrieve' do
51
+ it 'returns the proper result' do
52
+ stub_polling(3, 'image_request.json', 'completed_response.json', '/v1/images/sample_token')
53
+
54
+ response = described_class.retrieve('sample_token', poll_wait: 0.01)
55
+
56
+ expect(response["token"]).to eq "sample_token"
57
+ expect(response["url"]).to eq "http://www.example.com/your_headphones_image.jpg"
58
+ expect(response["status"]).to eq "completed"
59
+ end
60
+
61
+ it 'responds correctly to a response exception error' do
62
+ stub_polling(3, 'image_request.json', 'error_response.json', '/v1/images/sample_token')
63
+
64
+ expect { described_class.retrieve('sample_token', poll_wait: 0.01) }.to raise_error Cloudsight::ResponseException
65
+ end
66
+
67
+ it 'responds correctly to an unexpected response' do
68
+ stub_polling(3, 'image_request.json', 'unexpected_response.json', '/v1/images/sample_token')
69
+
70
+ expect { described_class.retrieve('sample_token', poll_wait: 0.01) }.to raise_error Cloudsight::UnexpectedResponseException
71
+ end
72
+
73
+ it 'responds correctly to an invalid JSON response' do
74
+ stub_polling(3, 'image_request.json', 'invalid_json.json', '/v1/images/sample_token')
75
+
76
+ expect { described_class.retrieve('sample_token', poll_wait: 0.01) }.to raise_error Cloudsight::UnexpectedResponseException
77
+ end
78
+ end
79
+ end
80
+
81
+ def stub_polling(num_retries, file_1, file_2, path)
82
+ retries = 0
83
+ while retries < num_retries
84
+ stub_get(path: path, response: fixture_file(file_1))
85
+ retries += 1
86
+ end
87
+
88
+ stub_get(path: path, response: fixture_file(file_2))
89
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'simple_oauth'
3
+
4
+ RSpec.describe Cloudsight do
5
+ context 'initialization' do
6
+ it 'should assign the proper basic attributes' do
7
+ Cloudsight.api_key = 'test_api_key'
8
+ Cloudsight.base_url = 'test_base_url'
9
+
10
+ expect(Cloudsight.api_key) .to eq 'test_api_key'
11
+ expect(Cloudsight.base_url).to eq 'test_base_url'
12
+ end
13
+
14
+ it 'should configure the oauth_options correctly' do
15
+ Cloudsight.oauth_options = {
16
+ consumer_key: 'test_consumer_key',
17
+ consumer_secret: 'test_consumer_secret'
18
+ }
19
+
20
+ expect(Cloudsight.oauth_options[:consumer_key]).to eq 'test_consumer_key'
21
+ expect(Cloudsight.oauth_options[:consumer_secret]).to eq 'test_consumer_secret'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ {
2
+ "status" : "completed",
3
+ "name" : "red beats by dre headphones",
4
+ "flags" : [],
5
+ "ttl" : 60,
6
+ "url" : "http://www.example.com/your_headphones_image.jpg",
7
+ "token" : "sample_token"
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "status" : "completed",
3
+ "name" : "red beats by dre headphones",
4
+ "error": "test_error",
5
+ "flags" : [],
6
+ "ttl" : 60,
7
+ "url" : "http://www.example.com/your_headphones_image.jpg",
8
+ "token" : "sample_token"
9
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "token": "sample_token",
3
+ "url": "https://example.com/image.jpg",
4
+ "status": "not completed"
5
+ }
@@ -0,0 +1,9 @@
1
+ <html><head>
2
+ <meta http-equiv="content-type" content="text/html;charset=utf-8">
3
+ <title>502 Server Error</title>
4
+ </head>
5
+ <body text=#000000 bgcolor=#ffffff>
6
+ <h1>Error: Server Error</h1>
7
+ <h2>The server encountered a temporary error and could not complete your request.<p>Please try again in 30 seconds.</h2>
8
+ <h2></h2>
9
+ </body></html>
@@ -0,0 +1,6 @@
1
+ {
2
+ "name" : "red beats by dre headphones",
3
+ "flags" : [],
4
+ "ttl" : 60,
5
+ "url" : "http://www.example.com/your_headphones_image.jpg"
6
+ }
@@ -0,0 +1,55 @@
1
+ require 'bundler/setup'
2
+ require 'cloudsight'
3
+ require 'webmock/rspec'
4
+ require 'pry'
5
+
6
+ RSpec.configure do |config|
7
+ # Enable flags like --only-failures and --next-failure
8
+ config.example_status_persistence_file_path = ".rspec_status"
9
+
10
+ # Disable RSpec exposing methods globally on `Module` and `main`
11
+ config.disable_monkey_patching!
12
+
13
+ config.expect_with :rspec do |c|
14
+ c.syntax = :expect
15
+ end
16
+
17
+ config.after(:each) do
18
+ Cloudsight.api_key = nil
19
+ Cloudsight.oauth_options = {}
20
+ Cloudsight.base_url = nil
21
+ end
22
+
23
+ end
24
+
25
+ def stub_get(path:, response:, status: 200, message: nil)
26
+ stub_request(:get, Cloudsight::BASE_URL + path).to_return(
27
+ status: status,
28
+ body: response,
29
+ exception: message
30
+ )
31
+ end
32
+
33
+ def stub_post(path:, body: {}, response: {}, status: 200, message: nil)
34
+ stub_request(:post, Cloudsight::BASE_URL + path).with(
35
+ body: hash_including(body)
36
+ ).to_return(
37
+ status: status,
38
+ body: response,
39
+ exception: message
40
+ )
41
+ end
42
+
43
+ def fixture_file(filename, options={})
44
+ return '' if filename == ''
45
+ file_path = File.expand_path(File.dirname(__FILE__) + '/fixtures/' + filename)
46
+ fixture = File.read(file_path)
47
+
48
+ case File.extname(file_path)
49
+ when '.json'
50
+ options[:parse] ? JSON.parse(fixture) : fixture
51
+ else
52
+ fixture
53
+ end
54
+ end
55
+
metadata CHANGED
@@ -1,88 +1,168 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudsight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brad Folkens
8
- autorequire:
8
+ - Jack McCallum
9
+ - Chris Weilemann
10
+ autorequire:
9
11
  bindir: bin
10
12
  cert_chain: []
11
- date: 2015-11-05 00:00:00.000000000 Z
13
+ date: 2020-09-14 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: json
15
17
  requirement: !ruby/object:Gem::Requirement
16
18
  requirements:
17
- - - ">="
19
+ - - "~>"
18
20
  - !ruby/object:Gem::Version
19
- version: '0'
21
+ version: '2.1'
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
24
- - - ">="
26
+ - - "~>"
25
27
  - !ruby/object:Gem::Version
26
- version: '0'
28
+ version: '2.1'
27
29
  - !ruby/object:Gem::Dependency
28
30
  name: rest-client
29
31
  requirement: !ruby/object:Gem::Requirement
30
32
  requirements:
31
33
  - - "~>"
32
34
  - !ruby/object:Gem::Version
33
- version: '1.6'
35
+ version: '2.0'
34
36
  type: :runtime
35
37
  prerelease: false
36
38
  version_requirements: !ruby/object:Gem::Requirement
37
39
  requirements:
38
40
  - - "~>"
39
41
  - !ruby/object:Gem::Version
40
- version: '1.6'
42
+ version: '2.0'
41
43
  - !ruby/object:Gem::Dependency
42
44
  name: bundler
43
45
  requirement: !ruby/object:Gem::Requirement
44
46
  requirements:
45
47
  - - "~>"
46
48
  - !ruby/object:Gem::Version
47
- version: '1.6'
49
+ version: '2.0'
48
50
  type: :development
49
51
  prerelease: false
50
52
  version_requirements: !ruby/object:Gem::Requirement
51
53
  requirements:
52
54
  - - "~>"
53
55
  - !ruby/object:Gem::Version
54
- version: '1.6'
56
+ version: '2.0'
55
57
  - !ruby/object:Gem::Dependency
56
58
  name: rake
57
59
  requirement: !ruby/object:Gem::Requirement
58
60
  requirements:
59
- - - ">="
61
+ - - "~>"
62
+ - !ruby/object:Gem::Version
63
+ version: '12.0'
64
+ type: :development
65
+ prerelease: false
66
+ version_requirements: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - "~>"
69
+ - !ruby/object:Gem::Version
70
+ version: '12.0'
71
+ - !ruby/object:Gem::Dependency
72
+ name: rspec
73
+ requirement: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - "~>"
76
+ - !ruby/object:Gem::Version
77
+ version: '3.6'
78
+ type: :development
79
+ prerelease: false
80
+ version_requirements: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - "~>"
83
+ - !ruby/object:Gem::Version
84
+ version: '3.6'
85
+ - !ruby/object:Gem::Dependency
86
+ name: pry
87
+ requirement: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - "~>"
90
+ - !ruby/object:Gem::Version
91
+ version: '0.10'
92
+ type: :development
93
+ prerelease: false
94
+ version_requirements: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: '0.10'
99
+ - !ruby/object:Gem::Dependency
100
+ name: webmock
101
+ requirement: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - "~>"
60
104
  - !ruby/object:Gem::Version
61
- version: '0'
105
+ version: '3.0'
62
106
  type: :development
63
107
  prerelease: false
64
108
  version_requirements: !ruby/object:Gem::Requirement
65
109
  requirements:
66
- - - ">="
110
+ - - "~>"
111
+ - !ruby/object:Gem::Version
112
+ version: '3.0'
113
+ - !ruby/object:Gem::Dependency
114
+ name: simple_oauth
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: '0.3'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - "~>"
67
125
  - !ruby/object:Gem::Version
68
- version: '0'
126
+ version: '0.3'
69
127
  description: A simple CloudSight API Client for Image Recognition
70
- email: brad@cloudsightapi.com
71
- executables: []
128
+ email: oss@cloudsight.ai
129
+ executables:
130
+ - console
131
+ - setup
72
132
  extensions: []
73
133
  extra_rdoc_files: []
74
134
  files:
135
+ - ".gitignore"
136
+ - ".rspec"
137
+ - ".tool-versions"
138
+ - ".travis.yml"
75
139
  - Gemfile
76
- - Gemfile.lock
77
140
  - MIT-LICENSE
78
141
  - README.md
142
+ - Rakefile
143
+ - bin/console
144
+ - bin/setup
79
145
  - cloudsight.gemspec
80
146
  - lib/cloudsight.rb
147
+ - lib/cloudsight/api.rb
148
+ - lib/cloudsight/request.rb
149
+ - lib/cloudsight/response.rb
150
+ - lib/cloudsight/version.rb
151
+ - spec/cloudsight/api_spec.rb
152
+ - spec/cloudsight/request_spec.rb
153
+ - spec/cloudsight/response_spec.rb
154
+ - spec/cloudsight_spec.rb
155
+ - spec/fixtures/completed_response.json
156
+ - spec/fixtures/error_response.json
157
+ - spec/fixtures/image_request.json
158
+ - spec/fixtures/invalid_json.json
159
+ - spec/fixtures/unexpected_response.json
160
+ - spec/spec_helper.rb
81
161
  homepage: http://github.com/cloudsight/cloudsight-ruby
82
162
  licenses:
83
163
  - MIT
84
164
  metadata: {}
85
- post_install_message:
165
+ post_install_message:
86
166
  rdoc_options: []
87
167
  require_paths:
88
168
  - lib
@@ -90,16 +170,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
90
170
  requirements:
91
171
  - - ">="
92
172
  - !ruby/object:Gem::Version
93
- version: 1.9.1
173
+ version: '2.1'
94
174
  required_rubygems_version: !ruby/object:Gem::Requirement
95
175
  requirements:
96
176
  - - ">="
97
177
  - !ruby/object:Gem::Version
98
178
  version: '0'
99
179
  requirements: []
100
- rubyforge_project:
101
- rubygems_version: 2.4.8
102
- signing_key:
180
+ rubygems_version: 3.1.2
181
+ signing_key:
103
182
  specification_version: 4
104
183
  summary: CloudSight API Client
105
- test_files: []
184
+ test_files:
185
+ - spec/cloudsight/api_spec.rb
186
+ - spec/cloudsight/request_spec.rb
187
+ - spec/cloudsight/response_spec.rb
188
+ - spec/cloudsight_spec.rb
189
+ - spec/fixtures/completed_response.json
190
+ - spec/fixtures/error_response.json
191
+ - spec/fixtures/image_request.json
192
+ - spec/fixtures/invalid_json.json
193
+ - spec/fixtures/unexpected_response.json
194
+ - spec/spec_helper.rb
@@ -1,36 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- cloudsight (0.0.2)
5
- json
6
- rest-client (~> 1.6)
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- domain_name (0.5.20170404)
12
- unf (>= 0.0.5, < 1.0.0)
13
- http-cookie (1.0.3)
14
- domain_name (~> 0.5)
15
- json (2.1.0)
16
- mime-types (2.99.3)
17
- netrc (0.11.0)
18
- rake (12.0.0)
19
- rest-client (1.8.0)
20
- http-cookie (>= 1.0.2, < 2.0)
21
- mime-types (>= 1.16, < 3.0)
22
- netrc (~> 0.7)
23
- unf (0.1.4)
24
- unf_ext
25
- unf_ext (0.0.7.4)
26
-
27
- PLATFORMS
28
- ruby
29
-
30
- DEPENDENCIES
31
- bundler (~> 1.6)
32
- cloudsight!
33
- rake
34
-
35
- BUNDLED WITH
36
- 1.13.7