suitcase 1.0.1 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -21,14 +21,14 @@ First, include the module in your code:
21
21
  Find nearby hotels:
22
22
 
23
23
  Hotel::API_KEY = "your_api_key_here"
24
- Hotel.near('Boston, MA', 10) # Returns 10 closest hotels to Boston, MA
25
- Hotel.near('Metropoliton Museum of Art') # Returns 50 closest hotels to the Met Museum in New York
24
+ Hotel.near(:location => 'Boston, MA', :results => 10) # Returns 10 closest hotels to Boston, MA
25
+ Hotel.near(:location => 'Metropoliton Museum of Art') # Returns 50 closest hotels to the Met Museum in New York
26
26
 
27
27
  Find available airline flights (not yet implemented):
28
28
 
29
29
  Flight:API_KEY = "your_api_key_here"
30
- Flight.available('June 23 2012', :from => "BOS", :to => "LHR") # Return all flights flying from Boston to London (Heathrow) on June 23, 2012
30
+ Flight.available(:date => 'June 23 2012', :departs => "BOS", :arrives => "LHR") # Return all flights flying from Boston to London (Heathrow) on June 23, 2012
31
31
 
32
32
  Contributing
33
33
  ------------
34
- Please submit any useful pull requests through GitHub. If you find any bugs, please report them! Thanks.
34
+ Please submit any useful pull requests through GitHub. If you find any bugs, please report them with the issue tracker! Thanks.
@@ -0,0 +1,28 @@
1
+ Feature: Hotels
2
+ As a developer
3
+ In order to use the EAN API in my application
4
+ I need to be able to manipulate hotel information
5
+
6
+ Scenario Outline: Listing available hotels
7
+ Given I have an API key
8
+ When I submit a request to find <number_of_results> hotels in <location>
9
+ Then I want to receive <number_of_results> hotels with their respective information
10
+
11
+ Examples:
12
+
13
+ | number_of_results | location |
14
+ | 10 | Boston, USA |
15
+ | 8 | Dublin, Ireland |
16
+ | 1 | London, UK |
17
+
18
+ Scenario Outline: Requesting more information about a given hotel
19
+ Given I have an API key
20
+ When I submit a request to find more information about a hotel with id <id>
21
+ Then I want to receive more information about that hotel
22
+
23
+ Examples:
24
+
25
+ | id |
26
+ | 252897 |
27
+ | 273655 |
28
+ | 174272 |
@@ -0,0 +1,21 @@
1
+ require 'suitcase'
2
+
3
+ Given /^I have an API key$/ do
4
+ Suitcase::Hotel::API_KEY = "3kx2vhr7sjrgmsyddb2cg47j"
5
+ end
6
+
7
+ When /^I submit a request to find (\d+) hotels in (.+)$/ do |results, location|
8
+ @hotels = Suitcase::Hotel.find(:near => location, :results => results.to_i)
9
+ end
10
+
11
+ Then /^I want to receive (\d+) hotels with their respective information$/ do |results|
12
+ @hotels.count.should eq(results.to_i)
13
+ end
14
+
15
+ When /^I submit a request to find more information about a hotel with id (\d+)$/ do |id|
16
+ @hotel = Suitcase::Hotel.find_by_id(id)
17
+ end
18
+
19
+ Then /^I want to receive more information about that hotel$/ do
20
+ @hotel.should_not be_nil
21
+ end
@@ -0,0 +1,151 @@
1
+ module Suitcase
2
+ class PaymentOption
3
+ attr_accessor :code, :name
4
+
5
+ def initialize(code, name)
6
+ @code = code
7
+ @name = name
8
+ end
9
+ end
10
+
11
+ class Room
12
+ attr_accessor :rate_key, :hotel_id, :supplier_type
13
+
14
+ def initialize(rate_key, hotel_id, supplier_type)
15
+ @rate_key = rate_key
16
+ @hotel_id = hotel_id
17
+ @supplier_type = supplier_type
18
+ end
19
+
20
+ def reserve!(info)
21
+ params = info
22
+ params["hotelId"] = @id
23
+ params["arrivalDate"] = info[:arrival]
24
+ params["departureDate"] = info[:departure]
25
+ params.delete(:arrival)
26
+ params.delete(:departure)
27
+ params["supplierType"] = supplier_type
28
+ params["rateKey"] = @rate_key
29
+ params["rateTypeCode"] = info[:room_type_code]
30
+ params["rateCode"] = info[:rate_code]
31
+ params.delete(:rate_code)
32
+ p Hotel.hit(Hotel.url(:res, true, true, params))
33
+ end
34
+ end
35
+
36
+ class Hotel
37
+ AMENITIES = { pool: 1,
38
+ fitness_center: 2,
39
+ restaurant: 3,
40
+ children_activities: 4,
41
+ breakfast: 5,
42
+ meeting_facilities: 6,
43
+ pets: 7,
44
+ wheelchair_accessible: 8,
45
+ kitchen: 9 }
46
+
47
+ attr_accessor :id, :name, :address, :city, :min_rate, :max_rate, :amenities, :country_code, :high_rate, :low_rate, :longitude, :latitude, :rating, :postal_code, :supplier_type
48
+
49
+ def initialize(info)
50
+ info.each do |k, v|
51
+ send (k.to_s + "=").to_sym, v
52
+ end
53
+ end
54
+
55
+ def self.url(action, include_key, include_cid, params)
56
+ url = "http://api.ean.com/ean-services/rs/hotel/v3/" + action.to_s + "?"
57
+ include_key ? params["apiKey"] = Suitcase::Hotel::API_KEY : nil
58
+ include_cid ? params["cid"] = "55505" : nil
59
+ params.each do |k, v|
60
+ url += k.to_s + "=" + v.to_s + "&"
61
+ end
62
+ if url =~ /^(.+)&$/
63
+ url = $1
64
+ end
65
+ URI.parse URI.escape(url)
66
+ end
67
+
68
+ def self.find(info)
69
+ if info[:id]
70
+ find_by_id(info[:id])
71
+ else
72
+ find_by_info(info)
73
+ end
74
+ end
75
+
76
+ def self.find_by_id(id)
77
+ Hotel.new(parse_hotel_information(hit(url(:info, true, true, { hotelId: id }))))
78
+ end
79
+
80
+ def self.find_by_info(info)
81
+ params = info
82
+ params["numberOfResults"] = params[:results] ? params[:results] : 10
83
+ params.delete(:results)
84
+ params["destinationString"] = params[:location]
85
+ params.delete(:location)
86
+ if params[:amenities]
87
+ amenities = ""
88
+ params[:amenities].each do |amenity|
89
+ amenities += AMENITIES[amenity].to_s + ","
90
+ end
91
+ if amenities =~ /^(.+),$/
92
+ amenities = $1
93
+ end
94
+ end
95
+ params["minRate"] = params[:min_rate] if params[:min_rate]
96
+ params["maxRate"] = params[:max_rate] if params[:max_rate]
97
+ params[:amenities] = amenities
98
+ hotels = []
99
+ split(hit(url(:list, true, true, params))).each do |hotel_data|
100
+ hotels.push Hotel.new(parse_hotel_information(hotel_data.to_json))
101
+ end
102
+ hotels
103
+ end
104
+
105
+ def self.hit(url)
106
+ Net::HTTP.get_response(url).body
107
+ end
108
+
109
+ def self.parse_hotel_information(json)
110
+ parsed = JSON.parse json
111
+ summary = parsed["hotelId"] ? parsed : parsed["HotelInformationResponse"]["HotelSummary"]
112
+ { id: summary["hotelId"], name: summary["name"], address: summary["address1"], city: summary["city"], postal_code: summary["postalCode"], country_code: summary["countryCode"], rating: summary["hotelRating"], high_rate: summary["highRate"], low_rate: summary["lowRate"], latitude: summary["latitude"].to_f, longitude: summary["longitude"].to_f }
113
+ end
114
+
115
+ def self.split(data)
116
+ parsed = JSON.parse(data)
117
+ hotels = parsed["HotelListResponse"]["HotelList"]
118
+ hotels["HotelSummary"]
119
+ end
120
+
121
+ def rooms(info)
122
+ params = info
123
+ params[:rooms].each_with_index do |room, n|
124
+ params["room#{n+1}"] = (room[:children] == 0 ? "" : room[:children].to_s + ",").to_s + room[:ages].join(",").to_s
125
+ end
126
+ params["arrivalDate"] = info[:arrival]
127
+ params["departureDate"] = info[:departure]
128
+ params.delete(:arrival)
129
+ params.delete(:departure)
130
+ params["hotelId"] = @id
131
+ parsed = JSON.parse(Hotel.hit(Hotel.url(:avail, true, true, params)))
132
+ hotel_id = parsed["HotelRoomAvailabilityResponse"]["hotelId"]
133
+ rate_key = parsed["HotelRoomAvailabilityResponse"]["rateKey"]
134
+ supplier_type = parsed["HotelRoomAvailabilityResponse"]["supplierType"]
135
+ Room.new(rate_key, hotel_id, supplier_type)
136
+ end
137
+
138
+ def payment_options
139
+ options = []
140
+ types_raw = JSON.parse Hotel.hit(Hotel.url(:paymentInfo, true, true, {}))
141
+ types_raw["HotelPaymentResponse"].each do |raw|
142
+ p raw
143
+ types = raw[0] != "PaymentType" ? [] : raw[1]
144
+ types.each do |type|
145
+ options.push PaymentOption.new(type["code"], type["name"])
146
+ end
147
+ end
148
+ options
149
+ end
150
+ end
151
+ end
@@ -1,3 +1,3 @@
1
1
  module Suitcase
2
- VERSION = "1.0.1"
2
+ VERSION = "1.1.0"
3
3
  end
data/lib/suitcase.rb CHANGED
@@ -1,7 +1,4 @@
1
+ require 'json'
2
+ require 'net/http'
1
3
  require 'suitcase/version'
2
- require 'suitcase/hotel/hotel'
3
- require 'suitcase/air/air'
4
-
5
- module Suitcase
6
-
7
- end
4
+ require 'suitcase/hotel'
data/spec/api_key.rb ADDED
@@ -0,0 +1 @@
1
+ HOTEL_API_KEY = "88m3ugkarmfzcq3z4syayymt"
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Suitcase::DataHelpers do
4
+ before :each do
5
+ class Hotel
6
+ API_KEY = HOTEL_API_KEY
7
+ extend Suitcase::DataHelpers
8
+ end
9
+ end
10
+
11
+ it "#url should return a valid url" do
12
+ URI.parse(Hotel.url(:hotel, :list, true, { location: "London, UK" })).should be_a(URI)
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe Suitcase::Hotel do
4
+ it "::find should return an Array if no ID is passed" do
5
+ Suitcase::Hotel.find(destination: "Boston, US").should be_a(Array)
6
+ end
7
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,2 @@
1
1
  require File.dirname(__FILE__) + '/../lib/suitcase'
2
2
  require 'api_key'
3
-
4
- Suitcase::Hotel::API_KEY = HOTEL_API_KEY
data/suitcase.gemspec CHANGED
@@ -19,6 +19,8 @@ Gem::Specification.new do |s|
19
19
  s.require_paths = ["lib"]
20
20
 
21
21
  s.add_development_dependency "rspec"
22
+ s.add_development_dependency "cucumber"
23
+ s.add_development_dependency "rake"
22
24
  s.add_runtime_dependency "json"
23
25
  s.add_runtime_dependency "nokogiri"
24
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: suitcase
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-11-05 00:00:00.000000000Z
12
+ date: 2011-12-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &11887140 !ruby/object:Gem::Requirement
16
+ requirement: &20325340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,32 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *11887140
24
+ version_requirements: *20325340
25
+ - !ruby/object:Gem::Dependency
26
+ name: cucumber
27
+ requirement: &20324640 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *20324640
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &20324160 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *20324160
25
47
  - !ruby/object:Gem::Dependency
26
48
  name: json
27
- requirement: &11886720 !ruby/object:Gem::Requirement
49
+ requirement: &20323700 !ruby/object:Gem::Requirement
28
50
  none: false
29
51
  requirements:
30
52
  - - ! '>='
@@ -32,10 +54,10 @@ dependencies:
32
54
  version: '0'
33
55
  type: :runtime
34
56
  prerelease: false
35
- version_requirements: *11886720
57
+ version_requirements: *20323700
36
58
  - !ruby/object:Gem::Dependency
37
59
  name: nokogiri
38
- requirement: &11886300 !ruby/object:Gem::Requirement
60
+ requirement: &20323260 !ruby/object:Gem::Requirement
39
61
  none: false
40
62
  requirements:
41
63
  - - ! '>='
@@ -43,7 +65,7 @@ dependencies:
43
65
  version: '0'
44
66
  type: :runtime
45
67
  prerelease: false
46
- version_requirements: *11886300
68
+ version_requirements: *20323260
47
69
  description: Suitcase utilizes the EAN API for locating available hotels, rental cars,
48
70
  and flights.
49
71
  email:
@@ -56,13 +78,16 @@ files:
56
78
  - Gemfile
57
79
  - README.md
58
80
  - Rakefile
81
+ - features/hotels.feature
82
+ - features/step_definitions/hotels_steps.rb
59
83
  - lib/suitcase.rb
60
- - lib/suitcase/air/air.rb
61
84
  - lib/suitcase/airport_codes.rb
62
85
  - lib/suitcase/country_codes.rb
63
- - lib/suitcase/hotel/hotel.rb
86
+ - lib/suitcase/hotel.rb
64
87
  - lib/suitcase/version.rb
65
- - spec/hotel_spec.rb
88
+ - spec/api_key.rb
89
+ - spec/data_helpers_spec.rb
90
+ - spec/hotels_spec.rb
66
91
  - spec/spec_helper.rb
67
92
  - suitcase.gemspec
68
93
  homepage: http://github.com/thoughtfusion/suitcase
@@ -77,16 +102,28 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
102
  - - ! '>='
78
103
  - !ruby/object:Gem::Version
79
104
  version: '0'
105
+ segments:
106
+ - 0
107
+ hash: -1859999531224729447
80
108
  required_rubygems_version: !ruby/object:Gem::Requirement
81
109
  none: false
82
110
  requirements:
83
111
  - - ! '>='
84
112
  - !ruby/object:Gem::Version
85
113
  version: '0'
114
+ segments:
115
+ - 0
116
+ hash: -1859999531224729447
86
117
  requirements: []
87
118
  rubyforge_project: suitcase
88
- rubygems_version: 1.8.6
119
+ rubygems_version: 1.8.10
89
120
  signing_key:
90
121
  specification_version: 3
91
122
  summary: Locates available hotels, rental cars, and flights
92
- test_files: []
123
+ test_files:
124
+ - features/hotels.feature
125
+ - features/step_definitions/hotels_steps.rb
126
+ - spec/api_key.rb
127
+ - spec/data_helpers_spec.rb
128
+ - spec/hotels_spec.rb
129
+ - spec/spec_helper.rb
@@ -1,86 +0,0 @@
1
- require 'open-uri'
2
- require 'json'
3
- require 'nokogiri'
4
- require File.dirname(__FILE__) + '/../airport_codes'
5
-
6
- module Suitcase
7
- class Flight
8
- attr_accessor :flights, :key, :origin, :destination, :departure, :arrival, :adults, :children, :seniors, :fare, :direct, :round_trip, :currency, :search_window, :results, :airline, :airline_code, :price, :segments, :outgoing
9
-
10
- def to_s
11
- puts <<EOS
12
- ----------
13
- FLIGHT:
14
- airline: #{airline} (#{airline_code})
15
- origin: #{origin}
16
- destination: #{destination}
17
- departure: #{departure}
18
- arrival: #{arrival}
19
- price: #{price} (#{currency})
20
- key: #{key}
21
- ----------
22
- EOS
23
- end
24
-
25
- def self.available(data)
26
- origin_city = data[:from]
27
- destination_city = data[:to]
28
- departure_date_time = data[:departs]
29
- arrival_date_time = data[:arrives]
30
- adult_passengers = data[:adults] ? data[:adults] : 0
31
- child_passengers = data[:children] ? data[:children].inject("") { |result, element| result + "C" + (element < 10 ? "0" : "") + element.to_s + (data[:children].last == element ? "" : ",") } : "" # :children => [2, 9, 11] (ages of children) should yield "C02,C09,C11"
32
- senior_passengers = data[:seniors] ? data[:seniors] : 0
33
- fare_class = data[:fare] ? data[:fare] : "Y" # F: first class; Y: coach; B: business
34
- direct_flight = data[:direct_only] ? data[:direct_only] : false
35
- round_trip = data[:round_trip] ? data[:round_trip] : "O"
36
- currency = data[:currency] ? data[:currency] : "USD"
37
- search_window = data[:search_window] ? data[:search_window] : 2
38
- number_of_results = data[:results] ? data[:results] : 50
39
- xml_format = <<EOS
40
- <AirSessionRequest method="getAirAvailability">
41
- <AirAvailabilityQuery>
42
- <originCityCode>#{origin_city}</originCityCode>
43
- <destinationCityCode>#{destination_city}</destinationCityCode>
44
- <departureDateTime>#{departure_date_time}</departureDateTime>
45
- <returnDateTime>#{arrival_date_time}</returnDateTime>
46
- <fareClass>#{fare_class}</fareClass>
47
- <tripType>#{round_trip}</tripType>
48
- <Passengers>
49
- <adultPassengers>#{adult_passengers}</adultPassengers>
50
- <seniorPassengers>#{senior_passengers}</seniorPassengers>
51
- <childCodes>#{child_passengers}</childCodes>
52
- </Passengers>
53
- </AirAvailabilityQuery>
54
- </AirSessionRequest>
55
- EOS
56
- uri = URI.escape("http://api.ean.com/ean-services/rs/air/200919/xmlinterface.jsp?cid=#{CID}&resType=air&intfc=ws&apiKey=#{API_KEY}&xml=#{xml_format}")
57
- xml = Nokogiri::XML(open(uri))
58
- segments = []
59
- xml.xpath('//Segment').each do |segment|
60
- f = Flight.new
61
- f.key = segment.xpath("@key")
62
- f.origin = segment.xpath("//originCity") + segment.xpath("//originStateProvince") + segment.xpath("//originCountry")
63
- f.destination = segment.xpath("//destinationCity")
64
- f.airline = segment.xpath("//airline")
65
- f.airline_code = segment.xpath("//airlineCode")
66
- f.departure = segment.xpath("//departureDateTime")
67
- f.arrival = segment.xpath("//arrivalDateTime")
68
- segments.push(f)
69
- end
70
- flights = []
71
- xml.xpath("//AirAvailabilityReply").each do |aar|
72
- f = Flight.new
73
- f.segments = []
74
- f.price = aar.xpath("//nativeTotalPrice")
75
- f.currency = aar.xpath("//displayCurrencyCode")
76
- aar.xpath("//FlightSegment").each do |subseg|
77
- fn = segments.find { |x| x.key == subseg.xpath("//segmentKey") }
78
- f.segments.push(fn)
79
- f.segments.compact!
80
- end
81
- flights.push(f)
82
- end
83
- flights
84
- end
85
- end
86
- end
@@ -1,49 +0,0 @@
1
- require 'net/http'
2
- require 'uri'
3
- require 'json'
4
- require File.dirname(__FILE__) + '/../country_codes'
5
-
6
- module Suitcase
7
- class Hotel
8
- attr_accessor :id, :name, :address, :city, :postal_code, :country, :airport_code, :rating, :confidence_rating, :description, :high_rate, :low_rate, :tripadvisor_rating, :currency_code, :latitude, :longitude
9
-
10
- def self.find(hash)
11
- hotels = []
12
- json = JSON.parse Net::HTTP.get_response(URI.parse(URI.escape("http://api.ean.com/ean-services/rs/hotel/v3/list?apiKey=#{Suitcase::Hotel::API_KEY}&city=#{hash[:near]}&numberOfResults=#{hash[:results]}"))).body
13
- if json["HotelListResponse"]["HotelList"]
14
- json["HotelListResponse"]["HotelList"]["HotelSummary"].each do |hotel_data|
15
- h = Hotel.new
16
- h.id = hotel_data["hotelId"]
17
- h.name = hotel_data["name"]
18
- h.address = hotel_data["address1"]
19
- h.city = hotel_data["city"]
20
- h.postal_code = hotel_data["postalCode"]
21
- h.country = COUNTRY_CODES[hotel_data["countryCode"]]
22
- h.airport_code = hotel_data["airportCode"]
23
- h.rating = hotel_data["hotelRating"]
24
- h.confidence_rating = hotel_data["confidenceRating"]
25
- h.tripadvisor_rating = hotel_data["tripAdvisorRating"]
26
- h.currency_code = hotel_data["rateCurrencyCode"]
27
- h.latitude = hotel_data["latitude"]
28
- h.longitude = hotel_data["longitude"]
29
- h.high_rate = hotel_data["highRate"]
30
- h.low_rate = hotel_data["lowRate"]
31
- hotels.push(h)
32
- end
33
- hotels[0..hash[:results]-1]
34
- else
35
- if json["HotelListResponse"]["EanWsError"]
36
- raise "An error occured. Check data."
37
- end
38
- end
39
- end
40
-
41
- def geolocation
42
- latitude + ", " + longitude
43
- end
44
-
45
- def complete_address
46
- address + " " + city + ", " + country + " " + postal_code
47
- end
48
- end
49
- end
data/spec/hotel_spec.rb DELETED
@@ -1,23 +0,0 @@
1
- require 'spec_helper'
2
-
3
- include Suitcase
4
-
5
- describe Hotel do
6
- before(:each) do
7
- @attr = { :near => "Boston", :results => 50 }
8
- end
9
-
10
- describe "find method" do
11
- it "should return the correct number of results" do
12
- Hotel.find(@attr).count.should eq(50)
13
- end
14
-
15
- it "should return an array of hotels" do
16
- Hotel.find(@attr).class.should eq(Array)
17
- end
18
-
19
- it "should return all hotels" do
20
- Hotel.find(@attr).map { |x| x.class }.should eq([Hotel] * 50)
21
- end
22
- end
23
- end