rain_jackets 0.1.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 +7 -0
- data/bin/rain_jackets +5 -0
- data/config/environment.rb +11 -0
- data/lib/rain_jackets/cli.rb +127 -0
- data/lib/rain_jackets/jacket.rb +16 -0
- data/lib/rain_jackets/scraper.rb +91 -0
- data/lib/rain_jackets/version.rb +3 -0
- metadata +106 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: '0995f74068a6719cf371aafd4f3b48425bc8b8620a60408a7506ccee8f06476e'
|
|
4
|
+
data.tar.gz: 23c70660023c2fe4866eaca0487a335975cfe2be50f9a41e9e98b5496fe0b554
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: a7efa8a84dc66d59412f2ad7af7eae5bfdb0bb5d427fc98530191850bd7c1884a2fab1ad3103188769470abab58e25a47a06ec2d61b0f87399f0834a9c51af33
|
|
7
|
+
data.tar.gz: 998c956c6b2ba4d4548d6e1ba21664ef5841a5b6e885231237808b52070396e25708360be0cef6db8ea23d8eca326dec4ad2ed1c18ac42506927345b2778010b
|
data/bin/rain_jackets
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
### REQUIRED GEMS ###
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
require 'open-uri'
|
|
4
|
+
require 'pry'
|
|
5
|
+
|
|
6
|
+
### REQUIRED FILES ###
|
|
7
|
+
require_relative '../lib/rain_jackets/version'
|
|
8
|
+
require_relative '../lib/rain_jackets/cli'
|
|
9
|
+
require_relative '../lib/rain_jackets/scraper'
|
|
10
|
+
require_relative '../lib/rain_jackets/jacket'
|
|
11
|
+
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
class RainJackets::CLI
|
|
2
|
+
attr_accessor :jackets
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@jackets = RainJackets::Scraper.initialize_jacket_objects
|
|
6
|
+
puts "Welcome to the Best Rain Jackets Rater!"
|
|
7
|
+
prompt_user_input
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def prompt_user_input
|
|
11
|
+
puts "► What would you like to do?"
|
|
12
|
+
puts "► Enter: 'menu' to see all commands / 'exit' to exit program."
|
|
13
|
+
call
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Initiates call procedure to get and handle user input
|
|
17
|
+
def call
|
|
18
|
+
input = gets.chomp.strip
|
|
19
|
+
handle_input(input)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Handles the user pint
|
|
23
|
+
def handle_input(input)
|
|
24
|
+
if input == "all"
|
|
25
|
+
print_list_all
|
|
26
|
+
|
|
27
|
+
elsif (1..5).include?(input.to_i)
|
|
28
|
+
print_selected_jacket(input.to_i)
|
|
29
|
+
|
|
30
|
+
elsif ['wr', 'b', 'c', 'w', 'd', 'ps'].include?(input.downcase)
|
|
31
|
+
print_ratings(input.downcase)
|
|
32
|
+
|
|
33
|
+
elsif input == "menu"
|
|
34
|
+
print_menu
|
|
35
|
+
call
|
|
36
|
+
|
|
37
|
+
elsif input == "exit"
|
|
38
|
+
puts "Goodbye! Have a great day!"
|
|
39
|
+
exit
|
|
40
|
+
|
|
41
|
+
else #- make sure that the program doesn't break when user's input is unexpected
|
|
42
|
+
puts "I don't understand that answer. Please try again"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
prompt_user_input
|
|
46
|
+
call #reinitiate call loop at the end of non-exited handle_input logic
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def print_list_all
|
|
50
|
+
puts "---------------------------- Best Rain Jackets of 2019: ------------------------"
|
|
51
|
+
@jackets.each_with_index do |jacket, i|
|
|
52
|
+
puts " #{(i+1).to_s}. #{jacket.name.split(" - ").first} — #{jacket.price} - #{jacket.overall_rating}/100 Overall Rating"
|
|
53
|
+
end
|
|
54
|
+
puts "--------------------------------------------------------------------------------"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def print_selected_jacket(jacket_number)
|
|
58
|
+
jacket = @jackets[jacket_number - 1]
|
|
59
|
+
puts "---------------- #{jacket_number}. #{jacket.name} ----------------"
|
|
60
|
+
puts "• Jacket Description: #{jacket.description}"
|
|
61
|
+
puts "• Price: #{jacket.price}"
|
|
62
|
+
puts "• Pros: #{jacket.pros}"
|
|
63
|
+
puts "• Cons: #{jacket.cons}"
|
|
64
|
+
puts "• URL: #{jacket.url}"
|
|
65
|
+
puts "• Overall Rating: #{jacket.overall_rating}/100"
|
|
66
|
+
puts "• Rating Categories:"
|
|
67
|
+
puts " - Water Resistance: #{jacket.water_resistance_rating}/10"
|
|
68
|
+
puts " - Breathability: #{jacket.breathability_rating}/10"
|
|
69
|
+
puts " - Comfort: #{jacket.comfort_rating}/10"
|
|
70
|
+
puts " - Weight: #{jacket.weight_rating}/10"
|
|
71
|
+
puts " - Durability: #{jacket.durability_rating}/10"
|
|
72
|
+
puts " - Packed Size: #{jacket.packed_size_rating}/10"
|
|
73
|
+
puts "-----------------------------------------------------------------"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Converts user shortcut input to jacket attribute name as string
|
|
77
|
+
def read_rating_input(input)
|
|
78
|
+
if input == 'wr'
|
|
79
|
+
rating_category = "water_resistance_rating"
|
|
80
|
+
elsif input == 'b'
|
|
81
|
+
rating_category = "breathability_rating"
|
|
82
|
+
elsif input == 'c'
|
|
83
|
+
rating_category = "comfort_rating"
|
|
84
|
+
elsif input == 'w'
|
|
85
|
+
rating_category = "weight_rating"
|
|
86
|
+
elsif input == 'd'
|
|
87
|
+
rating_category = "durability_rating"
|
|
88
|
+
elsif input == 'ps'
|
|
89
|
+
rating_category = "packed_size_rating"
|
|
90
|
+
else
|
|
91
|
+
puts "Incorrect input. Please try again."
|
|
92
|
+
prompt_user_input
|
|
93
|
+
end
|
|
94
|
+
rating_category
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def print_ratings(input)
|
|
98
|
+
rating_attribute = read_rating_input(input)
|
|
99
|
+
jackets_sorted_by_rating = @jackets.sort_by { |jacket| jacket.send(rating_attribute) }.reverse
|
|
100
|
+
|
|
101
|
+
# Convert rating attribute name to readable capitalized title
|
|
102
|
+
rating_category_name = rating_attribute.split('_').map(&:capitalize).join(' ')
|
|
103
|
+
|
|
104
|
+
puts "-------------Best Jackets Ranked by #{rating_category_name} ------------------"
|
|
105
|
+
jackets_sorted_by_rating.each_with_index do |jacket, idx|
|
|
106
|
+
puts " #{idx + 1}. #{jacket.name} — #{jacket.send(rating_attribute)}/10"
|
|
107
|
+
end
|
|
108
|
+
puts "-----------------------------------------------------------------"
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Display all menu commands
|
|
112
|
+
def print_menu
|
|
113
|
+
puts "========================== MENU ==============================="
|
|
114
|
+
puts "• List all jackets -> enter 'all'"
|
|
115
|
+
puts "• More information on specific jacket -> enter jacket #'1-5'"
|
|
116
|
+
puts "• List jackets by speific rating category -> enter:"
|
|
117
|
+
puts " 'wr' — Water Resistance"
|
|
118
|
+
puts " 'b' — Brethability"
|
|
119
|
+
puts " 'c' — Comfort"
|
|
120
|
+
puts " 'w' — Weight"
|
|
121
|
+
puts " 'd' — Durability"
|
|
122
|
+
puts " 'ps' — Packed Size"
|
|
123
|
+
puts "• Exit program -> enter 'exit'"
|
|
124
|
+
puts "==============================================================="
|
|
125
|
+
puts "► What would you like to do?"
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class RainJackets::Jacket
|
|
2
|
+
attr_accessor :name, :url, :price, :description, :pros, :cons, :overall_rating
|
|
3
|
+
attr_accessor :water_resistance_rating, :breathability_rating, :comfort_rating, :weight_rating, :durability_rating, :packed_size_rating, :rating_category
|
|
4
|
+
|
|
5
|
+
@@all = []
|
|
6
|
+
|
|
7
|
+
# Take in an argument of an array and sets new jacket's attributes
|
|
8
|
+
def initialize
|
|
9
|
+
@@all << self
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.all # Class method to expose variable @@all
|
|
13
|
+
@@all
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
class RainJackets::Scraper
|
|
2
|
+
|
|
3
|
+
def self.get_page
|
|
4
|
+
Nokogiri::HTML(open("https://www.outdoorgearlab.com/topics/clothing-womens/best-rain-jacket-womens"))
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def self.scrape_jackets_table
|
|
8
|
+
self.get_page.css("div.content_table_xwide tr")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def self.initialize_jacket_objects
|
|
12
|
+
all_jackets = []
|
|
13
|
+
# Determines which row you're on, hence which property you're trying to populate
|
|
14
|
+
scrape_jackets_table.each_with_index do |tr_element, tr_index|
|
|
15
|
+
|
|
16
|
+
# Product name and URL
|
|
17
|
+
if tr_index == 0
|
|
18
|
+
# td_value = td_element
|
|
19
|
+
product_name_row = tr_element.css("div.compare_product_name")
|
|
20
|
+
|
|
21
|
+
product_name_row.each do |td_element|
|
|
22
|
+
new_jacket = RainJackets::Jacket.new
|
|
23
|
+
new_jacket.name = td_element.text
|
|
24
|
+
new_jacket.url = "https://www.outdoorgearlab.com" + td_element.css("a").first.attributes["href"].value
|
|
25
|
+
all_jackets << new_jacket
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Product Price
|
|
29
|
+
elsif tr_index == 2
|
|
30
|
+
product_price_row = tr_element.css("td.compare_items span").each_with_index do |td_element, td_index|
|
|
31
|
+
td_value = td_element.text
|
|
32
|
+
all_jackets[td_index].price = td_value #price in string "$149.93"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Overall rating
|
|
36
|
+
elsif tr_index == 3
|
|
37
|
+
overall_rating_row = tr_element.css("div.rating_score")
|
|
38
|
+
overall_rating_row.each_with_index do |rating_score, rating_row_index|
|
|
39
|
+
# rating_score.text is an Intergerç
|
|
40
|
+
all_jackets[rating_row_index].overall_rating = rating_score.text
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Pros
|
|
44
|
+
elsif tr_index == 5
|
|
45
|
+
pros_row = tr_element.css("td.compare_items").each_with_index do |td_element, td_index|
|
|
46
|
+
td_value = td_element.text
|
|
47
|
+
all_jackets[td_index].pros = td_value
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Cons
|
|
51
|
+
elsif tr_index == 6
|
|
52
|
+
pros_row = tr_element.css("td.compare_items").each_with_index do |td_element, td_index|
|
|
53
|
+
td_value = td_element.text
|
|
54
|
+
all_jackets[td_index].cons = td_value
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Desciption
|
|
58
|
+
elsif tr_index == 7
|
|
59
|
+
description_row = tr_element.css("td.compare_items").each_with_index do |td_element, td_index|
|
|
60
|
+
td_value = td_element.text
|
|
61
|
+
all_jackets[td_index].description = td_value
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Rating categories (tr_index 11-14): water_resistance_rating, breathability_rating, comfort_rating, weight_rating, packed_size_rating
|
|
65
|
+
elsif (9..14).include?(tr_index)
|
|
66
|
+
tr_element.css("div.rating_score").each_with_index do |rating_score, rating_row_index|
|
|
67
|
+
jacket = all_jackets[rating_row_index]
|
|
68
|
+
rating_score = rating_score.text
|
|
69
|
+
|
|
70
|
+
if tr_index == 9
|
|
71
|
+
jacket.water_resistance_rating = rating_score
|
|
72
|
+
elsif tr_index == 10
|
|
73
|
+
jacket.breathability_rating = rating_score
|
|
74
|
+
elsif tr_index == 11
|
|
75
|
+
jacket.comfort_rating = rating_score
|
|
76
|
+
elsif tr_index == 12
|
|
77
|
+
jacket.weight_rating = rating_score
|
|
78
|
+
elsif tr_index == 13
|
|
79
|
+
jacket.durability_rating = rating_score
|
|
80
|
+
elsif tr_index == 14
|
|
81
|
+
jacket.packed_size_rating = rating_score
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
all_jackets[rating_row_index] = jacket
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
all_jackets
|
|
90
|
+
end
|
|
91
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rain_jackets
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- "'Jacqueline Lam'"
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2019-11-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '2.0'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '2.0'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: pry
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: nokogiri
|
|
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'
|
|
69
|
+
description: Get the details for 2019's best rain jackets from Outdoor Gear Lab.
|
|
70
|
+
email:
|
|
71
|
+
- "'jacqueline.karin.lam@gmail.com'"
|
|
72
|
+
executables:
|
|
73
|
+
- rain_jackets
|
|
74
|
+
extensions: []
|
|
75
|
+
extra_rdoc_files: []
|
|
76
|
+
files:
|
|
77
|
+
- bin/rain_jackets
|
|
78
|
+
- config/environment.rb
|
|
79
|
+
- lib/rain_jackets/cli.rb
|
|
80
|
+
- lib/rain_jackets/jacket.rb
|
|
81
|
+
- lib/rain_jackets/scraper.rb
|
|
82
|
+
- lib/rain_jackets/version.rb
|
|
83
|
+
homepage: https://rubygems.org/profiles/jacqueline-lam
|
|
84
|
+
licenses:
|
|
85
|
+
- MIT
|
|
86
|
+
metadata: {}
|
|
87
|
+
post_install_message:
|
|
88
|
+
rdoc_options: []
|
|
89
|
+
require_paths:
|
|
90
|
+
- lib
|
|
91
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: '0'
|
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
|
+
requirements:
|
|
98
|
+
- - ">="
|
|
99
|
+
- !ruby/object:Gem::Version
|
|
100
|
+
version: '0'
|
|
101
|
+
requirements: []
|
|
102
|
+
rubygems_version: 3.0.3
|
|
103
|
+
signing_key:
|
|
104
|
+
specification_version: 4
|
|
105
|
+
summary: CLI for best rain jackets
|
|
106
|
+
test_files: []
|