publicstorage 1.2.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24f5bb4366cb716cf259fb43e0df167617389a71bbcffa20c2e3534c588b06c1
4
- data.tar.gz: 5b3be4bad58043fdfe30dee4067935bfc2346b778c967231155b670490a08d70
3
+ metadata.gz: c9f5251b3a20251494fcb996abc4a615d4aea13328e56930cadf9d9cc55b7b85
4
+ data.tar.gz: c6118d03fc038114cca43d836c7699a3b1992a482bda995f2138272076ee318e
5
5
  SHA512:
6
- metadata.gz: e117b9fa84c46cbae5a14756cb4f5926a6a1405a91be4963c112fbe2c22d71f8090a33df5ad4b7c9a9126c64c09b524caaa01a1e10c58975d98b5ee593f22a4e
7
- data.tar.gz: 15e95167c0d18276093a62594d95c13b9d2be48276541045c3b683b14748fbe65f38d43e58aeb609e75c3dc98cd82dc688d54d8a22aeb7ebbc514d4dd5e90dbd
6
+ metadata.gz: f29a0afa30474641681ec49b9a3b80e3e5fcffd30b26b53ae65aaf316d78bceafb894bbc789bcc8440f95220d7e1e44f290915464ebcab658560538d3c6f794b
7
+ data.tar.gz: 193ffa5234a99e8238d8f06c3e31bdaeb6bf6fe17e3be3b5378718866a7a943982d56b70695b314a0bda23edac14b6f7f7cf209edcf8ac82a51033c0e80fa53a
@@ -51,11 +51,21 @@ module PublicStorage
51
51
  # @return [Address]
52
52
  def self.parse(data:)
53
53
  new(
54
- street: data['streetAddress'],
54
+ street: stripe_leading_or_trailing_null(data['streetAddress']),
55
55
  city: data['addressLocality'],
56
56
  state: data['addressRegion'],
57
57
  zip: data['postalCode']
58
58
  )
59
59
  end
60
+
61
+ # NOTE: this fixes a bug w/ publicstorage that currently exists where addresses have a leading / trailing null.
62
+ #
63
+ # @param value [String]
64
+ #
65
+ # @return [String]
66
+ def self.stripe_leading_or_trailing_null(value)
67
+ match = value.match(/\A(?:null)?(?<text>.*?)(?:null)?\z/)
68
+ match[:text]
69
+ end
60
70
  end
61
71
  end
@@ -8,6 +8,7 @@ module PublicStorage
8
8
  DEFAULT_PHONE = '1-800-742-8048'
9
9
  DEFAULT_EMAIL = 'customerservice@publicstorage.com'
10
10
 
11
+ NAME_SELECTOR = '.plp-page-header'
11
12
  PRICE_SELECTOR = '.units-results-section .unit-list-group .unit-list-item'
12
13
  LD_SELECTOR = 'script[type="application/ld+json"]'
13
14
 
@@ -62,17 +63,36 @@ module PublicStorage
62
63
  #
63
64
  # @return [Facility]
64
65
  def self.parse(url:, document:)
65
- data = parse_ld(document:)
66
- id = Integer(data['url'].match(ID_REGEX)[:id])
67
- name = data['name']
66
+ data = parse_ld(document: document)
67
+ id = parse_id(data: data)
68
+ name = parse_name(document: document)
68
69
  address = Address.parse(data: data['address'])
69
70
  geocode = Geocode.parse(data: data['geo'])
70
-
71
- prices = document.css(PRICE_SELECTOR).map { |element| Price.parse(element:) }
71
+ prices = parse_prices(document: document)
72
72
 
73
73
  new(id:, url:, name:, address:, geocode:, prices:)
74
74
  end
75
75
 
76
+ # @param data [Hash]
77
+ #
78
+ # @return [Integer]
79
+ def self.parse_id(data:)
80
+ Integer(data['url'].match(ID_REGEX)[:id])
81
+ end
82
+
83
+ # @param document [NokoGiri::XML::Document]
84
+ #
85
+ # @return [String]
86
+ def self.parse_name(document:)
87
+ document.at_css(NAME_SELECTOR).text.gsub(/\s+/, ' ').strip
88
+ end
89
+
90
+ # @param docunent [NokoGiri::XML::Document]
91
+ # @return Array<Price>
92
+ def self.parse_prices(document:)
93
+ document.css(PRICE_SELECTOR).map { |element| Price.parse(element:) }
94
+ end
95
+
76
96
  # @param document [NokoGiri::XML::Document]
77
97
  #
78
98
  # @return [Hash]
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PublicStorage
4
+ # The features (e.g. climate-controlled, inside-drive-up-access, outside-drive-up-access, etc) of a price.
5
+ class Features
6
+ # @param data [Hash]
7
+ #
8
+ # @return [Features]
9
+ def self.parse(data:)
10
+ features = data['features']
11
+ new(
12
+ climate_controlled: features&.include?('climate controlled'),
13
+ drive_up_access: features&.include?('drive-up access'),
14
+ first_floor_access: features&.include?('1st floor')
15
+ )
16
+ end
17
+
18
+ # @param climate_controlled [Boolean]
19
+ # @param drive_up_access [Boolean]
20
+ # @param first_floor_access [Boolean]
21
+ def initialize(climate_controlled:, drive_up_access:, first_floor_access:)
22
+ @climate_controlled = climate_controlled
23
+ @drive_up_access = drive_up_access
24
+ @first_floor_access = first_floor_access
25
+ end
26
+
27
+ # @return [String]
28
+ def inspect
29
+ props = [
30
+ "climate_controlled=#{@climate_controlled}",
31
+ "drive_up_access=#{@drive_up_access}",
32
+ "first_floor_access=#{@first_floor_access}"
33
+ ]
34
+
35
+ "#<#{self.class.name} #{props.join(' ')}>"
36
+ end
37
+
38
+ # @return [String] e.g. "Climate Controlled + First Floor Access"
39
+ def text
40
+ amenities.join(' + ')
41
+ end
42
+
43
+ # @return [Array<String>]
44
+ def amenities
45
+ [].tap do |amenities|
46
+ amenities << 'Climate Controlled' if climate_controlled?
47
+ amenities << 'Drive-Up Access' if drive_up_access?
48
+ amenities << 'First Floor Access' if first_floor_access?
49
+ end
50
+ end
51
+
52
+ # @return [Boolean]
53
+ def climate_controlled?
54
+ @climate_controlled
55
+ end
56
+
57
+ # @return [Boolean]
58
+ def drive_up_access?
59
+ @drive_up_access
60
+ end
61
+
62
+ # @return [Boolean]
63
+ def first_floor_access?
64
+ @first_floor_access
65
+ end
66
+ end
67
+ end
@@ -13,16 +13,22 @@ module PublicStorage
13
13
  # @return [Dimensions]
14
14
  attr_accessor :dimensions
15
15
 
16
+ # @attribute [rw] features
17
+ # @return [Features]
18
+ attr_accessor :features
19
+
16
20
  # @attribute [rw] rates
17
21
  # @return [Rates]
18
22
  attr_accessor :rates
19
23
 
20
24
  # @param id [String]
21
25
  # @param dimensions [Dimensions]
26
+ # @param features [Features]
22
27
  # @param rates [Rates]
23
- def initialize(id:, dimensions:, rates:)
28
+ def initialize(id:, dimensions:, features:, rates:)
24
29
  @id = id
25
30
  @dimensions = dimensions
31
+ @features = features
26
32
  @rates = rates
27
33
  end
28
34
 
@@ -31,14 +37,15 @@ module PublicStorage
31
37
  props = [
32
38
  "id=#{@id.inspect}",
33
39
  "dimensions=#{@dimensions.inspect}",
40
+ "features=#{@features.inspect}",
34
41
  "rates=#{@rates.inspect}"
35
42
  ]
36
43
  "#<#{self.class.name} #{props.join(' ')}>"
37
44
  end
38
45
 
39
- # @return [String] e.g. "123 | 5' × 5' (25 sqft) | $100 (street) / $90 (web)"
46
+ # @return [String] e.g. "123 | 5' × 5' (25 sqft) | $100 (street) / $90 (web) | Climate Controlled"
40
47
  def text
41
- "#{@id} | #{@dimensions.text} | #{@rates.text}"
48
+ "#{@id} | #{@dimensions.text} | #{@rates.text} | #{@features.text}"
42
49
  end
43
50
 
44
51
  # @param element [Nokogiri::XML::Element]
@@ -49,10 +56,12 @@ module PublicStorage
49
56
 
50
57
  rates = Rates.parse(data:)
51
58
  dimensions = Dimensions.parse(data:)
59
+ features = Features.parse(data:)
52
60
 
53
61
  new(
54
62
  id: element.attr('data-unitid'),
55
63
  dimensions: dimensions,
64
+ features: features,
56
65
  rates: rates
57
66
  )
58
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PublicStorage
4
- VERSION = '1.2.0'
4
+ VERSION = '1.4.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: publicstorage
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
@@ -87,6 +87,7 @@ files:
87
87
  - lib/publicstorage/crawler.rb
88
88
  - lib/publicstorage/dimensions.rb
89
89
  - lib/publicstorage/facility.rb
90
+ - lib/publicstorage/features.rb
90
91
  - lib/publicstorage/fetch_error.rb
91
92
  - lib/publicstorage/geocode.rb
92
93
  - lib/publicstorage/link.rb
@@ -100,8 +101,8 @@ licenses:
100
101
  metadata:
101
102
  rubygems_mfa_required: 'true'
102
103
  homepage_uri: https://github.com/ksylvest/publicstorage
103
- source_code_uri: https://github.com/ksylvest/publicstorage/tree/v1.2.0
104
- changelog_uri: https://github.com/ksylvest/publicstorage/releases/tag/v1.2.0
104
+ source_code_uri: https://github.com/ksylvest/publicstorage/tree/v1.4.0
105
+ changelog_uri: https://github.com/ksylvest/publicstorage/releases/tag/v1.4.0
105
106
  documentation_uri: https://publicstorage.ksylvest.com/
106
107
  post_install_message:
107
108
  rdoc_options: []