extraspace 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d0f31dad347795d2fb0a8cbd14b3c6452fc8c8dfea0f9b66639bc4c1bf1c433
4
- data.tar.gz: 35cedca68983cab7e29c76abc7c8c83d617dad6c2ef881bbd13ecced436fd89d
3
+ metadata.gz: b2d656b5fbca3894562492b6a8c3e90c97a4c785cf88d6ff7c2c65c380a5ba8e
4
+ data.tar.gz: c564ac28246067bfb3d843070aa8ea3dcaa0898e12161e15c7570439cd8d4907
5
5
  SHA512:
6
- metadata.gz: e56ad3839e7a9f5a11b8298e7977c518590aade51b78a7248c201b03027b35b697ef792e311e76b797d1d6aa51d00e996d753651ff66e2fb5e00b74d2c8ab86c
7
- data.tar.gz: 5bb15f6c216c19d628f2179dd4dafe714804ee50d9142d72039d7fba0e68a5ad7ceaaa29e54259868a3ad0f53be9e0d9c677ce207ced6a5730471a2ac0439f13
6
+ metadata.gz: 503b60e74410c4fe5cf0db8644382555cf0ddb8343790e5eed69d61c7b8d5e494be3cdbd55097fee3454f555f2bd030722b704906384da65d020e688252ad46a
7
+ data.tar.gz: d48d92e05c00b065619738803344b79254ecb29cec4e9d461a47709169c1125864d278f07ce421647b17d2e6f83efdb09c9a102fe393766edab8d5aa457639db
data/README.md CHANGED
@@ -17,22 +17,26 @@ gem install extrapsace
17
17
  ```ruby
18
18
  require 'extraspace'
19
19
 
20
- URL = 'https://www.extraspace.com/storage/facilities/us/alabama/auburn/3264/'
21
- facility = ExtraSpace::Facility.fetch(url: URL)
22
-
23
- puts "Line 1: #{facility.address.line1}"
24
- puts "Line 2: #{facility.address.line2}"
25
- puts "City: #{facility.address.city}"
26
- puts "State: #{facility.address.state}"
27
- puts "ZIP: #{facility.address.zip}"
28
- puts "Latitude: #{facility.geocode.latitude}"
29
- puts "Longitude: #{facility.geocode.longitude}"
30
- puts
31
-
32
- facility.prices.each do |price|
33
- puts "UID: #{price.uid}"
34
- puts "Dimensions: #{price.dimensions.display}"
35
- puts "Rates: $#{price.rates.street} (street) / $#{price.rates.web} (web)"
20
+ sitemap = ExtraSpace::Facility.sitemap
21
+ sitemap.links.each do |link|
22
+ url = link.loc
23
+
24
+ facility = ExtraSpace::Facility.fetch(url:)
25
+
26
+ puts "Line 1: #{facility.address.line1}"
27
+ puts "Line 2: #{facility.address.line2}"
28
+ puts "City: #{facility.address.city}"
29
+ puts "State: #{facility.address.state}"
30
+ puts "ZIP: #{facility.address.zip}"
31
+ puts "Latitude: #{facility.geocode.latitude}"
32
+ puts "Longitude: #{facility.geocode.longitude}"
36
33
  puts
34
+
35
+ facility.prices.each do |price|
36
+ puts "UID: #{price.uid}"
37
+ puts "Dimensions: #{price.dimensions.display}"
38
+ puts "Rates: $#{price.rates.street} (street) / $#{price.rates.web} (web)"
39
+ puts
40
+ end
37
41
  end
38
42
  ```
@@ -26,9 +26,8 @@ module ExtraSpace
26
26
  # @param line1 [String]
27
27
  # @param line2 [String]
28
28
  # @param city [String]
29
- # @param state_abbreviation [String]
30
- # @param state_name [String]
31
- # @param postal_code [String]
29
+ # @param state [String]
30
+ # @param zip [String]
32
31
  def initialize(line1:, line2:, city:, state:, zip:)
33
32
  @line1 = line1
34
33
  @line2 = line2
@@ -37,6 +36,7 @@ module ExtraSpace
37
36
  @zip = zip
38
37
  end
39
38
 
39
+ # @return [String]
40
40
  def inspect
41
41
  props = [
42
42
  "line1=#{@line1.inspect}",
@@ -7,7 +7,7 @@ module ExtraSpace
7
7
  # @return [String]
8
8
  attr_accessor :available
9
9
 
10
- # @param uid [String]
10
+ # @param available [String]
11
11
  def initialize(available:)
12
12
  @available = available
13
13
  end
@@ -22,7 +22,7 @@ module ExtraSpace
22
22
 
23
23
  # @param data [Hash]
24
24
  #
25
- # @return [Address]
25
+ # @return [Availability]
26
26
  def self.parse(data:)
27
27
  new(available: data['available'])
28
28
  end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExtraSpace
4
+ # Used to fetch and parse either HTML or XML via a URL.
5
+ class Crawler
6
+ # Raised for unexpected HTTP responses.
7
+ class FetchError < StandardError
8
+ # @param url [String]
9
+ # @param response [HTTP::Response]
10
+ def initialize(url:, response:)
11
+ super("url=#{url} status=#{response.status.inspect} body=#{response.body.inspect}")
12
+ end
13
+ end
14
+
15
+ # @param url [String]
16
+ # @raise [FetchError]
17
+ # @return [Nokogiri::HTML::Document]
18
+ def self.html(url:)
19
+ new.html(url:)
20
+ end
21
+
22
+ # @param url [String]
23
+ # @raise [FetchError]
24
+ # @return [Nokogiri::XML::Document]
25
+ def self.xml(url:)
26
+ new.xml(url:)
27
+ end
28
+
29
+ # @param url [String]
30
+ # @return [HTTP::Response]
31
+ def fetch(url:)
32
+ response = HTTP.get(url)
33
+ raise FetchError(url:, response: response.flush) unless response.status.ok?
34
+
35
+ response
36
+ end
37
+
38
+ # @param url [String]
39
+ # @raise [FetchError]
40
+ # @return [Nokogiri::XML::Document]
41
+ def html(url:)
42
+ Nokogiri::HTML(String(fetch(url:).body))
43
+ end
44
+
45
+ # @param url [String]
46
+ # @raise [FetchError]
47
+ # @return [Nokogiri::XML::Document]
48
+ def xml(url:)
49
+ Nokogiri::XML(String(fetch(url:).body))
50
+ end
51
+ end
52
+ end
@@ -19,7 +19,10 @@ module ExtraSpace
19
19
  # @return [String]
20
20
  attr_accessor :display
21
21
 
22
- # @param uid [String]
22
+ # @param depth [Integer]
23
+ # @param width [Integer]
24
+ # @param sqft [Integer]
25
+ # @param display [String]
23
26
  def initialize(depth:, width:, sqft:, display:)
24
27
  @depth = depth
25
28
  @width = width
@@ -40,7 +43,7 @@ module ExtraSpace
40
43
 
41
44
  # @param data [Hash]
42
45
  #
43
- # @return [Address]
46
+ # @return [Dimensions]
44
47
  def self.parse(data:)
45
48
  new(depth: data['depth'], width: data['width'], sqft: data['squareFoot'], display: data['display'])
46
49
  end
@@ -3,6 +3,8 @@
3
3
  module ExtraSpace
4
4
  # e.g. https://www.extraspace.com/storage/facilities/us/alabama/auburn/3264/
5
5
  class Facility
6
+ SITEMAP_URL = 'https://www.extraspace.com/facility-sitemap.xml'
7
+
6
8
  # @attribute [rw] address
7
9
  # @return [Address]
8
10
  attr_accessor :address
@@ -24,6 +26,7 @@ module ExtraSpace
24
26
  @prices = prices
25
27
  end
26
28
 
29
+ # @return [String]
27
30
  def inspect
28
31
  props = [
29
32
  "address=#{@address.inspect}",
@@ -33,15 +36,18 @@ module ExtraSpace
33
36
  "#<#{self.class.name} #{props.join(' ')}>"
34
37
  end
35
38
 
39
+ # @return [Sitemap]
40
+ def self.sitemap
41
+ Sitemap.fetch(url: SITEMAP_URL)
42
+ end
43
+
36
44
  # @param url [String]
37
45
  #
38
46
  # @return [Facility]
39
47
  def self.fetch(url:)
40
- response = HTTP.get(url)
41
- document = Nokogiri::HTML(String(response.body))
48
+ document = Crawler.html(url:)
42
49
  data = JSON.parse(document.at('#__NEXT_DATA__').text)
43
-
44
- parse(data: data)
50
+ parse(data:)
45
51
  end
46
52
 
47
53
  # @param data [Hash]
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExtraSpace
4
+ # A link in a sitemap.
5
+ class Link
6
+ # @attribute [rw] loc
7
+ # @return [String]
8
+ attr_accessor :loc
9
+
10
+ # @attribute [rw] lastmod
11
+ # @return [Time]
12
+ attr_accessor :lastmod
13
+
14
+ # @param loc [String]
15
+ # @param lastmod [String]
16
+ def initialize(loc:, lastmod:)
17
+ @loc = loc
18
+ @lastmod = Time.parse(lastmod)
19
+ end
20
+
21
+ # @return [String]
22
+ def inspect
23
+ "#<#{self.class.name} loc=#{@loc.inspect} lastmod=#{@lastmod.inspect}>"
24
+ end
25
+ end
26
+ end
@@ -43,7 +43,7 @@ module ExtraSpace
43
43
 
44
44
  # @param data [Hash]
45
45
  #
46
- # @return [Address]
46
+ # @return [Price]
47
47
  def self.parse(data:)
48
48
  availability = Availability.parse(data: data['availability'])
49
49
  dimensions = Dimensions.parse(data: data['dimensions'])
@@ -15,7 +15,9 @@ module ExtraSpace
15
15
  # @return [Integer]
16
16
  attr_accessor :web
17
17
 
18
- # @param uid [String]
18
+ # @param nsc [Integer]
19
+ # @param street [Integer]
20
+ # @param web [Integer]
19
21
  def initialize(nsc:, street:, web:)
20
22
  @nsc = nsc
21
23
  @street = street
@@ -34,7 +36,7 @@ module ExtraSpace
34
36
 
35
37
  # @param data [Hash]
36
38
  #
37
- # @return [Address]
39
+ # @return [Rates]
38
40
  def self.parse(data:)
39
41
  new(
40
42
  nsc: data['nsc'],
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ExtraSpace
4
+ # e.g. https://www.extraspace.com/facility-sitemap.xml
5
+ class Sitemap
6
+ # @attribute [rw] links
7
+ # @return [Array<Link>]
8
+ attr_accessor :links
9
+
10
+ # @param document [NokoGiri::XML::Document]
11
+ #
12
+ # @return [Sitemap]
13
+ def self.parse(document:)
14
+ links = document.xpath('//xmlns:url').map do |url|
15
+ loc = url.at_xpath('xmlns:loc')&.text
16
+ lastmod = url.at_xpath('xmlns:lastmod')&.text
17
+ Link.new(loc:, lastmod:)
18
+ end
19
+
20
+ new(links: links)
21
+ end
22
+
23
+ # @param url [String]
24
+ #
25
+ # @return [Sitemap]
26
+ def self.fetch(url:)
27
+ document = Crawler.xml(url:)
28
+ parse(document:)
29
+ end
30
+
31
+ # @param links [Array<Link>]
32
+ def initialize(links:)
33
+ @links = links
34
+ end
35
+
36
+ # @return [String]
37
+ def inspect
38
+ "#<#{self.class.name} links=#{@links.inspect}>"
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExtraSpace
4
- VERSION = '0.1.0'
4
+ VERSION = '0.1.2'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extraspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-20 00:00:00.000000000 Z
11
+ date: 2024-11-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -80,11 +80,14 @@ files:
80
80
  - lib/extraspace.rb
81
81
  - lib/extraspace/address.rb
82
82
  - lib/extraspace/availability.rb
83
+ - lib/extraspace/crawler.rb
83
84
  - lib/extraspace/dimensions.rb
84
85
  - lib/extraspace/facility.rb
85
86
  - lib/extraspace/geocode.rb
87
+ - lib/extraspace/link.rb
86
88
  - lib/extraspace/price.rb
87
89
  - lib/extraspace/rates.rb
90
+ - lib/extraspace/sitemap.rb
88
91
  - lib/extraspace/version.rb
89
92
  homepage: https://github.com/ksylvest/extraspace
90
93
  licenses:
@@ -94,7 +97,7 @@ metadata:
94
97
  homepage_uri: https://github.com/ksylvest/extraspace
95
98
  source_code_uri: https://github.com/ksylvest/extraspace
96
99
  changelog_uri: https://github.com/ksylvest/extraspace
97
- post_install_message:
100
+ post_install_message:
98
101
  rdoc_options: []
99
102
  require_paths:
100
103
  - lib
@@ -109,8 +112,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
109
112
  - !ruby/object:Gem::Version
110
113
  version: '0'
111
114
  requirements: []
112
- rubygems_version: 3.5.22
113
- signing_key:
115
+ rubygems_version: 3.5.23
116
+ signing_key:
114
117
  specification_version: 4
115
118
  summary: A crawler for ExtraSpace.
116
119
  test_files: []