Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.

Commit 24389b1

Browse files
authored
Added Spotify::SDK with Initialization (#11)
* added active support * added files to exclude * updated spec * added initialization code * added initialization spec files * added tests for Spotify::SDK * fixed all rubocop errors * added oauth2_access_token method * added more tests for sdk spec * added to_hash method * added docs * fixes
1 parent 71903cd commit 24389b1

20 files changed

+391
-1
lines changed

SPEC.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,18 @@ Authorization: # For integrating OAuth.
1616
redirect_uri: ""
1717
})
1818
```
19+
20+
SDK: # For building amazing things.
21+
22+
Initialization accepts:
23+
- OAuth2::AccessToken instance
24+
- Plain Access Token
25+
- Query Hash containing access_token
26+
- Query String containing access_token
27+
- URL String containing a query or fragment containing access_token
28+
29+
Code sample:
30+
```
31+
sdk = Spotify::SDK.new(access_token)
32+
sdk.connect.devices
33+
```

lib/spotify.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# frozen_string_literal: true
22

3+
require "active_support"
4+
require "active_support/core_ext"
5+
36
require "spotify/version"
47
require "spotify/auth"
8+
require "spotify/sdk"
59

610
##
711
# The declaration for the Spotify namespace.

lib/spotify/auth.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def initialize(config)
7575
#
7676
# @param [Hash] override_params Optional hash containing any overriding values for parameters.
7777
# Parameters used are client_id, redirect_uri, response_type and scope.
78+
# @return [String] A fully qualified Spotify authorization URL to send the user to.
7879
#
7980
# @see https://developer.spotify.com/web-api/authorization-guide/
8081
#
@@ -92,6 +93,7 @@ def authorize_url(override_params={})
9293
# Validate initialization configuration and raise errors.
9394
#
9495
# @param [Hash] config OAuth configuration containing the Client ID, secret and redirect URL.
96+
# @return [nil]
9597
#
9698
def validate_initialized_input(config)
9799
raise Errors::AuthClientCredentialsError.new(OAUTH_I18N[:must_be_hash]) unless config.is_a?(Hash)

lib/spotify/sdk.rb

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# frozen_string_literal: true
2+
3+
require "spotify/sdk/initialization"
4+
5+
module Spotify
6+
##
7+
# Spotify::SDK contains the complete Ruby DSL to interact with the Spotify Platform.
8+
#
9+
class SDK
10+
##
11+
# Initialize the Spotify SDK object.
12+
#
13+
# @example
14+
# # Example 1: Load it in from an access token value.
15+
# @sdk = Spotify::SDK.new("access_token_here")
16+
#
17+
# # Example 2: Load it in with values from your database.
18+
# @sdk = Spotify::SDK.new({
19+
# access_token: "access_token_here",
20+
# expires_at: 3_000_000,
21+
# refresh_token: "refresh_token_here"
22+
# })
23+
#
24+
# # Example 4: Load it in from an OAuth2::AccessToken object.
25+
# @sdk = Spotify::SDK.new(@auth.auth_code.get_token("auth code"))
26+
#
27+
# # Example 5: Load it from a query string or a fully qualified URL.
28+
# @sdk = Spotify::SDK.new("https://localhost:8080/#token=...&expires_at=...")
29+
# @sdk = Spotify::SDK.new("token=...&expires_at=...")
30+
#
31+
# @param [String, Hash, OAuth2::AccessToken] obj Any supported object which contains an access token. See examples.
32+
#
33+
def initialize(obj)
34+
@payload = Spotify::SDK::Initialization.detect(obj)
35+
@access_token = @payload[:access_token]
36+
@expires_at = @payload[:expires_at]
37+
@refresh_token = @payload[:refresh_token]
38+
end
39+
40+
##
41+
# Helper method to a fully qualified OAuth2::AccessToken instance.
42+
#
43+
# @example
44+
# @auth = Spotify::Auth.new({
45+
# client_id: "[client id goes here]",
46+
# client_secret: "[client secret goes here]",
47+
# redirect_uri: "http://localhost"
48+
# })
49+
#
50+
# @sdk = Spotify::SDK.new("access_token_here")
51+
# @sdk.oauth2_access_token(@auth) # => #<OAuth2::AccessToken:...>
52+
#
53+
# @param [Spotify::Auth] client An instance of Spotify::Auth. See example.
54+
# @return [OAuth2::AccessToken] An fully qualified instance of OAuth2::AccessToken.
55+
#
56+
def oauth2_access_token(client)
57+
OAuth2::AccessToken.new(client, @access_token, expires_at: @expires_at,
58+
refresh_token: @refresh_token)
59+
end
60+
61+
##
62+
# Obtain a hash containing all of the user's authorization details.
63+
#
64+
# @example
65+
# @auth = Spotify::Auth.new({
66+
# client_id: "[client id goes here]",
67+
# client_secret: "[client secret goes here]",
68+
# redirect_uri: "http://localhost"
69+
# })
70+
#
71+
# @sdk = Spotify::SDK.new("access_token_here")
72+
# @sdk.to_hash # => { access_token: ..., expires_at: ... }
73+
#
74+
# @return [Hash] Containing access_token, expires_at and refresh_token
75+
#
76+
def to_hash
77+
@payload.with_indifferent_access.symbolize_keys
78+
end
79+
80+
attr_reader :access_token, :expires_at, :refresh_token
81+
end
82+
end

lib/spotify/sdk/initialization.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# frozen_string_literal: true
2+
3+
require "spotify/sdk/initialization/base"
4+
require "spotify/sdk/initialization/oauth_access_token"
5+
require "spotify/sdk/initialization/plain_string"
6+
require "spotify/sdk/initialization/query_hash"
7+
require "spotify/sdk/initialization/query_string"
8+
require "spotify/sdk/initialization/url_string"
9+
10+
module Spotify
11+
class SDK
12+
class Initialization
13+
CLASSES = %i[
14+
OAuthAccessToken
15+
QueryString
16+
URLString
17+
PlainString
18+
QueryHash
19+
].freeze
20+
21+
class << self
22+
def detect(subject)
23+
klasses = CLASSES.map do |klass_name|
24+
("Spotify::SDK::Initialization::%s" % klass_name).constantize.new(subject)
25+
end
26+
27+
matches = klasses.select(&:should_perform?)
28+
29+
case matches.size
30+
when 1
31+
matches.first.perform
32+
when 0
33+
raise Spotify::Errors::InitializationObjectInvalidError
34+
else
35+
raise Spotify::Errors::InitializationObjectDuplicationError
36+
end
37+
end
38+
end
39+
end
40+
end
41+
42+
class Errors
43+
##
44+
# A Error class for when the initialization subjectect is not valid (see `initialize(subject)` for more info).
45+
#
46+
class InitializationObjectInvalidError < StandardError; end
47+
48+
##
49+
# A Error class for when the initialization subjectect matches against multiple selectors.
50+
#
51+
class InitializationObjectDuplicationError < StandardError; end
52+
end
53+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# frozen_string_literal: true
2+
3+
module Spotify
4+
class SDK
5+
class Initialization
6+
class Base
7+
def initialize(subject)
8+
@subject = subject
9+
end
10+
11+
def should_perform?
12+
false
13+
end
14+
15+
def perform
16+
{
17+
access_token: nil,
18+
expires_at: nil,
19+
refresh_token: nil
20+
}
21+
end
22+
23+
attr_accessor :subject
24+
end
25+
end
26+
end
27+
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
module Spotify
4+
class SDK
5+
class Initialization
6+
class OAuthAccessToken < Base
7+
def should_perform?
8+
subject.is_a?(OAuth2::AccessToken)
9+
end
10+
11+
def perform
12+
{
13+
access_token: subject.token,
14+
expires_at: subject.expires_at,
15+
refresh_token: subject.refresh_token
16+
}
17+
end
18+
end
19+
end
20+
end
21+
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
module Spotify
4+
class SDK
5+
class Initialization
6+
class PlainString < Base
7+
def should_perform?
8+
subject.is_a?(String) && subject =~ /^[a-zA-Z0-9_-]+$/
9+
end
10+
11+
def perform
12+
{
13+
access_token: subject,
14+
expires_at: nil,
15+
refresh_token: nil
16+
}
17+
end
18+
end
19+
end
20+
end
21+
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
module Spotify
4+
class SDK
5+
class Initialization
6+
class QueryHash < Base
7+
def subject_hash
8+
subject.try(:with_indifferent_access) || {}
9+
end
10+
11+
def should_perform?
12+
subject_hash.has_key?(:access_token)
13+
end
14+
15+
def perform
16+
subject_hash.slice(:access_token, :expires_at, :refresh_token).symbolize_keys
17+
end
18+
end
19+
end
20+
end
21+
end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# frozen_string_literal: true
2+
3+
module Spotify
4+
class SDK
5+
class Initialization
6+
class QueryString < Base
7+
def params
8+
CGI.parse(subject).with_indifferent_access
9+
rescue NoMethodError
10+
{}
11+
end
12+
13+
def should_perform?
14+
subject.is_a?(String) && params.has_key?(:token)
15+
end
16+
17+
def perform
18+
{
19+
access_token: params[:token][0].presence,
20+
expires_at: params[:expires_at][0],
21+
refresh_token: params[:refresh_token][0]
22+
}
23+
end
24+
end
25+
end
26+
end
27+
end

0 commit comments

Comments
 (0)