stew 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|