stew 0.5.1 → 0.5.2
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/README.md +3 -3
- data/lib/stew.rb +11 -8
- data/lib/stew/community/community_client.rb +53 -0
- data/lib/stew/community/xml_client/xml_client.rb +50 -0
- data/lib/stew/community/xml_client/xml_client_response_friends.rb +20 -0
- data/lib/stew/community/xml_client/xml_client_response_games.rb +20 -0
- data/lib/stew/community/xml_client/xml_client_response_profile.rb +14 -0
- data/lib/stew/store/store_client.rb +41 -0
- data/lib/stew/store/web_client.rb +31 -0
- data/lib/stew/version.rb +1 -1
- data/spec/fixtures/profiles/friends/76561197994486912.yml +5 -0
- data/spec/fixtures/profiles/games/76561197994486912.yml +5 -0
- data/spec/integration/store_integration_spec.rb +5 -21
- data/spec/lib/stew/community/community_client_spec.rb +118 -0
- data/spec/lib/stew/community/steam_id_spec.rb +2 -2
- data/spec/lib/stew/{xml_client_spec.rb → community/xml_client/xml_client_spec.rb} +4 -4
- data/spec/lib/stew/{store_client_spec.rb → store/store_client_spec.rb} +3 -3
- data/spec/lib/stew/{web_client_spec.rb → store/web_client_spec.rb} +2 -2
- metadata +23 -16
- data/lib/stew/community_client.rb +0 -42
- data/lib/stew/store_client.rb +0 -39
- data/lib/stew/web_client.rb +0 -30
- data/lib/stew/xml_client.rb +0 -49
- data/spec/lib/stew/community_client_spec.rb +0 -88
data/README.md
CHANGED
@@ -56,17 +56,17 @@ steam_id.friends.each {|friend| puts friend.profile.nickname}
|
|
56
56
|
|
57
57
|
##### From an App id
|
58
58
|
```ruby
|
59
|
-
app = Stew::StoreClient.new.create_app(220240)
|
59
|
+
app = Stew::Store::StoreClient.new.create_app(220240)
|
60
60
|
```
|
61
61
|
|
62
62
|
##### From a URL
|
63
63
|
```ruby
|
64
|
-
app = Stew::StoreClient.new.create_app("http://store.steampowered.com/app/220240/")
|
64
|
+
app = Stew::Store::StoreClient.new.create_app("http://store.steampowered.com/app/220240/")
|
65
65
|
```
|
66
66
|
|
67
67
|
##### From a URL with a region
|
68
68
|
```ruby
|
69
|
-
app = Stew::StoreClient.new.create_app("http://store.steampowered.com/app/220240/?cc=uk")
|
69
|
+
app = Stew::Store::StoreClient.new.create_app("http://store.steampowered.com/app/220240/?cc=uk")
|
70
70
|
```
|
71
71
|
|
72
72
|
All the examples above will create a Stew::Store::App instance for the game Far Cry 3. You can then access data like so:
|
data/lib/stew.rb
CHANGED
@@ -8,17 +8,20 @@ require 'money'
|
|
8
8
|
|
9
9
|
require "stew/version"
|
10
10
|
|
11
|
-
require 'stew/
|
12
|
-
require 'stew/xml_client'
|
13
|
-
require 'stew/
|
14
|
-
require 'stew/
|
11
|
+
require 'stew/community/xml_client/xml_client'
|
12
|
+
require 'stew/community/xml_client/xml_client_response_profile'
|
13
|
+
require 'stew/community/xml_client/xml_client_response_games'
|
14
|
+
require 'stew/community/xml_client/xml_client_response_friends'
|
15
15
|
|
16
|
+
require 'stew/community/community_client'
|
16
17
|
require 'stew/community/steam_id'
|
17
18
|
require 'stew/community/profile'
|
18
19
|
require 'stew/community/profile_friends'
|
19
20
|
require 'stew/community/profile_game'
|
20
21
|
require 'stew/community/profile_games'
|
21
22
|
|
23
|
+
require 'stew/store/web_client'
|
24
|
+
require 'stew/store/store_client'
|
22
25
|
require 'stew/store/app'
|
23
26
|
require 'stew/store/app_offers'
|
24
27
|
require 'stew/store/app_offer'
|
@@ -28,10 +31,10 @@ module Stew
|
|
28
31
|
Money.assume_from_symbol = true
|
29
32
|
|
30
33
|
@config = {
|
31
|
-
:default_community_client => CommunityClient,
|
32
|
-
:default_store_client => StoreClient,
|
33
|
-
:default_xml_client => XmlClient,
|
34
|
-
:default_web_client => WebClient,
|
34
|
+
:default_community_client => Community::CommunityClient,
|
35
|
+
:default_store_client => Store::StoreClient,
|
36
|
+
:default_xml_client => Community::XmlClient,
|
37
|
+
:default_web_client => Store::WebClient,
|
35
38
|
:default_region => :us
|
36
39
|
}
|
37
40
|
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Stew
|
2
|
+
module Community
|
3
|
+
# Creation of all profile* objects.
|
4
|
+
# Uses a given or default XmlClient instance to communicate with the Steam API
|
5
|
+
# The main identifier for most methods is the 64-bit steam id
|
6
|
+
# @example Create a Profile
|
7
|
+
# Stew::CommunityClient.new.profile(76561197992917668) #=> Stew::Community::Profile
|
8
|
+
#
|
9
|
+
# @example Resolve a Steam Vanity name
|
10
|
+
# Stew::CommunityClient.steam_id_from_vanity_name('eekon20') #=> 76561197986383225
|
11
|
+
#
|
12
|
+
class CommunityClient
|
13
|
+
COMMUNITY_URL = 'http://steamcommunity.com'
|
14
|
+
DEFAULT_BASE_PATH = 'profiles'
|
15
|
+
|
16
|
+
# @deprecated Use CommunityClient.new.steam_id_from_vanity_name instead
|
17
|
+
def self.steam_id_from_vanity_name(vanity_name)
|
18
|
+
self.new.steam_id_from_vanity_name(vanity_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(opts = {})
|
22
|
+
@xml_client = opts[:client] || Stew.config[:default_xml_client].new(COMMUNITY_URL)
|
23
|
+
@base_path = opts[:base_path] || DEFAULT_BASE_PATH
|
24
|
+
end
|
25
|
+
|
26
|
+
def steam_id_from_vanity_name(vanity_name)
|
27
|
+
response = XmlClientResponseProfile.new(@xml_client.get("/id/#{vanity_name}"))
|
28
|
+
response.profile['steamID64'].to_i
|
29
|
+
end
|
30
|
+
|
31
|
+
def profile(steam_id)
|
32
|
+
response = XmlClientResponseProfile.new(@xml_client.get(path(steam_id)))
|
33
|
+
Community::Profile.new(response.profile)
|
34
|
+
end
|
35
|
+
|
36
|
+
def profile_games(steam_id)
|
37
|
+
response = XmlClientResponseGames.new(@xml_client.get(path(steam_id,'games')))
|
38
|
+
Community::ProfileGames.new(response.games)
|
39
|
+
end
|
40
|
+
|
41
|
+
def profile_friends(steam_id)
|
42
|
+
response = XmlClientResponseFriends.new(@xml_client.get(path(steam_id,'friends')))
|
43
|
+
Community::ProfileFriends.new(response.friends)
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def path(steam_id,command=nil)
|
49
|
+
"/#{@base_path}/#{steam_id}/#{command}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Stew
|
2
|
+
module Community
|
3
|
+
# Client for accessing the steam community XML api
|
4
|
+
class XmlClient
|
5
|
+
def initialize(uri)
|
6
|
+
@connection = XmlClient.connection(uri)
|
7
|
+
end
|
8
|
+
|
9
|
+
# The Steam community is notorious for responding with error 503
|
10
|
+
# Retries up to 10 times for the same request to compensate for this
|
11
|
+
def get(path)
|
12
|
+
10.times do
|
13
|
+
response = request(path)
|
14
|
+
return XmlClient.parse_response(response.body) unless response.status == 503
|
15
|
+
sleep 0.5
|
16
|
+
end
|
17
|
+
raise ServiceUnavailableError
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def request(path)
|
23
|
+
@connection.get path do |req|
|
24
|
+
req.params['xml'] = 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.connection(uri)
|
29
|
+
Faraday.new uri do |conn|
|
30
|
+
conn.response :xml, :content_type => /\bxml$/
|
31
|
+
conn.request :retry
|
32
|
+
conn.use FaradayMiddleware::FollowRedirects
|
33
|
+
conn.adapter Faraday.default_adapter
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.parse_response(response)
|
38
|
+
raise(ObjectNotFoundError) if response.is_a?(String)
|
39
|
+
raise(ObjectNotFoundError, response['response']['error']) if response.has_key?('response')
|
40
|
+
response
|
41
|
+
end
|
42
|
+
|
43
|
+
# Raised when the Steam community API fails to respond after 10 tries
|
44
|
+
class ServiceUnavailableError < StandardError; end
|
45
|
+
|
46
|
+
# Raised when the reply is malformatted or if nothing is found
|
47
|
+
class ObjectNotFoundError < StandardError; end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Stew
|
2
|
+
module Community
|
3
|
+
# A friends response from the Xml Client
|
4
|
+
class XmlClientResponseFriends
|
5
|
+
def initialize(response)
|
6
|
+
@response = response
|
7
|
+
end
|
8
|
+
|
9
|
+
def friends
|
10
|
+
has_friends? ? @response['friendsList']['friends']['friend'] : []
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def has_friends?
|
16
|
+
!@response['friendsList']['friends'].nil?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Stew
|
2
|
+
module Community
|
3
|
+
# A games response from the Xml Client
|
4
|
+
class XmlClientResponseGames
|
5
|
+
def initialize(response)
|
6
|
+
@response = response
|
7
|
+
end
|
8
|
+
|
9
|
+
def games
|
10
|
+
has_games? ? @response['gamesList']['games']['game'] : []
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def has_games?
|
16
|
+
!@response['gamesList']['games'].nil?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Stew
|
2
|
+
module Store
|
3
|
+
# Creation of app objects from URLs or app_ids
|
4
|
+
#
|
5
|
+
# Can create apps for any steam region. When no region is given, it defaults to the default region in the configuration
|
6
|
+
#
|
7
|
+
# @example Creation of a Stew::Store::App from a URL
|
8
|
+
# Stew::StoreClient.new.create_app('http://store.steampowered.com/app/211420') #=> Stew::StoreClient::App
|
9
|
+
#
|
10
|
+
# @example Creation of a Stew::Store::App from an id
|
11
|
+
# Stew::StoreClient.new.create_app(211420) #=> Stew::StoreClient::App
|
12
|
+
#
|
13
|
+
# @example Creation of a Stew::Store::App from a URL with a different region
|
14
|
+
# Stew::StoreClient.new.create_app('http://store.steampowered.com/app/211420?cc=uk') #=> Stew::StoreClient::App
|
15
|
+
#
|
16
|
+
# @example Creation of a Stew::Store::App from an id and a region
|
17
|
+
# Stew::StoreClient.new.app(211420, :uk) #=> Stew::StoreClient::App
|
18
|
+
#
|
19
|
+
class StoreClient
|
20
|
+
STORE_URL = 'http://store.steampowered.com'
|
21
|
+
|
22
|
+
def initialize(opts = {})
|
23
|
+
@client = opts[:client] || Stew.config[:default_web_client].new(STORE_URL)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_app(data)
|
27
|
+
return app(data) if data.class == Fixnum
|
28
|
+
return app($1,$2) if data =~ /store.steampowered.com\/app\/([0-9]+)\/?\?cc=([a-zA-Z]{2})/
|
29
|
+
return app($1) if data =~ /store.steampowered.com\/app\/([0-9]+)/
|
30
|
+
raise AppIdNotFoundError
|
31
|
+
end
|
32
|
+
|
33
|
+
def app(app_id,region = Stew.config[:default_region])
|
34
|
+
Store::App.new(@client.get("/app/#{app_id}",:cc => region.to_sym))
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Error used when an app cannot be found
|
39
|
+
class AppIdNotFoundError < StandardError; end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Stew
|
2
|
+
module Store
|
3
|
+
# Client wrapper for performing requests to the Steam Store
|
4
|
+
class WebClient
|
5
|
+
def initialize(uri)
|
6
|
+
@connection = WebClient.connection(uri)
|
7
|
+
end
|
8
|
+
|
9
|
+
def get(path, options={})
|
10
|
+
request(path, options).body
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def request(path,options={})
|
16
|
+
@connection.get(path) do |request|
|
17
|
+
request.params = options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.connection(uri)
|
22
|
+
Faraday.new uri do |conn|
|
23
|
+
conn.headers[:cookie] = "birthtime=365842801"
|
24
|
+
conn.request :retry
|
25
|
+
conn.use FaradayMiddleware::FollowRedirects
|
26
|
+
conn.adapter Faraday.default_adapter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/stew/version.rb
CHANGED
@@ -4,7 +4,7 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe "Store", :vcr do
|
6
6
|
|
7
|
-
let(:store_client){Stew::StoreClient.new}
|
7
|
+
let(:store_client){Stew::Store::StoreClient.new}
|
8
8
|
subject{store_client.app(id)}
|
9
9
|
|
10
10
|
describe "Creation of a store app with data" do
|
@@ -15,7 +15,7 @@ describe "Store", :vcr do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
it "sets the score" do
|
18
|
-
subject.score.should
|
18
|
+
subject.score.should be_a(Integer)
|
19
19
|
end
|
20
20
|
|
21
21
|
it "sets the release date" do
|
@@ -62,7 +62,7 @@ describe "Store", :vcr do
|
|
62
62
|
end
|
63
63
|
|
64
64
|
it "has a base price" do
|
65
|
-
subject.price.should eq Money.parse("$59.99")
|
65
|
+
subject.price.currency.should eq Money.parse("$59.99").currency
|
66
66
|
end
|
67
67
|
|
68
68
|
describe "the basic offer" do
|
@@ -76,24 +76,8 @@ describe "Store", :vcr do
|
|
76
76
|
offer.description.should be_nil
|
77
77
|
end
|
78
78
|
|
79
|
-
it "has the correct
|
80
|
-
offer.price.should eq Money.parse("$59.99")
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
describe "the 4 pack" do
|
85
|
-
let(:offer){subject.offers.entries[1]}
|
86
|
-
|
87
|
-
it "has the correct name" do
|
88
|
-
offer.name.should eq 'Borderlands 2 - 4-Pack'
|
89
|
-
end
|
90
|
-
|
91
|
-
it "has the correct description" do
|
92
|
-
offer.description.should eq "Includes four copies of Borderlands 2 - Send the extra copies to your friends"
|
93
|
-
end
|
94
|
-
|
95
|
-
it "has the correct price" do
|
96
|
-
offer.price.should eq Money.parse("$179.99")
|
79
|
+
it "has the correct currency" do
|
80
|
+
offer.price.currency.should eq Money.parse("$59.99").currency
|
97
81
|
end
|
98
82
|
end
|
99
83
|
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Stew::CommunityClient" do
|
4
|
+
let(:client){double('xml_client')}
|
5
|
+
subject{Stew::Community::CommunityClient.new({:client => client})}
|
6
|
+
let(:id){76561197992917668}
|
7
|
+
|
8
|
+
describe "#steam_id_from_vanity_name" do
|
9
|
+
let(:vanity_name){"foobar"}
|
10
|
+
|
11
|
+
it "calls steam_id_from_vanity_name on a new instance" do
|
12
|
+
Stew::Community::CommunityClient.any_instance.should_receive(:steam_id_from_vanity_name).with(vanity_name)
|
13
|
+
Stew::Community::CommunityClient.steam_id_from_vanity_name(vanity_name)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
describe ".steam_id_from_vanity_name" do
|
19
|
+
let(:response){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
20
|
+
let(:name){"Somename"}
|
21
|
+
|
22
|
+
before :each do
|
23
|
+
client.should_receive(:get).with("/id/#{name}").and_return(response)
|
24
|
+
end
|
25
|
+
|
26
|
+
context "when the vanity name exists" do
|
27
|
+
it "returns the 64-bit id" do
|
28
|
+
subject.steam_id_from_vanity_name(name).should eq id
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "setting the base path" do
|
34
|
+
context "when the base path is not set" do
|
35
|
+
let(:results){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
36
|
+
|
37
|
+
it "should perform requests to the 'profile'" do
|
38
|
+
client.should_receive(:get).with("/profiles/#{id}/").and_return(results)
|
39
|
+
subject.profile(id)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when the base path is set to 'id'" do
|
44
|
+
let(:results){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
45
|
+
subject{Stew::Community::CommunityClient.new({:client => client, :base_path => 'id'})}
|
46
|
+
|
47
|
+
it "should perform profile-requests to the 'id'" do
|
48
|
+
client.should_receive(:get).with("/id/#{id}/").and_return(results)
|
49
|
+
subject.profile(id)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe ".profile" do
|
55
|
+
let(:results){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
56
|
+
|
57
|
+
it "sends the correct message to its client" do
|
58
|
+
client.should_receive(:get).with("/profiles/#{id}/").and_return(results)
|
59
|
+
subject.profile(id)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "creates a profile object" do
|
63
|
+
client.stub(:get).with("/profiles/#{id}/").and_return(results)
|
64
|
+
Stew::Community::Profile.should_receive(:new).with(results['profile'])
|
65
|
+
subject.profile(id)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe ".profile_games" do
|
70
|
+
let(:results){YAML.load_file("spec/fixtures/profiles/games/#{id}.yml")}
|
71
|
+
|
72
|
+
it "sends the correct message to its client" do
|
73
|
+
client.should_receive(:get).with("/profiles/#{id}/games").and_return(results)
|
74
|
+
subject.profile_games(id)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "creates a ProfileGames object" do
|
78
|
+
client.stub(:get).with("/profiles/#{id}/games").and_return(results)
|
79
|
+
Stew::Community::ProfileGames.should_receive(:new).with(results['gamesList']['games']['game'])
|
80
|
+
subject.profile_games(id)
|
81
|
+
end
|
82
|
+
|
83
|
+
context "when the profile has no games" do
|
84
|
+
let(:id){76561197994486912}
|
85
|
+
|
86
|
+
it "creates an empty ProfileGames instance if the profile has no games" do
|
87
|
+
client.stub(:get).with("/profiles/#{id}/games").and_return(results)
|
88
|
+
profile_games = subject.profile_games(id)
|
89
|
+
profile_games.entries.count.should eq 0
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe ".profile_friends" do
|
95
|
+
let(:results){YAML.load_file("spec/fixtures/profiles/friends/#{id}.yml")}
|
96
|
+
|
97
|
+
it "sends the correct message to its client" do
|
98
|
+
client.should_receive(:get).with("/profiles/#{id}/friends").and_return(results)
|
99
|
+
subject.profile_friends(id)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "creates a ProfileFriends object" do
|
103
|
+
client.stub(:get).with("/profiles/#{id}/friends").and_return(results)
|
104
|
+
Stew::Community::ProfileFriends.should_receive(:new).with(results['friendsList']['friends']['friend'])
|
105
|
+
subject.profile_friends(id)
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when the profile has no friends" do
|
109
|
+
let(:id){76561197994486912}
|
110
|
+
|
111
|
+
it "creates an empty ProfileFriends instance if the profile has no friends" do
|
112
|
+
client.stub(:get).with("/profiles/#{id}/friends").and_return(results)
|
113
|
+
profile_friends = subject.profile_friends(id)
|
114
|
+
profile_friends.entries.count.should eq 0
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -56,7 +56,7 @@ describe "Stew::Community::SteamId" do
|
|
56
56
|
end
|
57
57
|
|
58
58
|
it "should create a community client with no options" do
|
59
|
-
Stew::CommunityClient.should_receive(:new).with()
|
59
|
+
Stew::Community::CommunityClient.should_receive(:new).with()
|
60
60
|
Stew::Community::SteamId.new(id)
|
61
61
|
end
|
62
62
|
end
|
@@ -69,7 +69,7 @@ describe "Stew::Community::SteamId" do
|
|
69
69
|
end
|
70
70
|
|
71
71
|
it "should create a community client with the base_path option set to 'id'" do
|
72
|
-
Stew::CommunityClient.should_receive(:new).with({:base_path => 'id'})
|
72
|
+
Stew::Community::CommunityClient.should_receive(:new).with({:base_path => 'id'})
|
73
73
|
Stew::Community::SteamId.new(id)
|
74
74
|
end
|
75
75
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "Stew::XmlClient" do
|
3
|
+
describe "Stew::Community::XmlClient" do
|
4
4
|
let(:uri){'http://steamcommunity.com'}
|
5
5
|
let(:results){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
6
6
|
let(:id){76561197992917668}
|
7
7
|
|
8
|
-
subject{Stew::XmlClient.new(uri)}
|
8
|
+
subject{Stew::Community::XmlClient.new(uri)}
|
9
9
|
|
10
10
|
describe "#get" do
|
11
11
|
context "when no error is found in the reply" do
|
@@ -15,7 +15,7 @@ describe "Stew::XmlClient" do
|
|
15
15
|
stub_request(:get, "http://steamcommunity.com/profiles/#{id}?xml=1").to_return(File.new("spec/fixtures/profiles/#{id}.txt"))
|
16
16
|
end
|
17
17
|
|
18
|
-
it "returns
|
18
|
+
it "returns the response" do
|
19
19
|
subject.get(path).should eq results
|
20
20
|
end
|
21
21
|
end
|
@@ -29,7 +29,7 @@ describe "Stew::XmlClient" do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it "throws an ObjectNotFound error" do
|
32
|
-
expect{subject.get(path).should}.to raise_error(Stew::XmlClient::ObjectNotFoundError)
|
32
|
+
expect{subject.get(path).should}.to raise_error(Stew::Community::XmlClient::ObjectNotFoundError)
|
33
33
|
end
|
34
34
|
end
|
35
35
|
end
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "Stew::StoreClient" do
|
3
|
+
describe "Stew::Store::StoreClient" do
|
4
4
|
let(:client){double('web_client')}
|
5
5
|
let(:response){open("spec/fixtures/store/apps/#{id}.txt")}
|
6
6
|
let(:region){:us}
|
7
|
-
subject{Stew::StoreClient.new({:client => client})}
|
7
|
+
subject{Stew::Store::StoreClient.new({:client => client})}
|
8
8
|
|
9
9
|
describe ".app" do
|
10
10
|
let(:id) {211420}
|
@@ -51,7 +51,7 @@ describe "Stew::StoreClient" do
|
|
51
51
|
let(:url){"sodijfsdf"}
|
52
52
|
|
53
53
|
it "raises a Stew::Store::AppIdNotFoundError" do
|
54
|
-
expect{subject.create_app(url)}.to raise_error(Stew::AppIdNotFoundError)
|
54
|
+
expect{subject.create_app(url)}.to raise_error(Stew::Store::AppIdNotFoundError)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe "Stew::WebClient", :vcr do
|
3
|
+
describe "Stew::Store::WebClient", :vcr do
|
4
4
|
let(:uri){'http://store.steampowered.com/'}
|
5
5
|
|
6
|
-
subject{Stew::WebClient.new(uri)}
|
6
|
+
subject{Stew::Store::WebClient.new(uri)}
|
7
7
|
|
8
8
|
describe ".get" do
|
9
9
|
let(:id){216390}
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stew
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2
|
5
5
|
prerelease:
|
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-02-
|
12
|
+
date: 2013-02-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -299,25 +299,30 @@ files:
|
|
299
299
|
- README.md
|
300
300
|
- Rakefile
|
301
301
|
- lib/stew.rb
|
302
|
+
- lib/stew/community/community_client.rb
|
302
303
|
- lib/stew/community/profile.rb
|
303
304
|
- lib/stew/community/profile_friends.rb
|
304
305
|
- lib/stew/community/profile_game.rb
|
305
306
|
- lib/stew/community/profile_games.rb
|
306
307
|
- lib/stew/community/steam_id.rb
|
307
|
-
- lib/stew/
|
308
|
+
- lib/stew/community/xml_client/xml_client.rb
|
309
|
+
- lib/stew/community/xml_client/xml_client_response_friends.rb
|
310
|
+
- lib/stew/community/xml_client/xml_client_response_games.rb
|
311
|
+
- lib/stew/community/xml_client/xml_client_response_profile.rb
|
308
312
|
- lib/stew/store/app.rb
|
309
313
|
- lib/stew/store/app_offer.rb
|
310
314
|
- lib/stew/store/app_offer_sale.rb
|
311
315
|
- lib/stew/store/app_offers.rb
|
312
|
-
- lib/stew/store_client.rb
|
316
|
+
- lib/stew/store/store_client.rb
|
317
|
+
- lib/stew/store/web_client.rb
|
313
318
|
- lib/stew/version.rb
|
314
|
-
- lib/stew/web_client.rb
|
315
|
-
- lib/stew/xml_client.rb
|
316
319
|
- spec/fixtures/profiles/4d.txt
|
317
320
|
- spec/fixtures/profiles/76561197992917668.txt
|
318
321
|
- spec/fixtures/profiles/76561197992917668.yml
|
319
322
|
- spec/fixtures/profiles/friends/76561197992917668.yml
|
323
|
+
- spec/fixtures/profiles/friends/76561197994486912.yml
|
320
324
|
- spec/fixtures/profiles/games/76561197992917668.yml
|
325
|
+
- spec/fixtures/profiles/games/76561197994486912.yml
|
321
326
|
- spec/fixtures/store/apps/16870.txt
|
322
327
|
- spec/fixtures/store/apps/211400_offers_sale.txt
|
323
328
|
- spec/fixtures/store/apps/211400_sale.txt
|
@@ -330,19 +335,19 @@ files:
|
|
330
335
|
- spec/fixtures/store/apps/no_app.txt
|
331
336
|
- spec/integration/community_integration_spec.rb
|
332
337
|
- spec/integration/store_integration_spec.rb
|
338
|
+
- spec/lib/stew/community/community_client_spec.rb
|
333
339
|
- spec/lib/stew/community/profile_friends_spec.rb
|
334
340
|
- spec/lib/stew/community/profile_game_spec.rb
|
335
341
|
- spec/lib/stew/community/profile_games_spec.rb
|
336
342
|
- spec/lib/stew/community/profile_spec.rb
|
337
343
|
- spec/lib/stew/community/steam_id_spec.rb
|
338
|
-
- spec/lib/stew/
|
344
|
+
- spec/lib/stew/community/xml_client/xml_client_spec.rb
|
339
345
|
- spec/lib/stew/store/app_offer_sale_spec.rb
|
340
346
|
- spec/lib/stew/store/app_offer_spec.rb
|
341
347
|
- spec/lib/stew/store/app_offers_spec.rb
|
342
348
|
- spec/lib/stew/store/app_spec.rb
|
343
|
-
- spec/lib/stew/store_client_spec.rb
|
344
|
-
- spec/lib/stew/web_client_spec.rb
|
345
|
-
- spec/lib/stew/xml_client_spec.rb
|
349
|
+
- spec/lib/stew/store/store_client_spec.rb
|
350
|
+
- spec/lib/stew/store/web_client_spec.rb
|
346
351
|
- spec/lib/stew_spec.rb
|
347
352
|
- spec/spec_helper.rb
|
348
353
|
- stew.gemspec
|
@@ -360,7 +365,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
360
365
|
version: '0'
|
361
366
|
segments:
|
362
367
|
- 0
|
363
|
-
hash: -
|
368
|
+
hash: -5319004060931315
|
364
369
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
365
370
|
none: false
|
366
371
|
requirements:
|
@@ -369,7 +374,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
369
374
|
version: '0'
|
370
375
|
segments:
|
371
376
|
- 0
|
372
|
-
hash: -
|
377
|
+
hash: -5319004060931315
|
373
378
|
requirements: []
|
374
379
|
rubyforge_project:
|
375
380
|
rubygems_version: 1.8.24
|
@@ -381,7 +386,9 @@ test_files:
|
|
381
386
|
- spec/fixtures/profiles/76561197992917668.txt
|
382
387
|
- spec/fixtures/profiles/76561197992917668.yml
|
383
388
|
- spec/fixtures/profiles/friends/76561197992917668.yml
|
389
|
+
- spec/fixtures/profiles/friends/76561197994486912.yml
|
384
390
|
- spec/fixtures/profiles/games/76561197992917668.yml
|
391
|
+
- spec/fixtures/profiles/games/76561197994486912.yml
|
385
392
|
- spec/fixtures/store/apps/16870.txt
|
386
393
|
- spec/fixtures/store/apps/211400_offers_sale.txt
|
387
394
|
- spec/fixtures/store/apps/211400_sale.txt
|
@@ -394,19 +401,19 @@ test_files:
|
|
394
401
|
- spec/fixtures/store/apps/no_app.txt
|
395
402
|
- spec/integration/community_integration_spec.rb
|
396
403
|
- spec/integration/store_integration_spec.rb
|
404
|
+
- spec/lib/stew/community/community_client_spec.rb
|
397
405
|
- spec/lib/stew/community/profile_friends_spec.rb
|
398
406
|
- spec/lib/stew/community/profile_game_spec.rb
|
399
407
|
- spec/lib/stew/community/profile_games_spec.rb
|
400
408
|
- spec/lib/stew/community/profile_spec.rb
|
401
409
|
- spec/lib/stew/community/steam_id_spec.rb
|
402
|
-
- spec/lib/stew/
|
410
|
+
- spec/lib/stew/community/xml_client/xml_client_spec.rb
|
403
411
|
- spec/lib/stew/store/app_offer_sale_spec.rb
|
404
412
|
- spec/lib/stew/store/app_offer_spec.rb
|
405
413
|
- spec/lib/stew/store/app_offers_spec.rb
|
406
414
|
- spec/lib/stew/store/app_spec.rb
|
407
|
-
- spec/lib/stew/store_client_spec.rb
|
408
|
-
- spec/lib/stew/web_client_spec.rb
|
409
|
-
- spec/lib/stew/xml_client_spec.rb
|
415
|
+
- spec/lib/stew/store/store_client_spec.rb
|
416
|
+
- spec/lib/stew/store/web_client_spec.rb
|
410
417
|
- spec/lib/stew_spec.rb
|
411
418
|
- spec/spec_helper.rb
|
412
419
|
has_rdoc:
|
@@ -1,42 +0,0 @@
|
|
1
|
-
module Stew
|
2
|
-
# Creation of all profile* objects.
|
3
|
-
# Uses a given or default XmlClient instance to communicate with the Steam API
|
4
|
-
# The main identifier for most methods is the 64-bit steam id
|
5
|
-
# @example Create a Profile
|
6
|
-
# Stew::CommunityClient.new.profile(76561197992917668) #=> Stew::Community::Profile
|
7
|
-
#
|
8
|
-
# @example Resolve a Steam Vanity name
|
9
|
-
# Stew::CommunityClient.steam_id_from_vanity_name('eekon20') #=> 76561197986383225
|
10
|
-
#
|
11
|
-
class CommunityClient
|
12
|
-
COMMUNITY_URL = 'http://steamcommunity.com'
|
13
|
-
DEFAULT_BASE_PATH = 'profiles'
|
14
|
-
|
15
|
-
def self.steam_id_from_vanity_name(vanity_name)
|
16
|
-
Stew::XmlClient.new(COMMUNITY_URL).get("/id/#{vanity_name}")['profile']['steamID64'].to_i
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(opts = {})
|
20
|
-
@xml_client = opts[:client] || Stew.config[:default_xml_client].new(COMMUNITY_URL)
|
21
|
-
@base_path = opts[:base_path] || DEFAULT_BASE_PATH
|
22
|
-
end
|
23
|
-
|
24
|
-
def profile(steam_id)
|
25
|
-
Community::Profile.new @xml_client.get(path(steam_id))['profile']
|
26
|
-
end
|
27
|
-
|
28
|
-
def profile_games(steam_id)
|
29
|
-
Community::ProfileGames.new @xml_client.get(path(steam_id,'games'))['gamesList']['games']['game']
|
30
|
-
end
|
31
|
-
|
32
|
-
def profile_friends(steam_id)
|
33
|
-
Community::ProfileFriends.new @xml_client.get(path(steam_id,'friends'))['friendsList']['friends']['friend']
|
34
|
-
end
|
35
|
-
|
36
|
-
private
|
37
|
-
|
38
|
-
def path(steam_id,command=nil)
|
39
|
-
"/#{@base_path}/#{steam_id}/#{command}"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/lib/stew/store_client.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
module Stew
|
2
|
-
# Creation of app objects from URLs or app_ids
|
3
|
-
#
|
4
|
-
# Can create apps for any steam region. When no region is given, it defaults to the default region in the configuration
|
5
|
-
#
|
6
|
-
# @example Creation of a Stew::Store::App from a URL
|
7
|
-
# Stew::StoreClient.new.create_app('http://store.steampowered.com/app/211420') #=> Stew::StoreClient::App
|
8
|
-
#
|
9
|
-
# @example Creation of a Stew::Store::App from an id
|
10
|
-
# Stew::StoreClient.new.create_app(211420) #=> Stew::StoreClient::App
|
11
|
-
#
|
12
|
-
# @example Creation of a Stew::Store::App from a URL with a different region
|
13
|
-
# Stew::StoreClient.new.create_app('http://store.steampowered.com/app/211420?cc=uk') #=> Stew::StoreClient::App
|
14
|
-
#
|
15
|
-
# @example Creation of a Stew::Store::App from an id and a region
|
16
|
-
# Stew::StoreClient.new.app(211420, :uk) #=> Stew::StoreClient::App
|
17
|
-
#
|
18
|
-
class StoreClient
|
19
|
-
STORE_URL = 'http://store.steampowered.com'
|
20
|
-
|
21
|
-
def initialize(opts = {})
|
22
|
-
@client = opts[:client] || Stew.config[:default_web_client].new(STORE_URL)
|
23
|
-
end
|
24
|
-
|
25
|
-
def create_app(data)
|
26
|
-
return app(data) if data.class == Fixnum
|
27
|
-
return app($1,$2) if data =~ /store.steampowered.com\/app\/([0-9]+)\/?\?cc=([a-zA-Z]{2})/
|
28
|
-
return app($1) if data =~ /store.steampowered.com\/app\/([0-9]+)/
|
29
|
-
raise AppIdNotFoundError
|
30
|
-
end
|
31
|
-
|
32
|
-
def app(app_id,region = Stew.config[:default_region])
|
33
|
-
Store::App.new(@client.get("/app/#{app_id}",:cc => region.to_sym))
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# Error used when an app cannot be found
|
38
|
-
class AppIdNotFoundError < StandardError; end
|
39
|
-
end
|
data/lib/stew/web_client.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
module Stew
|
2
|
-
|
3
|
-
# Client wrapper for performing requests to the Steam Store
|
4
|
-
class WebClient
|
5
|
-
def initialize(uri)
|
6
|
-
@connection = WebClient.connection(uri)
|
7
|
-
end
|
8
|
-
|
9
|
-
def get(path, options={})
|
10
|
-
request(path, options).body
|
11
|
-
end
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def request(path,options={})
|
16
|
-
@connection.get(path) do |request|
|
17
|
-
request.params = options
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.connection(uri)
|
22
|
-
Faraday.new uri do |conn|
|
23
|
-
conn.headers[:cookie] = "birthtime=365842801"
|
24
|
-
conn.request :retry
|
25
|
-
conn.use FaradayMiddleware::FollowRedirects
|
26
|
-
conn.adapter Faraday.default_adapter
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
data/lib/stew/xml_client.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
module Stew
|
2
|
-
|
3
|
-
# Client for accessing the steam community XML api
|
4
|
-
class XmlClient
|
5
|
-
def initialize(uri)
|
6
|
-
@connection = XmlClient.connection(uri)
|
7
|
-
end
|
8
|
-
|
9
|
-
# The Steam community is notorious for responding with error 503
|
10
|
-
# Retries up to 10 times for the same request to compensate for this
|
11
|
-
def get(path)
|
12
|
-
10.times do
|
13
|
-
response = request(path)
|
14
|
-
return XmlClient.parse_response(response.body) unless response.status == 503
|
15
|
-
sleep 0.5
|
16
|
-
end
|
17
|
-
raise ServiceUnavailableError
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def request(path)
|
23
|
-
@connection.get path do |req|
|
24
|
-
req.params['xml'] = 1
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.connection(uri)
|
29
|
-
Faraday.new uri do |conn|
|
30
|
-
conn.response :xml, :content_type => /\bxml$/
|
31
|
-
conn.request :retry
|
32
|
-
conn.use FaradayMiddleware::FollowRedirects
|
33
|
-
conn.adapter Faraday.default_adapter
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.parse_response(response)
|
38
|
-
raise(ObjectNotFoundError) if response.is_a?(String)
|
39
|
-
raise(ObjectNotFoundError, response['response']['error']) if response.has_key?('response')
|
40
|
-
response
|
41
|
-
end
|
42
|
-
|
43
|
-
# Raised when the Steam community API fails to respond after 10 tries
|
44
|
-
class ServiceUnavailableError < StandardError; end
|
45
|
-
|
46
|
-
# Raised when the reply is malformatted or if nothing is found
|
47
|
-
class ObjectNotFoundError < StandardError; end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Stew::CommunityClient" do
|
4
|
-
let(:client){double('xml_client')}
|
5
|
-
subject{Stew::CommunityClient.new({:client => client})}
|
6
|
-
let(:id){76561197992917668}
|
7
|
-
|
8
|
-
describe "#steam_id_from_vanity_name" do
|
9
|
-
let(:response){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
10
|
-
let(:name){"Somename"}
|
11
|
-
|
12
|
-
before :each do
|
13
|
-
Stew::XmlClient.any_instance.should_receive(:get).with("/id/#{name}").and_return(response)
|
14
|
-
end
|
15
|
-
|
16
|
-
context "when the vanity name exists" do
|
17
|
-
it "returns the 64-bit id" do
|
18
|
-
Stew::CommunityClient.steam_id_from_vanity_name(name).should eq id
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "setting the base path" do
|
24
|
-
context "when the base path is not set" do
|
25
|
-
let(:response){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
26
|
-
|
27
|
-
it "should perform requests to the 'profile'" do
|
28
|
-
client.should_receive(:get).with("/profiles/#{id}/").and_return(response)
|
29
|
-
subject.profile(id)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context "when the base path is set to 'id'" do
|
34
|
-
let(:response){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
35
|
-
subject{Stew::CommunityClient.new({:client => client, :base_path => 'id'})}
|
36
|
-
|
37
|
-
it "should perform profile-requests to the 'id'" do
|
38
|
-
client.should_receive(:get).with("/id/#{id}/").and_return(response)
|
39
|
-
subject.profile(id)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe ".profile" do
|
45
|
-
let(:response){YAML.load_file("spec/fixtures/profiles/#{id}.yml")}
|
46
|
-
|
47
|
-
it "sends the correct message to its client" do
|
48
|
-
client.should_receive(:get).with("/profiles/#{id}/").and_return(response)
|
49
|
-
subject.profile(id)
|
50
|
-
end
|
51
|
-
|
52
|
-
it "creates a profile object" do
|
53
|
-
client.stub(:get).with("/profiles/#{id}/").and_return(response)
|
54
|
-
Stew::Community::Profile.should_receive(:new).with(response['profile'])
|
55
|
-
subject.profile(id)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
describe ".profile_games" do
|
60
|
-
let(:response){YAML.load_file("spec/fixtures/profiles/games/#{id}.yml")}
|
61
|
-
|
62
|
-
it "sends the correct message to its client" do
|
63
|
-
client.should_receive(:get).with("/profiles/#{id}/games").and_return(response)
|
64
|
-
subject.profile_games(id)
|
65
|
-
end
|
66
|
-
|
67
|
-
it "creates a ProfileGames object" do
|
68
|
-
client.stub(:get).with("/profiles/#{id}/games").and_return(response)
|
69
|
-
Stew::Community::ProfileGames.should_receive(:new).with(response['gamesList']['games']['game'])
|
70
|
-
subject.profile_games(id)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
describe ".profile_friends" do
|
75
|
-
let(:response){YAML.load_file("spec/fixtures/profiles/friends/#{id}.yml")}
|
76
|
-
|
77
|
-
it "sends the correct message to its client" do
|
78
|
-
client.should_receive(:get).with("/profiles/#{id}/friends").and_return(response)
|
79
|
-
subject.profile_friends(id)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "returns the value of the ['friendsList']['friends']['friend'] key from the response hash" do
|
83
|
-
client.stub(:get).with("/profiles/#{id}/friends").and_return(response)
|
84
|
-
Stew::Community::ProfileFriends.should_receive(:new).with(response['friendsList']['friends']['friend'])
|
85
|
-
subject.profile_friends(id)
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|