cubesmart 0.3.0 → 0.5.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: 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