rain_jackets 0.1.3 → 0.1.4
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 +4 -4
- data/bin/rain_jackets +1 -0
- data/config/environment.rb +3 -1
- data/lib/rain_jackets/cli.rb +32 -24
- data/lib/rain_jackets/jacket.rb +6 -6
- data/lib/rain_jackets/scraper.rb +24 -14
- data/lib/rain_jackets/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2db2b5acf891f0b2bcea3c4d438dd3b5efd5bc6a
|
|
4
|
+
data.tar.gz: 6bd0e9787540efb11ecd0836fc1636dee16c2969
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4f64bb9034469c3d03326231de09023988beda0096457449b3412355cab4d99f1c139d0e369f35173ad959055e7f590dd55e467e4c7f0fe09adb2471a82c61c0
|
|
7
|
+
data.tar.gz: 0644436574c221a574e4cab7cad3f745ab4444c6f64ebde78332b9bb681905cb13d6f671580bc82422d5e3917dcb01f01ab627fc967b910f25d4b31f390d3a83
|
data/bin/rain_jackets
CHANGED
data/config/environment.rb
CHANGED
data/lib/rain_jackets/cli.rb
CHANGED
|
@@ -2,23 +2,25 @@ class RainJackets::CLI
|
|
|
2
2
|
attr_accessor :jackets
|
|
3
3
|
|
|
4
4
|
def call
|
|
5
|
-
#
|
|
6
|
-
@jackets
|
|
5
|
+
# Calls Scraper class method that will return array of all jacket objects
|
|
6
|
+
# Store all Jacket instances in CLI's instance variable @jackets
|
|
7
|
+
RainJackets::Scraper.initialize_jacket_objects
|
|
8
|
+
@jackets = RainJackets::Jacket.all
|
|
9
|
+
# Greet user with text input
|
|
7
10
|
puts ""
|
|
8
11
|
puts "Welcome to the Best Women's Rain Jackets Rater!"
|
|
9
12
|
prompt_input
|
|
10
13
|
end
|
|
11
14
|
|
|
12
|
-
# Print instructions to screen and
|
|
15
|
+
# Print instructions to screen and prompts user for input
|
|
13
16
|
def prompt_input
|
|
14
17
|
puts "► What would you like to do?"
|
|
15
18
|
puts "► Enter: 'menu' to see all commands / 'exit' to exit program."
|
|
16
19
|
get_input
|
|
17
20
|
end
|
|
18
21
|
|
|
19
|
-
# Initiates call procedure to get and handle user input
|
|
20
22
|
def get_input
|
|
21
|
-
input = gets.
|
|
23
|
+
input = gets.strip.downcase
|
|
22
24
|
handle_input(input)
|
|
23
25
|
end
|
|
24
26
|
|
|
@@ -30,8 +32,8 @@ class RainJackets::CLI
|
|
|
30
32
|
elsif (1..5).include?(input.to_i)
|
|
31
33
|
print_selected_jacket(input.to_i)
|
|
32
34
|
|
|
33
|
-
elsif ['wr', 'b', 'c', 'w', 'd', 'ps'].include?(input
|
|
34
|
-
print_ratings(input
|
|
35
|
+
elsif ['wr', 'b', 'c', 'w', 'd', 'ps'].include?(input)
|
|
36
|
+
print_ratings(input)
|
|
35
37
|
|
|
36
38
|
elsif input == "menu"
|
|
37
39
|
print_menu
|
|
@@ -42,10 +44,11 @@ class RainJackets::CLI
|
|
|
42
44
|
exit
|
|
43
45
|
|
|
44
46
|
else # Make sure that the program doesn't break with unexpected user input
|
|
47
|
+
puts ""
|
|
45
48
|
puts "I don't understand that answer. Please try again!"
|
|
46
49
|
end
|
|
47
50
|
|
|
48
|
-
prompt_input # Reinitiate
|
|
51
|
+
prompt_input # Reinitiate program loop at the end of non-exited handle_input logic
|
|
49
52
|
end
|
|
50
53
|
|
|
51
54
|
# Display all best rain jackets
|
|
@@ -53,7 +56,8 @@ class RainJackets::CLI
|
|
|
53
56
|
puts ""
|
|
54
57
|
puts "----------------------- Best Women's Rain Jackets of 2019: -----------------------------"
|
|
55
58
|
@jackets.each_with_index do |jacket, i|
|
|
56
|
-
|
|
59
|
+
ranking = (i+1).to_s
|
|
60
|
+
puts " #{ranking}. #{jacket.name.split(" - ").first} — #{jacket.price} - #{jacket.overall_rating}/100 Overall Rating"
|
|
57
61
|
end
|
|
58
62
|
puts "-----------------------------------------------------------------------------------"
|
|
59
63
|
end
|
|
@@ -79,20 +83,22 @@ class RainJackets::CLI
|
|
|
79
83
|
puts "-----------------------------------------------------------------"
|
|
80
84
|
end
|
|
81
85
|
|
|
82
|
-
# Convert user
|
|
86
|
+
# Convert user input to jacket attribute name string
|
|
83
87
|
def read_rating_input(input)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
88
|
+
# case statement to run multiple conditions against input value
|
|
89
|
+
case input
|
|
90
|
+
when 'wr'
|
|
91
|
+
rating_category = "water_resistance_rating"
|
|
92
|
+
when 'b'
|
|
93
|
+
rating_category = "breathability_rating"
|
|
94
|
+
when 'c'
|
|
95
|
+
rating_category = "comfort_rating"
|
|
96
|
+
when 'w'
|
|
97
|
+
rating_category = "weight_rating"
|
|
98
|
+
when 'd'
|
|
99
|
+
rating_category = "durability_rating"
|
|
100
|
+
when 'ps'
|
|
101
|
+
rating_category = "packed_size_rating"
|
|
96
102
|
end
|
|
97
103
|
rating_category
|
|
98
104
|
end
|
|
@@ -100,7 +106,9 @@ class RainJackets::CLI
|
|
|
100
106
|
# Display ranked list based on chosen rating category
|
|
101
107
|
def print_ratings(input)
|
|
102
108
|
rating_attribute = read_rating_input(input)
|
|
103
|
-
|
|
109
|
+
# Dynamically access specified attribute reader and
|
|
110
|
+
# Sort all jacket instances in descending order of the rating attribute's value
|
|
111
|
+
jackets_sorted_by_rating = @jackets.sort_by { |jacket| jacket.send(rating_attribute)}.reverse
|
|
104
112
|
|
|
105
113
|
# Convert rating attribute name to readable capitalized title
|
|
106
114
|
rating_category_name = rating_attribute.split('_').map(&:capitalize).join(' ')
|
|
@@ -113,7 +121,7 @@ class RainJackets::CLI
|
|
|
113
121
|
puts "---------------------------------------------------------------------"
|
|
114
122
|
end
|
|
115
123
|
|
|
116
|
-
# Display all menu commands
|
|
124
|
+
# Display all menu commands/ Define input interface
|
|
117
125
|
def print_menu
|
|
118
126
|
puts ""
|
|
119
127
|
puts "========================== MENU ==============================="
|
data/lib/rain_jackets/jacket.rb
CHANGED
|
@@ -4,13 +4,13 @@ class RainJackets::Jacket
|
|
|
4
4
|
|
|
5
5
|
@@all = []
|
|
6
6
|
|
|
7
|
-
#
|
|
8
|
-
def
|
|
9
|
-
@@all
|
|
7
|
+
# Set class method @@all to equate jackets array created by Scraper
|
|
8
|
+
def self.all=(jackets)
|
|
9
|
+
@@all = jackets.uniq
|
|
10
10
|
end
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
# Class method to expose variable @@all
|
|
13
|
+
def self.all
|
|
13
14
|
@@all
|
|
14
15
|
end
|
|
15
|
-
|
|
16
|
-
end
|
|
16
|
+
end
|
data/lib/rain_jackets/scraper.rb
CHANGED
|
@@ -1,41 +1,53 @@
|
|
|
1
1
|
class RainJackets::Scraper
|
|
2
2
|
|
|
3
|
+
# Take HTML string returned by open-uri's open method
|
|
4
|
+
# and convert it into a NodeSet
|
|
3
5
|
def self.get_page
|
|
4
6
|
Nokogiri::HTML(open("https://www.outdoorgearlab.com/topics/clothing-womens/best-rain-jacket-womens"))
|
|
5
7
|
end
|
|
6
8
|
|
|
7
9
|
def self.scrape_jackets_table
|
|
10
|
+
# Use CSS selector to grab all HTML elements that contain a table
|
|
11
|
+
# return array of Nokogiri XML elements representing
|
|
12
|
+
# table described on scraped webpage
|
|
8
13
|
self.get_page.css("div.content_table_xwide tr")
|
|
9
14
|
end
|
|
10
15
|
|
|
16
|
+
# Instantiate jacket objects and assign attributes to each instance
|
|
11
17
|
def self.initialize_jacket_objects
|
|
12
18
|
all_jackets = []
|
|
19
|
+
|
|
13
20
|
# Determines which row you're on, hence which property you're trying to populate
|
|
21
|
+
# Iterate through collection of table rows
|
|
22
|
+
|
|
14
23
|
scrape_jackets_table.each_with_index do |tr_element, tr_index|
|
|
15
24
|
|
|
16
|
-
#
|
|
25
|
+
# Scrape product Name and URL
|
|
17
26
|
if tr_index == 0
|
|
27
|
+
# Grab the element that contains our desired data
|
|
18
28
|
product_name_row = tr_element.css("div.compare_product_name")
|
|
19
29
|
|
|
30
|
+
# Iterate through each of td element and instantiate new jacket
|
|
20
31
|
product_name_row.each do |td_element|
|
|
21
|
-
#
|
|
32
|
+
# Create a new Jacket instance out of each aray element
|
|
33
|
+
# instantiating Jacket objects and giving each jacket object the correct attributes
|
|
22
34
|
new_jacket = RainJackets::Jacket.new
|
|
23
|
-
new_jacket.name = td_element.text
|
|
35
|
+
new_jacket.name = td_element.text #access text content inside an element scraped by Nokogiri
|
|
24
36
|
new_jacket.url = "https://www.outdoorgearlab.com" + td_element.css("a").first.attributes["href"].value
|
|
25
37
|
all_jackets << new_jacket
|
|
26
38
|
end
|
|
27
39
|
|
|
28
|
-
#
|
|
40
|
+
# Scrape Price
|
|
29
41
|
elsif tr_index == 2
|
|
30
42
|
product_price_row = tr_element.css("td.compare_items span")
|
|
31
43
|
# Iterate through each td_element (column) and
|
|
32
44
|
# Populate each jacket's price attribute
|
|
33
45
|
product_price_row.each_with_index do |td_element, td_index|
|
|
34
46
|
td_value = td_element.text
|
|
35
|
-
all_jackets[td_index].price = td_value #
|
|
47
|
+
all_jackets[td_index].price = td_value # Price in string "$149.93"
|
|
36
48
|
end
|
|
37
49
|
|
|
38
|
-
# Overall
|
|
50
|
+
# Scrape Overall Rating
|
|
39
51
|
elsif tr_index == 3
|
|
40
52
|
overall_rating_row = tr_element.css("div.rating_score")
|
|
41
53
|
# Iterate through each rating_score (column) and
|
|
@@ -44,28 +56,28 @@ class RainJackets::Scraper
|
|
|
44
56
|
all_jackets[rating_row_index].overall_rating = rating_score.text #an integer
|
|
45
57
|
end
|
|
46
58
|
|
|
47
|
-
# Pros
|
|
59
|
+
# Scrape Pros
|
|
48
60
|
elsif tr_index == 5
|
|
49
61
|
pros_row = tr_element.css("td.compare_items").each_with_index do |td_element, td_index|
|
|
50
62
|
td_value = td_element.text
|
|
51
63
|
all_jackets[td_index].pros = td_value
|
|
52
64
|
end
|
|
53
65
|
|
|
54
|
-
# Cons
|
|
66
|
+
# Scrape Cons
|
|
55
67
|
elsif tr_index == 6
|
|
56
68
|
pros_row = tr_element.css("td.compare_items").each_with_index do |td_element, td_index|
|
|
57
69
|
td_value = td_element.text
|
|
58
70
|
all_jackets[td_index].cons = td_value
|
|
59
71
|
end
|
|
60
72
|
|
|
61
|
-
# Description
|
|
73
|
+
# Scrape Description
|
|
62
74
|
elsif tr_index == 7
|
|
63
75
|
description_row = tr_element.css("td.compare_items").each_with_index do |td_element, td_index|
|
|
64
76
|
td_value = td_element.text
|
|
65
77
|
all_jackets[td_index].description = td_value
|
|
66
78
|
end
|
|
67
79
|
|
|
68
|
-
#
|
|
80
|
+
# Scrape rating categories if tr_index is between 9-14
|
|
69
81
|
elsif (9..14).include?(tr_index)
|
|
70
82
|
tr_element.css("div.rating_score").each_with_index do |rating_score, rating_row_index|
|
|
71
83
|
jacket = all_jackets[rating_row_index]
|
|
@@ -84,12 +96,10 @@ class RainJackets::Scraper
|
|
|
84
96
|
elsif tr_index == 14
|
|
85
97
|
jacket.packed_size_rating = rating_score
|
|
86
98
|
end
|
|
87
|
-
|
|
88
|
-
all_jackets[rating_row_index] = jacket
|
|
89
99
|
end
|
|
90
100
|
end
|
|
91
101
|
end
|
|
92
|
-
#
|
|
93
|
-
all_jackets
|
|
102
|
+
# Store all_jackets array in Jacket class variable @@all
|
|
103
|
+
RainJackets::Jacket.all = all_jackets
|
|
94
104
|
end
|
|
95
105
|
end
|
data/lib/rain_jackets/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rain_jackets
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- "'Jacqueline Lam'"
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2019-11-
|
|
11
|
+
date: 2019-11-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|