cubesmart 0.3.0 → 0.5.0

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: 3e26402813c2f507a7a4902766a26821194de2f1c9c2d31ef633b2138c45e2f5
4
- data.tar.gz: 91628c2ca652fc5be1788d4616652b82483863ab3b0bc3107cf7f3b9861cac51
3
+ metadata.gz: 4632b3c1c352b868287bc92291fb0535ee9bf4b0c419a9501cdf60ebc4ca272c
4
+ data.tar.gz: 9839c357de5c6337185a84592f626bd8e39b1effc586dacf9a1685dc05474bed
5
5
  SHA512:
6
- metadata.gz: e1f88ebc04f150dc9cbf0d590e01f05245be3a3a323d31526b6f5cdd6f445b38ad66c2cf7a0f77847ba20c62c364b58a1fd9db1bb87ee2fd8d610f0fc30f53cc
7
- data.tar.gz: 04f620cbfe554d8ecaeb77e363ad7a31c506a954c86deec4f6ad597af182c39c42340667f202fe9a7880740d4c4525c657368813d8a9bd6d6751aea8398db3ca
6
+ metadata.gz: 43f365fb2584f00de5dce8ecb4199fdb8659db50c2b59a61d0f0891b58b099403a65e0fd0c8b1b8e4bb58b72fb82c2b30590951a9d597f99b82466806f9b7ce2
7
+ data.tar.gz: 3fc196914dde673a3e95111204a1ba1d282ccc3d0d4fe99db571cb2a646f4ccd125dc38b454ee4a4221e9875229a40a038694fe6066d384b0165547dacb07966
@@ -3,6 +3,8 @@
3
3
  module CubeSmart
4
4
  # The dimensions (width + depth + sqft) of a price.
5
5
  class Dimensions
6
+ DEFAULT_HEIGHT = 8 # feet
7
+
6
8
  # @attribute [rw] depth
7
9
  # @return [Integer]
8
10
  attr_accessor :depth
@@ -11,17 +13,17 @@ module CubeSmart
11
13
  # @return [Integer]
12
14
  attr_accessor :width
13
15
 
14
- # @attribute [rw] sqft
16
+ # @attribute [rw] height
15
17
  # @return [Integer]
16
- attr_accessor :sqft
18
+ attr_accessor :height
17
19
 
18
20
  # @param depth [Integer]
19
21
  # @param width [Integer]
20
- # @param sqft [Integer]
21
- def initialize(depth:, width:, sqft:)
22
+ # @param height [Integer]
23
+ def initialize(depth:, width:, height: DEFAULT_HEIGHT)
22
24
  @depth = depth
23
25
  @width = width
24
- @sqft = sqft
26
+ @height = height
25
27
  end
26
28
 
27
29
  # @return [String]
@@ -29,11 +31,21 @@ module CubeSmart
29
31
  props = [
30
32
  "depth=#{@depth.inspect}",
31
33
  "width=#{@width.inspect}",
32
- "sqft=#{@sqft.inspect}"
34
+ "height=#{@height.inspect}"
33
35
  ]
34
36
  "#<#{self.class.name} #{props.join(' ')}>"
35
37
  end
36
38
 
39
+ # @return [Integer]
40
+ def sqft
41
+ Integer(@width * @depth)
42
+ end
43
+
44
+ # @return [Integer]
45
+ def cuft
46
+ Integer(@width * @depth * @height)
47
+ end
48
+
37
49
  # @return [String] e.g. "10' × 10' (100 sqft)"
38
50
  def text
39
51
  "#{format('%g', @width)}' × #{format('%g', @depth)}' (#{@sqft} sqft)"
@@ -49,8 +61,7 @@ module CubeSmart
49
61
 
50
62
  width = Float(match[:width])
51
63
  depth = Float(match[:depth])
52
- sqft = Integer(width * depth)
53
- new(depth:, width:, sqft:)
64
+ new(depth:, width:, height: DEFAULT_HEIGHT)
54
65
  end
55
66
  end
56
67
  end
@@ -22,6 +22,10 @@ module CubeSmart
22
22
  # @return [String]
23
23
  attr_accessor :id
24
24
 
25
+ # @attribute [rw] url
26
+ # @return [String]
27
+ attr_accessor :url
28
+
25
29
  # @attribute [rw] name
26
30
  # @return [String]
27
31
  attr_accessor :name
@@ -56,22 +60,23 @@ module CubeSmart
56
60
  # @return [Facility]
57
61
  def self.fetch(url:)
58
62
  document = Crawler.html(url:)
59
- parse(document:)
63
+ parse(url:, document:)
60
64
  end
61
65
 
66
+ # @param url [String]
62
67
  # @param document [Nokogiri::HTML::Document]
63
68
  #
64
69
  # @return [Facility]
65
- def self.parse(document:)
70
+ def self.parse(url:, document:)
66
71
  data = parse_json_ld(document:)
67
72
 
68
- id = data['url'].match(ID_REGEX)[:id]
73
+ id = ID_REGEX.match(url)[:id]
69
74
  name = data['name']
70
75
  address = Address.parse(data: data['address'])
71
76
  geocode = Geocode.parse(data: data['geo'])
72
77
  prices = document.css(PRICE_SELECTOR).map { |element| Price.parse(element: element) }
73
78
 
74
- new(id:, name:, address:, geocode:, prices:)
79
+ new(id:, url:, name:, address:, geocode:, prices:)
75
80
  end
76
81
 
77
82
  # @param document [Nokogiri::HTML::Document]
@@ -85,14 +90,16 @@ module CubeSmart
85
90
  end
86
91
 
87
92
  # @param id [String]
93
+ # @param url [String]
88
94
  # @param name [String]
89
95
  # @param address [Address]
90
96
  # @param geocode [Geocode]
91
97
  # @param phone [String]
92
98
  # @param email [String]
93
99
  # @param prices [Array<Price>]
94
- def initialize(id:, name:, address:, geocode:, phone: DEFAULT_PHONE, email: DEFAULT_EMAIL, prices: [])
100
+ def initialize(id:, url:, name:, address:, geocode:, phone: DEFAULT_PHONE, email: DEFAULT_EMAIL, prices: [])
95
101
  @id = id
102
+ @url = url
96
103
  @name = name
97
104
  @address = address
98
105
  @geocode = geocode
@@ -105,6 +112,7 @@ module CubeSmart
105
112
  def inspect
106
113
  props = [
107
114
  "id=#{@id.inspect}",
115
+ "url=#{@url.inspect}",
108
116
  "address=#{@address.inspect}",
109
117
  "geocode=#{@geocode.inspect}",
110
118
  "phone=#{@phone.inspect}",
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CubeSmart
4
+ # The features (e.g. climate-controlled, inside-drive-up-access, outside-drive-up-access, etc) of a price.
5
+ class Features
6
+ # @param element [Nokogiri::XML::Element]
7
+ #
8
+ # @return [Features]
9
+ def self.parse(element:)
10
+ text = element.text
11
+
12
+ new(
13
+ climate_controlled: text.include?('Climate controlled'),
14
+ inside_drive_up_access: text.include?('Inside drive-up access'),
15
+ outside_drive_up_access: text.include?('Outside drive-up access'),
16
+ first_floor_access: text.include?('1st floor access')
17
+ )
18
+ end
19
+
20
+ # @param climate_controlled [Boolean]
21
+ # @param inside_drive_up_access [Boolean]
22
+ # @param outside_drive_up_access [Boolean]
23
+ # @param first_floor_access [Boolean]
24
+ def initialize(climate_controlled:, inside_drive_up_access:, outside_drive_up_access:, first_floor_access:)
25
+ @climate_controlled = climate_controlled
26
+ @inside_drive_up_access = inside_drive_up_access
27
+ @outside_drive_up_access = outside_drive_up_access
28
+ @first_floor_access = first_floor_access
29
+ end
30
+
31
+ # @return [String]
32
+ def inspect
33
+ props = [
34
+ "climate_controlled=#{@climate_controlled}",
35
+ "inside_drive_up_access=#{@inside_drive_up_access}",
36
+ "outside_drive_up_access=#{@outside_drive_up_access}",
37
+ "first_floor_access=#{@first_floor_access}"
38
+ ]
39
+
40
+ "#<#{self.class.name} #{props.join(' ')}>"
41
+ end
42
+
43
+ # @return [String] e.g. "Climate Controlled + First Floor Access"
44
+ def text
45
+ amenities.join(' + ')
46
+ end
47
+
48
+ # @return [Array<String>]
49
+ def amenities
50
+ [].tap do |amenities|
51
+ amenities << 'Climate Controlled' if climate_controlled?
52
+ amenities << 'Inside Drive-Up Access' if inside_drive_up_access?
53
+ amenities << 'Outside Drive-Up Access' if outside_drive_up_access?
54
+ amenities << 'First Floor Access' if first_floor_access?
55
+ end
56
+ end
57
+
58
+ # @return [Boolean]
59
+ def climate_controlled?
60
+ @climate_controlled
61
+ end
62
+
63
+ # @return [Boolean]
64
+ def inside_drive_up_access?
65
+ @inside_drive_up_access
66
+ end
67
+
68
+ # @return [Boolean]
69
+ def outside_drive_up_access?
70
+ @outside_drive_up_access
71
+ end
72
+
73
+ # @return [Boolean]
74
+ def drive_up_access?
75
+ inside_drive_up_access? || outside_drive_up_access?
76
+ end
77
+
78
+ # @return [Boolean]
79
+ def first_floor_access?
80
+ @first_floor_access
81
+ end
82
+ end
83
+ end
@@ -11,16 +11,22 @@ module CubeSmart
11
11
  # @return [Dimensions]
12
12
  attr_accessor :dimensions
13
13
 
14
+ # @attribute [rw] features
15
+ # @return [Features]
16
+ attr_accessor :features
17
+
14
18
  # @attribute [rw] rates
15
19
  # @return [Rates]
16
20
  attr_accessor :rates
17
21
 
18
22
  # @param id [String]
19
23
  # @param dimensions [Dimensions]
24
+ # @param features [Features]
20
25
  # @param rates [Rates]
21
- def initialize(id:, dimensions:, rates:)
26
+ def initialize(id:, dimensions:, features:, rates:)
22
27
  @id = id
23
28
  @dimensions = dimensions
29
+ @features = features
24
30
  @rates = rates
25
31
  end
26
32
 
@@ -29,6 +35,7 @@ module CubeSmart
29
35
  props = [
30
36
  "id=#{@id.inspect}",
31
37
  "dimensions=#{@dimensions.inspect}",
38
+ "features=#{@features.inspect}",
32
39
  "rates=#{@rates.inspect}"
33
40
  ]
34
41
  "#<#{self.class.name} #{props.join(' ')}>"
@@ -36,20 +43,18 @@ module CubeSmart
36
43
 
37
44
  # @return [String] e.g. "123 | 5' × 5' (25 sqft) | $100 (street) / $90 (web)"
38
45
  def text
39
- "#{@id} | #{@dimensions.text} | #{@rates.text}"
46
+ "#{@id} | #{@dimensions.text} | #{@rates.text} | #{@features.text}"
40
47
  end
41
48
 
42
49
  # @param element [Nokogiri::XML::Element]
43
50
  #
44
51
  # @return [Price]
45
52
  def self.parse(element:)
46
- id = element.attr('id')
47
- dimensions = Dimensions.parse(element:)
48
- rates = Rates.parse(element:)
49
53
  new(
50
- id:,
51
- dimensions: dimensions,
52
- rates: rates
54
+ id: element.attr('id'),
55
+ dimensions: Dimensions.parse(element:),
56
+ features: Features.parse(element:),
57
+ rates: Rates.parse(element:)
53
58
  )
54
59
  end
55
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CubeSmart
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cubesmart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.5.0
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-12-04 00:00:00.000000000 Z
11
+ date: 2024-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -101,6 +101,7 @@ files:
101
101
  - lib/cubesmart/crawler.rb
102
102
  - lib/cubesmart/dimensions.rb
103
103
  - lib/cubesmart/facility.rb
104
+ - lib/cubesmart/features.rb
104
105
  - lib/cubesmart/fetch_error.rb
105
106
  - lib/cubesmart/geocode.rb
106
107
  - lib/cubesmart/link.rb