hotel_beds 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +17 -4
- data/hotel_beds.gemspec +1 -0
- data/lib/hotel_beds.rb +0 -2
- data/lib/hotel_beds/client.rb +7 -2
- data/lib/hotel_beds/connection.rb +8 -10
- data/lib/hotel_beds/{operation/search.rb → hotel_search/envelope.rb} +35 -21
- data/lib/hotel_beds/hotel_search/operation.rb +36 -0
- data/lib/hotel_beds/{model/search.rb → hotel_search/request.rb} +10 -9
- data/lib/hotel_beds/hotel_search/response.rb +90 -0
- data/lib/hotel_beds/model.rb +13 -0
- data/lib/hotel_beds/model/available_room.rb +6 -3
- data/lib/hotel_beds/model/hotel.rb +4 -3
- data/lib/hotel_beds/model/hotel_room.rb +5 -2
- data/lib/hotel_beds/version.rb +1 -1
- data/spec/features/hotel_search_spec.rb +55 -36
- data/spec/lib/hotel_beds/connection_spec.rb +2 -2
- data/spec/lib/hotel_beds/{model/search_spec.rb → hotel_search/request_spec.rb} +2 -2
- data/spec/lib/hotel_beds/version_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -0
- metadata +23 -13
- data/lib/hotel_beds/model/base.rb +0 -35
- data/lib/hotel_beds/model_invalid.rb +0 -12
- data/lib/hotel_beds/operation/base.rb +0 -29
- data/lib/hotel_beds/response/base.rb +0 -27
- data/lib/hotel_beds/response/search.rb +0 -43
- data/spec/lib/hotel_beds/model_invalid_spec.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 55dc805389b4efeb9ef72bd55a2399ec361b8092
|
4
|
+
data.tar.gz: 8d2a36c3f58e9b573dfe41d30d81436157c71c4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1c5da4a532371c2b08dda8ef38d6393b1954c8d81672e355ae8b9082e4a347d8ab4f43a2af05446295dbd16de7560f15df43c2f0751602b8ea82a85a8cac53a
|
7
|
+
data.tar.gz: bfc1dc68a2794149cb659e82211ca595f564f2bdeccc5bb49a729dea40e79fda2cc0c06bcfc32dac977c9133ca96b29c7af7d840917c2232675a2ec65967ffee
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
[![Code Climate](https://codeclimate.com/github/platformq/hotel_beds.png)](https://codeclimate.com/github/platformq/hotel_beds)
|
1
|
+
[![Codeship Status](https://www.codeship.io/projects/808271e0-e973-0131-1052-5240ebfefa5a/status)](https://www.codeship.io/projects/26188) [![Code Climate](https://codeclimate.com/github/platformq/hotel_beds.png)](https://codeclimate.com/github/platformq/hotel_beds) [![Code Climate](https://codeclimate.com/github/platformq/hotel_beds/coverage.png)](https://codeclimate.com/github/platformq/hotel_beds)
|
2
2
|
|
3
3
|
The `hotel_beds` gem interfaces with the [HotelBeds.com](http://www.hotelbeds.com/) SOAP API to search for and book hotel rooms.
|
4
4
|
|
@@ -16,11 +16,24 @@ Manually, via command line:
|
|
16
16
|
|
17
17
|
## Usage
|
18
18
|
|
19
|
+
# create the connection to HotelBeds
|
19
20
|
client = HotelBeds::Client.new(endpoint: :test, username: "user", password: "pass")
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
|
22
|
+
# perform the search
|
23
|
+
search = client.perform_hotel_search({
|
24
|
+
check_in_date: Date.today,
|
25
|
+
check_out_date: Date.today + 1,
|
26
|
+
rooms: [{ adult_count: 2 }],
|
27
|
+
destination: "SYD"
|
28
|
+
})
|
29
|
+
|
30
|
+
# inspect the response
|
31
|
+
puts search.response.hotels
|
23
32
|
# => [<HotelBeds::Model::Hotel>, <HotelBeds::Model::Hotel>]
|
33
|
+
puts search.response.total_pages
|
34
|
+
# => 10
|
35
|
+
puts search.response.current_page
|
36
|
+
# => 1
|
24
37
|
|
25
38
|
## Contributing
|
26
39
|
|
data/hotel_beds.gemspec
CHANGED
@@ -27,4 +27,5 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0.0"
|
28
28
|
spec.add_development_dependency "guard-rspec", "~> 4.2.10"
|
29
29
|
spec.add_development_dependency "dotenv", "~> 0.11.1"
|
30
|
+
spec.add_development_dependency "codeclimate-test-reporter"
|
30
31
|
end
|
data/lib/hotel_beds.rb
CHANGED
data/lib/hotel_beds/client.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "hotel_beds/configuration"
|
2
2
|
require "hotel_beds/connection"
|
3
|
+
require "hotel_beds/hotel_search/operation"
|
3
4
|
|
4
5
|
module HotelBeds
|
5
6
|
class Client
|
@@ -12,8 +13,12 @@ module HotelBeds
|
|
12
13
|
freeze
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
-
|
16
|
+
# builds and performs a hotel search, returning an operation object which
|
17
|
+
# contains both the request and response objects.
|
18
|
+
def perform_hotel_search(*args)
|
19
|
+
HotelSearch::Operation.new(*args).perform(
|
20
|
+
connection: connection
|
21
|
+
)
|
17
22
|
end
|
18
23
|
end
|
19
24
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require "savon"
|
2
|
+
require "securerandom"
|
2
3
|
|
3
4
|
module HotelBeds
|
4
5
|
class Connection
|
@@ -11,21 +12,20 @@ module HotelBeds
|
|
11
12
|
freeze
|
12
13
|
end
|
13
14
|
|
14
|
-
def
|
15
|
-
message =
|
16
|
-
message[operation.namespace] = message.fetch(operation.namespace).merge({
|
15
|
+
def call(method:, namespace:, data:)
|
16
|
+
message = { namespace => {
|
17
17
|
:@xmlns => "http://www.hotelbeds.com/schemas/2005/06/messages",
|
18
18
|
:"@xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
19
|
-
:"@xsi:schemaLocation" => "http://www.hotelbeds.com/schemas/2005/06/messages #{
|
20
|
-
:@echoToken =>
|
21
|
-
:@sessionId =>
|
19
|
+
:"@xsi:schemaLocation" => "http://www.hotelbeds.com/schemas/2005/06/messages #{namespace}.xsd",
|
20
|
+
:@echoToken => SecureRandom.hex[0..15],
|
21
|
+
:@sessionId => SecureRandom.hex[0..15],
|
22
22
|
:Credentials => {
|
23
23
|
User: configuration.username,
|
24
24
|
Password: configuration.password
|
25
25
|
}
|
26
|
-
})
|
26
|
+
}.merge(data) }
|
27
27
|
# send the call
|
28
|
-
response = client.call(
|
28
|
+
response = client.call(method, {
|
29
29
|
soap_action: "",
|
30
30
|
attributes: {
|
31
31
|
:"xmlns:hb" => "http://axis.frontend.hydra.hotelbeds.com",
|
@@ -33,8 +33,6 @@ module HotelBeds
|
|
33
33
|
},
|
34
34
|
message: message
|
35
35
|
})
|
36
|
-
# parse the response
|
37
|
-
operation.parse_response(response)
|
38
36
|
end
|
39
37
|
|
40
38
|
private
|
@@ -1,33 +1,33 @@
|
|
1
|
-
require "
|
2
|
-
require "hotel_beds/response/search"
|
1
|
+
require "delegate"
|
3
2
|
|
4
3
|
module HotelBeds
|
5
|
-
module
|
6
|
-
class
|
7
|
-
def
|
8
|
-
|
9
|
-
end
|
10
|
-
|
11
|
-
def namespace
|
12
|
-
:HotelValuedAvailRQ
|
13
|
-
end
|
14
|
-
|
15
|
-
def message
|
16
|
-
{ namespace => {
|
4
|
+
module HotelSearch
|
5
|
+
class Envelope < SimpleDelegator
|
6
|
+
def attributes
|
7
|
+
{
|
17
8
|
PaginationData: pagination_data,
|
18
9
|
Language: language,
|
19
10
|
CheckInDate: check_in_date,
|
20
11
|
CheckOutDate: check_out_date,
|
21
|
-
Destination: destination,
|
22
12
|
OccupancyList: occupancy_list
|
23
|
-
}
|
13
|
+
}.merge(Hash(destination)).merge(Hash(hotels)).merge(Hash(extra_params))
|
24
14
|
end
|
25
15
|
|
26
|
-
|
27
|
-
|
16
|
+
private
|
17
|
+
def extra_params
|
18
|
+
{ ExtraParamList: {
|
19
|
+
ExtendedData: [{
|
20
|
+
:@type => "EXT_ADDITIONAL_PARAM",
|
21
|
+
:Name => "PARAM_KEY_PRICE_BREAKDOWN",
|
22
|
+
:Value => "Y"
|
23
|
+
}, {
|
24
|
+
:@type => "EXT_ORDER",
|
25
|
+
:Name => "ORDER_CONTRACT_PRICE",
|
26
|
+
:Value => "ASC"
|
27
|
+
}]
|
28
|
+
} }
|
28
29
|
end
|
29
30
|
|
30
|
-
private
|
31
31
|
def pagination_data
|
32
32
|
{ :@pageNumber => Integer(page_number) }
|
33
33
|
end
|
@@ -45,7 +45,21 @@ module HotelBeds
|
|
45
45
|
end
|
46
46
|
|
47
47
|
def destination
|
48
|
-
|
48
|
+
if __getobj__.destination
|
49
|
+
{ Destination: {
|
50
|
+
:@code => String(__getobj__.destination).upcase,
|
51
|
+
:@type => "SIMPLE"
|
52
|
+
} }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def hotels
|
57
|
+
if Array(__getobj__.hotels).any?
|
58
|
+
{ HotelCodeList: {
|
59
|
+
:@withinResults => "Y",
|
60
|
+
:ProductCode => Array(__getobj__.hotels)
|
61
|
+
} }
|
62
|
+
end
|
49
63
|
end
|
50
64
|
|
51
65
|
def occupancy_list
|
@@ -56,7 +70,7 @@ module HotelBeds
|
|
56
70
|
AdultCount: Integer(room.adult_count),
|
57
71
|
ChildCount: Integer(room.child_count)
|
58
72
|
},
|
59
|
-
GuestList: room.child_ages.each { |age|
|
73
|
+
GuestList: Array(room.child_ages).each { |age|
|
60
74
|
{ Customer: { :@type => "CH", :Age => Integer(age) } }
|
61
75
|
}
|
62
76
|
} }
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require_relative "request"
|
2
|
+
require_relative "response"
|
3
|
+
require_relative "envelope"
|
4
|
+
|
5
|
+
module HotelBeds
|
6
|
+
module HotelSearch
|
7
|
+
class Operation
|
8
|
+
attr_accessor :request, :response, :errors
|
9
|
+
private :request=, :response=, :errors=
|
10
|
+
|
11
|
+
def initialize(*args)
|
12
|
+
self.request = Request.new(*args)
|
13
|
+
end
|
14
|
+
|
15
|
+
def perform(connection:)
|
16
|
+
if request.valid?
|
17
|
+
self.response = Response.new(retrieve(connection))
|
18
|
+
self.errors = response.errors
|
19
|
+
else
|
20
|
+
self.errors = request.errors
|
21
|
+
end
|
22
|
+
freeze
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def retrieve(connection)
|
28
|
+
connection.call({
|
29
|
+
method: :getHotelValuedAvail,
|
30
|
+
namespace: :HotelValuedAvailRQ,
|
31
|
+
data: Envelope.new(request).attributes
|
32
|
+
})
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,19 +1,17 @@
|
|
1
|
-
require "hotel_beds/model
|
2
|
-
require "virtus"
|
3
|
-
require "active_model"
|
1
|
+
require "hotel_beds/model"
|
4
2
|
|
5
3
|
module HotelBeds
|
6
|
-
module
|
7
|
-
class
|
8
|
-
class Room
|
4
|
+
module HotelSearch
|
5
|
+
class Request
|
6
|
+
class Room
|
7
|
+
include HotelBeds::Model
|
8
|
+
|
9
9
|
# attributes
|
10
|
-
include Virtus.model
|
11
10
|
attribute :adult_count, Integer, default: 0
|
12
11
|
attribute :child_count, Integer, default: 0
|
13
12
|
attribute :child_ages, Array[Integer], default: Array.new
|
14
|
-
|
13
|
+
|
15
14
|
# validation
|
16
|
-
include ActiveModel::Validations
|
17
15
|
validates :adult_count, :child_count, numericality: {
|
18
16
|
greater_than_or_equal_to: 0,
|
19
17
|
less_than_or_equal_to: 4,
|
@@ -25,6 +23,8 @@ module HotelBeds
|
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
26
|
+
|
27
|
+
include HotelBeds::Model
|
28
28
|
|
29
29
|
# attributes
|
30
30
|
attribute :page_number, Integer, default: 1
|
@@ -32,6 +32,7 @@ module HotelBeds
|
|
32
32
|
attribute :check_in_date, Date
|
33
33
|
attribute :check_out_date, Date
|
34
34
|
attribute :destination, String
|
35
|
+
attribute :hotels, Array[Integer]
|
35
36
|
attribute :rooms, Array[Room]
|
36
37
|
|
37
38
|
# validation
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "active_model/errors"
|
2
|
+
require "hotel_beds/model/hotel"
|
3
|
+
|
4
|
+
module HotelBeds
|
5
|
+
module HotelSearch
|
6
|
+
class Response
|
7
|
+
attr_accessor :headers, :body, :errors
|
8
|
+
private :headers=, :body=, :errors=
|
9
|
+
|
10
|
+
def initialize(response)
|
11
|
+
self.headers = response.header
|
12
|
+
self.body = Nokogiri::XML(response.body.fetch(:get_hotel_valued_avail))
|
13
|
+
self.errors = ActiveModel::Errors.new(self).tap do |errors|
|
14
|
+
if response.http_error?
|
15
|
+
errors.add(:base, "HTTP error")
|
16
|
+
elsif response.soap_fault?
|
17
|
+
errors.add(:base, "SOAP error")
|
18
|
+
elsif !response.success?
|
19
|
+
errors.add(:base, "Request failed")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
freeze
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"<#{self.class.name} headers=#{headers.inspect} body=#{body.to_s}>"
|
27
|
+
end
|
28
|
+
|
29
|
+
def current_page
|
30
|
+
Integer(body.css("PaginationData").first.attr("currentPage"))
|
31
|
+
end
|
32
|
+
|
33
|
+
def total_pages
|
34
|
+
Integer(body.css("PaginationData").first.attr("totalPages"))
|
35
|
+
end
|
36
|
+
|
37
|
+
def hotels
|
38
|
+
body.css("ServiceHotel").lazy.map do |hotel|
|
39
|
+
HotelBeds::Model::Hotel.new({
|
40
|
+
id: hotel.css("HotelInfo Code").first.content,
|
41
|
+
name: hotel.css("HotelInfo Name").first.content,
|
42
|
+
images: hotel.css("HotelInfo ImageList Image Url").map(&:content),
|
43
|
+
latitude: hotel.css("HotelInfo Position").first.attr("latitude"),
|
44
|
+
longitude: hotel.css("HotelInfo Position").first.attr("longitude"),
|
45
|
+
results: parse_available_rooms(hotel.css("AvailableRoom"))
|
46
|
+
})
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def parse_available_rooms(rooms)
|
53
|
+
Array(rooms).map do |room|
|
54
|
+
{
|
55
|
+
adult_count: room.css("HotelOccupancy AdultCount").first.content,
|
56
|
+
child_count: room.css("HotelOccupancy ChildCount").first.content,
|
57
|
+
rooms: parse_hotel_rooms(room.css("HotelRoom"))
|
58
|
+
}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def parse_hotel_rooms(rooms)
|
63
|
+
Array(rooms).map do |room|
|
64
|
+
{
|
65
|
+
number_available: room.attr("availCount"),
|
66
|
+
id: room.attr("SHRUI"),
|
67
|
+
description: room.css("RoomType").first.content,
|
68
|
+
board: room.css("Board").first.content,
|
69
|
+
price: room.css("Price Amount").first.content,
|
70
|
+
currency: body.css("Currency").first.attribute("code").value,
|
71
|
+
rates: parse_price_list(room.css("PriceList Price"))
|
72
|
+
}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def parse_price_list(prices)
|
77
|
+
Array(prices).inject({}) do |result, price|
|
78
|
+
from = Date.parse(price.css("DateTimeFrom").first.attr("date"))
|
79
|
+
to = Date.parse(price.css("DateTimeTo").first.attr("date"))
|
80
|
+
dates = (from..to).to_a
|
81
|
+
amount = BigDecimal.new(price.css("Amount").first.content) / dates.size
|
82
|
+
dates.each do |date|
|
83
|
+
result.merge!(date => amount)
|
84
|
+
end
|
85
|
+
result
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -1,12 +1,15 @@
|
|
1
|
-
require "hotel_beds/model
|
2
|
-
|
1
|
+
require "hotel_beds/model"
|
2
|
+
require_relative "hotel_room"
|
3
3
|
|
4
4
|
module HotelBeds
|
5
5
|
module Model
|
6
6
|
class AvailableRoom
|
7
|
+
include HotelBeds::Model
|
8
|
+
|
7
9
|
# attributes
|
8
|
-
include Virtus.model
|
9
10
|
attribute :rooms, Array[HotelRoom]
|
11
|
+
attribute :adult_count, Integer
|
12
|
+
attribute :child_count, Integer
|
10
13
|
end
|
11
14
|
end
|
12
15
|
end
|
@@ -1,11 +1,12 @@
|
|
1
|
-
require "hotel_beds/model
|
2
|
-
|
1
|
+
require "hotel_beds/model"
|
2
|
+
require_relative "available_room"
|
3
3
|
|
4
4
|
module HotelBeds
|
5
5
|
module Model
|
6
6
|
class Hotel
|
7
|
+
include HotelBeds::Model
|
8
|
+
|
7
9
|
# attributes
|
8
|
-
include Virtus.model
|
9
10
|
attribute :id, Integer
|
10
11
|
attribute :name, String
|
11
12
|
attribute :images, Array[String]
|
@@ -1,15 +1,18 @@
|
|
1
|
-
require "
|
1
|
+
require "hotel_beds/model"
|
2
2
|
|
3
3
|
module HotelBeds
|
4
4
|
module Model
|
5
5
|
class HotelRoom
|
6
|
+
include HotelBeds::Model
|
7
|
+
|
6
8
|
# attributes
|
7
|
-
include Virtus.model
|
8
9
|
attribute :id, Integer
|
9
10
|
attribute :description, String
|
10
11
|
attribute :board, String
|
11
12
|
attribute :price, BigDecimal
|
12
13
|
attribute :currency, String
|
14
|
+
attribute :number_available, Integer
|
15
|
+
attribute :rates, Hash[Date => BigDecimal]
|
13
16
|
end
|
14
17
|
end
|
15
18
|
end
|
data/lib/hotel_beds/version.rb
CHANGED
@@ -1,50 +1,69 @@
|
|
1
1
|
require "hotel_beds"
|
2
2
|
|
3
3
|
RSpec.describe "performing a hotel search" do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
})
|
22
|
-
end
|
23
|
-
|
24
|
-
let(:response) { client.perform(search) }
|
4
|
+
describe "#response" do
|
5
|
+
before(:all) do
|
6
|
+
@client = HotelBeds::Client.new({
|
7
|
+
endpoint: :test,
|
8
|
+
username: ENV.fetch("HOTEL_BEDS_USERNAME"),
|
9
|
+
password: ENV.fetch("HOTEL_BEDS_PASSWORD"),
|
10
|
+
proxy: ENV.fetch("HOTEL_BEDS_PROXY", nil)
|
11
|
+
})
|
12
|
+
@check_in_date = Date.today + 28 + rand(10)
|
13
|
+
@check_out_date = @check_in_date + rand(3) + 1
|
14
|
+
@response = @client.perform_hotel_search({
|
15
|
+
check_in_date: @check_in_date,
|
16
|
+
check_out_date: @check_out_date,
|
17
|
+
rooms: [{ adult_count: 2 }],
|
18
|
+
destination: "SYD"
|
19
|
+
}).response
|
20
|
+
end
|
25
21
|
|
26
|
-
|
27
|
-
|
22
|
+
let(:check_in_date) { @check_in_date }
|
23
|
+
let(:check_out_date) { @check_out_date }
|
24
|
+
let(:response) { @response }
|
28
25
|
|
29
|
-
|
30
|
-
|
31
|
-
|
26
|
+
describe "#errors" do
|
27
|
+
subject { response.errors }
|
28
|
+
|
29
|
+
it "should be empty" do
|
30
|
+
expect(subject).to be_empty
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#hotels" do
|
35
|
+
subject { response.hotels }
|
36
|
+
|
37
|
+
it "should return an array of the hotels available" do
|
38
|
+
expect(subject.to_a).to be_kind_of(Array)
|
39
|
+
expect(subject.first).to be_kind_of(HotelBeds::Model::Hotel)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should parse the rates correctly" do
|
43
|
+
room = subject.first.results.first.rooms.first
|
44
|
+
expect(room.price).to eq(room.rates.values.inject(:+))
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have the same number of rates as nights reuqested" do
|
48
|
+
room = subject.first.results.first.rooms.first
|
49
|
+
expect(room.rates.size).to eq(check_out_date - check_in_date)
|
50
|
+
end
|
32
51
|
end
|
33
|
-
end
|
34
52
|
|
35
|
-
|
36
|
-
|
53
|
+
describe "#current_page" do
|
54
|
+
subject { response.current_page }
|
37
55
|
|
38
|
-
|
39
|
-
|
56
|
+
it "should return '1'" do
|
57
|
+
expect(subject).to eq(1)
|
58
|
+
end
|
40
59
|
end
|
41
|
-
end
|
42
60
|
|
43
|
-
|
44
|
-
|
61
|
+
describe "#total_pages" do
|
62
|
+
subject { response.total_pages }
|
45
63
|
|
46
|
-
|
47
|
-
|
64
|
+
it "should be greater or equal to current page" do
|
65
|
+
expect(subject).to be >= response.current_page
|
66
|
+
end
|
48
67
|
end
|
49
68
|
end
|
50
69
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hotel_beds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Townsend
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-07-
|
11
|
+
date: 2014-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: savon
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.11.1
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: codeclimate-test-reporter
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
139
153
|
description:
|
140
154
|
email:
|
141
155
|
- ryan@ryantownsend.co.uk
|
@@ -158,23 +172,20 @@ files:
|
|
158
172
|
- lib/hotel_beds/client.rb
|
159
173
|
- lib/hotel_beds/configuration.rb
|
160
174
|
- lib/hotel_beds/connection.rb
|
175
|
+
- lib/hotel_beds/hotel_search/envelope.rb
|
176
|
+
- lib/hotel_beds/hotel_search/operation.rb
|
177
|
+
- lib/hotel_beds/hotel_search/request.rb
|
178
|
+
- lib/hotel_beds/hotel_search/response.rb
|
179
|
+
- lib/hotel_beds/model.rb
|
161
180
|
- lib/hotel_beds/model/available_room.rb
|
162
|
-
- lib/hotel_beds/model/base.rb
|
163
181
|
- lib/hotel_beds/model/hotel.rb
|
164
182
|
- lib/hotel_beds/model/hotel_room.rb
|
165
|
-
- lib/hotel_beds/model/search.rb
|
166
|
-
- lib/hotel_beds/model_invalid.rb
|
167
|
-
- lib/hotel_beds/operation/base.rb
|
168
|
-
- lib/hotel_beds/operation/search.rb
|
169
|
-
- lib/hotel_beds/response/base.rb
|
170
|
-
- lib/hotel_beds/response/search.rb
|
171
183
|
- lib/hotel_beds/version.rb
|
172
184
|
- spec/features/hotel_search_spec.rb
|
173
185
|
- spec/lib/hotel_beds/client_spec.rb
|
174
186
|
- spec/lib/hotel_beds/configuration_spec.rb
|
175
187
|
- spec/lib/hotel_beds/connection_spec.rb
|
176
|
-
- spec/lib/hotel_beds/
|
177
|
-
- spec/lib/hotel_beds/model_invalid_spec.rb
|
188
|
+
- spec/lib/hotel_beds/hotel_search/request_spec.rb
|
178
189
|
- spec/lib/hotel_beds/version_spec.rb
|
179
190
|
- spec/spec_helper.rb
|
180
191
|
homepage: https://www.hotelsindex.com/open-source
|
@@ -206,7 +217,6 @@ test_files:
|
|
206
217
|
- spec/lib/hotel_beds/client_spec.rb
|
207
218
|
- spec/lib/hotel_beds/configuration_spec.rb
|
208
219
|
- spec/lib/hotel_beds/connection_spec.rb
|
209
|
-
- spec/lib/hotel_beds/
|
210
|
-
- spec/lib/hotel_beds/model_invalid_spec.rb
|
220
|
+
- spec/lib/hotel_beds/hotel_search/request_spec.rb
|
211
221
|
- spec/lib/hotel_beds/version_spec.rb
|
212
222
|
- spec/spec_helper.rb
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require "hotel_beds/model_invalid"
|
2
|
-
require "securerandom"
|
3
|
-
require "virtus"
|
4
|
-
require "active_model"
|
5
|
-
|
6
|
-
module HotelBeds
|
7
|
-
module Model
|
8
|
-
class Base
|
9
|
-
# generator for random tokens
|
10
|
-
RANDOM_TOKEN = -> (model, attr) { SecureRandom.hex[0..15] }
|
11
|
-
|
12
|
-
# returns the operation for this model
|
13
|
-
def self.operation_class
|
14
|
-
HotelBeds::Operation.const_get(name.split("::").last)
|
15
|
-
end
|
16
|
-
|
17
|
-
# attributes
|
18
|
-
include Virtus.model
|
19
|
-
attribute :session_id, String, default: RANDOM_TOKEN, writer: :private
|
20
|
-
attribute :echo_token, String, default: RANDOM_TOKEN, writer: :private
|
21
|
-
|
22
|
-
# validation
|
23
|
-
include ActiveModel::Validations
|
24
|
-
validates :session_id, :echo_token, presence: true
|
25
|
-
|
26
|
-
def to_operation
|
27
|
-
if valid?
|
28
|
-
self.class.operation_class.new(self)
|
29
|
-
else
|
30
|
-
raise HotelsBeds::ModelInvalid.new(self)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require "delegate"
|
2
|
-
require "securerandom"
|
3
|
-
|
4
|
-
module HotelBeds
|
5
|
-
module Operation
|
6
|
-
class Base < SimpleDelegator
|
7
|
-
def method
|
8
|
-
raise NotImplementedError, "#method should return a symbol for the \
|
9
|
-
remote method to be called"
|
10
|
-
end
|
11
|
-
|
12
|
-
def namespace
|
13
|
-
raise NotImplementedError, "#namespace should return a symbol for the \
|
14
|
-
root element within the <message> element"
|
15
|
-
end
|
16
|
-
|
17
|
-
def message
|
18
|
-
raise NotImplementedError, "#message should return a hash containing \
|
19
|
-
the contents of the <message> element, the #namespace should be \
|
20
|
-
included as a key"
|
21
|
-
end
|
22
|
-
|
23
|
-
def parse_response(response)
|
24
|
-
raise NotImplementedError, "#parse_response should accept a SOAP \
|
25
|
-
response and return a HotelBeds::Response::Base subclass object"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
require "forwardable"
|
2
|
-
require "nokogiri"
|
3
|
-
|
4
|
-
module HotelBeds
|
5
|
-
module Response
|
6
|
-
class Base
|
7
|
-
# attributes
|
8
|
-
attr_accessor :response, :body, :headers
|
9
|
-
private :response, :response=, :body=, :headers=
|
10
|
-
|
11
|
-
# delegation
|
12
|
-
extend Forwardable
|
13
|
-
def_delegators :response, :success?, :soap_fault?, :http_error?
|
14
|
-
|
15
|
-
def initialize(response)
|
16
|
-
self.response = response
|
17
|
-
self.headers = response.header
|
18
|
-
self.body = Nokogiri::XML(response.body.fetch(:get_hotel_valued_avail))
|
19
|
-
freeze
|
20
|
-
end
|
21
|
-
|
22
|
-
def inspect
|
23
|
-
"<#{self.class.name} headers=#{headers.inspect} body=#{body.inspect}>"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require "hotel_beds/response/base"
|
2
|
-
require "hotel_beds/model/hotel"
|
3
|
-
require "hotel_beds/model/available_room"
|
4
|
-
require "hotel_beds/model/hotel_room"
|
5
|
-
|
6
|
-
module HotelBeds
|
7
|
-
module Response
|
8
|
-
class Search < Base
|
9
|
-
def current_page
|
10
|
-
Integer(body.css("PaginationData").attr("currentPage").value)
|
11
|
-
end
|
12
|
-
|
13
|
-
def total_pages
|
14
|
-
Integer(body.css("PaginationData").attr("totalPages").value)
|
15
|
-
end
|
16
|
-
|
17
|
-
def hotels
|
18
|
-
body.css("ServiceHotel").lazy.map do |hotel|
|
19
|
-
HotelBeds::Model::Hotel.new({
|
20
|
-
id: hotel.css("HotelInfo Code").first.content,
|
21
|
-
name: hotel.css("HotelInfo Name").first.content,
|
22
|
-
images: hotel.css("HotelInfo ImageList Image Url").map(&:content),
|
23
|
-
latitude: hotel.css("HotelInfo Position").attr("latitude").value,
|
24
|
-
longitude: hotel.css("HotelInfo Position").attr("longitude").value,
|
25
|
-
results: hotel.css("AvailableRoom").map { |result|
|
26
|
-
HotelBeds::Model::AvailableRoom.new({
|
27
|
-
rooms: result.css("HotelRoom").map { |room|
|
28
|
-
HotelBeds::Model::HotelRoom.new({
|
29
|
-
id: room.attribute("SHRUI").value,
|
30
|
-
description: room.css("RoomType").first.content,
|
31
|
-
board: room.css("Board").first.content,
|
32
|
-
price: room.css("Price Amount").first.content,
|
33
|
-
currency: body.css("Currency").first.attribute("code").value
|
34
|
-
})
|
35
|
-
}
|
36
|
-
})
|
37
|
-
}
|
38
|
-
})
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require "hotel_beds/model_invalid"
|
2
|
-
|
3
|
-
RSpec.describe HotelBeds::ModelInvalid do
|
4
|
-
let(:model) { Object.new }
|
5
|
-
let(:instance) { described_class.new(model) }
|
6
|
-
|
7
|
-
describe "an instance" do
|
8
|
-
subject { instance }
|
9
|
-
|
10
|
-
it "should be immutable" do
|
11
|
-
expect(subject).to be_frozen
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "#model" do
|
16
|
-
subject { instance.model }
|
17
|
-
|
18
|
-
it "should return the given model" do
|
19
|
-
expect(subject).to eq(model)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|