extraspace 0.1.1 → 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: 5c85ab034de8c329973cfe53e470745608a52076d9dce4a037532dc8214f5913
4
- data.tar.gz: fa535b917b40c8349b79683642ce5e367b0ea34c519fbfd16c094fba87025ebe
3
+ metadata.gz: b2d656b5fbca3894562492b6a8c3e90c97a4c785cf88d6ff7c2c65c380a5ba8e
4
+ data.tar.gz: c564ac28246067bfb3d843070aa8ea3dcaa0898e12161e15c7570439cd8d4907
5
5
  SHA512:
6
- metadata.gz: d243f120d52703c773053469004d735eb8deadd63f0706012f1b4e92abe2fc747db2010f8a99e561cce4336841b3e350ebe27376a2de1f037fce75d6da14935c
7
- data.tar.gz: 21db75d1f583a0577bc4b62ea4465eca29e69185f668b254c5fb1ee19dc4215ebb77f2abdf3234820e06964b4bc1926255b74a36b7619017cf203ea0a68a8b89
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
  ```
@@ -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
@@ -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
@@ -34,15 +36,18 @@ module ExtraSpace
34
36
  "#<#{self.class.name} #{props.join(' ')}>"
35
37
  end
36
38
 
39
+ # @return [Sitemap]
40
+ def self.sitemap
41
+ Sitemap.fetch(url: SITEMAP_URL)
42
+ end
43
+
37
44
  # @param url [String]
38
45
  #
39
46
  # @return [Facility]
40
47
  def self.fetch(url:)
41
- response = HTTP.get(url)
42
- document = Nokogiri::HTML(String(response.body))
48
+ document = Crawler.html(url:)
43
49
  data = JSON.parse(document.at('#__NEXT_DATA__').text)
44
-
45
- parse(data: data)
50
+ parse(data:)
46
51
  end
47
52
 
48
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
@@ -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.1'
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.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-21 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: