squash_matrix 0.1.0 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8c24a61db8c036d8b4dbf10aed040446a6d3f2eb
4
- data.tar.gz: ecfdb5e030bcedd8ee643a9f1caacb33d21b5872
3
+ metadata.gz: 7c7451a0708b8453d1b01238019f90ce0cb6ba9a
4
+ data.tar.gz: c30bf4f51f4d4052088790229cf7becfdf6601b4
5
5
  SHA512:
6
- metadata.gz: 31ab76413209e60a0cdd66effad75366d04209db305b9650ac58334412664a8518fa1b053a146f1924e30d0adcbc749769b4d1b71502827f93f7dba419a4b849
7
- data.tar.gz: 2f41bf2fa14b77c71b997810d6a8e0502d7f663da4f95ad364d2173176bd761b7c8669f616810e1ede857e707205f297578daf8610f93ac95f193582f6e19cb2
6
+ metadata.gz: aa4f3f77ddd2cd63a8d230cc1dd2e3c182073fd6576d942c4b402a9c1a337edafdaf0d7a321169843e4aed972779e2d03748df209d6e67a8a64fdc91dcf4922b
7
+ data.tar.gz: f307aa98a263ad7f7a860b641691acb50a76c227c4b3b5c73eb302f5edb3691fa86af768c6e5b4f1a0c7d82a104f5cad456917aa9f23370c308719ad0228fdd8
data/.gitignore CHANGED
@@ -6,6 +6,6 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
-
9
+ **/*.gem
10
10
  # rspec failure tracking
11
11
  .rspec_status
data/Gemfile.lock CHANGED
@@ -2,13 +2,19 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  squash_matrix (0.1.0)
5
- nokogiri (~> 1.8.4)
5
+ http-cookie (~> 1.0, >= 1.0.3)
6
+ nokogiri (~> 1.8, >= 1.8.4)
7
+ user-agent-randomizer (~> 0.2)
6
8
 
7
9
  GEM
8
10
  remote: https://rubygems.org/
9
11
  specs:
10
12
  coderay (1.1.2)
11
13
  diff-lcs (1.3)
14
+ domain_name (0.5.20180417)
15
+ unf (>= 0.0.5, < 1.0.0)
16
+ http-cookie (1.0.3)
17
+ domain_name (~> 0.5)
12
18
  method_source (0.8.2)
13
19
  mini_portile2 (2.3.0)
14
20
  nokogiri (1.8.4)
@@ -18,20 +24,24 @@ GEM
18
24
  method_source (~> 0.8.1)
19
25
  slop (~> 3.4)
20
26
  rake (10.5.0)
21
- rspec (3.7.0)
22
- rspec-core (~> 3.7.0)
23
- rspec-expectations (~> 3.7.0)
24
- rspec-mocks (~> 3.7.0)
25
- rspec-core (3.7.1)
26
- rspec-support (~> 3.7.0)
27
- rspec-expectations (3.7.0)
27
+ rspec (3.8.0)
28
+ rspec-core (~> 3.8.0)
29
+ rspec-expectations (~> 3.8.0)
30
+ rspec-mocks (~> 3.8.0)
31
+ rspec-core (3.8.0)
32
+ rspec-support (~> 3.8.0)
33
+ rspec-expectations (3.8.1)
28
34
  diff-lcs (>= 1.2.0, < 2.0)
29
- rspec-support (~> 3.7.0)
30
- rspec-mocks (3.7.0)
35
+ rspec-support (~> 3.8.0)
36
+ rspec-mocks (3.8.0)
31
37
  diff-lcs (>= 1.2.0, < 2.0)
32
- rspec-support (~> 3.7.0)
33
- rspec-support (3.7.1)
38
+ rspec-support (~> 3.8.0)
39
+ rspec-support (3.8.0)
34
40
  slop (3.6.0)
41
+ unf (0.1.4)
42
+ unf_ext
43
+ unf_ext (0.0.7.5)
44
+ user-agent-randomizer (0.2.0)
35
45
 
36
46
  PLATFORMS
37
47
  ruby
@@ -44,4 +54,4 @@ DEPENDENCIES
44
54
  squash_matrix!
45
55
 
46
56
  BUNDLED WITH
47
- 1.16.1
57
+ 1.16.2
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # SquashMatrix
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/squash_matrix`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Ruby SDK for www.squashmatrix.com
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ The generated client interacts with www.squashmatrix.com by retrieving player and club information and performing search requests.
6
6
 
7
7
  ## Installation
8
8
 
@@ -22,7 +22,94 @@ Or install it yourself as:
22
22
 
23
23
  ## Usage
24
24
 
25
- TODO: Write usage instructions here
25
+ ```ruby
26
+ client = SquashMatrix::Client.new # initialize client
27
+ => SquashMatrix::Client
28
+ client.player_info(42547) # retrieve player info for joshua wilkosz #42547
29
+ => [
30
+ {
31
+ :event=>"2017 Melbourne Autumn State Open Pennant",
32
+ :division=>"State 2",
33
+ :round=>"7",
34
+ :position=>"3",
35
+ :games=>"2-3",
36
+ :points=>"67-73",
37
+ :rating_adjustment=>0.58,
38
+ :rating=>250.2,
39
+ :opponent_rating=>275.24,
40
+ :opponent_name=>"David Crossley",
41
+ :date=> Time,
42
+ :opponent_id=>26809,
43
+ :match_id=>1003302
44
+ }
45
+ ]
46
+ client.club_info(336) # retrieve club info for melbourne university #336
47
+ => {
48
+ :name=>"Melbourne University Squash Club",
49
+ :players=>[
50
+ {
51
+ :name=>"David Clegg",
52
+ :rating=>342.5,
53
+ :rank=>0,
54
+ :id=>43076
55
+ }
56
+ ],
57
+ :juniors=>[
58
+ {
59
+ :name=>"Trevor Bryden",
60
+ :rating=>95.28,
61
+ :rank=>0,
62
+ :id=>72728
63
+ }
64
+ ]
65
+ }
66
+ client.search("joshua") # search for 'joshua'
67
+ => {
68
+ :players=>[
69
+ {
70
+ :name=>"Joshua Altmann",
71
+ :club_name=>"Monash University",
72
+ :id=>47508,
73
+ :rating=>107.821
74
+ }
75
+ ],
76
+ :teams=>[
77
+ {
78
+ :name=>"Joshua mallison",
79
+ :division_name=>"Box 08",
80
+ :event_name=>"2017 Briars @ Thornleigh Box Challenge (Season 29)",
81
+ :id=>80792
82
+ }
83
+ ],
84
+ :clubs=>[]
85
+ }
86
+ client.search("melbourne") # search for 'melbourne'
87
+ => {
88
+ :players=>[
89
+ {
90
+ :name=>"Melbourne Simpson",
91
+ :club_name=>"Mirrabooka",
92
+ :id=>17797,
93
+ :rating=>199.607
94
+ }
95
+ ],
96
+ :teams=>[
97
+ {
98
+ :name=>"Melbourne Uni (2)@Fitz",
99
+ :division_name=>"C Reserve",
100
+ :event_name=>"2012 Melbourne Spring SSL Women's Pennant",
101
+ :id=>39605
102
+ }
103
+ ],
104
+ :clubs=>[
105
+ {
106
+ :name=>"Melbourne University",
107
+ :state=>"Victoria",
108
+ :id=>336
109
+ }
110
+ ]
111
+ }
112
+ ```
26
113
 
27
114
  ## Development
28
115
 
@@ -30,9 +117,11 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
30
117
 
31
118
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
119
 
120
+ To run tests, run `bundle exec rspec`
121
+
33
122
  ## Contributing
34
123
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/squash_matrix. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
124
+ Bug reports and pull requests are welcome on GitHub at https://github.com/wilkosz/squash_matrix. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
125
 
37
126
  ## License
38
127
 
@@ -1,47 +1,47 @@
1
1
  require 'net/http'
2
2
  require 'date'
3
3
  require 'timeout'
4
+ require 'http-cookie'
5
+ require 'user_agent_randomizer'
4
6
  require_relative 'constants'
5
7
  require_relative 'nokogiri-parser'
6
8
  require_relative 'errors'
7
9
 
8
10
  module SquashMatrix
9
11
 
10
- # Client for http interactions with squashmatrix.com website.
12
+ # Client for retrieving player and club information from squashmatrix.com.
11
13
  # If authentication credentials are provided squash matrix will allow
12
14
  # considerably more requests for an IP address and allow forbidden conent
13
15
  # to be requested.
14
16
 
15
17
  class Client
16
18
 
17
- # Returns newly created Client for making club and player requests
19
+ # Returns newly created Client
18
20
  # @note If suppress_errors == false SquashMatrix::Errors::AuthorizationError will be raised if specified credentials are incorrect and squash matrix authentication returns forbidden
19
21
  # @param [Hash] opts the options to create client
20
22
  # @return [Client]
21
23
 
22
24
  def initialize(player: nil, email: nil, password: nil, suppress_errors: false, timeout: 60)
25
+ @user_agent = UserAgentRandomizer::UserAgent.fetch(type: "desktop_browser").string
26
+ @squash_matrix_home_uri = URI::HTTP.build({ host: SquashMatrix::Constants::SQUASH_MATRIX_URL })
23
27
  @suppress_errors = suppress_errors
24
28
  @timeout = timeout
25
29
  if ![player || email, password].any?(&:nil?)
26
- @authenticated = {
27
- valid: false,
28
- authenticated_at: nil,
29
- updated_at: nil,
30
- cookie: nil,
31
- player: player,
32
- email: email,
33
- password: password
34
- }
30
+ @cookie_jar = HTTP::CookieJar.new()
31
+ @player = player
32
+ @email = email
33
+ @password = password
35
34
  authenticate
36
35
  end
37
36
  end
38
37
 
39
- # Returns club information.
38
+ # Returns club info.
40
39
  # @note If suppress_errors == false SquashMatrix Errors will be raised upon HttpNotFound, HttpConflict, Timeout::Error, etc...
41
- # @param id [Numeric] club id found on squash matrix
40
+ # @param id [Fixnum] club id found on squash matrix
42
41
  # @return [Hash] hash object containing club information
43
42
 
44
43
  def club_info(id=nil)
44
+ return if id.nil?
45
45
  uri = URI::HTTP.build({
46
46
  host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
47
47
  path: SquashMatrix::Constants::CLUB_PATH.gsub(':id', id.to_s)
@@ -50,9 +50,9 @@ module SquashMatrix
50
50
  handle_http_request(uri, success_proc)
51
51
  end
52
52
 
53
- # Returns player information.
53
+ # Returns player info.
54
54
  # @note If suppress_errors == false SquashMatrix Errors will be raised upon HttpNotFound, HttpConflict, Timeout::Error, etc...
55
- # @param id [Numeric] played id found on squash matrix
55
+ # @param id [Fixnum] played id found on squash matrix
56
56
  # @return [Hash] hash object containing player information
57
57
 
58
58
  def player_info(id=nil)
@@ -78,8 +78,8 @@ module SquashMatrix
78
78
  path: SquashMatrix::Constants::SEARCH_PATH})
79
79
  query_params = {
80
80
  Criteria: query,
81
- SquashOnly: false,
82
- RacquetballOnly: false}
81
+ SquashOnly: squash_only,
82
+ RacquetballOnly: racquetball_only}
83
83
  success_proc = lambda {|res| SquashMatrix::NokogiriParser.search_results(res.body)}
84
84
  handle_http_request(uri, success_proc,
85
85
  {
@@ -96,15 +96,23 @@ module SquashMatrix
96
96
  if is_get_request
97
97
  req = Net::HTTP::Get.new(uri)
98
98
  set_headers(req, headers: headers)
99
- res = Net::HTTP.start(uri.hostname, uri.port) {|http| http.request(req)}
100
99
  else
101
- res = Net::HTTP.post_form(uri, query_params)
100
+ req = Net::HTTP::Post.new(uri)
101
+ set_headers(req)
102
+ form_data = []
103
+ query_params.each {|key, value| form_data.push([key.to_s, value.to_s])}
104
+ set_headers(req, headers: headers)
105
+ req.set_form(form_data, SquashMatrix::Constants::MULTIPART_FORM_DATA)
102
106
  end
107
+ res = Net::HTTP.start(uri.hostname, uri.port, {use_ssl: uri.scheme == 'https'}) {|http| http.request(req)}
103
108
  case res
104
- when Net::HTTPSuccess
109
+ when Net::HTTPSuccess, Net::HTTPFound
105
110
  return success_proc && success_proc.call(res) || res
106
111
  when Net::HTTPConflict
107
- raise SquashMatrix::Errors::ForbiddenError.new(res) unless @suppress_errors
112
+ unless @suppress_errors
113
+ raise SquashMatrix::Errors::ForbiddenError.new(res.body) if SquashMatrix::Constants::FORBIDDEN_ERROR_REGEX.match(res.body)
114
+ raise SquashMatrix::Errors::TooManyRequestsError.new(res.body) if SquashMatrix::Constants::TOO_MANY_REQUESTS_ERROR_REGEX.match(res.body)
115
+ end
108
116
  else
109
117
  raise SquashMatrix::Errors::UnknownError.new(res) unless @suppress_errors
110
118
  end
@@ -115,32 +123,35 @@ module SquashMatrix
115
123
  end
116
124
 
117
125
  def authenticate
118
- return unless @authenticated
119
- uri = URI::HTTP.build({
126
+ uri = URI::HTTPS.build({
120
127
  host: SquashMatrix::Constants::SQUASH_MATRIX_URL,
121
128
  path: SquashMatrix::Constants::LOGIN_PATH})
122
- headers = {
123
- SquashMatrix::Constants::CONTENT_TYPE_HEADER.to_sym => SquashMatrix::Constants::X_WWW__FROM_URL_ENCODED
124
- }
125
129
  query_params = {
126
- UserName: @authenticated[:player] || @authenticated[:email],
127
- Password: @authenticated[:password],
130
+ UserName: @player&.to_s || @email,
131
+ Password: @password,
128
132
  RememberMe: false
129
133
  }
134
+ headers = {
135
+ SquashMatrix::Constants::CONTENT_TYPE_HEADER => SquashMatrix::Constants::MULTIPART_FORM_DATA
136
+ }
137
+ # need to retrieve the asp.net session id
138
+ home_page_res = handle_http_request(@squash_matrix_home_uri, nil)
139
+ raise SquashMatrix::Errors::AuthorizationError.new(SquashMatrix::Constants::ERROR_RETRIEVING_ASPNET_SESSION) unless home_page_res
140
+ home_page_res[SquashMatrix::Constants::SET_COOKIE_HEADER].split('; ').each do |v|
141
+ @cookie_jar.parse(v, @squash_matrix_home_uri)
142
+ end
130
143
  res = handle_http_request(uri, nil,
131
144
  {
132
145
  is_get_request: false,
133
146
  query_params: query_params,
134
147
  headers: headers
135
148
  })
136
- return unless res
137
- @authenticated[:cookie] = res.response[SquashMatrix::Constants::SET_COOKIE_HEADER]
138
- if auth_token_from_cookie(@authenticated[:cookie])
139
- @authenticated[:authenticated_at] = Time.now.utc
140
- @authenticated[:updated_at] = Time.now.utc
141
- @authenticated[:valid] = true
142
- @authenticated[:player] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(res.response[SquashMatrix::Constants::LOCATION_HEADER])[1] if @authenticated[:email] && res.response[SquashMatrix::Constants::LOCATION_HEADER]
143
- elsif !@suppress_errors
149
+ raise SquashMatrix::Errors::AuthorizationError.new(SquashMatrix::Constants::ERROR_RETRIEVING_ASPAUX_TOKEN) unless res
150
+ res[SquashMatrix::Constants::SET_COOKIE_HEADER].split('; ').each do |v|
151
+ @cookie_jar.parse(v, @squash_matrix_home_uri)
152
+ end
153
+ @player = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(res[SquashMatrix::Constants::LOCATION_HEADER])[1] if @player.nil? && res[SquashMatrix::Constants::LOCATION_HEADER]
154
+ unless !@suppress_errors && @cookie_jar.cookies(@squash_matrix_home_uri).find {|c| c.name == SquashMatrix::Constants::ASPXAUTH_COOKIE_NAME && !c.value.empty?}
144
155
  error_string = SquashMatrix::NokogiriParser.log_on_error(res.body).join(', ')
145
156
  raise SquashMatrix::Errors::AuthorizationError.new(error_string)
146
157
  end
@@ -148,19 +159,21 @@ module SquashMatrix
148
159
 
149
160
  def set_headers(req=nil, headers: nil)
150
161
  return unless req
151
- headers_to_add = {}
152
- headers_to_add.merge(headers) if headers
153
- headers_to_add.merge({
154
- Cookie: @authenticated[:cookie],
155
- Referer: SquashMatrix::Constants::REFERER.gsub(':id', @authenticated[:player]),
156
- }) if @authenticated
157
- headers_to_add.each {|key, val| req[key] = val}
158
- end
159
-
160
- def auth_token_from_cookie(cookie=nil)
161
- return unless !cookie.nil? && !cookie.empty?
162
- rtn = SquashMatrix::Constants::ASPXAUTH_TOKEN_FROM_COOKIE_REGEX.match(cookie)
163
- rtn[1] if rtn
162
+ headers_to_add = {
163
+ SquashMatrix::Constants::USER_AGENT_HEADER => @user_agent,
164
+ SquashMatrix::Constants::HOST_HEADER => SquashMatrix::Constants::SQUASH_MATRIX_URL}
165
+ headers_to_add = headers_to_add.merge(headers) if headers
166
+ if @cookie_jar
167
+ cookies = @cookie_jar.cookies(@squash_matrix_home_uri).select do |c|
168
+ [
169
+ SquashMatrix::Constants::ASP_NET_SESSION_ID_COOKIE_NAME,
170
+ SquashMatrix::Constants::GROUP_ID_COOKIE_NAME,
171
+ SquashMatrix::Constants::ASPXAUTH_COOKIE_NAME
172
+ ].include?(c.name)
173
+ end
174
+ headers_to_add = headers_to_add.merge({SquashMatrix::Constants::COOKIE_HEADER => HTTP::Cookie.cookie_value(cookies)})
175
+ end
176
+ headers_to_add.each {|key, val| req[key.to_s] = val}
164
177
  end
165
178
  end
166
179
  end
@@ -8,17 +8,28 @@ module SquashMatrix
8
8
  SEARCH_PATH = "/Home/Search"
9
9
  PLAYER_RSULTS_QUERY = "max=0&X-Requested-With=XMLHttpRequest"
10
10
  SET_COOKIE_HEADER = 'set-cookie'
11
+ COOKIE_HEADER = 'cookie'
11
12
  LOCATION_HEADER = 'location'
12
13
  X_WWW__FROM_URL_ENCODED = 'application/x-www-form-urlencoded'
13
14
  MULTIPART_FORM_DATA = 'multipart/form-data'
14
- CONTENT_TYPE_HEADER = 'Content-Type'
15
+ CONTENT_TYPE_HEADER = 'content-type'
15
16
  REFERER = "Home/Player/:id"
17
+ ASPXAUTH_COOKIE_NAME = ".ASPXAUTH"
18
+ ASP_NET_SESSION_ID_COOKIE_NAME = "ASP.NET_SessionId"
19
+ GROUP_ID_COOKIE_NAME = "GroupId"
20
+ HOST_HEADER = 'host'
21
+ USER_AGENT_HEADER = 'user-agent'
16
22
 
17
23
  PLAYER_FROM_PATH_REGEX = /\/Home\/Player\/(.*)/
18
24
  TEAM_FROM_PATH_REGEX = /\/Home\/Team\/(.*)/
19
25
  CLUB_FROM_PATH_REGEX = /\/Home\/Club\/(.*)/
20
26
  MATCH_FROM_PATH_REGEX = /\/Home\/Match\/(.*)/
21
27
  CLUB_FROM_TITLE_REGEX = /Club - (.*)/
22
- ASPXAUTH_TOKEN_FROM_COOKIE_REGEX = /.ASPXAUTH=([a-zA-Z0-9]*);/
28
+
29
+ ERROR_RETRIEVING_ASPNET_SESSION = "Error retrieving ASP.NET_SessionId"
30
+ ERROR_RETRIEVING_ASPAUX_TOKEN = "Error retrieving .ASPXAUTH_TOKEN"
31
+
32
+ TOO_MANY_REQUESTS_ERROR_REGEX = /Request made too soon. This is to prevent abuse to the site. We apologise for the inconvenience/
33
+ FORBIDDEN_ERROR_REGEX = /Forbidden/
23
34
  end
24
35
  end
@@ -1,5 +1,6 @@
1
1
  module SquashMatrix
2
2
  module Errors
3
+ class TooManyRequestsError < StandardError; end
3
4
  class AuthorizationError < StandardError; end
4
5
  class ForbiddenError < StandardError; end
5
6
  class UnknownError < StandardError; end
@@ -3,122 +3,129 @@ require_relative 'constants'
3
3
 
4
4
  module SquashMatrix
5
5
  class NokogiriParser
6
- def self.player_info(body)
7
- Nokogiri::HTML(body)&.xpath('//table[@id="results"]//tbody//tr')&.map do |r|
8
- date = r.at_css('td[1]')&.content
9
- opponent_id = r.at_css('td[10]//a')&.attribute('href')&.content
10
- match_id = r.at_css('td[12]//a')&.attribute('href')&.content
11
- rtn = {
12
- event: r.at_css('td[2]')&.content,
13
- division: r.at_css('td[3]')&.content,
14
- round: r.at_css('td[4]')&.content,
15
- position: r.at_css('td[5]')&.content,
16
- games: r.at_css('td[6]')&.content,
17
- points: r.at_css('td[7]')&.content,
18
- rating_adjustment: r.at_css('td[8]')&.content,
19
- rating: r.at_css('td[9]')&.content,
20
- opponent_rating: r.at_css('td[11]')&.content,
21
- opponent_name: r.at_css('td[10]//a')&.content
22
- }
23
- rtn[:date] = Date.parse(date) if date
24
- rtn[:opponent_id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(opponent_id)[1] if opponent_id
25
- rtn[:match_id] = SquashMatrix::Constants::MATCH_FROM_PATH_REGEX.match(match_id)[1] if match_id
26
- rtn.values.any?(&:nil?) ? nil : rtn
27
- end.compact
28
- end
6
+ class << self
7
+ def player_info(body)
8
+ Nokogiri::HTML(body)&.xpath('//table[@id="results"]//tbody//tr')&.map do |r|
9
+ date = r.at_css('td[1]')&.content
10
+ opponent_id = r.at_css('td[10]//a')&.attribute('href')&.content
11
+ match_id = r.at_css('td[12]//a')&.attribute('href')&.content
12
+ rtn = {
13
+ event: r.at_css('td[2]')&.content,
14
+ division: r.at_css('td[3]')&.content,
15
+ round: r.at_css('td[4]')&.content,
16
+ position: r.at_css('td[5]')&.content,
17
+ games: r.at_css('td[6]')&.content,
18
+ points: r.at_css('td[7]')&.content,
19
+ rating_adjustment: r.at_css('td[8]')&.content&.to_f,
20
+ rating: r.at_css('td[9]')&.content&.to_f,
21
+ opponent_rating: r.at_css('td[11]')&.content&.to_f,
22
+ opponent_name: r.at_css('td[10]//a')&.content
23
+ }
24
+ rtn[:date] = Date.parse(date) if date
25
+ rtn[:opponent_id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(opponent_id)[1].to_i if opponent_id
26
+ rtn[:match_id] = SquashMatrix::Constants::MATCH_FROM_PATH_REGEX.match(match_id)[1].to_i if match_id
27
+ rtn.values.any?(&:nil?) ? nil : rtn
28
+ end.compact
29
+ end
29
30
 
30
- def self.club_info(body)
31
- html = Nokogiri::HTML(body)
32
- name = SquashMatrix::Constants::CLUB_FROM_TITLE_REGEX.match(html.css('title').text)[1]
33
- players = html.xpath('//div[@id="Rankings"]//div[@class="columnmain"]//table[@class="alternaterows"]//tbody//tr')&.map do |r|
34
- player_path = r.css('td[2]//a').attribute('href').value
35
- rank = r.css('td[1]').text
36
- rtn = {
37
- name: r.css('td[2]').text,
38
- rating: r.css('td[3]').text.to_f
31
+ def club_info(body)
32
+ html = Nokogiri::HTML(body)
33
+ name = SquashMatrix::Constants::CLUB_FROM_TITLE_REGEX.match(html.css('title').text)[1]
34
+ players = html.xpath('//div[@id="Rankings"]//div[@class="columnmain"]//table[@class="alternaterows"]//tbody//tr')&.map do |r|
35
+ player_path = r.css('td[2]//a').attribute('href').value
36
+ rank = r.css('td[1]').text
37
+ rtn = {
38
+ name: r.css('td[2]').text,
39
+ rating: r.css('td[3]').text.to_f
40
+ }
41
+ rtn[:rank] = rank.to_i if rank
42
+ rtn[:id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(player_path)[1].to_i if player_path
43
+ rtn
44
+ end.compact
45
+ juniors = html.xpath('//div[@id="Rankings"]//div[@class="columnside"]//table[@class="alternaterows"]//tbody//tr')&.map do |r|
46
+ player_path = r.css('td[2]//a').attribute('href').value
47
+ rank = r.css('td[1]').text
48
+ rtn = {
49
+ name: r.css('td[2]').text,
50
+ rating: r.css('td[3]').text.to_f
51
+ }
52
+ rtn[:rank] = rank.to_i if rank
53
+ rtn[:id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(player_path)[1].to_i if player_path
54
+ rtn
55
+ end.compact
56
+ {
57
+ name: name,
58
+ players: players,
59
+ juniors: juniors
39
60
  }
40
- rtn[:rank] = rank.to_i if rank
41
- rtn[:id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(player_path)[1] if player_path
42
- rtn
43
- end.compact
44
- juniors = html.xpath('//div[@id="Rankings"]//div[@class="columnside"]//table[@class="alternaterows"]//tbody//tr')&.map do |r|
45
- player_path = r.css('td[2]//a').attribute('href').value
46
- rank = r.css('td[1]').text
47
- rtn = {
48
- name: r.css('td[2]').text,
49
- rating: r.css('td[3]').text.to_f
50
- }
51
- rtn[:rank] = rank.to_i if rank
52
- rtn[:id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(player_path)[1] if player_path
53
- rtn
54
- end.compact
55
- {
56
- name: name,
57
- players: players,
58
- juniors: juniors
59
- }
60
- end
61
+ end
61
62
 
62
- def self.search_results(body)
63
- bc = Nokogiri::HTML.parse(body).at_xpath('//div[@id="bodycontent"]')&.children
64
- return unless bc&.length
65
- rtn = {}
66
- bc&.each_with_index do |c, i|
67
- if c.name == "h2"
68
- case c.text
69
- when "Players"
70
- rtn[:players] = players_from_search(bc[i+2]) if bc[i+2].children.length
71
- when "Teams"
72
- rtn[:teams] = teams_from_search(bc[i+2]) if bc[i+2].children.length
73
- when "Clubs"
74
- rtn[:clubs] = clubs_from_search(bc[i+2]) if bc[i+2].children.length
63
+ def search_results(body)
64
+ bc = Nokogiri::HTML.parse(body).at_xpath('//div[@id="bodycontent"]')&.children
65
+ return unless bc&.length
66
+ rtn = {}
67
+ bc&.each_with_index do |c, i|
68
+ if c.name == "h2"
69
+ case c.text
70
+ when "Players"
71
+ rtn[:players] = players_from_search(bc[i+2]) if bc[i+2].children.length
72
+ when "Teams"
73
+ rtn[:teams] = teams_from_search(bc[i+2]) if bc[i+2].children.length
74
+ when "Clubs"
75
+ rtn[:clubs] = clubs_from_search(bc[i+2]) if bc[i+2].children.length
76
+ end
75
77
  end
76
78
  end
79
+ rtn
77
80
  end
78
- rtn
79
- end
80
81
 
81
- def self.log_on_error(body)
82
- Nokogiri::HTML(body)&.xpath('//div[@class="validation-summary-errors"]//ul//li')&.map(&:content)
83
- end
82
+ def log_on_error(body)
83
+ Nokogiri::HTML(body)&.xpath('//div[@class="validation-summary-errors"]//ul//li')&.map(&:content)
84
+ end
84
85
 
85
- def self.players_from_search(node)
86
- node.css('tbody').css('tr')&.map do |tr|
87
- id = tr.css('td[1]//a')&.attribute('href')&.value
88
- rating = tr.css('td[3]')&.text
89
- rtn = {
90
- name: tr.css('td[1]')&.text,
91
- club_name: tr.css('td[2]')&.text
92
- }
93
- rtn[:id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(id)[1].to_i if id && !id.empty?
94
- rtn[:rating] = rating.to_f if rating
95
- rtn
86
+ private
87
+
88
+ def players_from_search(node)
89
+ node.css('tbody//tr')&.map do |tr|
90
+ id = tr.css('td[1]//a')&.attribute('href')&.value
91
+ rating = tr.css('td[3]')&.text
92
+ rtn = {
93
+ name: tr.css('td[1]')&.text,
94
+ club_name: tr.css('td[2]')&.text
95
+ }
96
+ rtn[:id] = SquashMatrix::Constants::PLAYER_FROM_PATH_REGEX.match(id)[1].to_i if id && !id.empty?
97
+ rtn[:rating] = rating.to_f if rating
98
+ rtn
99
+ end
96
100
  end
97
- end
98
101
 
99
- def self.teams_from_search(node)
100
- node.css('tbody').css('tr')&.map do |tr|
101
- id = tr.css('td[1]//a')&.attribute('href')&.value
102
- rtn = {
103
- name: tr.css('td[1]')&.text,
104
- division_name: tr.css('td[2]')&.text,
105
- event_name: tr.css('td[3]')&.text
106
- }
107
- rtn[:id] = SquashMatrix::Constants::TEAM_FROM_PATH_REGEX.match(id)[1].to_i if id
108
- rtn
102
+ def teams_from_search(node)
103
+ node.css('tbody//tr')&.map do |tr|
104
+ id = tr.css('td[1]//a')&.attribute('href')&.value
105
+ rtn = {
106
+ name: tr.css('td[1]')&.text,
107
+ division_name: tr.css('td[2]')&.text,
108
+ event_name: tr.css('td[3]')&.text
109
+ }
110
+ rtn[:id] = SquashMatrix::Constants::TEAM_FROM_PATH_REGEX.match(id)[1].to_i if id
111
+ rtn
112
+ end
109
113
  end
110
- end
111
114
 
112
- def self.clubs_from_search(node)
113
- node.css('tbody').css('tr')&.map do |tr|
114
- puts tr
115
- id = tr.css('td[1]//a')&.attribute('href')&.value
116
- rtn = {
117
- name: tr.css('td[1]')&.text,
118
- state: tr.css('td[2]')&.text
119
- }
120
- rtn[:id] = SquashMatrix::Constants::CLUB_FROM_PATH_REGEX.match(id)[1].to_i if id
121
- rtn
115
+ def clubs_from_search(node)
116
+ node.css('tbody//tr')&.map do |tr|
117
+ id = tr.css('td[1]//a')&.attribute('href')&.value
118
+ rtn = {
119
+ name: tr.css('td[1]')&.text,
120
+ state: tr.css('td[2]')&.text
121
+ }
122
+ rtn[:id] = SquashMatrix::Constants::CLUB_FROM_PATH_REGEX.match(id)[1].to_i if id
123
+ rtn
124
+ end
125
+ end
126
+
127
+ def requests_made_to_soon?(body)
128
+ Nokogiri::HTML(body)&.xpath('//body')
122
129
  end
123
130
  end
124
131
  end
@@ -1,3 +1,3 @@
1
1
  module SquashMatrix
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
@@ -9,8 +9,8 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Joshua Wilkosz"]
10
10
  spec.email = ["joshua@wilkosz.com.au"]
11
11
 
12
- spec.summary = %q{Client for squashmatrix.com http request/response}
13
- spec.description = %q{User for retrieving information on squashmatrix.com}
12
+ spec.summary = %q{Ruby SDK for www.squashmatrix.com}
13
+ spec.description = %q{The generated client interacts with www.squashmatrix.com by retrieving player and club information and performing search requests}
14
14
  spec.homepage = "https://github.com/wilkosz/squash_matrix"
15
15
  spec.license = "MIT"
16
16
 
@@ -36,7 +36,8 @@ Gem::Specification.new do |spec|
36
36
  spec.add_development_dependency "rake", "~> 10.0"
37
37
  spec.add_development_dependency "rspec", "~> 3.0"
38
38
  spec.add_development_dependency "pry", "~> 0.10.3"
39
-
39
+ spec.add_runtime_dependency 'user-agent-randomizer', '~> 0.2'
40
+ spec.add_runtime_dependency 'http-cookie', '~> 1.0', '>= 1.0.3'
40
41
  spec.add_runtime_dependency 'nokogiri', '~> 1.8', '>= 1.8.4'
41
42
  spec.required_ruby_version = '>= 2.3.0'
42
43
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: squash_matrix
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joshua Wilkosz
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-13 00:00:00.000000000 Z
11
+ date: 2018-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,40 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.10.3
69
+ - !ruby/object:Gem::Dependency
70
+ name: user-agent-randomizer
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: http-cookie
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.0'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.0.3
93
+ type: :runtime
94
+ prerelease: false
95
+ version_requirements: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.0'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.0.3
69
103
  - !ruby/object:Gem::Dependency
70
104
  name: nokogiri
71
105
  requirement: !ruby/object:Gem::Requirement
@@ -86,7 +120,8 @@ dependencies:
86
120
  - - ">="
87
121
  - !ruby/object:Gem::Version
88
122
  version: 1.8.4
89
- description: User for retrieving information on squashmatrix.com
123
+ description: The generated client interacts with www.squashmatrix.com by retrieving
124
+ player and club information and performing search requests
90
125
  email:
91
126
  - joshua@wilkosz.com.au
92
127
  executables: []
@@ -132,8 +167,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
132
167
  version: '0'
133
168
  requirements: []
134
169
  rubyforge_project:
135
- rubygems_version: 2.6.14.1
170
+ rubygems_version: 2.6.12
136
171
  signing_key:
137
172
  specification_version: 4
138
- summary: Client for squashmatrix.com http request/response
173
+ summary: Ruby SDK for www.squashmatrix.com
139
174
  test_files: []