suitcase 1.2.5 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- Suitcase ![build status](https://secure.travis-ci.org/thoughtfusion/suitcase.png)
1
+ Suitcase
2
2
  ========
3
3
 
4
4
  Suitcase is a Ruby library that utilizes the EAN (Expedia.com) API for locating available hotels, rental cars, and flights.
@@ -16,23 +16,19 @@ First, configure the library:
16
16
  Suitcase::Configuration.hotel_api_key = "..." # set the Hotel API key from developer.ean.com
17
17
  Suitcase::Configuration.cid = "..." # set the CID from developer.ean.com
18
18
  Suitcase::Configuration.cache = Hash.new # set the caching mechanism (see below)
19
- Suitcase::Configuration.session_cache = Hash.new # set the session caching store (see below)
20
19
 
21
20
  Find nearby hotels:
22
21
 
23
22
  hotels = Suitcase::Hotel.find(:location => 'Boston, MA', :results => 10) # Returns 10 closest hotels to Boston, MA
24
23
  room = hotels.first.rooms(arrival: "2/19/2012", departure: "2/26/2012", rooms: [{ children: 1, ages: [8] }, { children: 1, ages: [12] }] # Check the availability of two rooms at that hotel with 1 child in each room of ages 8 and 9
25
- room.reserve!(info) # Not yet implemented
24
+ room.reserve!(info) # See wiki page "User flow" for options
26
25
 
27
26
  ### Caching
28
27
 
29
28
  #### Requests
30
29
 
31
- You can setup a cache to store all API requests that do not contain secure information (i.e. anything but booking requests). A cache needs to be able store deeply nested Hashes and have a method called [] to access them. An example of setting the cache is given above.
30
+ You can setup a cache to store all API requests that do not contain secure information (i.e. anything but booking requests). A cache needs to be able store deeply nested Hashes and have a method called [] to access them. An example of setting the cache is given above. Check the `examples/hash_adapter.rb` for a trivial example of the required methods. A Redis adapter should be coming soon.
32
31
 
33
- #### Sessions
34
-
35
- You **must** also set up a cache to store user sessions. A session object simply stores the internal ID used by Expedia, the user agent, the IP address of the user, the user's locale, and the user's currency code. The store is configured similarly to the query store, and have the same requirements.
36
32
 
37
33
  Contributing
38
34
  ------------
@@ -0,0 +1,15 @@
1
+ class HashAdapter
2
+ attr_accessor :hash
3
+
4
+ def [](key)
5
+ @hash[key]
6
+ end
7
+
8
+ def []=(key, value)
9
+ @hash[key] = value
10
+ end
11
+
12
+ def keys
13
+ @hash.keys
14
+ end
15
+ end
@@ -1,12 +1,16 @@
1
1
  module Suitcase
2
2
  class Cache
3
+ attr_accessor :store
4
+
3
5
  def initialize(store)
4
6
  @store = store
5
7
  end
6
8
 
7
9
  def save_query(action, params, response)
8
- params.delete("apiKey")
9
- params.delete("cid")
10
+ %w(apiKey cid customerSessionId customerIpAddress locale customerUserAgent).each do |param|
11
+ params.delete(param)
12
+ end
13
+ params.delete("currencyCode") unless action == :paymentInfo
10
14
  @store[action] ||= {}
11
15
  @store[action][params] = response
12
16
  end
@@ -27,17 +27,5 @@ module Suitcase
27
27
  def self.hotel_cid
28
28
  @@hotel_cid if defined? @@hotel_cid
29
29
  end
30
-
31
- def self.session_cache=(store)
32
- @@session_cache = Suitcase::SessionCache.new(store)
33
- end
34
-
35
- def self.session_cache
36
- return @@session_cache if session_cache?
37
- end
38
-
39
- def self.session_cache?
40
- defined? @@session_cache
41
- end
42
30
  end
43
31
  end
@@ -1,10 +1,22 @@
1
1
  module Suitcase
2
2
  module Helpers
3
- def url(method, params, include_key=true, include_cid=true, secure=false, as_form=false)
3
+ def url(builder)
4
+ builder[:include_key] ||= true
5
+ builder[:include_cid] ||= true
6
+ builder[:secure] ||= false
7
+ builder[:as_form] ||= false
8
+ builder[:session] ||= Suitcase::Session.new
9
+ method, params, include_key, include_cid = builder[:method], builder[:params], builder[:include_key], builder[:include_cid]
4
10
  params["apiKey"] = Configuration.hotel_api_key if include_key
5
11
  params["cid"] = (Configuration.hotel_cid ||= 55505) if include_cid
6
- url = main_url(secure) + method.to_s + (as_form ? "" : "?")
7
- url += params.map { |key, value| "#{key}=#{value}"}.join("&")
12
+ url = main_url(builder[:secure]) + method.to_s + (builder[:as_form] ? "" : "?")
13
+ session_info = {}
14
+ session_info["customerSessionId"] = builder[:session].id if builder[:session].id
15
+ session_info["customerIpAddress"] = builder[:session].ip_address if builder[:session].ip_address
16
+ session_info["locale"] = builder[:session].locale if builder[:session].locale
17
+ session_info["currencyCode"] = builder[:session].currency_code if builder[:session].currency_code
18
+ session_info["customerUserAgent"] = builder[:session].user_agent if builder[:session].user_agent
19
+ url += params.merge(session_info).map { |key, value| "#{key}=#{value}"}.join("&") unless builder[:as_form]
8
20
  URI.parse(URI.escape(url))
9
21
  end
10
22
 
@@ -23,5 +35,10 @@ module Suitcase
23
35
  URI.parse main_url(false)
24
36
  end
25
37
  end
38
+
39
+ def update_session(parsed, session)
40
+ session ||= Suitcase::Session.new
41
+ session.id = parsed[parsed.keys.first]["customerSessionId"] if parsed[parsed.keys.first]
42
+ end
26
43
  end
27
44
  end
@@ -52,9 +52,9 @@ module Suitcase
52
52
  # an Array of Hotels.
53
53
  def self.find(info)
54
54
  if info[:ids]
55
- info[:ids].map { |id| find_by_id(id) }
55
+ info[:ids].map { |id| find_by_id(id, info[:session]) }
56
56
  elsif info[:id]
57
- find_by_id(info[:id])
57
+ find_by_id(info[:id], info[:session])
58
58
  else
59
59
  find_by_info(info)
60
60
  end
@@ -66,16 +66,17 @@ module Suitcase
66
66
  # id.
67
67
  #
68
68
  # Returns a single Hotel object.
69
- def self.find_by_id(id)
69
+ def self.find_by_id(id, session)
70
70
  params = { hotelId: id }
71
71
  if Configuration.cache? and Configuration.cache.cached?(:info, params)
72
72
  raw = Configuration.cache.get_query(:info, params)
73
73
  else
74
- url = url(:info, params)
74
+ url = url(:method => "info", :params => params, :session => session)
75
75
  raw = parse_response(url)
76
76
  Configuration.cache.save_query(:info, params, raw) if Configuration.cache?
77
77
  end
78
78
  hotel_data = parse_information(raw)
79
+ update_session(raw, session)
79
80
  Hotel.new(hotel_data)
80
81
  end
81
82
 
@@ -96,11 +97,17 @@ module Suitcase
96
97
  params["maxRate"] = params[:max_rate] if params[:max_rate]
97
98
  params[:amenities] = amenities if amenities
98
99
  hotels = []
99
- parsed = parse_response(url(:list, params))
100
- handle_errors(parsed)
100
+ if Configuration.cache? and Configuration.cache.cached?(:list, params)
101
+ parsed = Configuration.cache.get_query(:list, params)
102
+ else
103
+ parsed = parse_response(url(:method => "list", :params => params, :session => info[:session]))
104
+ handle_errors(parsed)
105
+ Configuration.cache.save_query(:list, params, parsed) if Configuration.cache?
106
+ end
101
107
  split(parsed).each do |hotel_data|
102
108
  hotels.push Hotel.new(parse_information(hotel_data))
103
109
  end
110
+ update_session(parsed, info[:session])
104
111
  info[:results] ? hotels[0..(info[:results]-1)] : hotels
105
112
  end
106
113
 
@@ -172,11 +179,17 @@ module Suitcase
172
179
  params.delete(:arrival)
173
180
  params.delete(:departure)
174
181
  params["hotelId"] = @id
175
- parsed = Hotel.parse_response(Hotel.url(:avail, params))
176
- Hotel.handle_errors(parsed)
182
+ if Configuration.cache? and Configuration.cache.cached?(:avail, params)
183
+ parsed = Configuration.cache.get_query(:avail, params)
184
+ else
185
+ parsed = Hotel.parse_response(Hotel.url(:method => "avail", :params => params, :session => info[:session]))
186
+ Hotel.handle_errors(parsed)
187
+ Configuration.cache.save_query(:avail, params, parsed) if Configuration.cache?
188
+ end
177
189
  hotel_id = parsed["HotelRoomAvailabilityResponse"]["hotelId"]
178
190
  rate_key = parsed["HotelRoomAvailabilityResponse"]["rateKey"]
179
191
  supplier_type = parsed["HotelRoomAvailabilityResponse"]["HotelRoomResponse"][0]["supplierType"]
192
+ Hotel.update_session(parsed, info[:session])
180
193
  rooms = parsed["HotelRoomAvailabilityResponse"]["HotelRoomResponse"].map do |raw_data|
181
194
  room_data = {}
182
195
  room_data[:rate_code] = raw_data["rateCode"]
@@ -9,8 +9,13 @@ module Suitcase
9
9
  end
10
10
 
11
11
  def self.find(info)
12
- currency_code = info[:currency_code]
13
- types_raw = parse_response(url(:paymentInfo, { "currencyCode" => currency_code }))
12
+ params = { "currencyCode" => info[:currency_code] }
13
+ if Configuration.cache? and Configuration.cache.cached?(:paymentInfo, params)
14
+ types_raw = Configuration.cache.get_query(:paymentInfo, params)
15
+ else
16
+ types_raw = parse_response(url(:method => "paymentInfo", :params => params, :session => info[:session]))
17
+ Configuration.cache.save_query(:paymentInfo, params, types_raw) if Configuration.cache?
18
+ end
14
19
  options = []
15
20
  types_raw["HotelPaymentResponse"].each do |raw|
16
21
  types = raw[0] != "PaymentType" ? [] : raw[1]
@@ -18,6 +23,7 @@ module Suitcase
18
23
  options.push PaymentOption.new(type["code"], type["name"])
19
24
  end
20
25
  end
26
+ update_session(types_raw, info[:session])
21
27
  options
22
28
  end
23
29
  end
@@ -50,7 +50,7 @@ module Suitcase
50
50
  params["stateProvinceCode"] = info[:province]
51
51
  params["countryCode"] = info[:country]
52
52
  params["postalCode"] = info[:postal_code]
53
- uri = Room.url :res, params, true, true, true
53
+ uri = Room.url :method => "res", :params => params, :include_key => true, :include_cid => true, :secure => true
54
54
  session = Patron::Session.new
55
55
  session.base_url = "https://" + uri.host
56
56
  res = session.post uri.request_uri, {}
@@ -1,34 +1,5 @@
1
1
  module Suitcase
2
2
  class Session
3
- attr_accessor :locale, :currency_code, :session_id, :ip_address, :user_agent
4
-
5
- # Public: Instantiate a new session
6
- #
7
- # info - a Hash of the attributes:
8
- # - locale: the user's locale
9
- # - currency_code: the user's currency code
10
- # - session_id: the session_id
11
- # - ip_address: the user's IP address (request.remote_ip)
12
- # - user_agent: the user's user agent
13
- def initialize(info={})
14
- %w(locale currency_code session_id ip_address user_agent).each do |attr|
15
- send (attr + "=").to_sym, info[attr.to_sym]
16
- end
17
- Suitcase::Configuration.session_cache.push self
18
- end
19
-
20
- def delete(session_id)
21
- Session.store.delete Session.store.find { |session| session.session_id == session_id }
22
- end
23
-
24
- def find_or_create(info)
25
- session = Session.store.find { |session| session.session_id == session_id }
26
- session = Session.new(info) unless session
27
- session
28
- end
29
-
30
- def self.store
31
- Suitcase::Configuration.session_store
32
- end
3
+ attr_accessor :id, :user_agent, :ip_address, :locale, :currency_code
33
4
  end
34
5
  end
@@ -1,3 +1,3 @@
1
1
  module Suitcase
2
- VERSION = "1.2.5"
2
+ VERSION = "1.2.6"
3
3
  end
data/lib/suitcase.rb CHANGED
@@ -7,7 +7,7 @@ require 'suitcase/session'
7
7
  require 'suitcase/core_ext/string'
8
8
  require 'suitcase/version'
9
9
  require 'suitcase/configuration'
10
- require 'suitcase/session_cache'
10
+ # require 'suitcase/session_cache'
11
11
  require 'suitcase/cache'
12
12
  require 'suitcase/helpers'
13
13
  require 'suitcase/hotel/amenity'
data/spec/caching_spec.rb CHANGED
@@ -6,14 +6,27 @@ describe Suitcase do
6
6
  end
7
7
 
8
8
  it "should cache all non-secure queries" do
9
- Suitcase::Hotel.find(id: 123904)
10
- Suitcase::Configuration.cache.keys.count.should eq(1)
9
+ hotel = Suitcase::Hotel.find(id: 123904)
10
+ Suitcase::Hotel.find(location: "Boston, US")
11
+ room = hotel.rooms(arrival: "6/23/2012", departure: "6/30/2012").first
12
+ Suitcase::PaymentOption.find currency_code: "USD"
13
+ room.rooms[0][:bed_type] = room.bed_types[0]
14
+ room.rooms[0][:smoking_preference] = "NS"
15
+ room.reserve!(Keys::VALID_RESERVATION_INFO) # We don't want to cache this
16
+ Suitcase::Configuration.cache.keys.count.should eq(4)
11
17
  end
12
18
 
13
19
  it "should retrieve from the cache if it's there" do
20
+ hotel = Suitcase::Hotel.find(id: 123904)
21
+ Suitcase::Hotel.find(location: "Boston, US")
22
+ hotel.rooms(arrival: "6/23/2012", departure: "6/30/2012")
23
+ Suitcase::PaymentOption.find currency_code: "USD"
14
24
  lambda do
15
25
  Net::HTTP.stub!(:get_response).and_return nil # disable access to the API
16
- Suitcase::Hotel.find(id: 123904)
26
+ hotel = Suitcase::Hotel.find(id: 123904)
27
+ Suitcase::Hotel.find(location: "Boston, US")
28
+ hotel.rooms(arrival: "6/23/2012", departure: "6/30/2012")
29
+ Suitcase::PaymentOption.find currency_code: "USD"
17
30
  end.should_not raise_error
18
31
  end
19
32
  end
data/spec/helpers_spec.rb CHANGED
@@ -6,7 +6,7 @@ describe Suitcase::Helpers do
6
6
  end
7
7
 
8
8
  it "#url should return a URI with the correct base URL" do
9
- returned = Dummy.url(:action, {})
9
+ returned = Dummy.url(:method => "action", :params => {})
10
10
  returned.should be_a(URI)
11
11
  returned.host.should match(/api.ean.com/)
12
12
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ describe Suitcase::Session do
4
+ it { should respond_to :id }
5
+ it { should respond_to :ip_address }
6
+ it { should respond_to :user_agent }
7
+ it { should respond_to :locale }
8
+ it { should respond_to :currency_code }
9
+
10
+ before :each do
11
+ @s = Suitcase::Session.new
12
+ end
13
+
14
+ it "should be able to be passed in to a Hotel.find_by_id query" do
15
+ Suitcase::Hotel.find(id: 123904, session: @s)
16
+ @s.id.should_not be_nil
17
+ end
18
+
19
+ it "should be able to be passed in to a Hotel.find_by_info query" do
20
+ Suitcase::Hotel.find(location: "Boston, US", session: @s)
21
+ @s.id.should_not be_nil
22
+ end
23
+
24
+ it "should be able to be passed in to a Hotel#rooms query" do
25
+ hotel = Suitcase::Hotel.find(id: 123904, session: @s)
26
+ hotel.rooms(arrival: "6/23/2012", departure: "6/25/2012", session: @s)
27
+ @s.id.should_not be_nil
28
+ end
29
+
30
+ it "should be able to be passed in to a Room#reserve! query" do
31
+ hotel = Suitcase::Hotel.find(id: 123904, session: @s)
32
+ room = hotel.rooms(arrival: "6/23/2012", departure: "6/25/2012", session: @s).first
33
+ room.rooms[0][:bed_type] = room.bed_types[0]
34
+ room.rooms[0][:smoking_preference] = "NS"
35
+ room.reserve! Keys::VALID_RESERVATION_INFO
36
+ @s.id.should_not be_nil
37
+ end
38
+
39
+ it "should be able to be passed in to a PaymentOption.find query" do
40
+ payment_options = Suitcase::PaymentOption.find(currency_code: "USD", session: @s)
41
+ @s.id.should_not be_nil
42
+ end
43
+ 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.2.5
4
+ version: 1.2.6
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: 2012-01-14 00:00:00.000000000 Z
12
+ date: 2012-01-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- requirement: &9333440 !ruby/object:Gem::Requirement
16
+ requirement: &22060760 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :development
23
23
  prerelease: false
24
- version_requirements: *9333440
24
+ version_requirements: *22060760
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &9332900 !ruby/object:Gem::Requirement
27
+ requirement: &22059980 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *9332900
35
+ version_requirements: *22059980
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: factory_girl
38
- requirement: &9332260 !ruby/object:Gem::Requirement
38
+ requirement: &22058860 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *9332260
46
+ version_requirements: *22058860
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: json
49
- requirement: &9331660 !ruby/object:Gem::Requirement
49
+ requirement: &22058320 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ! '>='
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *9331660
57
+ version_requirements: *22058320
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: patron
60
- requirement: &9330780 !ruby/object:Gem::Requirement
60
+ requirement: &22057560 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *9330780
68
+ version_requirements: *22057560
69
69
  description: Suitcase utilizes the EAN (Expedia.com) API for locating info about hotels,
70
70
  rental cars, and flights.
71
71
  email:
@@ -76,10 +76,10 @@ extra_rdoc_files: []
76
76
  files:
77
77
  - .gitignore
78
78
  - .rspec
79
- - .travis.yml
80
79
  - Gemfile
81
80
  - README.md
82
81
  - Rakefile
82
+ - examples/hash_adapter.rb
83
83
  - lib/suitcase.rb
84
84
  - lib/suitcase/airport_codes.rb
85
85
  - lib/suitcase/cache.rb
@@ -95,7 +95,6 @@ files:
95
95
  - lib/suitcase/hotel/reservation.rb
96
96
  - lib/suitcase/hotel/room.rb
97
97
  - lib/suitcase/session.rb
98
- - lib/suitcase/session_cache.rb
99
98
  - lib/suitcase/version.rb
100
99
  - spec/caching_spec.rb
101
100
  - spec/helpers_spec.rb
@@ -104,6 +103,7 @@ files:
104
103
  - spec/payment_options_spec.rb
105
104
  - spec/reservation_spec.rb
106
105
  - spec/rooms_spec.rb
106
+ - spec/sessions_spec.rb
107
107
  - spec/spec_helper.rb
108
108
  - suitcase.gemspec
109
109
  homepage: http://github.com/thoughtfusion/suitcase
@@ -120,7 +120,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
120
120
  version: '0'
121
121
  segments:
122
122
  - 0
123
- hash: -1373010167553481948
123
+ hash: -2601824217631768176
124
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  none: false
126
126
  requirements:
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
129
  version: '0'
130
130
  segments:
131
131
  - 0
132
- hash: -1373010167553481948
132
+ hash: -2601824217631768176
133
133
  requirements: []
134
134
  rubyforge_project: suitcase
135
135
  rubygems_version: 1.8.10
@@ -144,4 +144,5 @@ test_files:
144
144
  - spec/payment_options_spec.rb
145
145
  - spec/reservation_spec.rb
146
146
  - spec/rooms_spec.rb
147
+ - spec/sessions_spec.rb
147
148
  - spec/spec_helper.rb
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 1.9.2
4
- - 1.9.3
@@ -1,27 +0,0 @@
1
- module Suitcase
2
- class SessionCache
3
- def initialize(store)
4
- @store = store
5
- end
6
-
7
- def save_session(session)
8
- @store.push session
9
- end
10
-
11
- def get_session(session_id)
12
- @store.find { |session| session.session_id == session_id }
13
- end
14
-
15
- def delete_session(session_id)
16
- @store.delete get_session(session_id)
17
- end
18
-
19
- def count
20
- @store.count
21
- end
22
-
23
- def push(item)
24
- @store.push item
25
- end
26
- end
27
- end