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 +4 -4
- data/README.md +20 -16
- data/lib/extraspace/crawler.rb +52 -0
- data/lib/extraspace/facility.rb +9 -4
- data/lib/extraspace/link.rb +26 -0
- data/lib/extraspace/sitemap.rb +41 -0
- data/lib/extraspace/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b2d656b5fbca3894562492b6a8c3e90c97a4c785cf88d6ff7c2c65c380a5ba8e
|
4
|
+
data.tar.gz: c564ac28246067bfb3d843070aa8ea3dcaa0898e12161e15c7570439cd8d4907
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
puts "
|
27
|
-
puts "
|
28
|
-
puts "
|
29
|
-
puts "
|
30
|
-
puts
|
31
|
-
|
32
|
-
facility.
|
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
|
data/lib/extraspace/facility.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/extraspace/version.rb
CHANGED
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.
|
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-
|
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:
|