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 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,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../config/environment/'
4
+
5
+ RainJackets::CLI.new.call
@@ -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
@@ -0,0 +1,3 @@
1
+ module RainJackets
2
+ VERSION = "0.1.0"
3
+ 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: []