boston_marathon 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.
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ *.gem
2
+ *.rbc
3
+ .DS_Store
4
+ .bundle
5
+ .rvmrc
6
+ .yardoc
7
+ Gemfile.lock
8
+ coverage/*
9
+ doc/*
10
+ log/*
11
+ pkg/*
12
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # gem dependencies are specified in boston_marathon.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ boston_marathon (0.0.1)
5
+ nokogiri (= 1.5.0)
6
+ rest-client (= 1.6.7)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ fakeweb (1.3.0)
12
+ mime-types (1.17.2)
13
+ nokogiri (1.5.0)
14
+ redgreen (1.2.2)
15
+ rest-client (1.6.7)
16
+ mime-types (>= 1.16)
17
+ shoulda-context (1.0.0)
18
+ vcr (1.11.3)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ boston_marathon!
25
+ fakeweb (= 1.3.0)
26
+ redgreen (>= 1.2.2)
27
+ shoulda-context (~> 1.0.0)
28
+ vcr (= 1.11.3)
data/README.md ADDED
@@ -0,0 +1,99 @@
1
+ Boston Marathon
2
+ ===============
3
+
4
+ A Ruby wrapper for race results from the [2011 Boston Marathon](http://www.baa.org/races/boston-marathon/results-commentary/results-search.aspx).
5
+ Result data is retrieved by parsing HTML documents with [Nokogiri](http://nokogiri.org/),
6
+ so this version of the gem will work as long as the format of the site doesn't change.
7
+
8
+ Install / Getting Started
9
+ -------------------------
10
+
11
+ gem install boston_marathon
12
+
13
+ Usage
14
+ -----
15
+
16
+ ### Look up an athlete's result by their bib number
17
+
18
+ result = BostonMarathon.result(43)
19
+ result.name # => 'Krah, Nathan M.'
20
+ result.time # => '2:22:24'
21
+ result.pace # => '0:05:26'
22
+ result.place # => '29'
23
+
24
+ Like ActiveRecord, a RecordNotFound exception is raised when looking up a bib that has no result.
25
+
26
+ ### Search the results
27
+
28
+ This method will return a maximum of 25 entries, a limit imposed by the Boston Marathon website.
29
+ To specify a smaller limit, use the VarTargetCount param.
30
+
31
+ top_20_women = BostonMarathon.results({'GenderID' => 2, 'VarTargetCount' => 20})
32
+ top_20_women.each do |result|
33
+ puts "#{result.gender_place.rjust(2)}. #{result.name}"
34
+ end
35
+
36
+ Query Params for #results
37
+ -------------------------
38
+
39
+ - BibNumber
40
+ - LastName
41
+ - FirstName
42
+ - GenderID
43
+ - City
44
+ - StateID
45
+ - CountryOfResID
46
+ - ReportingSegmentID
47
+ - QualClassID
48
+ - AwardsDivisionID
49
+ - VarTargetCount
50
+
51
+ ### IDs for genders
52
+
53
+ {"1" => "M", "2" => "F"}
54
+
55
+ ### IDs for reporting segments
56
+
57
+ {"1" => "Runners", "2" => "Wheelchairs", "3" => "Handcycles"}
58
+
59
+ ### IDs for qualification classes
60
+
61
+ {"8" => "Handcycle", "2" => "Mobility Impaired", "4" => "Push Rim Wheelchair Class 1 (Quad)", "5" => "Push Rim Wheelchair Class 2 (Quad)", "6" => "Push Rim Wheelchair Class 3 (Open)", "7" => "Push Rim Wheelchair Class 4 (Open)", "1" => "Visually Impaired (B1, B2, B3)"}
62
+
63
+ ### IDs for awards divisions
64
+
65
+ {"1" => "18-39 Age Group", "2" => "40-44 Age Group", "9" => "45-49 Age Group", "3" => "50-54 Age Group", "10" => "55-59 Age Group", "4" => "60-64 Age Group", "11" => "65-69 Age Group", "8" => "70-74 Age Group", "12" => "75-79 Age Group", "13" => "80+ Age Group"}
66
+
67
+ ### IDs for states
68
+
69
+ {"5" => "Alabama", "4" => "Alaska", "64" => "Alberta", "8" => "American Samoa", "9" => "Arizona", "7" => "Arkansas", "2" => "Armed Forces Americas", "3" => "Armed Forces Europe", "6" => "Armed Forces Pacific", "65" => "British Columbia", "10" => "California", "11" => "Colorado", "12" => "Connecticut", "14" => "Delaware", "13" => "District Of Columbia", "16" => "Federated States of Micronesia", "15" => "Florida", "17" => "Georgia", "18" => "Guam", "19" => "Hawaii", "21" => "Idaho", "22" => "Illinois", "23" => "Indiana", "20" => "Iowa", "24" => "Kansas", "25" => "Kentucky", "26" => "Louisiana", "29" => "Maine", "67" => "Manitoba", "30" => "Marshall Island", "28" => "Maryland", "27" => "Massachusetts", "31" => "Michigan", "32" => "Minnesota", "35" => "Mississippi", "33" => "Missouri", "36" => "Montana", "39" => "Nebraska", "43" => "Nevada", "68" => "New Brunswick", "40" => "New Hampshire", "41" => "New Jersey", "42" => "New Mexico", "44" => "New York", "66" => "Newfoundland and Labrador", "37" => "North Carolina", "38" => "North Dakota", "34" => "Northern Mariana Islands", "71" => "Northwest Territories", "70" => "Nova Scotia", "77" => "Nunavut", "45" => "Ohio", "46" => "Oklahoma", "72" => "Ontario", "47" => "Oregon", "50" => "Palau", "48" => "Pennsylvania", "73" => "Prince Edward Island", "49" => "Puerto Rico", "74" => "Quebec", "51" => "Rhode Island", "75" => "Saskatchewan", "52" => "South Carolina", "53" => "South Dakota", "54" => "Tennessee", "55" => "Texas", "56" => "Utah", "59" => "Vermont", "58" => "Virgin Islands", "57" => "Virginia", "60" => "Washington", "62" => "West Virginia", "61" => "Wisconsin", "63" => "Wyoming", "76" => "Yukon"}
70
+
71
+ ### IDs for countries
72
+
73
+ {"196"=>"Venezuela", "168"=>"Saint Lucia", "54"=>"Djibouti", "25"=>"Belize", "82"=>"Hong Kong", "197"=>"Vietnam", "169"=>"Sao Tome and Principe", "26"=>"Burkina Faso", "110"=>"Luxembourg", "83"=>"Honduras", "55"=>"Dominica", "27"=>"Belarus", "84"=>"Hungary", "140"=>"Oman", "56"=>"Dominican Republic", "28"=>"Bolivia", "112"=>"Madagascar", "85"=>"Indonesia", "141"=>"Pakistan", "113"=>"Morocco", "29"=>"Botswana", "86"=>"India", "57"=>"Ecuador", "170"=>"Saint Vincent and the Grenadines", "142"=>"Palestine", "114"=>"Malaysia", "87"=>"Ireland", "58"=>"Egypt", "171"=>"Sudan", "143"=>"Panama", "115"=>"Malawi", "59"=>"El Salvador", "172"=>"Switzerland", "144"=>"Paraguay", "116"=>"Mexico", "30"=>"Brazil", "88"=>"Islamic Republic of Iran", "200"=>"Yugoslavia", "173"=>"Suriname", "145"=>"Peru", "117"=>"Mongolia", "31"=>"Brunei Darussalam", "89"=>"Iraq", "60"=>"Spain", "174"=>"Slovakia", "146"=>"Philippines", "118"=>"Maldives", "32"=>"Bulgaria", "201"=>"Congo, The Democratic Republic of the", "202"=>"Zambia", "175"=>"Sweden", "147"=>"Poland", "119"=>"Mali", "61"=>"Estonia", "203"=>"Zimbabwe", "176"=>"Swaziland", "148"=>"Portugal", "90"=>"Iceland", "62"=>"Ethiopia", "177"=>"Syrian Arab Republic", "34"=>"British Virgin Islands", "91"=>"Israel", "149"=>"Korea, Democratic People's Republic of", "63"=>"Fiji", "204"=>"Burundi", "178"=>"Tanzania, United Republic of", "35"=>"Central African Republic", "64"=>"Finland", "205"=>"Bosnia and Herzegovina", "179"=>"Thailand", "120"=>"Malta", "2"=>"Afghanistan", "93"=>"Italy", "65"=>"France", "206"=>"Eritrea", "36"=>"Canada", "3"=>"Netherlands Antilles", "94"=>"Jamaica", "37"=>"Cayman Islands", "150"=>"Yemen", "122"=>"Moldova, Republic of", "4"=>"Albania", "95"=>"Jordan", "66"=>"Gabon", "208"=>"Lao People's Democratic Republic", "38"=>"Congo", "209"=>"Slovenia", "151"=>"Qatar", "123"=>"Monaco", "5"=>"Algeria", "96"=>"Japan", "67"=>"Gambia", "39"=>"Chad", "68"=>"United Kingdom", "180"=>"Tajikistan", "124"=>"Mozambique", "97"=>"Kenya", "10"=>"Antigua and Barbuda", "181"=>"Turkmenistan", "153"=>"Romania", "125"=>"Mauritius", "7"=>"Andorra", "98"=>"Kyrgyzstan", "69"=>"Guinea-Bissau", "154"=>"South Africa", "11"=>"Argentina", "40"=>"Chile", "8"=>"Angola", "183"=>"Togo", "155"=>"Russian Federation", "12"=>"Armenia", "210"=>"Macedonia, The Former Yugoslav Republic of", "127"=>"Mauritania", "41"=>"China", "99"=>"Cambodia", "184"=>"Tonga", "211"=>"Taiwan", "156"=>"Rwanda", "128"=>"Myanmar", "13"=>"Aruba", "70"=>"Georgia", "42"=>"Cote d'Ivoire (Ivory Coast)", "212"=>"Serbia and Montenegro", "157"=>"Samoa", "129"=>"Namibia", "14"=>"Australia", "71"=>"Equatorial Guinea", "43"=>"Cook Islands", "186"=>"Trinidad and Tobago", "158"=>"Saudi Arabia", "72"=>"Germany", "15"=>"Austria", "187"=>"Tunisia", "159"=>"Senegal", "100"=>"Korea, Republic of", "73"=>"Ghana", "44"=>"Cameroon", "16"=>"Azerbaijan", "188"=>"Turkey", "101"=>"Kuwait", "45"=>"Colombia", "17"=>"Bahamas", "189"=>"United Arab Emirates", "130"=>"Nauru", "75"=>"Greece", "46"=>"Comoros", "18"=>"Bangladesh", "102"=>"Kazakhstan", "131"=>"Nicaragua", "76"=>"Grenada", "47"=>"Costa Rica", "19"=>"Barbados", "103"=>"Latvia", "160"=>"Seychelles", "132"=>"Netherlands", "48"=>"Croatia", "104"=>"Libyan Arab Jamahiriya", "161"=>"Singapore", "133"=>"Nepal", "77"=>"Guatemala", "49"=>"Cuba", "105"=>"Liberia", "190"=>"Uganda", "162"=>"Sierra Leone", "134"=>"Nigeria", "106"=>"Lesotho", "20"=>"Belgium", "78"=>"Guinea", "191"=>"Ukraine", "163"=>"San Marino", "135"=>"Papua New Guinea", "107"=>"Lebanon", "21"=>"Benin", "192"=>"Uruguay", "164"=>"Solomon Islands", "136"=>"Niger", "50"=>"Cape Verde", "108"=>"Liechtenstein", "193"=>"United States of America", "165"=>"Somalia", "51"=>"Cyprus", "109"=>"Lithuania", "22"=>"Bermuda", "194"=>"Uzbekistan", "166"=>"Sri Lanka", "138"=>"Norway", "52"=>"Czech Republic", "23"=>"Bahrain", "80"=>"Guyana", "195"=>"Vanatu", "167"=>"Saint Kitts and Nevis", "139"=>"New Zealand", "53"=>"Denmark", "24"=>"Bhutan", "81"=>"Haiti"}
74
+
75
+ License
76
+ -------
77
+
78
+ (The MIT License)
79
+
80
+ Copyright (c) 2011 John B. Hall
81
+
82
+ Permission is hereby granted, free of charge, to any person obtaining
83
+ a copy of this software and associated documentation files (the
84
+ 'Software'), to deal in the Software without restriction, including
85
+ without limitation the rights to use, copy, modify, merge, publish,
86
+ distribute, sublicense, and/or sell copies of the Software, and to
87
+ permit persons to whom the Software is furnished to do so, subject to
88
+ the following conditions:
89
+
90
+ The above copyright notice and this permission notice shall be
91
+ included in all copies or substantial portions of the Software.
92
+
93
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
94
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
95
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
96
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
97
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
98
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
99
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler'
2
+ include Rake::DSL
3
+ Bundler::GemHelper.install_tasks
4
+
5
+ require 'rake/testtask'
6
+ Rake::TestTask.new do |t|
7
+ t.libs << 'test'
8
+ end
9
+
10
+ desc "Run tests"
11
+ task :default => :test
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "boston_marathon/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'boston_marathon'
7
+ s.version = BostonMarathon::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.date = '2011-11-25'
10
+ s.summary = "Ruby wrapper for race results from the 2011 Boston Marathon"
11
+ s.authors = ["John B. Hall"]
12
+ s.email = 'johnbrianhall@gmail.com'
13
+
14
+ s.add_runtime_dependency 'rest-client', '= 1.6.7'
15
+ s.add_runtime_dependency 'nokogiri', '= 1.5.0'
16
+
17
+ s.add_development_dependency 'redgreen', ">= 1.2.2"
18
+ s.add_development_dependency 'vcr', '1.11.3'
19
+ s.add_development_dependency 'fakeweb', '1.3.0'
20
+ s.add_development_dependency 'shoulda-context', '~> 1.0.0'
21
+
22
+ s.require_paths = ["lib"]
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ["lib"]
28
+
29
+ end
@@ -0,0 +1,7 @@
1
+ module BostonMarathon
2
+
3
+ class RecordNotFound < Exception
4
+
5
+ end
6
+
7
+ end
@@ -0,0 +1,95 @@
1
+ module BostonMarathon
2
+
3
+ class Result
4
+
5
+ ATTR_TRANSLATE = {
6
+ 'm/f' => 'gender',
7
+ 'st' => 'state',
8
+ 'ctry' => 'country',
9
+ 'ctz' => 'citizenship',
10
+ 'proj. time' => 'projected_time',
11
+ 'offl. time' => 'time',
12
+ 'overall' => 'place',
13
+ 'gender' => 'gender_place',
14
+ 'division' => 'division_place'
15
+ }
16
+
17
+ attr_reader :attrs
18
+
19
+ def initialize(header, infogrid)
20
+ @header = header # athlete bib, name, age, gender, city, state, country
21
+ @infogrid = infogrid # splits and finish info (pace, time, place, gender_place, division_place)
22
+ set_attrs
23
+ end
24
+
25
+ def method_missing(method, *args)
26
+ m = method.to_s.downcase
27
+ if @attrs.has_key? m
28
+ @attrs[m]
29
+ else
30
+ super
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ # ATHLETE
37
+
38
+ def athlete_keys
39
+ ['Bib', 'Name', 'Age', 'M/F', 'City', 'St', 'Ctry', 'Ctz', '']
40
+ end
41
+
42
+ def athlete_values
43
+ cleanse(@header.css('td'))
44
+ end
45
+
46
+ # RESULT (which contains splits and finish info)
47
+
48
+ def results_rows
49
+ @results_rows ||= @infogrid.css('tr')
50
+ end
51
+
52
+ # SPLITS
53
+
54
+ def split_keys
55
+ cleanse(results_rows[0].css('th')[1..-1])
56
+ end
57
+
58
+ def split_values
59
+ cleanse(results_rows[1].css('td'))
60
+ end
61
+
62
+ # FINISH INFO
63
+
64
+ def finish_info_keys
65
+ cleanse(results_rows[2].css('th')[1..-1])
66
+ end
67
+
68
+ def finish_info_values
69
+ cleanse(results_rows[3].css('td'))
70
+ end
71
+
72
+ def set_attrs
73
+ athlete = hashify(athlete_keys, athlete_values)
74
+ splits = {'splits' => hashify(split_keys, split_values)}
75
+ finish_info = hashify(finish_info_keys, finish_info_values)
76
+ @attrs = athlete.merge(splits).merge(finish_info)
77
+ end
78
+
79
+ # hashify does not belong on the result model. Move it later.
80
+ # usage: hashify(["dog", "cat"], ["woof", "meow"]) # => {"cat"=>"meow", "dog"=>"woof"}
81
+ def hashify(keys, values)
82
+ keys = keys.map(&:downcase).map{ |k| ATTR_TRANSLATE.has_key?(k) ? ATTR_TRANSLATE[k] : k }
83
+ arr_of_arrs = keys.zip(values).delete_if { |arr| arr[0] == "" }
84
+ Hash[arr_of_arrs]
85
+ end
86
+
87
+ # cleanse does not belong on the result model. Move it later.
88
+ # remove whitespaces and instances of &nbsp;
89
+ def cleanse(arr)
90
+ arr.map{|cell| cell.inner_text.gsub(/\302\240/, ' ').strip}
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,18 @@
1
+ module BostonMarathon
2
+
3
+ class ResultSet < Array
4
+
5
+ def initialize(response)
6
+ noko = Nokogiri::HTML(response.body)
7
+ results = []
8
+ headers = noko.css('.tr_header')
9
+ infogrids = noko.css('.table_infogrid')
10
+ unless headers.empty? || infogrids.empty?
11
+ headers.zip(infogrids).map { |arr| results << Result.new(arr[0], arr[1]) }
12
+ end
13
+ replace(results)
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,3 @@
1
+ module BostonMarathon
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,40 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'rest_client'
4
+ require 'nokogiri'
5
+
6
+ require 'boston_marathon/record_not_found'
7
+ require 'boston_marathon/result_set'
8
+ require 'boston_marathon/result'
9
+
10
+ module BostonMarathon
11
+
12
+ BASE_URL = "http://registration.baa.org/2011/cf/Public/iframe_ResultsSearch.cfm?mode=results"
13
+ RESULTS_PER_PAGE = 25 # up to 25 results can be retrieved at a time
14
+ RACE_CAP = 30000 # an arbitrary number that's larger than the number of race participants
15
+
16
+ class << self
17
+
18
+ # returns the result for a specific bib number
19
+ def result(bib)
20
+ result_set = fetch({'BibNumber' => bib})
21
+ raise BostonMarathon::RecordNotFound if result_set.empty?
22
+ result_set[0]
23
+ end
24
+
25
+ # returns a max of RESULTS_PER_PAGE results.
26
+ # see README for list of query params
27
+ def results(params)
28
+ fetch({'VarTargetCount' => RACE_CAP}.merge params)
29
+ end
30
+
31
+ private
32
+
33
+ def fetch(params={})
34
+ response = RestClient.post BASE_URL, params
35
+ BostonMarathon::ResultSet.new(response)
36
+ end
37
+
38
+ end
39
+
40
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,14 @@
1
+ # I know it's bad to require rubygems, but I haven't yet figured out how to get around it
2
+ require 'rubygems'
3
+ require 'test/unit'
4
+ require 'redgreen'
5
+ require 'vcr'
6
+ require 'fakeweb'
7
+ require 'shoulda-context'
8
+ require 'boston_marathon'
9
+
10
+ VCR.config do |c|
11
+ c.cassette_library_dir = 'test/vcr_cassettes'
12
+ c.stub_with :fakeweb
13
+ c.default_cassette_options = { :record => :once }
14
+ end
@@ -0,0 +1,97 @@
1
+ require 'test/helper'
2
+
3
+ class TestBostonMarathon < Test::Unit::TestCase
4
+
5
+ context "when looking up a result by an INVALID bib number" do
6
+
7
+ should "raise a RecordNotFound exception" do
8
+ assert_raise BostonMarathon::RecordNotFound do
9
+ VCR.use_cassette('bad_bib') do
10
+ @result = BostonMarathon.result('a')
11
+ end
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ context "when looking up a result by a VALID bib number" do
18
+
19
+ setup do
20
+ VCR.use_cassette('bib_43') do
21
+ @result = BostonMarathon.result(43)
22
+ end
23
+ end
24
+
25
+ should "have the correct athlete attributes" do
26
+ expected = ['43', 'Krah, Nathan M.', '25', 'M', 'Boston', 'MA', 'USA']
27
+ tested = [@result.bib, @result.name, @result.age, @result.gender, @result.city, @result.state, @result.country]
28
+ assert_equal expected, tested
29
+ end
30
+
31
+ should "have the correct splits" do
32
+ expected = {
33
+ '5k' => '0:16:40',
34
+ '10k' => '0:33:24',
35
+ '15k' => '0:50:03',
36
+ '20k' => '1:06:46',
37
+ 'half' => '1:10:25',
38
+ '25k' => '1:23:42',
39
+ '30k' => '1:40:39',
40
+ '35k' => '1:57:52',
41
+ '40k' => '2:14:53'
42
+ }
43
+ assert_equal expected, @result.splits
44
+ end
45
+
46
+ should "have the correct finish info" do
47
+ expected = ['0:05:26', '', '2:22:24', '29', '29', '25']
48
+ tested = [@result.pace, @result.projected_time, @result.time, @result.place, @result.gender_place, @result.division_place]
49
+ assert_equal expected, tested
50
+ end
51
+
52
+ end
53
+
54
+ context "when searching for" do
55
+
56
+ context "the top 20 women" do
57
+
58
+ setup do
59
+ VCR.use_cassette('top_20_women') do
60
+ @results = BostonMarathon.results({'GenderID' => 2, 'VarTargetCount' => 20})
61
+ end
62
+ end
63
+
64
+ should "return the results of the 20 fastest female runners" do
65
+ assert_equal 20, @results.length
66
+ assert_equal ["F"], @results.map(&:gender).uniq
67
+ end
68
+
69
+ end
70
+
71
+ context "someone matching very specific attributes" do
72
+
73
+ setup do
74
+ VCR.use_cassette('ryan_hall') do
75
+ @results = BostonMarathon.results({
76
+ 'BibNumber' => 3,
77
+ 'LastName' => 'Hall',
78
+ 'FirstName' => 'Ryan',
79
+ 'ReportingSegmentId' => 1,
80
+ 'GenderID' => 1,
81
+ 'City' => 'Mammoth Lakes',
82
+ 'StateID' => '10',
83
+ 'CountryOfResID' => 193
84
+ })
85
+ end
86
+ end
87
+
88
+ should "return the athlete we're looking for" do
89
+ assert_equal 1, @results.length
90
+ assert_equal "Hall, Ryan", @results[0].name
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+
97
+ end