gamercard 0.0.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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format nested
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create 1.9.3@gamercard_gem
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gamercard.gemspec
4
+ gemspec
5
+
6
+ # Guard & Devtools
7
+ gem 'guard', '~> 0.8.8'
8
+ # MacOS notifications:
9
+ gem 'rb-fsevent', :require => ('rb-fsevent' if RUBY_PLATFORM =~ /darwin/i)
10
+ gem 'growl', :require => ('growl' if RUBY_PLATFORM =~ /darwin/i)
11
+ gem 'guard-bundler'
12
+ gem 'guard-rspec'
@@ -0,0 +1,10 @@
1
+ guard 'bundler' do
2
+ watch('Gemfile')
3
+ watch(/^.+\.gemspec/)
4
+ end
5
+
6
+ guard 'rspec', :version => 2, :cli => '--color --format nested', :all_on_start => true, :all_after_pass => true do
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ watch(%r{^spec/.+_spec\.rb$})
9
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
10
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Matt Wilson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,134 @@
1
+ # Gamercard
2
+
3
+ Retrieves and parses an Xbox Live Gamercard for a player, providing a hash of the relevant data about the player or the raw HTML.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'gamercard'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install gamercard
18
+
19
+ ## Usage
20
+
21
+ Returns a hash suitable for JSON serialization.
22
+
23
+ ```ruby
24
+ resp = Gamercard.get('laikal1')
25
+ pp resp
26
+ # =>
27
+ {"gamertag"=>"laikal1",
28
+ "link"=>"http://live.xbox.com/en-US/Profile?Gamertag=laikal1",
29
+ "gamerpic"=>"http://avatar.xboxlive.com/avatar/laikal1/avatarpic-l.png",
30
+ "gamerscore"=>49646,
31
+ "location"=>"Ann Arbor, MI",
32
+ "motto"=>"Complexify!",
33
+ "name"=>"Nyarlathotep (1 bucket)",
34
+ "bio"=>"Design is how it works.",
35
+ "reputation"=>4.25,
36
+ "recent_games"=>
37
+ [{"comparison_url"=>
38
+ "http://live.xbox.com/en-US/Activity/Details?titleId=1161890110&compareTo=laikal1",
39
+ "image"=>
40
+ "http://tiles.xbox.com/tiles/9a/SL/0mdsb2JhbA9ECgQNGwEfV1wmL2ljb24vMC84MDAwIAAAAAAAAP2kpOo=.jpg",
41
+ "title"=>"KoA: Reckoning",
42
+ "last_played"=>"3/29/2012",
43
+ "earned_gamerscore"=>10,
44
+ "available_gamerscore"=>1300,
45
+ "earned_achievements"=>1,
46
+ "available_achievements"=>61,
47
+ "percentage_complete"=>"1%"},
48
+ {"comparison_url"=>
49
+ "http://live.xbox.com/en-US/Activity/Details?titleId=1161890141&compareTo=laikal1",
50
+ "image"=>
51
+ "http://tiles.xbox.com/tiles/np/G2/12dsb2JhbA9ECgQNGwEfV1onL2ljb24vMC84MDAwIAAAAAAAAPiZkYE=.jpg",
52
+ "title"=>"Mass Effect 3",
53
+ "last_played"=>"3/28/2012",
54
+ "earned_gamerscore"=>1025,
55
+ "available_gamerscore"=>1050,
56
+ "earned_achievements"=>51,
57
+ "available_achievements"=>52,
58
+ "percentage_complete"=>"98%"},
59
+ {"comparison_url"=>
60
+ "http://live.xbox.com/en-US/Activity/Details?titleId=1161890083&compareTo=laikal1",
61
+ "image"=>
62
+ "http://tiles.xbox.com/tiles/WQ/nz/0Wdsb2JhbA9ECgQNGwEfV11QL2ljb24vMC84MDAwIAAAAAAAAP7cCUY=.jpg",
63
+ "title"=>"Syndicate",
64
+ "last_played"=>"3/11/2012",
65
+ "earned_gamerscore"=>530,
66
+ "available_gamerscore"=>1000,
67
+ "earned_achievements"=>33,
68
+ "available_achievements"=>50,
69
+ "percentage_complete"=>"66%"},
70
+ {"comparison_url"=>
71
+ "http://live.xbox.com/en-US/Activity/Details?titleId=1414793176&compareTo=laikal1",
72
+ "image"=>
73
+ "http://tiles.xbox.com/tiles/fc/qf/0Wdsb2JhbA9ECgUMGgQfWStbL2ljb24vMC84MDAwIAAAAAAAAP6wymI=.jpg",
74
+ "title"=>"BioShock",
75
+ "last_played"=>"2/25/2012",
76
+ "earned_gamerscore"=>1100,
77
+ "available_gamerscore"=>1100,
78
+ "earned_achievements"=>51,
79
+ "available_achievements"=>51,
80
+ "percentage_complete"=>"100%"},
81
+ {"comparison_url"=>
82
+ "http://live.xbox.com/en-US/Activity/Details?titleId=1112737766&compareTo=laikal1",
83
+ "image"=>
84
+ "http://tiles.xbox.com/tiles/qR/QI/1Gdsb2JhbA9ECgQKGgMfWSpVL2ljb24vMC84MDAwIAAAAAAAAPsnFLY=.jpg",
85
+ "title"=>"Skyrim",
86
+ "last_played"=>"2/14/2012",
87
+ "earned_gamerscore"=>910,
88
+ "available_gamerscore"=>1000,
89
+ "earned_achievements"=>47,
90
+ "available_achievements"=>50,
91
+ "percentage_complete"=>"94%"}]}
92
+ ```
93
+
94
+ ### Configuration
95
+
96
+ Gamercard uses [Faraday](https://github.com/technoweenie/faraday), so you can use any http backend that Faraday supports. It assumes [Typhoeus](https://github.com/dbalatero/typhoeus) by default. Tell Gamercard what http library you are using by:
97
+
98
+ ```ruby
99
+ Gamercard.adapter = :excon # (or :typhoeus, w/e)
100
+ ```
101
+
102
+ A block-style configurator is also available:
103
+
104
+ ```ruby
105
+ Gamercard.configure do |c|
106
+ c.adapter = :typhoeus
107
+ c.user_agent = "My Awesome Client"
108
+ end
109
+ ```
110
+
111
+ ## CHANGELOG
112
+
113
+ * v0.0.1 Hello World
114
+ * Returns all the basic gamercard data, sans status. Status can be had from a public site, though, so that is next!
115
+
116
+ ## Thanks to
117
+
118
+ This project builds on work done by the following people and projects:
119
+
120
+ * [barisbalic](https://github.com/barisbalic)'s [gamertag](https://github.com/barisbalic/gamertag), which depends on unfortunately unreliable 3rd-party proxies to Microsoft's service. This gem provides less data, but scrapes it directly from http://live.xbox.com – Straight from the horse's mouth, if you will.
121
+
122
+ So: thanks a ton to him.
123
+
124
+ ## Note on Patches/Pull Requests
125
+
126
+ * Fork the project.
127
+ * Make your feature addition or bug fix.
128
+ * Add tests for it. This is important so I don't break it in a future version unintentionally.
129
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
130
+ * Send me a pull request. Bonus points for topic branches.
131
+
132
+ ## Copyright
133
+
134
+ Copyright (c) 2011 Matt Wilson. See LICENSE for details.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/gamercard/version', __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.authors = ["Matt Wilson"]
6
+ s.email = ["mhw@hypomodern.com"]
7
+ s.description = %q{A Simple & Straightforward XBox Live Gamercard parser.}
8
+ s.summary = %q{A Simple & Straightforward XBox Live Gamercard parser.}
9
+ s.homepage = "https://github.com/hypomodern/gamercard"
10
+
11
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ s.files = `git ls-files`.split("\n")
13
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ s.name = "gamercard"
15
+ s.require_paths = ["lib"]
16
+ s.version = Gamercard::VERSION
17
+
18
+ s.add_development_dependency 'rake'
19
+ s.add_development_dependency 'rspec'
20
+ s.add_development_dependency 'typhoeus'
21
+ s.add_development_dependency 'vcr'
22
+ s.add_development_dependency 'fakeweb'
23
+
24
+ s.add_dependency 'nokogiri'
25
+ s.add_dependency 'faraday', '>= 0.8.0.rc2'
26
+ end
@@ -0,0 +1,12 @@
1
+ require "gamercard/version"
2
+ require "gamercard/configuration"
3
+ require "gamercard/client"
4
+ require "gamercard/card_parser"
5
+
6
+ module Gamercard
7
+ extend Configuration
8
+
9
+ def self.get gamertag
10
+ Client.new(gamertag).fetch
11
+ end
12
+ end
@@ -0,0 +1,69 @@
1
+ require 'nokogiri'
2
+
3
+ module Gamercard
4
+ class CardParser
5
+ attr_accessor :raw_response
6
+
7
+ def initialize http_response
8
+ self.raw_response = http_response
9
+ end
10
+
11
+ def self.parse http_response
12
+ new(http_response).parse
13
+ end
14
+
15
+ def parse
16
+ doc = Nokogiri::HTML(raw_response.body)
17
+ gamertag = doc.css("#Gamertag").first
18
+ {
19
+ 'gamertag' => gamertag.content,
20
+ 'link' => gamertag.attribute("href").value,
21
+ 'gamerpic' => doc.css("#Gamerpic").first.attribute("src").value,
22
+ 'gamerscore' => doc.css("#Gamerscore").first.content.to_i,
23
+ 'location' => doc.css("#Location").first.content,
24
+ 'motto' => doc.css("#Motto").first.content,
25
+ 'name' => doc.css("#Name").first.content,
26
+ 'bio' => doc.css("#Bio").first.content,
27
+ 'reputation' => count_reputation(doc),
28
+ 'recent_games' => summarize_games(doc)
29
+ }
30
+ end
31
+
32
+ def count_reputation doc
33
+ rep = doc.css('.RepContainer')
34
+ counts = {
35
+ 1.0 => rep.css('.Full').size,
36
+ 0.75 => rep.css('.ThreeQuarter').size,
37
+ 0.5 => rep.css('.Half').size,
38
+ 0.25 => rep.css('.Quarter').size
39
+ }
40
+ counts.inject(0) do |rep, (value, count)|
41
+ rep += count * value
42
+ rep
43
+ end
44
+ end
45
+
46
+ def summarize_games doc
47
+ doc.css('#PlayedGames li').inject([]) do |array, game_node|
48
+ array.push summarize(game_node)
49
+ array
50
+ end
51
+ end
52
+
53
+ def summarize game
54
+ link = game.css('a').first
55
+ {
56
+ 'comparison_url' => link.attribute('href').value,
57
+ 'image' => link.css('img').first.attribute('src').value,
58
+ 'title' => link.css('.Title').first.content,
59
+ 'last_played' => link.css('.LastPlayed').first.content,
60
+ 'earned_gamerscore' => link.css('.EarnedGamerscore').first.content.to_i,
61
+ 'available_gamerscore' => link.css('.AvailableGamerscore').first.content.to_i,
62
+ 'earned_achievements' => link.css('.EarnedAchievements').first.content.to_i,
63
+ 'available_achievements' => link.css('.AvailableAchievements').first.content.to_i,
64
+ 'percentage_complete' => link.css('.PercentageComplete').first.content
65
+ }
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,45 @@
1
+ require 'faraday'
2
+
3
+ module Gamercard
4
+ class Client
5
+ attr_accessor :gamertag
6
+
7
+ GAMERCARD_SERVICE_URL = "http://gamercard.xbox.com"
8
+
9
+ def initialize gamertag
10
+ self.gamertag = gamertag
11
+ end
12
+
13
+ def fetch
14
+ response = fetch_with_redirect
15
+ if response.success?
16
+ parse response
17
+ else
18
+ response
19
+ end
20
+ end
21
+
22
+ def fetch_with_redirect
23
+ resp = connection.get(build_url)
24
+ if resp.status == 302 && resp['location']
25
+ resp = connection.get(resp['location'])
26
+ end
27
+ resp
28
+ end
29
+
30
+ def connection
31
+ @connection ||= Faraday.new(:url => GAMERCARD_SERVICE_URL) do |b|
32
+ b.adapter Gamercard.adapter
33
+ end
34
+ end
35
+
36
+ def build_url
37
+ "#{gamertag}.card"
38
+ end
39
+
40
+ def parse response
41
+ CardParser.parse response
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ module Gamercard
2
+ module Configuration
3
+ # Set a custom User-Agent string (default: Gamercard Gem #{version})
4
+ attr_accessor :user_agent
5
+
6
+ # Select a different http library for Faraday to use (default: Typhoeus)
7
+ attr_accessor :adapter
8
+
9
+ # Yield self to be able to configure Gamercard
10
+ #
11
+ # Example:
12
+ #
13
+ # Gamercard.configure do |c|
14
+ # c.user_agent = "MyCoolApp Gamercard Client v2.51"
15
+ # c.adapter = :excon
16
+ # end
17
+ def configure
18
+ yield self
19
+ end
20
+
21
+ def user_agent
22
+ @user_agent || "Gamercard Gem #{Gamercard::VERSION}"
23
+ end
24
+
25
+ def adapter
26
+ @adapter || :typhoeus
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,3 @@
1
+ module Gamercard
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,215 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://gamercard.xbox.com/laikal1.card
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers: {}
10
+ response:
11
+ status:
12
+ code: 302
13
+ message:
14
+ headers:
15
+ !binary "Q2FjaGUtQ29udHJvbA==":
16
+ - !binary |-
17
+ cHJpdmF0ZQ==
18
+ !binary "TG9jYXRpb24=":
19
+ - !binary |-
20
+ aHR0cDovL2dhbWVyY2FyZC54Ym94LmNvbTo4MC9lbi1VUy9sYWlrYWwxLmNh
21
+ cmQ=
22
+ !binary "WC1Db250ZW50LVR5cGUtT3B0aW9ucw==":
23
+ - !binary |-
24
+ bm9zbmlmZg==
25
+ !binary "Q29udGVudC1MZW5ndGg=":
26
+ - !binary |-
27
+ MA==
28
+ !binary "RGF0ZQ==":
29
+ - !binary |-
30
+ U3VuLCAwMSBBcHIgMjAxMiAyMjo1MjowMCBHTVQ=
31
+ !binary "Q29ubmVjdGlvbg==":
32
+ - !binary |-
33
+ a2VlcC1hbGl2ZQ==
34
+ body:
35
+ encoding: ASCII-8BIT
36
+ string: !binary ""
37
+ http_version:
38
+ recorded_at: Sun, 01 Apr 2012 22:52:00 GMT
39
+ - request:
40
+ method: get
41
+ uri: http://gamercard.xbox.com/en-US/laikal1.card
42
+ body:
43
+ encoding: US-ASCII
44
+ string: ''
45
+ headers: {}
46
+ response:
47
+ status:
48
+ code: 200
49
+ message:
50
+ headers:
51
+ !binary "Q2FjaGUtQ29udHJvbA==":
52
+ - !binary |-
53
+ cHJpdmF0ZQ==
54
+ !binary "Q29udGVudC1UeXBl":
55
+ - !binary |-
56
+ dGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04
57
+ !binary "WC1Db250ZW50LVR5cGUtT3B0aW9ucw==":
58
+ - !binary |-
59
+ bm9zbmlmZg==
60
+ !binary "VmFyeQ==":
61
+ - !binary |-
62
+ QWNjZXB0LUVuY29kaW5n
63
+ !binary "Q29udGVudC1FbmNvZGluZw==":
64
+ - !binary |-
65
+ Z3ppcA==
66
+ !binary "Q29udGVudC1MZW5ndGg=":
67
+ - !binary |-
68
+ MTIwNQ==
69
+ !binary "RGF0ZQ==":
70
+ - !binary |-
71
+ U3VuLCAwMSBBcHIgMjAxMiAyMjo1MjowMSBHTVQ=
72
+ !binary "Q29ubmVjdGlvbg==":
73
+ - !binary |-
74
+ a2VlcC1hbGl2ZQ==
75
+ body:
76
+ encoding: ASCII-8BIT
77
+ string: !binary |-
78
+ DQo8IURPQ1RZUEUgaHRtbCBQVUJMSUMgIi0vL1czQy8vRFREIFhIVE1MIDEu
79
+ MCBUcmFuc2l0aW9uYWwvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIveGh0
80
+ bWwxL0RURC94aHRtbDEtdHJhbnNpdGlvbmFsLmR0ZCI+DQo8aHRtbCB4bWxu
81
+ cz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCIgbGFuZz0iZW5nIj4N
82
+ CiAgICA8aGVhZD4NCiAgICAgICAgPGxpbmsgcmVsPSJzdHlsZXNoZWV0IiB0
83
+ eXBlPSJ0ZXh0L2NzcyIgaHJlZj0iL0NvbnRlbnQvR2FtZXJjYXJkL2RlZmF1
84
+ bHQvZ2FtZXJjYXJkLmNzcyIgLz4NCiAgICAgICAgPG1ldGEgbmFtZT0icm9i
85
+ b3RzIiBjb250ZW50PSJub2luZGV4LG5vZm9sbG93IiAvPg0KICAgICAgICA8
86
+ bWV0YSBuYW1lPSJjYXRlZ29yeSIgY29udGVudD0iR2FtZXJjYXJkIiAvPg0K
87
+ ICAgICAgICA8YmFzZSB0YXJnZXQ9Il90b3AiIC8+DQogICAgICAgIDx0aXRs
88
+ ZT5sYWlrYWwxPC90aXRsZT4NCiAgICA8L2hlYWQ+DQogICAgPGJvZHk+DQog
89
+ ICAgICAgIDxkaXYgY2xhc3M9IlhiY0dhbWVyY2FyZCBHb2xkIE1hbGUgIj4N
90
+ CiAgICAgICAgICAgIA0KICAgICAgICAgICAgPGEgaWQ9IkdhbWVydGFnIiBo
91
+ cmVmPSJodHRwOi8vbGl2ZS54Ym94LmNvbS9lbi1VUy9Qcm9maWxlP0dhbWVy
92
+ dGFnPWxhaWthbDEiPmxhaWthbDE8L2E+DQogICAgICAgICAgICA8YSBocmVm
93
+ PSJodHRwOi8vbGl2ZS54Ym94LmNvbS9lbi1VUy9Qcm9maWxlP0dhbWVydGFn
94
+ PWxhaWthbDEiPg0KICAgICAgICAgICAgICAgIDxpbWcgaWQ9IkdhbWVycGlj
95
+ IiBzcmM9Imh0dHA6Ly9hdmF0YXIueGJveGxpdmUuY29tL2F2YXRhci9sYWlr
96
+ YWwxL2F2YXRhcnBpYy1sLnBuZyIgYWx0PSJsYWlrYWwxIiB0aXRsZT0ibGFp
97
+ a2FsMSIvPg0KICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgPGRpdiBj
98
+ bGFzcz0iUmVwQ29udGFpbmVyIj4NCiAgICAgICAgICAgICAgICA8bGFiZWw+
99
+ UmVwPC9sYWJlbD4NCiAgICAgICAgICAgICAgICANCiAgICAgICAgICAgICAg
100
+ ICAgICAgPGRpdiBjbGFzcz0iU3RhciBGdWxsIj48L2Rpdj4NCiAgICAgICAg
101
+ ICAgICAgICAgICAgPGRpdiBjbGFzcz0iU3RhciBGdWxsIj48L2Rpdj4NCiAg
102
+ ICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iU3RhciBGdWxsIj48L2Rp
103
+ dj4NCiAgICAgICAgICAgICAgICAgICAgPGRpdiBjbGFzcz0iU3RhciBGdWxs
104
+ Ij48L2Rpdj48ZGl2IGNsYXNzPSJTdGFyIFF1YXJ0ZXIiPjwvZGl2Pg0KICAg
105
+ ICAgICAgICAgPC9kaXY+DQogICAgICAgICAgICA8ZGl2IGNsYXNzPSJHYW1l
106
+ cnNjb3JlQ29udGFpbmVyIj4NCiAgICAgICAgICAgICAgICA8bGFiZWw+PC9s
107
+ YWJlbD4NCiAgICAgICAgICAgICAgICA8ZGl2IGlkPSJHYW1lcnNjb3JlIj40
108
+ OTY0NjwvZGl2Pg0KICAgICAgICAgICAgPC9kaXY+DQogICAgICAgICAgICA8
109
+ ZGl2IGlkPSJMb2NhdGlvbiI+QW5uIEFyYm9yLCBNSTwvZGl2Pg0KICAgICAg
110
+ ICAgICAgPGRpdiBpZD0iTW90dG8iPkNvbXBsZXhpZnkhPC9kaXY+DQogICAg
111
+ ICAgICAgICA8ZGl2IGlkPSJOYW1lIj5OeWFybGF0aG90ZXAgKDEgYnVja2V0
112
+ KTwvZGl2Pg0KICAgICAgICAgICAgPGRpdiBpZD0iQmlvIj5EZXNpZ24gaXMg
113
+ aG93IGl0IHdvcmtzLjwvZGl2Pg0KDQogICAgICAgICAgICANCiAgICAgICAg
114
+ ICAgIDxvbCBpZD0iUGxheWVkR2FtZXMiID4NCiAgICAgICAgICAgIA0KICAg
115
+ ICAgICAgICAgICAgIDxsaSA+DQogICAgICAgICAgICAgICAgICAgIA0KICAg
116
+ ICAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwOi8vbGl2ZS54Ym94LmNv
117
+ bS9lbi1VUy9BY3Rpdml0eS9EZXRhaWxzP3RpdGxlSWQ9MTE2MTg5MDExMCZh
118
+ bXA7Y29tcGFyZVRvPWxhaWthbDEiPg0KICAgICAgICAgICAgICAgICAgICAg
119
+ ICA8aW1nIHNyYz0iaHR0cDovL3RpbGVzLnhib3guY29tL3RpbGVzLzlhL1NM
120
+ LzBtZHNiMkpoYkE5RUNnUU5Hd0VmVjF3bUwybGpiMjR2TUM4NE1EQXdJQUFB
121
+ QUFBQUFQMmtwT289LmpwZyIgYWx0PSJLb0E6IFJlY2tvbmluZyIgdGl0bGU9
122
+ IktvQTogUmVja29uaW5nIiAvPg0KICAgICAgICAgICAgICAgICAgICAgICA8
123
+ c3BhbiBjbGFzcz0iVGl0bGUiPktvQTogUmVja29uaW5nPC9zcGFuPg0KICAg
124
+ ICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iTGFzdFBsYXllZCI+
125
+ My8yOS8yMDEyPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICA8c3Bh
126
+ biBjbGFzcz0iRWFybmVkR2FtZXJzY29yZSI+MTA8L3NwYW4+DQogICAgICAg
127
+ ICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJBdmFpbGFibGVHYW1lcnNj
128
+ b3JlIj4xMzAwPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICA8c3Bh
129
+ biBjbGFzcz0iRWFybmVkQWNoaWV2ZW1lbnRzIj4xPC9zcGFuPg0KICAgICAg
130
+ ICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iQXZhaWxhYmxlQWNoaWV2
131
+ ZW1lbnRzIj42MTwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgPHNw
132
+ YW4gY2xhc3M9IlBlcmNlbnRhZ2VDb21wbGV0ZSI+MSU8L3NwYW4+DQogICAg
133
+ ICAgICAgICAgICAgICAgIDwvYT4NCiAgICAgICAgICAgICAgICA8L2xpPg0K
134
+ ICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgPGxpID4NCiAgICAgICAg
135
+ ICAgICAgICAgICAgDQogICAgICAgICAgICAgICAgICAgIDxhIGhyZWY9Imh0
136
+ dHA6Ly9saXZlLnhib3guY29tL2VuLVVTL0FjdGl2aXR5L0RldGFpbHM/dGl0
137
+ bGVJZD0xMTYxODkwMTQxJmFtcDtjb21wYXJlVG89bGFpa2FsMSI+DQogICAg
138
+ ICAgICAgICAgICAgICAgICAgIDxpbWcgc3JjPSJodHRwOi8vdGlsZXMueGJv
139
+ eC5jb20vdGlsZXMvbnAvRzIvMTJkc2IySmhiQTlFQ2dRTkd3RWZWMW9uTDJs
140
+ amIyNHZNQzg0TURBd0lBQUFBQUFBQVBpWmtZRT0uanBnIiBhbHQ9Ik1hc3Mg
141
+ RWZmZWN0IDMiIHRpdGxlPSJNYXNzIEVmZmVjdCAzIiAvPg0KICAgICAgICAg
142
+ ICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iVGl0bGUiPk1hc3MgRWZmZWN0
143
+ IDM8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNz
144
+ PSJMYXN0UGxheWVkIj4zLzI4LzIwMTI8L3NwYW4+DQogICAgICAgICAgICAg
145
+ ICAgICAgICAgIDxzcGFuIGNsYXNzPSJFYXJuZWRHYW1lcnNjb3JlIj4xMDI1
146
+ PC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0i
147
+ QXZhaWxhYmxlR2FtZXJzY29yZSI+MTA1MDwvc3Bhbj4NCiAgICAgICAgICAg
148
+ ICAgICAgICAgICAgPHNwYW4gY2xhc3M9IkVhcm5lZEFjaGlldmVtZW50cyI+
149
+ NTE8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNz
150
+ PSJBdmFpbGFibGVBY2hpZXZlbWVudHMiPjUyPC9zcGFuPg0KICAgICAgICAg
151
+ ICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iUGVyY2VudGFnZUNvbXBsZXRl
152
+ Ij45OCU8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgIDwvYT4NCiAgICAg
153
+ ICAgICAgICAgICA8L2xpPg0KICAgICAgICAgICAgDQogICAgICAgICAgICAg
154
+ ICAgPGxpID4NCiAgICAgICAgICAgICAgICAgICAgDQogICAgICAgICAgICAg
155
+ ICAgICAgIDxhIGhyZWY9Imh0dHA6Ly9saXZlLnhib3guY29tL2VuLVVTL0Fj
156
+ dGl2aXR5L0RldGFpbHM/dGl0bGVJZD0xMTYxODkwMDgzJmFtcDtjb21wYXJl
157
+ VG89bGFpa2FsMSI+DQogICAgICAgICAgICAgICAgICAgICAgIDxpbWcgc3Jj
158
+ PSJodHRwOi8vdGlsZXMueGJveC5jb20vdGlsZXMvV1EvbnovMFdkc2IySmhi
159
+ QTlFQ2dRTkd3RWZWMTFRTDJsamIyNHZNQzg0TURBd0lBQUFBQUFBQVA3Y0NV
160
+ WT0uanBnIiBhbHQ9IlN5bmRpY2F0ZSIgdGl0bGU9IlN5bmRpY2F0ZSIgLz4N
161
+ CiAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9IlRpdGxlIj5T
162
+ eW5kaWNhdGU8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgIDxzcGFu
163
+ IGNsYXNzPSJMYXN0UGxheWVkIj4zLzExLzIwMTI8L3NwYW4+DQogICAgICAg
164
+ ICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJFYXJuZWRHYW1lcnNjb3Jl
165
+ Ij41MzA8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNs
166
+ YXNzPSJBdmFpbGFibGVHYW1lcnNjb3JlIj4xMDAwPC9zcGFuPg0KICAgICAg
167
+ ICAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iRWFybmVkQWNoaWV2ZW1l
168
+ bnRzIj4zMzwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4g
169
+ Y2xhc3M9IkF2YWlsYWJsZUFjaGlldmVtZW50cyI+NTA8L3NwYW4+DQogICAg
170
+ ICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPSJQZXJjZW50YWdlQ29t
171
+ cGxldGUiPjY2JTwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgPC9hPg0K
172
+ ICAgICAgICAgICAgICAgIDwvbGk+DQogICAgICAgICAgICANCiAgICAgICAg
173
+ ICAgICAgICA8bGkgY2xhc3M9IkNvbXBsZXRlIiA+DQogICAgICAgICAgICAg
174
+ ICAgICAgIA0KICAgICAgICAgICAgICAgICAgICA8YSBocmVmPSJodHRwOi8v
175
+ bGl2ZS54Ym94LmNvbS9lbi1VUy9BY3Rpdml0eS9EZXRhaWxzP3RpdGxlSWQ9
176
+ MTQxNDc5MzE3NiZhbXA7Y29tcGFyZVRvPWxhaWthbDEiPg0KICAgICAgICAg
177
+ ICAgICAgICAgICAgICA8aW1nIHNyYz0iaHR0cDovL3RpbGVzLnhib3guY29t
178
+ L3RpbGVzL2ZjL3FmLzBXZHNiMkpoYkE5RUNnVU1HZ1FmV1N0YkwybGpiMjR2
179
+ TUM4NE1EQXdJQUFBQUFBQUFQNnd5bUk9LmpwZyIgYWx0PSJCaW9TaG9jayIg
180
+ dGl0bGU9IkJpb1Nob2NrIiAvPg0KICAgICAgICAgICAgICAgICAgICAgICA8
181
+ c3BhbiBjbGFzcz0iVGl0bGUiPkJpb1Nob2NrPC9zcGFuPg0KICAgICAgICAg
182
+ ICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iTGFzdFBsYXllZCI+Mi8yNS8y
183
+ MDEyPC9zcGFuPg0KICAgICAgICAgICAgICAgICAgICAgICA8c3BhbiBjbGFz
184
+ cz0iRWFybmVkR2FtZXJzY29yZSI+MTEwMDwvc3Bhbj4NCiAgICAgICAgICAg
185
+ ICAgICAgICAgICAgPHNwYW4gY2xhc3M9IkF2YWlsYWJsZUdhbWVyc2NvcmUi
186
+ PjExMDA8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNs
187
+ YXNzPSJFYXJuZWRBY2hpZXZlbWVudHMiPjUxPC9zcGFuPg0KICAgICAgICAg
188
+ ICAgICAgICAgICAgICA8c3BhbiBjbGFzcz0iQXZhaWxhYmxlQWNoaWV2ZW1l
189
+ bnRzIj41MTwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4g
190
+ Y2xhc3M9IlBlcmNlbnRhZ2VDb21wbGV0ZSI+MTAwJTwvc3Bhbj4NCiAgICAg
191
+ ICAgICAgICAgICAgICAgPC9hPg0KICAgICAgICAgICAgICAgIDwvbGk+DQog
192
+ ICAgICAgICAgICANCiAgICAgICAgICAgICAgICA8bGkgPg0KICAgICAgICAg
193
+ ICAgICAgICAgICANCiAgICAgICAgICAgICAgICAgICAgPGEgaHJlZj0iaHR0
194
+ cDovL2xpdmUueGJveC5jb20vZW4tVVMvQWN0aXZpdHkvRGV0YWlscz90aXRs
195
+ ZUlkPTExMTI3Mzc3NjYmYW1wO2NvbXBhcmVUbz1sYWlrYWwxIj4NCiAgICAg
196
+ ICAgICAgICAgICAgICAgICAgPGltZyBzcmM9Imh0dHA6Ly90aWxlcy54Ym94
197
+ LmNvbS90aWxlcy9xUi9RSS8xR2RzYjJKaGJBOUVDZ1FLR2dNZldTcFZMMmxq
198
+ YjI0dk1DODRNREF3SUFBQUFBQUFBUHNuRkxZPS5qcGciIGFsdD0iU2t5cmlt
199
+ IiB0aXRsZT0iU2t5cmltIiAvPg0KICAgICAgICAgICAgICAgICAgICAgICA8
200
+ c3BhbiBjbGFzcz0iVGl0bGUiPlNreXJpbTwvc3Bhbj4NCiAgICAgICAgICAg
201
+ ICAgICAgICAgICAgPHNwYW4gY2xhc3M9Ikxhc3RQbGF5ZWQiPjIvMTQvMjAx
202
+ Mjwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xhc3M9
203
+ IkVhcm5lZEdhbWVyc2NvcmUiPjkxMDwvc3Bhbj4NCiAgICAgICAgICAgICAg
204
+ ICAgICAgICAgPHNwYW4gY2xhc3M9IkF2YWlsYWJsZUdhbWVyc2NvcmUiPjEw
205
+ MDA8L3NwYW4+DQogICAgICAgICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNz
206
+ PSJFYXJuZWRBY2hpZXZlbWVudHMiPjQ3PC9zcGFuPg0KICAgICAgICAgICAg
207
+ ICAgICAgICAgICA8c3BhbiBjbGFzcz0iQXZhaWxhYmxlQWNoaWV2ZW1lbnRz
208
+ Ij41MDwvc3Bhbj4NCiAgICAgICAgICAgICAgICAgICAgICAgPHNwYW4gY2xh
209
+ c3M9IlBlcmNlbnRhZ2VDb21wbGV0ZSI+OTQlPC9zcGFuPg0KICAgICAgICAg
210
+ ICAgICAgICAgICA8L2E+DQogICAgICAgICAgICAgICAgPC9saT4NCiAgICAg
211
+ ICAgICAgIA0KICAgICAgICAgICAgPC9vbD4NCiAgICAgICAgPC9kaXY+DQog
212
+ ICAgICAgIA0KICAgIDwvYm9keT4NCjwvaHRtbD4=
213
+ http_version:
214
+ recorded_at: Sun, 01 Apr 2012 22:52:01 GMT
215
+ recorded_with: VCR 2.0.0
@@ -0,0 +1,113 @@
1
+
2
+
3
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml" lang="eng">
5
+ <head>
6
+ <link rel="stylesheet" type="text/css" href="/Content/Gamercard/default/gamercard.css" />
7
+ <meta name="robots" content="noindex,nofollow" />
8
+ <meta name="category" content="Gamercard" />
9
+ <base target="_top" />
10
+ <title>laikal1</title>
11
+ </head>
12
+ <body>
13
+ <div class="XbcGamercard Gold Male ">
14
+
15
+ <a id="Gamertag" href="http://live.xbox.com/en-US/Profile?Gamertag=laikal1">laikal1</a>
16
+ <a href="http://live.xbox.com/en-US/Profile?Gamertag=laikal1">
17
+ <img id="Gamerpic" src="http://avatar.xboxlive.com/avatar/laikal1/avatarpic-l.png" alt="laikal1" title="laikal1"/>
18
+ </a>
19
+ <div class="RepContainer">
20
+ <label>Rep</label>
21
+
22
+ <div class="Star Full"></div>
23
+ <div class="Star Full"></div>
24
+ <div class="Star Full"></div>
25
+ <div class="Star Full"></div><div class="Star Quarter"></div>
26
+ </div>
27
+ <div class="GamerscoreContainer">
28
+ <label></label>
29
+ <div id="Gamerscore">49646</div>
30
+ </div>
31
+ <div id="Location">Ann Arbor, MI</div>
32
+ <div id="Motto">Complexify!</div>
33
+ <div id="Name">Nyarlathotep (1 bucket)</div>
34
+ <div id="Bio">Design is how it works.</div>
35
+
36
+
37
+ <ol id="PlayedGames" >
38
+
39
+ <li >
40
+
41
+ <a href="http://live.xbox.com/en-US/Activity/Details?titleId=1161890110&amp;compareTo=laikal1">
42
+ <img src="http://tiles.xbox.com/tiles/9a/SL/0mdsb2JhbA9ECgQNGwEfV1wmL2ljb24vMC84MDAwIAAAAAAAAP2kpOo=.jpg" alt="KoA: Reckoning" title="KoA: Reckoning" />
43
+ <span class="Title">KoA: Reckoning</span>
44
+ <span class="LastPlayed">3/28/2012</span>
45
+ <span class="EarnedGamerscore">10</span>
46
+ <span class="AvailableGamerscore">1300</span>
47
+ <span class="EarnedAchievements">1</span>
48
+ <span class="AvailableAchievements">61</span>
49
+ <span class="PercentageComplete">1%</span>
50
+ </a>
51
+ </li>
52
+
53
+ <li >
54
+
55
+ <a href="http://live.xbox.com/en-US/Activity/Details?titleId=1161890141&amp;compareTo=laikal1">
56
+ <img src="http://tiles.xbox.com/tiles/np/G2/12dsb2JhbA9ECgQNGwEfV1onL2ljb24vMC84MDAwIAAAAAAAAPiZkYE=.jpg" alt="Mass Effect 3" title="Mass Effect 3" />
57
+ <span class="Title">Mass Effect 3</span>
58
+ <span class="LastPlayed">3/27/2012</span>
59
+ <span class="EarnedGamerscore">1025</span>
60
+ <span class="AvailableGamerscore">1050</span>
61
+ <span class="EarnedAchievements">51</span>
62
+ <span class="AvailableAchievements">52</span>
63
+ <span class="PercentageComplete">98%</span>
64
+ </a>
65
+ </li>
66
+
67
+ <li >
68
+
69
+ <a href="http://live.xbox.com/en-US/Activity/Details?titleId=1161890083&amp;compareTo=laikal1">
70
+ <img src="http://tiles.xbox.com/tiles/WQ/nz/0Wdsb2JhbA9ECgQNGwEfV11QL2ljb24vMC84MDAwIAAAAAAAAP7cCUY=.jpg" alt="Syndicate" title="Syndicate" />
71
+ <span class="Title">Syndicate</span>
72
+ <span class="LastPlayed">3/11/2012</span>
73
+ <span class="EarnedGamerscore">530</span>
74
+ <span class="AvailableGamerscore">1000</span>
75
+ <span class="EarnedAchievements">33</span>
76
+ <span class="AvailableAchievements">50</span>
77
+ <span class="PercentageComplete">66%</span>
78
+ </a>
79
+ </li>
80
+
81
+ <li class="Complete" >
82
+
83
+ <a href="http://live.xbox.com/en-US/Activity/Details?titleId=1414793176&amp;compareTo=laikal1">
84
+ <img src="http://tiles.xbox.com/tiles/fc/qf/0Wdsb2JhbA9ECgUMGgQfWStbL2ljb24vMC84MDAwIAAAAAAAAP6wymI=.jpg" alt="BioShock" title="BioShock" />
85
+ <span class="Title">BioShock</span>
86
+ <span class="LastPlayed">2/24/2012</span>
87
+ <span class="EarnedGamerscore">1100</span>
88
+ <span class="AvailableGamerscore">1100</span>
89
+ <span class="EarnedAchievements">51</span>
90
+ <span class="AvailableAchievements">51</span>
91
+ <span class="PercentageComplete">100%</span>
92
+ </a>
93
+ </li>
94
+
95
+ <li >
96
+
97
+ <a href="http://live.xbox.com/en-US/Activity/Details?titleId=1112737766&amp;compareTo=laikal1">
98
+ <img src="http://tiles.xbox.com/tiles/qR/QI/1Gdsb2JhbA9ECgQKGgMfWSpVL2ljb24vMC84MDAwIAAAAAAAAPsnFLY=.jpg" alt="Skyrim" title="Skyrim" />
99
+ <span class="Title">Skyrim</span>
100
+ <span class="LastPlayed">2/14/2012</span>
101
+ <span class="EarnedGamerscore">910</span>
102
+ <span class="AvailableGamerscore">1000</span>
103
+ <span class="EarnedAchievements">47</span>
104
+ <span class="AvailableAchievements">50</span>
105
+ <span class="PercentageComplete">94%</span>
106
+ </a>
107
+ </li>
108
+
109
+ </ol>
110
+ </div>
111
+
112
+ </body>
113
+ </html>
@@ -0,0 +1,122 @@
1
+ require 'spec_helper'
2
+
3
+ module Gamercard
4
+ describe "CardParser" do
5
+ let(:mock_response) { mock(:body => File.read("spec/fixtures/laikal1.html")) }
6
+ let(:parser) { CardParser.new mock_response }
7
+ let(:doc) { Nokogiri::HTML(mock_response.body) }
8
+
9
+ def nokogirize html
10
+ Nokogiri::HTML(html)
11
+ end
12
+
13
+ describe ".parse" do
14
+ it "returns a hash representing a parsed gamercard" do
15
+ result = CardParser.parse mock_response
16
+ result['gamertag'].should == 'laikal1'
17
+ result['gamerpic'].should == 'http://avatar.xboxlive.com/avatar/laikal1/avatarpic-l.png'
18
+ result['gamerscore'].should == 49646
19
+ end
20
+ end
21
+
22
+ describe "attributes" do
23
+ it "takes one required parameter, viz the http response from the card service" do
24
+ parser = CardParser.new mock_response
25
+ parser.raw_response.should == mock_response
26
+ end
27
+ end
28
+
29
+ describe "#parse" do
30
+ it "chops the html up neatly" do
31
+ result = parser.parse
32
+ result['gamertag'].should == 'laikal1'
33
+ result['gamerpic'].should == 'http://avatar.xboxlive.com/avatar/laikal1/avatarpic-l.png'
34
+ result['gamerscore'].should == 49646
35
+ result['recent_games'].size.should == 5
36
+ end
37
+ end
38
+
39
+ describe "#count_reputation" do
40
+ it "returns laikal1's rep as 4.25" do
41
+ count = parser.count_reputation(doc).should == 4.25
42
+ end
43
+ it "counts the number of Full, Half, ThreeQuarter, and Quarter .Star elements in the .RepContainer" do
44
+ doc1 = <<-DOC1
45
+ <div class="RepContainer">
46
+ <label>Rep</label>
47
+ <div class="Star Full"></div>
48
+ <div class="Star Full"></div>
49
+ <div class="Star Full"></div>
50
+ <div class="Star ThreeQuarter"></div>
51
+ <div class="Star Empty"></div>
52
+ </div>
53
+ DOC1
54
+ parser.count_reputation(nokogirize(doc1)).should == 3.75
55
+
56
+ doc2 = <<-DOC2
57
+ <div class="RepContainer">
58
+ <label>Rep</label>
59
+ <div class="Star Full"></div>
60
+ <div class="Star Full"></div>
61
+ <div class="Star Half"></div>
62
+ <div class="Star Empty"></div>
63
+ <div class="Star Empty"></div>
64
+ </div>
65
+ DOC2
66
+ parser.count_reputation(nokogirize(doc2)).should == 2.5
67
+
68
+ doc3 = <<-DOC3
69
+ <div class="RepContainer">
70
+ <label>Rep</label>
71
+ <div class="Star Full"></div>
72
+ <div class="Star Empty"></div>
73
+ <div class="Star Half"></div>
74
+ <div class="Star Quarter"></div>
75
+ <div class="Star Empty"></div>
76
+ </div>
77
+ DOC3
78
+ parser.count_reputation(nokogirize(doc3)).should == 1.75
79
+ end
80
+ end
81
+
82
+ describe "#summarize_games" do
83
+ it "returns an array of game summaries" do
84
+ games = parser.summarize_games(doc)
85
+ games.should be_a_kind_of(Array)
86
+ games.size.should == 5
87
+ end
88
+ end
89
+
90
+ describe "#summarize" do
91
+ it "returns a hash of parsed values" do
92
+ game = <<-DOC
93
+ <li >
94
+ <a href="http://live.xbox.com/en-US/Activity/Details?titleId=1161890110&amp;compareTo=laikal1">
95
+ <img src="http://tiles.xbox.com/tiles/9a/SL/0mdsb2JhbA9ECgQNGwEfV1wmL2ljb24vMC84MDAwIAAAAAAAAP2kpOo=.jpg" alt="KoA: Reckoning" title="KoA: Reckoning" />
96
+ <span class="Title">KoA: Reckoning</span>
97
+ <span class="LastPlayed">3/28/2012</span>
98
+ <span class="EarnedGamerscore">10</span>
99
+ <span class="AvailableGamerscore">1300</span>
100
+ <span class="EarnedAchievements">1</span>
101
+ <span class="AvailableAchievements">61</span>
102
+ <span class="PercentageComplete">1%</span>
103
+ </a>
104
+ </li>
105
+ DOC
106
+ result = parser.summarize(nokogirize(game))
107
+ result.should == {
108
+ "comparison_url" => "http://live.xbox.com/en-US/Activity/Details?titleId=1161890110&compareTo=laikal1",
109
+ "image" => "http://tiles.xbox.com/tiles/9a/SL/0mdsb2JhbA9ECgQNGwEfV1wmL2ljb24vMC84MDAwIAAAAAAAAP2kpOo=.jpg",
110
+ "title" => "KoA: Reckoning",
111
+ "last_played" => "3/28/2012",
112
+ "earned_gamerscore" => 10,
113
+ "available_gamerscore" => 1300,
114
+ "earned_achievements" => 1,
115
+ "available_achievements" => 61,
116
+ "percentage_complete" => "1%"
117
+ }
118
+ end
119
+ end
120
+
121
+ end
122
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ module Gamercard
4
+ describe "Client" do
5
+ let(:client) { Client.new("laikal1") }
6
+
7
+ it "should be loaded correctly" do
8
+ lambda { Gamercard::Client }.should_not raise_error
9
+ end
10
+
11
+ it "takes the gamertag as the only input parameter" do
12
+ client.gamertag.should == "laikal1"
13
+ end
14
+
15
+ describe "#fetch" do
16
+ it "should return a hash of useful values" do
17
+ VCR.use_cassette('fetch_laikal1', :record => :new_episodes) do
18
+ response = client.fetch
19
+ response['gamertag'].should == 'laikal1'
20
+ response['gamerpic'].should == 'http://avatar.xboxlive.com/avatar/laikal1/avatarpic-l.png'
21
+ response['gamerscore'].should == 49646
22
+ response['recent_games'].size.should == 5
23
+ end
24
+ end
25
+ it "should return the raw response if there is a problem with the response" do
26
+ client.stub!(:connection).and_return(
27
+ Faraday.new do |builder|
28
+ builder.adapter :test do |stub|
29
+ stub.get('laikal1.card') {[ 500, {}, 'Oh Noes! I blew it up!' ]}
30
+ end
31
+ end
32
+ )
33
+ VCR.turned_off do
34
+ response = client.fetch
35
+ response.status.should == 500
36
+ response.body.should == 'Oh Noes! I blew it up!'
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#fetch_with_redirect" do
42
+ it "follows the redirect like a boss" do
43
+ VCR.use_cassette('fetch_laikal1', :record => :new_episodes) do
44
+ response = client.fetch_with_redirect
45
+ response.status.should == 200
46
+ response.body[0, 16].should == "\r\n<!DOCTYPE html"
47
+ end
48
+ end
49
+ end
50
+
51
+ describe "#connection" do
52
+ it "returns a Faraday connection, using the configured http library, to the gamercard url" do
53
+ conn = client.send(:connection)
54
+ conn.host.should == Client::GAMERCARD_SERVICE_URL.sub("http://", "")
55
+ conn.builder.handlers.should include(Faraday::Adapter::Typhoeus)
56
+ end
57
+ end
58
+
59
+ describe "#build_url" do
60
+ it "returns the portion of the URL that generates the card for the given gamertag" do
61
+ client.build_url.should == "laikal1.card"
62
+ end
63
+ end
64
+
65
+ describe "#parse" do
66
+ it "delegates to a CardParser object" do
67
+ CardParser.should_receive(:parse).with("foo").and_return({ "gamertag" => "laikal1" })
68
+ client.parse "foo"
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ describe Gamercard do
4
+ it "should be configurable" do
5
+ Gamercard.should respond_to(:configure)
6
+ end
7
+
8
+ it "has a sensible default for .adapter" do
9
+ Gamercard.adapter.should == :typhoeus
10
+ end
11
+
12
+ describe "#get" do
13
+ it "is a shortcut to Client#fetch" do
14
+ Gamercard::Client.should_receive(:new).and_return(mock(:fetch => "OK."))
15
+ Gamercard.get("foo").should == "OK."
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'gamercard' # and any other gems you need
5
+ require 'vcr'
6
+
7
+ RSpec.configure do |c|
8
+ c.extend VCR::RSpec::Macros
9
+ end
10
+
11
+ VCR.configure do |c|
12
+ c.cassette_library_dir = 'spec/fixtures'
13
+ c.hook_into :faraday
14
+ end
15
+
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+ RSpec.configure do |config|
18
+ config.treat_symbols_as_metadata_keys_with_true_values = true
19
+ # config.run_all_when_everything_filtered = true
20
+ # config.filter_run :focus
21
+ end
metadata ADDED
@@ -0,0 +1,148 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gamercard
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Matt Wilson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-04-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: &2152009940 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2152009940
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2152009460 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2152009460
36
+ - !ruby/object:Gem::Dependency
37
+ name: typhoeus
38
+ requirement: &2152008860 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2152008860
47
+ - !ruby/object:Gem::Dependency
48
+ name: vcr
49
+ requirement: &2152008300 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2152008300
58
+ - !ruby/object:Gem::Dependency
59
+ name: fakeweb
60
+ requirement: &2152007700 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *2152007700
69
+ - !ruby/object:Gem::Dependency
70
+ name: nokogiri
71
+ requirement: &2152007120 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *2152007120
80
+ - !ruby/object:Gem::Dependency
81
+ name: faraday
82
+ requirement: &2152006420 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: 0.8.0.rc2
88
+ type: :runtime
89
+ prerelease: false
90
+ version_requirements: *2152006420
91
+ description: A Simple & Straightforward XBox Live Gamercard parser.
92
+ email:
93
+ - mhw@hypomodern.com
94
+ executables: []
95
+ extensions: []
96
+ extra_rdoc_files: []
97
+ files:
98
+ - .gitignore
99
+ - .rspec
100
+ - .rvmrc
101
+ - Gemfile
102
+ - Guardfile
103
+ - LICENSE
104
+ - README.md
105
+ - Rakefile
106
+ - gamercard.gemspec
107
+ - lib/gamercard.rb
108
+ - lib/gamercard/card_parser.rb
109
+ - lib/gamercard/client.rb
110
+ - lib/gamercard/configuration.rb
111
+ - lib/gamercard/version.rb
112
+ - spec/fixtures/fetch_laikal1.yml
113
+ - spec/fixtures/laikal1.html
114
+ - spec/gamercard/card_parser_spec.rb
115
+ - spec/gamercard/client_spec.rb
116
+ - spec/gamercard_spec.rb
117
+ - spec/spec_helper.rb
118
+ homepage: https://github.com/hypomodern/gamercard
119
+ licenses: []
120
+ post_install_message:
121
+ rdoc_options: []
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ none: false
126
+ requirements:
127
+ - - ! '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ none: false
132
+ requirements:
133
+ - - ! '>='
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 1.8.17
139
+ signing_key:
140
+ specification_version: 3
141
+ summary: A Simple & Straightforward XBox Live Gamercard parser.
142
+ test_files:
143
+ - spec/fixtures/fetch_laikal1.yml
144
+ - spec/fixtures/laikal1.html
145
+ - spec/gamercard/card_parser_spec.rb
146
+ - spec/gamercard/client_spec.rb
147
+ - spec/gamercard_spec.rb
148
+ - spec/spec_helper.rb