best_boutique_hotels 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5c04aec528e5c33f0b73af606a200e081af7372e
4
+ data.tar.gz: dbca376bdb8eec593c1f7ced010acbb36a5fc298
5
+ SHA512:
6
+ metadata.gz: 775237a3de636b097ca9b53bd2db6ee14eb23b0e1762ab1cf007648b51de9891c7f1a118c522967d8382e0d06b845ada2609824f75f5518410d410381fed774c
7
+ data.tar.gz: 2f566c472f613af49d990ac6bc6e75eef72be1df41b333de37f9c13b850848a98b7812beee0bd60a7ae1fdaa1df9b43b44a1397d6537423c18eb1cf059bef804
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/best_boutique_hotels.rb'
4
+
5
+ CommandLineInterface.new.run
@@ -0,0 +1,10 @@
1
+ require 'nokogiri'
2
+ require 'colorize'
3
+ require 'pry'
4
+ require 'ruby-progressbar'
5
+ require 'require_all'
6
+ require 'open-uri'
7
+ require_relative '../lib/best_boutique_hotels/category.rb'
8
+ require_relative '../lib/best_boutique_hotels/command_line.rb'
9
+ require_relative '../lib/best_boutique_hotels/hotel.rb'
10
+ require_relative '../lib/best_boutique_hotels/scraper.rb'
@@ -0,0 +1 @@
1
+ require_relative '../config/environment.rb'
@@ -0,0 +1,32 @@
1
+ class Category
2
+
3
+ attr_accessor :name, :url, :hotels
4
+
5
+ @@all = []
6
+
7
+ def initialize(name, url)
8
+ @name = name
9
+ @url = url
10
+ @hotels = []
11
+ end
12
+
13
+ def add_hotels(hotels_array)
14
+ hotels_array.each do |hotel|
15
+ unless @hotels.include?(hotel)
16
+ @hotels << hotel
17
+ hotel.category = self
18
+ end
19
+ end
20
+ end
21
+
22
+ def self.create_from_collection(categories_array)
23
+ categories_array.each_with_index do |category|
24
+ self.all << Category.new(category[:category_name], category[:category_url])
25
+ end
26
+ end
27
+
28
+ def self.all
29
+ @@all
30
+ end
31
+
32
+ end
@@ -0,0 +1,146 @@
1
+ # require_relative "../best_boutique_hotels.rb"
2
+
3
+ class CommandLineInterface
4
+ BASE_URL = "http://www.boutiquehotelawards.com/boutique-hotels/latest-winners/"
5
+
6
+ @current_category = ""
7
+ @current_category_index = ""
8
+
9
+ def run
10
+ make_categories
11
+ make_hotels
12
+ add_details_to_hotels
13
+ begin_navigation
14
+ end
15
+
16
+ def make_categories
17
+ categories_array = Scraper.scrape_index_page(BASE_URL)
18
+ Category.create_from_collection(categories_array)
19
+ puts "Getting Categories...".white.on_blue.underline
20
+ end
21
+
22
+ def make_hotels
23
+ hotels_array = []
24
+ Category.all.each do |category|
25
+ hotels_array = Scraper.scrape_category_page(category.url)
26
+ category_hotels = Hotel.create_from_collection(hotels_array)
27
+ category.add_hotels(category_hotels)
28
+ puts "#{category.name} created.".colorize(:blue)
29
+ end
30
+ end
31
+
32
+
33
+ def add_details_to_hotels
34
+ puts "Getting Hotel details...".white.on_blue.underline
35
+ progressbar = ProgressBar.create(:total=>Hotel.all.size)
36
+ Hotel.all.each_with_index do |hotel, index|
37
+ progressbar.increment
38
+ attributes = Scraper.scrape_hotel_page(hotel.hotel_url)
39
+ hotel.add_hotel_attributes(attributes)
40
+ end
41
+ end
42
+
43
+ def begin_navigation
44
+ puts "www.boutiquehotelawards.com".white.on_blue.underline
45
+ puts "A list of the top boutique hotels in the world in the following categories:".white.on_blue.underline
46
+ puts ""
47
+ Category.all.each_with_index do |c, i|
48
+ puts "#{i+1}. #{c.name}".colorize(:blue)
49
+ end
50
+ category_navigation
51
+ end
52
+
53
+ def category_navigation
54
+ puts ""
55
+ puts "Choose a category to view hotels.".white.on_blue.underline
56
+ c_index = gets.strip
57
+ if c_index.to_i.between?(1, Category.all.size)
58
+ @current_category_index = c_index.to_i-1
59
+ list_hotels(c_index.to_i-1)
60
+ else
61
+ puts "Yikes, try a valid category.".colorize(:red)
62
+ category_navigation
63
+ end
64
+ end
65
+
66
+ def list_hotels(c_index)
67
+ @current_category = Category.all[c_index]
68
+ puts "#{@current_category.name} hotels:".white.on_blue.underline
69
+ puts ""
70
+ @current_category.hotels.each_with_index do |h, i|
71
+ puts "#{i+1}. #{h.hotel_name}".colorize(:blue)
72
+ end
73
+ hotel_navigation
74
+ end
75
+
76
+ def hotel_navigation
77
+ puts ""
78
+ puts "Choose a hotel to view details.".white.on_blue
79
+ h_index = gets.strip
80
+ if h_index.to_i.between?(1, @current_category.hotels.size)
81
+ view_hotel(@current_category.hotels[h_index.to_i-1])
82
+ else
83
+ puts "Oops, that's not a valid hotel.".colorize(:red)
84
+ hotel_navigation
85
+ end
86
+ end
87
+
88
+ def view_hotel(hotel)
89
+ puts ""
90
+ puts "#{hotel.hotel_name.upcase}".white.on_blue.underline
91
+ puts wrap("#{hotel.headline}".colorize(:light_blue))
92
+ puts " . - - - . "
93
+ puts wrap(" Location: ".colorize(:blue) + "#{hotel.location}")
94
+ puts wrap(" Category: ".colorize(:blue) + "#{hotel.category.name}")
95
+ puts wrap(" Website: ".colorize(:blue) + "#{hotel.hotel_website}")
96
+ puts wrap(" Number of Rooms: ".colorize(:blue) + "#{hotel.number_of_rooms}")
97
+ puts wrap(" Price: ".colorize(:blue) + "#{hotel.price}")
98
+ hotel.notes.each_with_index do |note, i|
99
+ i == 0 ? (puts " Additional Details:\n".colorize(:blue) + wrap(" #{note}")) : (puts wrap(" #{note}"))
100
+ end
101
+ continue?
102
+ end
103
+
104
+ def continue?
105
+ puts ""
106
+ puts "Would you like to continue? (Y/N)".white.on_blue
107
+ answer = gets.strip.upcase
108
+ if answer == "Y"
109
+ repeat_navigation
110
+ elsif
111
+ answer == "N"
112
+ puts "Bye!"
113
+ exit
114
+ else
115
+ "I didn't understand you."
116
+ continue?
117
+ end
118
+ end
119
+
120
+ def repeat_navigation
121
+ puts wrap("Would you like to go (back) to the hotel listings for #{@current_category.name} or go to the (categories) page?")
122
+ answer = gets.strip.downcase
123
+ if answer == "back"
124
+ list_hotels(@current_category_index)
125
+ elsif
126
+ answer == "categories"
127
+ @current_category = ""
128
+ @current_category_index = 0
129
+ begin_navigation
130
+ else
131
+ repeat_navigation
132
+ end
133
+ end
134
+ end
135
+
136
+ def wrap(string, line_width=78)
137
+ return string if string.length <= line_width
138
+ if string[0...line_width].index(" ") != nil
139
+ space_index = (line_width-1) - string[0...line_width].reverse.index(" ")
140
+ string[0...space_index] + "\n " + wrap(string[space_index+1..-1], line_width-5)
141
+ elsif string[line_width] == " "
142
+ string[0...line_width] + "\n " + wrap(string[line_width+1..-1], line_width-5)
143
+ else
144
+ string[0...line_width] + "\n " + wrap(string[line_width..-1], line_width-5)
145
+ end
146
+ end
@@ -0,0 +1,24 @@
1
+ class Hotel
2
+
3
+ attr_accessor :hotel_name, :category, :location, :hotel_website, :number_of_rooms, :price, :notes, :headline, :hotel_url
4
+
5
+ @@all = []
6
+
7
+ def initialize(hotel_details)
8
+ hotel_details.each {|key, value| self.send(("#{key}="), value)}
9
+ self.class.all << self
10
+ end
11
+
12
+ def self.create_from_collection(hotels_array)
13
+ new_hotels = hotels_array.collect {|hotel| Hotel.new(hotel)}
14
+ new_hotels
15
+ end
16
+
17
+ def add_hotel_attributes(attributes_hash)
18
+ attributes_hash.each {|key, value| self.send(("#{key}="), value)}
19
+ end
20
+
21
+ def self.all
22
+ @@all
23
+ end
24
+ end
@@ -0,0 +1,51 @@
1
+ class Scraper
2
+
3
+ def self.scrape_index_page(index_url)
4
+ categories_array = []
5
+ hotels_array = []
6
+
7
+ doc = Nokogiri::HTML(open(index_url))
8
+ category_links = doc.css('div.overlay-content-cat a').collect {|el| el['href'] }
9
+ category_names = doc.css('div.overlay-content-cat a').collect {|el| el.text.strip }
10
+
11
+ category_names.each_with_index do |category, index|
12
+ categories_array << Hash[category_name: category, category_url: category_links[index]]
13
+ end
14
+ categories_array
15
+ end
16
+
17
+ def self.scrape_category_page(category_url)
18
+ hotel_array = []
19
+ doc = Nokogiri::HTML(open(category_url))
20
+ hotel_links = doc.css('h3.title-hotel-row a').collect {|el| el['href'].strip }
21
+ hotel_names = doc.css('h3.title-hotel-row a').collect {|el| el.text.strip }
22
+ hotel_names.each_with_index do |hotel, index|
23
+ hotel_array << Hash[hotel_name: hotel, hotel_url: hotel_links[index]]
24
+ end
25
+ hotel_array
26
+ end
27
+
28
+ def self.scrape_hotel_page(hotel_url)
29
+ hotel_details = []
30
+ location = ""
31
+ hotel_website = ""
32
+ headline = ""
33
+ notes = []
34
+ price = nil
35
+ number_of_rooms = nil
36
+
37
+ doc = Nokogiri::HTML(open(hotel_url))
38
+ location = doc.css('div.address-section div li')[0].text unless doc.css('div.address-section div li')[0] == nil
39
+ hotel_website = doc.css('div.action-link-hotel a')[1]['href'] unless (doc.css('div.action-link-hotel a')[1] == nil || doc.css('div.action-link-hotel a')[1]['href'].include?('boutiquehotelawards'))
40
+ headline = doc.css('div.tag-line').text unless doc.css('div.tag-line') == nil
41
+ notes = doc.css('div.hotel-info ul')[0] unless doc.css('div.hotel-info ul')[0] == nil
42
+ notes = notes.css('li').collect {|el| el.text} unless notes == []
43
+ number_of_rooms = notes[0] unless notes == nil
44
+ notes.shift unless notes == nil
45
+ price = notes.detect {|text| (text.include?("$") || text.include?("USD") || text.include?("EUR"))} unless notes == nil
46
+ notes.reject!{ |item| item == price} unless notes == nil
47
+ hotel_details = Hash[location: location, hotel_website: hotel_website, number_of_rooms: number_of_rooms, price: price, notes: notes, headline: headline]
48
+ hotel_details.reject!{|k , v| (v == nil || v == "" || v == [])}
49
+ hotel_details
50
+ end
51
+ end
metadata ADDED
@@ -0,0 +1,131 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: best_boutique_hotels
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Joseph Lim
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-06-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.6.8
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '1.6'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.6.8
33
+ - !ruby/object:Gem::Dependency
34
+ name: bundler
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.12'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.12.5
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.12'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.12.5
53
+ - !ruby/object:Gem::Dependency
54
+ name: ruby-progressbar
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '1.8'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.8.1
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.8'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.8.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: colorize
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '0.7'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 0.7.7
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.7'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 0.7.7
93
+ description: A simple gem
94
+ email: joseph.d.lim.@.gmail
95
+ executables:
96
+ - best_boutique_hotels
97
+ extensions: []
98
+ extra_rdoc_files: []
99
+ files:
100
+ - bin/best_boutique_hotels
101
+ - config/environment.rb
102
+ - lib/best_boutique_hotels.rb
103
+ - lib/best_boutique_hotels/category.rb
104
+ - lib/best_boutique_hotels/command_line.rb
105
+ - lib/best_boutique_hotels/hotel.rb
106
+ - lib/best_boutique_hotels/scraper.rb
107
+ homepage: ''
108
+ licenses:
109
+ - MIT
110
+ metadata: {}
111
+ post_install_message:
112
+ rdoc_options: []
113
+ require_paths:
114
+ - lib
115
+ required_ruby_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ required_rubygems_version: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 2.4.8
128
+ signing_key:
129
+ specification_version: 4
130
+ summary: A CLI for www.boutiquehotelawards.com's best hotels list.
131
+ test_files: []