extraspace 0.2.0 → 0.3.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: c428e33759133c5e280f2dfb72c99c04e71ee4c64f96f6b9ba2228cd5fdc033e
4
- data.tar.gz: a2be67b968e35c3fa689583d00cacf92608cf74906d8b854c52f9333059a1857
3
+ metadata.gz: e31518705b665cfcff3914a8553164f1463a3c66140cb41ea14be9154abf44fa
4
+ data.tar.gz: bf86b8674cf0557e239b286acaca2f77d1688bd3f431434ad15914db9624a143
5
5
  SHA512:
6
- metadata.gz: c66f9b36b6ee74d375a791c57a9f0712efe65c65a3aa5b6c7bc146779e22cb2f10cb5e2f176eea2b6430a7255620f0fa218d4bcefa015b39723c35653821ea15
7
- data.tar.gz: d0f1f59b09c2f6d86baad0819ab63f5ca68491e9ccfc9895c0f5f43ccb69418130dc898ed1087ad9d1580397ad9270256f8253d61982c092969e1bbde27214dc
6
+ metadata.gz: 6204e8de2f7349debac7049c5ca1ade4fc0b5328be5faaf61eefb42d982e735897c28fc6292ac98c6a40e36dadf94550fcd30f5a066b3eb58ba8de7db3c2c20d
7
+ data.tar.gz: edd94f3a7d6dadc415f112f7dd3fa1ff7e8ae5fd8592794e3a218a3806e5ec7777659eeaee3bde305af51eee67f23fb5b5862925f51fc54d22ff5aa5ad863f34
data/README.md CHANGED
@@ -20,23 +20,20 @@ require 'extraspace'
20
20
  sitemap = ExtraSpace::Facility.sitemap
21
21
  sitemap.links.each do |link|
22
22
  url = link.loc
23
-
24
23
  facility = ExtraSpace::Facility.fetch(url:)
25
24
 
26
- puts "Street: #{facility.address.street}"
27
- puts "City: #{facility.address.city}"
28
- puts "State: #{facility.address.state}"
29
- puts "ZIP: #{facility.address.zip}"
30
- puts "Latitude: #{facility.geocode.latitude}"
31
- puts "Longitude: #{facility.geocode.longitude}"
32
- puts
25
+ puts facility.text
33
26
 
34
27
  facility.prices.each do |price|
35
- puts "ID: #{price.id}"
36
- puts "Width: #{price.dimensions.width}"
37
- puts "Depth: #{price.dimensions.depth}"
38
- puts "Rates: $#{price.rates.street} (street) / $#{price.rates.web} (web)"
39
- puts
28
+ puts price.text
40
29
  end
30
+
31
+ puts
41
32
  end
42
33
  ```
34
+
35
+ ## CLI
36
+
37
+ ```bash
38
+ extraspace crawl
39
+ ```
data/exe/extraspace ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'extraspace'
5
+
6
+ cli = ExtraSpace::CLI.new
7
+ cli.parse
@@ -41,6 +41,11 @@ module ExtraSpace
41
41
  "#<#{self.class.name} #{props.join(' ')}>"
42
42
  end
43
43
 
44
+ # @return [String]
45
+ def text
46
+ "#{street}, #{city}, #{state} #{zip}"
47
+ end
48
+
44
49
  # @param data [Hash]
45
50
  #
46
51
  # @return [Address]
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module ExtraSpace
6
+ # Used when interacting with the library from the command line interface (CLI).
7
+ #
8
+ # Usage:
9
+ #
10
+ # cli = ExtraSpace::CLI.new
11
+ # cli.parse
12
+ class CLI
13
+ module Code
14
+ OK = 0
15
+ ERROR = 1
16
+ end
17
+
18
+ # @param argv [Array<String>]
19
+ def parse(argv = ARGV)
20
+ parser.parse!(argv)
21
+ command = argv.shift
22
+
23
+ case command
24
+ when 'crawl' then crawl
25
+ else
26
+ warn("unsupported command=#{command.inspect}")
27
+ exit(Code::ERROR)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def crawl
34
+ ExtraSpace::Facility.crawl
35
+ exit(Code::OK)
36
+ end
37
+
38
+ def help(options)
39
+ puts(options)
40
+ exit(Code::OK)
41
+ end
42
+
43
+ def version
44
+ puts(VERSION)
45
+ exit(Code::OK)
46
+ end
47
+
48
+ # @return [OptionParser]
49
+ def parser
50
+ OptionParser.new do |options|
51
+ options.banner = 'usage: extraspace [options] <command> [<args>]'
52
+
53
+ options.on('-h', '--help', 'help') { help(options) }
54
+ options.on('-v', '--version', 'version') { version }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -8,7 +8,7 @@ module ExtraSpace
8
8
  # @param url [String]
9
9
  # @param response [HTTP::Response]
10
10
  def initialize(url:, response:)
11
- super("url=#{url} status=#{response.status.inspect} body=#{response.body.inspect}")
11
+ super("url=#{url} status=#{response.status.inspect} body=#{String(response.body).inspect}")
12
12
  end
13
13
  end
14
14
 
@@ -30,7 +30,7 @@ module ExtraSpace
30
30
  # @return [HTTP::Response]
31
31
  def fetch(url:)
32
32
  response = HTTP.get(url)
33
- raise FetchError(url:, response: response.flush) unless response.status.ok?
33
+ raise FetchError.new(url:, response: response.flush) unless response.status.ok?
34
34
 
35
35
  response
36
36
  end
@@ -34,6 +34,11 @@ module ExtraSpace
34
34
  "#<#{self.class.name} #{props.join(' ')}>"
35
35
  end
36
36
 
37
+ # @return [String] e.g. "10' × 10' (100 sqft)"
38
+ def text
39
+ "#{format('%g', @width)}' × #{format('%g', @depth)}' (#{@sqft} sqft)"
40
+ end
41
+
37
42
  # @param data [Hash]
38
43
  #
39
44
  # @return [Dimensions]
@@ -7,6 +7,14 @@ module ExtraSpace
7
7
  class Facility
8
8
  SITEMAP_URL = 'https://www.extraspace.com/facility-sitemap.xml'
9
9
 
10
+ # @attribute [rw] id
11
+ # @return [String]
12
+ attr_accessor :id
13
+
14
+ # @attribute [rw] name
15
+ # @return [String]
16
+ attr_accessor :name
17
+
10
18
  # @attribute [rw] address
11
19
  # @return [Address]
12
20
  attr_accessor :address
@@ -19,25 +27,6 @@ module ExtraSpace
19
27
  # @return [Array<Price>]
20
28
  attr_accessor :prices
21
29
 
22
- # @param address [Address]
23
- # @param geocode [Geocode]
24
- # @param prices [Array<Price>]
25
- def initialize(address:, geocode:, prices:)
26
- @address = address
27
- @geocode = geocode
28
- @prices = prices
29
- end
30
-
31
- # @return [String]
32
- def inspect
33
- props = [
34
- "address=#{@address.inspect}",
35
- "geocode=#{@geocode.inspect}",
36
- "prices=#{@prices.inspect}"
37
- ]
38
- "#<#{self.class.name} #{props.join(' ')}>"
39
- end
40
-
41
30
  # @return [Sitemap]
42
31
  def self.sitemap
43
32
  Sitemap.fetch(url: SITEMAP_URL)
@@ -57,14 +46,60 @@ module ExtraSpace
57
46
  # @return [Facility]
58
47
  def self.parse(data:)
59
48
  page_data = data.dig('props', 'pageProps', 'pageData', 'data')
60
- facility_data = page_data.dig('facilityData', 'data')
49
+ store_data = page_data.dig('facilityData', 'data', 'store')
61
50
  unit_classes = page_data.dig('unitClasses', 'data', 'unitClasses')
51
+ id = store_data['number']
52
+ name = store_data['name']
62
53
 
63
- address = Address.parse(data: facility_data['store']['address'])
64
- geocode = Geocode.parse(data: facility_data['store']['geocode'])
54
+ address = Address.parse(data: store_data['address'])
55
+ geocode = Geocode.parse(data: store_data['geocode'])
65
56
  prices = unit_classes.map { |price_data| Price.parse(data: price_data) }
66
57
 
67
- new(address:, geocode:, prices:)
58
+ new(id:, name:, address:, geocode:, prices:)
59
+ end
60
+
61
+ def self.crawl
62
+ sitemap.links.each do |link|
63
+ url = link.loc
64
+
65
+ facility = fetch(url:)
66
+ puts facility.text
67
+
68
+ facility.prices.each do |price|
69
+ puts price.text
70
+ end
71
+
72
+ puts
73
+ end
74
+ end
75
+
76
+ # @param id [String]
77
+ # @param name [String]
78
+ # @param address [Address]
79
+ # @param geocode [Geocode]
80
+ # @param prices [Array<Price>]
81
+ def initialize(id:, name:, address:, geocode:, prices:)
82
+ @id = id
83
+ @name = name
84
+ @address = address
85
+ @geocode = geocode
86
+ @prices = prices
87
+ end
88
+
89
+ # @return [String]
90
+ def inspect
91
+ props = [
92
+ "id=#{@id.inspect}",
93
+ "address=#{@address.inspect}",
94
+ "geocode=#{@geocode.inspect}",
95
+ "prices=#{@prices.inspect}"
96
+ ]
97
+ "#<#{self.class.name} #{props.join(' ')}>"
98
+ end
99
+
100
+ # @return [String] e.g. "123 Main St, Springfield, IL 62701"
101
+ def text
102
+ "#{@id} | #{@name} | #{@address.text} | #{@geocode.text}"
68
103
  end
69
104
  end
70
105
  end
@@ -27,6 +27,11 @@ module ExtraSpace
27
27
  "#<#{self.class.name} #{props.join(' ')}>"
28
28
  end
29
29
 
30
+ # @return [String]
31
+ def text
32
+ "#{@latitude},#{@longitude}"
33
+ end
34
+
30
35
  # @param data [Hash]
31
36
  #
32
37
  # @return [Geocode]
@@ -34,6 +34,11 @@ module ExtraSpace
34
34
  "#<#{self.class.name} #{props.join(' ')}>"
35
35
  end
36
36
 
37
+ # @return [String] e.g. "123 | 5' × 5' (25 sqft) | $100 (street) / $90 (web)"
38
+ def text
39
+ "#{@id} | #{@dimensions.text} | #{@rates.text}"
40
+ end
41
+
37
42
  # @param data [Hash]
38
43
  #
39
44
  # @return [Price]
@@ -27,6 +27,11 @@ module ExtraSpace
27
27
  "#<#{self.class.name} #{props.join(' ')}>"
28
28
  end
29
29
 
30
+ # @return [String] e.g. "$80 (street) | $60 (web)"
31
+ def text
32
+ "$#{@street} (street) | $#{@web} (web)"
33
+ end
34
+
30
35
  # @param data [Hash]
31
36
  #
32
37
  # @return [Rates]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ExtraSpace
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
data/lib/extraspace.rb CHANGED
@@ -6,6 +6,7 @@ require 'zeitwerk'
6
6
 
7
7
  loader = Zeitwerk::Loader.for_gem
8
8
  loader.inflector.inflect 'extraspace' => 'ExtraSpace'
9
+ loader.inflector.inflect 'cli' => 'CLI'
9
10
  loader.setup
10
11
 
11
12
  module ExtraSpace
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extraspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Sylvestre
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: optparse
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: zeitwerk
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -69,7 +83,8 @@ dependencies:
69
83
  description: Uses HTTP.rb to scrape extraspace.com.
70
84
  email:
71
85
  - kevin@ksylvest.com
72
- executables: []
86
+ executables:
87
+ - extraspace
73
88
  extensions: []
74
89
  extra_rdoc_files: []
75
90
  files:
@@ -77,8 +92,10 @@ files:
77
92
  - README.md
78
93
  - bin/console
79
94
  - bin/setup
95
+ - exe/extraspace
80
96
  - lib/extraspace.rb
81
97
  - lib/extraspace/address.rb
98
+ - lib/extraspace/cli.rb
82
99
  - lib/extraspace/crawler.rb
83
100
  - lib/extraspace/dimensions.rb
84
101
  - lib/extraspace/facility.rb