bookingsync-api 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Gemfile +2 -1
  4. data/Guardfile +3 -6
  5. data/README.md +11 -3
  6. data/bookingsync-api.gemspec +2 -2
  7. data/lib/bookingsync/api.rb +0 -2
  8. data/lib/bookingsync/api/client.rb +151 -54
  9. data/lib/bookingsync/api/client/amenities.rb +22 -0
  10. data/lib/bookingsync/api/client/billing_addresses.rb +22 -0
  11. data/lib/bookingsync/api/client/bookings.rb +7 -9
  12. data/lib/bookingsync/api/client/bookings_payments.rb +22 -0
  13. data/lib/bookingsync/api/client/clients.rb +43 -0
  14. data/lib/bookingsync/api/client/destinations.rb +22 -0
  15. data/lib/bookingsync/api/client/inquiries.rb +2 -2
  16. data/lib/bookingsync/api/client/payments.rb +53 -0
  17. data/lib/bookingsync/api/client/periods.rb +54 -0
  18. data/lib/bookingsync/api/client/photos.rb +22 -0
  19. data/lib/bookingsync/api/client/rates.rb +23 -0
  20. data/lib/bookingsync/api/client/rates_rules.rb +22 -0
  21. data/lib/bookingsync/api/client/rates_tables.rb +53 -0
  22. data/lib/bookingsync/api/client/rental_agreements.rb +50 -0
  23. data/lib/bookingsync/api/client/rentals.rb +39 -1
  24. data/lib/bookingsync/api/client/reviews.rb +31 -0
  25. data/lib/bookingsync/api/client/seasons.rb +53 -0
  26. data/lib/bookingsync/api/client/special_offers.rb +54 -0
  27. data/lib/bookingsync/api/relation.rb +87 -0
  28. data/lib/bookingsync/api/resource.rb +58 -0
  29. data/lib/bookingsync/api/response.rb +79 -0
  30. data/lib/bookingsync/api/serializer.rb +100 -0
  31. data/lib/bookingsync/api/version.rb +1 -1
  32. data/spec/bookingsync/api/client/amenities_spec.rb +12 -0
  33. data/spec/bookingsync/api/client/billing_addresses_spec.rb +12 -0
  34. data/spec/bookingsync/api/client/billings_payments_spec.rb +12 -0
  35. data/spec/bookingsync/api/client/bookings_spec.rb +10 -8
  36. data/spec/bookingsync/api/client/clients_spec.rb +55 -0
  37. data/spec/bookingsync/api/client/destinations_spec.rb +12 -0
  38. data/spec/bookingsync/api/client/inquiries_spec.rb +1 -1
  39. data/spec/bookingsync/api/client/payments_spec.rb +56 -0
  40. data/spec/bookingsync/api/client/periods_spec.rb +61 -0
  41. data/spec/bookingsync/api/client/photos_spec.rb +12 -0
  42. data/spec/bookingsync/api/client/rates_rules_spec.rb +13 -0
  43. data/spec/bookingsync/api/client/rates_spec.rb +12 -0
  44. data/spec/bookingsync/api/client/rates_tables_spec.rb +59 -0
  45. data/spec/bookingsync/api/client/rental_agreements_spec.rb +64 -0
  46. data/spec/bookingsync/api/client/rentals_spec.rb +56 -6
  47. data/spec/bookingsync/api/client/reviews_spec.rb +33 -0
  48. data/spec/bookingsync/api/client/seasons_spec.rb +61 -0
  49. data/spec/bookingsync/api/client/special_offers_spec.rb +63 -0
  50. data/spec/bookingsync/api/client_spec.rb +31 -10
  51. data/spec/bookingsync/api/relation_spec.rb +72 -0
  52. data/spec/bookingsync/api/resource_spec.rb +79 -0
  53. data/spec/bookingsync/api/response_spec.rb +66 -0
  54. data/spec/cassettes/BookingSync_API_Client_Amenities/_amenities/returns_amenities.yml +72 -0
  55. data/spec/cassettes/BookingSync_API_Client_BillingAddresses/_billing_addresses/returns_billing_addresses.yml +65 -0
  56. data/spec/cassettes/BookingSync_API_Client_Bookings/_bookings/pagination/with_a_block/yields_block_with_batch_of_bookings.yml +12 -12
  57. data/spec/cassettes/BookingSync_API_Client_Bookings/_bookings/pagination/with_auto_paginate_true/returns_all_bookings_joined_from_many_requests.yml +12 -12
  58. data/spec/cassettes/BookingSync_API_Client_Bookings/_bookings/pagination/with_per_page_setting/returns_limited_number_of_bookings.yml +3 -3
  59. data/spec/cassettes/BookingSync_API_Client_Bookings/_clients/returns_clients.yml +66 -0
  60. data/spec/cassettes/BookingSync_API_Client_Bookings/_create_booking/creates_a_booking.yml +1 -1
  61. data/spec/cassettes/BookingSync_API_Client_Bookings/_create_client/creates_a_new_client.yml +64 -0
  62. data/spec/cassettes/BookingSync_API_Client_Bookings/_edit_booking/updates_given_booking_by_ID.yml +18 -14
  63. data/spec/cassettes/BookingSync_API_Client_Bookings/_edit_client/updates_given_client_by_ID.yml +62 -0
  64. data/spec/cassettes/BookingSync_API_Client_BookingsPayments/_bookings_payments/returns_bookings_payments.yml +65 -0
  65. data/spec/cassettes/BookingSync_API_Client_Destinations/_destinations/returns_destinations.yml +64 -0
  66. data/spec/cassettes/BookingSync_API_Client_Inquiries/_create_inquiry/creates_a_new_inquiry.yml +1 -1
  67. data/spec/cassettes/BookingSync_API_Client_Inquiries/_inquiries/returns_inquiries.yml +1 -1
  68. data/spec/cassettes/BookingSync_API_Client_Payments/_cancel_payment/cancels_given_payment.yml +57 -0
  69. data/spec/cassettes/BookingSync_API_Client_Payments/_create_payment/creates_a_new_payment.yml +63 -0
  70. data/spec/cassettes/BookingSync_API_Client_Payments/_edit_payment/updates_given_payment_by_ID.yml +61 -0
  71. data/spec/cassettes/BookingSync_API_Client_Payments/_payments/returns_payments.yml +64 -0
  72. data/spec/cassettes/BookingSync_API_Client_Periods/_create_period/creates_a_new_period.yml +63 -0
  73. data/spec/cassettes/BookingSync_API_Client_Periods/_delete_period/deletes_given_period.yml +70 -0
  74. data/spec/cassettes/BookingSync_API_Client_Periods/_edit_period/updates_given_period_by_ID.yml +61 -0
  75. data/spec/cassettes/BookingSync_API_Client_Periods/_periods/returns_periods.yml +64 -0
  76. data/spec/cassettes/BookingSync_API_Client_Photos/_photos/returns_photos.yml +72 -0
  77. data/spec/cassettes/BookingSync_API_Client_Rates/_rates/returns_rates.yml +64 -0
  78. data/spec/cassettes/BookingSync_API_Client_RatesRules/_rates_rules/returns_rates_rules.yml +64 -0
  79. data/spec/cassettes/BookingSync_API_Client_RatesTables/_create_rates_table/creates_a_new_rates_table.yml +64 -0
  80. data/spec/cassettes/BookingSync_API_Client_RatesTables/_delete_rates_table/deletes_given_rates_table.yml +57 -0
  81. data/spec/cassettes/BookingSync_API_Client_RatesTables/_edit_rates_table/updates_given_rates_table_by_ID.yml +62 -0
  82. data/spec/cassettes/BookingSync_API_Client_RatesTables/_rates_tables/returns_rates_tables.yml +74 -0
  83. data/spec/cassettes/BookingSync_API_Client_RentalAgreements/_create_rental_agreement/creates_a_new_rental_agreement.yml +63 -0
  84. data/spec/cassettes/BookingSync_API_Client_RentalAgreements/_create_rental_agreement_for_booking/creates_a_new_rental_agreement.yml +63 -0
  85. data/spec/cassettes/BookingSync_API_Client_RentalAgreements/_create_rental_agreement_for_rental/creates_a_new_rental_agreement.yml +63 -0
  86. data/spec/cassettes/BookingSync_API_Client_RentalAgreements/_rental_agreements/returns_rental_agreements.yml +64 -0
  87. data/spec/cassettes/BookingSync_API_Client_Rentals/_cancel_rental/cancels_given_rental.yml +57 -0
  88. data/spec/cassettes/BookingSync_API_Client_Rentals/_create_rental/creates_a_new_rental.yml +64 -0
  89. data/spec/cassettes/BookingSync_API_Client_Rentals/_edit_rental/updates_given_rental_by_ID.yml +64 -0
  90. data/spec/cassettes/BookingSync_API_Client_Rentals/_rental/returns_a_single_rental.yml +67 -0
  91. data/spec/cassettes/BookingSync_API_Client_Rentals/_rentals/links/returns_associated_photos.yml +152 -0
  92. data/spec/cassettes/BookingSync_API_Client_Rentals/_rentals/links/returns_links_to_associated_resources.yml +91 -0
  93. data/spec/cassettes/BookingSync_API_Client_Rentals/_rentals/returns_rentals.yml +45 -20
  94. data/spec/cassettes/BookingSync_API_Client_Reviews/_create_review/creates_a_new_review.yml +64 -0
  95. data/spec/cassettes/BookingSync_API_Client_Reviews/_reviews/returns_reviews.yml +83 -0
  96. data/spec/cassettes/BookingSync_API_Client_Seasons/_create_season/creates_a_new_season.yml +64 -0
  97. data/spec/cassettes/BookingSync_API_Client_Seasons/_delete_season/deletes_given_season.yml +57 -0
  98. data/spec/cassettes/BookingSync_API_Client_Seasons/_edit_season/updates_given_season_by_ID.yml +62 -0
  99. data/spec/cassettes/BookingSync_API_Client_Seasons/_seasons/returns_seasons.yml +74 -0
  100. data/spec/cassettes/BookingSync_API_Client_SpecialOffers/_create_special_offer/creates_a_new_special_offer.yml +63 -0
  101. data/spec/cassettes/BookingSync_API_Client_SpecialOffers/_delete_special_offer/deletes_given_special_offer.yml +57 -0
  102. data/spec/cassettes/BookingSync_API_Client_SpecialOffers/_edit_special_offer/updates_given_special_offer_by_ID.yml +61 -0
  103. data/spec/cassettes/{BookingSync_API_Client_Rentals/_rentals/with_specified_fields_in_options/returns_rentals_with_filtered_fields.yml → BookingSync_API_Client_SpecialOffers/_special_offers/returns_special_offers.yml} +17 -10
  104. data/spec/spec_helper.rb +1 -0
  105. metadata +143 -7
  106. data/lib/bookingsync/ext/resource.rb +0 -9
@@ -6,7 +6,7 @@ module BookingSync::API
6
6
  # Returns rentals for the account user is authenticated with.
7
7
  # @param options [Hash] A customizable set of options.
8
8
  # @option options [Array] fields: List of fields to be fetched.
9
- # @return [Array<Sawyer::Resource>] Array of rentals.
9
+ # @return [Array<BookingSync::API::Resource>] Array of rentals.
10
10
  #
11
11
  # @example Get the list of rentals for the current account
12
12
  # rentals = @api.rentals
@@ -17,6 +17,44 @@ module BookingSync::API
17
17
  def rentals(options = {}, &block)
18
18
  paginate :rentals, options, &block
19
19
  end
20
+
21
+ # Create a new rental
22
+ #
23
+ # @param options [Hash] rental attributes
24
+ # @return [BookingSync::API::Resource] Newly created rental
25
+ def create_rental(options = {})
26
+ post(:rentals, rentals: [options]).pop
27
+ end
28
+
29
+ # Edit a rental
30
+ #
31
+ # @param rental [BookingSync::API::Resource|Integer] rental or ID of the rental
32
+ # to be updated
33
+ # @param options [Hash] rental attributes to be updated
34
+ # @return [BookingSync::API::Resource] Updated rental on success, exception is raised otherwise
35
+ # @example
36
+ # rental = @api.rentals.first
37
+ # @api.edit_rental(rental, { sleeps: 3 })
38
+ def edit_rental(rental, options = {})
39
+ put("rentals/#{rental}", rentals: [options]).pop
40
+ end
41
+
42
+ # Cancel a rental
43
+ #
44
+ # @param rental [BookingSync::API::Resource|Integer] rental or ID of the rental
45
+ # to be canceled
46
+ # @return [Array] An empty Array on success, exception is raised otherwise
47
+ def cancel_rental(rental, options = {})
48
+ delete "rentals/#{rental}"
49
+ end
50
+
51
+ # Get a single rental
52
+ #
53
+ # @param rental [BookingSync::API::Resource|Integer] Rental or ID of the rental
54
+ # @return [BookingSync::API::Resource]
55
+ def rental(rental)
56
+ get("rentals/#{rental}").pop
57
+ end
20
58
  end
21
59
  end
22
60
  end
@@ -0,0 +1,31 @@
1
+ module BookingSync::API
2
+ class Client
3
+ module Reviews
4
+ # List reviews
5
+ #
6
+ # Returns reviews for the account user is authenticated with.
7
+ # @param options [Hash] A customizable set of options.
8
+ # @option options [Array] fields: List of fields to be fetched.
9
+ # @return [Array<BookingSync::API::Resource>] Array of reviews.
10
+ #
11
+ # @example Get the list of reviews for the current account
12
+ # reviews = @api.reviews
13
+ # reviews.first.name # => "John Smith"
14
+ # @example Get the list of reviews only with name and comment for smaller response
15
+ # @api.reviews(fields: [:name, :comment])
16
+ # @see http://docs.api.bookingsync.com/reference/endpoints/reviews/#list-reviews
17
+ def reviews(options = {}, &block)
18
+ paginate :reviews, options, &block
19
+ end
20
+
21
+ # Create a new review
22
+ #
23
+ # @param booking_id [Integer] ID of the booking
24
+ # @param options [Hash] review attributes
25
+ # @return [BookingSync::API::Resource] Newly created review
26
+ def create_review(booking_id, options = {})
27
+ post(:reviews, booking_id: booking_id, reviews: [options]).pop
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,53 @@
1
+ module BookingSync::API
2
+ class Client
3
+ module Seasons
4
+ # List seasons
5
+ #
6
+ # Returns seasons for the account user is authenticated with.
7
+ # @param options [Hash] A customizable set of options.
8
+ # @option options [Array] fields: List of fields to be fetched.
9
+ # @return [Array<BookingSync::API::Resource>] Array of seasons.
10
+ #
11
+ # @example Get the list of seasons for the current account
12
+ # seasons = @api.seasons
13
+ # seasons.first.name # => "Season 2"
14
+ # @example Get the list of seasons only with name and ratio for smaller response
15
+ # @api.seasons(fields: [:name, :ratio])
16
+ # @see http://docs.api.bookingsync.com/reference/endpoints/seasons/#list-seasons
17
+ def seasons(options = {}, &block)
18
+ paginate :seasons, options, &block
19
+ end
20
+
21
+ # Create a new season
22
+ #
23
+ # @param rates_table_id [Integer] ID of the rates table
24
+ # @param options [Hash] season attributes
25
+ # @return [BookingSync::API::Resource] Newly created season
26
+ def create_season(rates_table_id, options = {})
27
+ post(:seasons, rates_table_id: rates_table_id, seasons: [options]).pop
28
+ end
29
+
30
+ # Edit a season
31
+ #
32
+ # @param season [BookingSync::API::Resource|Integer] season or ID of the season
33
+ # to be updated
34
+ # @param options [Hash] season attributes to be updated
35
+ # @return [BookingSync::API::Resource] Updated season on success, exception is raised otherwise
36
+ # @example
37
+ # season = @api.seasons.first
38
+ # @api.edit_season(season, { name: "Some season" })
39
+ def edit_season(season, options = {})
40
+ put("seasons/#{season}", seasons: [options]).pop
41
+ end
42
+
43
+ # Delete a season
44
+ #
45
+ # @param season [BookingSync::API::Resource|Integer] season or ID of the season
46
+ # to be deleted
47
+ # @return [Array] An empty Array on success, exception is raised otherwise
48
+ def delete_season(season, options = {})
49
+ delete "seasons/#{season}"
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,54 @@
1
+ module BookingSync::API
2
+ class Client
3
+ module SpecialOffers
4
+ # List special_offers
5
+ #
6
+ # Returns special_offers for the account user is authenticated with.
7
+ # @param options [Hash] A customizable set of options.
8
+ # @option options [Array] fields: List of fields to be fetched.
9
+ # @return [Array<BookingSync::API::Resource>] Array of special_offers.
10
+ #
11
+ # @example Get the list of special_offers for the current account
12
+ # special_offers = @api.special_offers
13
+ # special_offers.first.name # => "Spring discount"
14
+ # @example Get the list of special_offers only with name and rental_id for smaller response
15
+ # @api.special_offers(fields: [:name, :rental_id])
16
+ # @see http://docs.api.bookingsync.com/reference/endpoints/special_offers/#list-special_offers
17
+ def special_offers(options = {}, &block)
18
+ paginate :special_offers, options, &block
19
+ end
20
+
21
+ # Create a new special_offer
22
+ #
23
+ # @param rental_id [Integer] ID of the rental
24
+ # @param options [Hash] special_offer attributes
25
+ # @return [BookingSync::API::Resource] Newly created special offer
26
+ def create_special_offer(rental_id, options = {})
27
+ post(:special_offers, rental_id: rental_id, special_offers: [options]).pop
28
+ end
29
+
30
+ # Edit a special_offer
31
+ #
32
+ # @param special_offer [BookingSync::API::Resource|Integer] special offer or
33
+ # ID of the special offer to be updated
34
+ # @param options [Hash] special offer attributes to be updated
35
+ # @return [BookingSync::API::Resource] Updated special offer on success,
36
+ # exception is raised otherwise
37
+ # @example
38
+ # special_offer = @api.special_offers.first
39
+ # @api.edit_special_offer(special_offer, { name: "New offer" })
40
+ def edit_special_offer(special_offer, options = {})
41
+ put("special_offers/#{special_offer}", special_offers: [options]).pop
42
+ end
43
+
44
+ # Delete a special_offer
45
+ #
46
+ # @param special_offer [BookingSync::API::Resource|Integer] special offer or
47
+ # ID of the special offer to be deleted
48
+ # @return [Array] An empty Array on success, exception is raised otherwise
49
+ def delete_special_offer(special_offer, options = {})
50
+ delete "special_offers/#{special_offer}"
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,87 @@
1
+ module BookingSync::API
2
+ class Relation
3
+ attr_reader :client, :name, :href_template, :method
4
+
5
+ # Build a hash of Relations from the `links` key in JSON API response.
6
+ #
7
+ # @param client [BookingSync::API::Client] The client that made the HTTP
8
+ # request.
9
+ # @param links [Hash] Hash of relation_name => relation options.
10
+ # @return [Hash] Hash of relation_name => relation elements.
11
+ def self.from_links(client, links)
12
+ relations = {}
13
+ links.each do |name, options|
14
+ relations[name] = from_link(client, name, options)
15
+ end if links
16
+ relations
17
+ end
18
+
19
+ # Build a single Relation from the given options.
20
+ #
21
+ # @param client [BookingSync::API::Client] The client that made the HTTP
22
+ # request
23
+ #
24
+ # @param name [Symbol] Name of the Relation.
25
+ # @param options [Hash] A Hash containing the other Relation properties.
26
+ # @option options [String] href: The String URL of the next action's location.
27
+ # @option options [String] method: The optional String HTTP method.
28
+ # @return [BookingSync::API::Relation] New relation
29
+ def self.from_link(client, name, options)
30
+ case options
31
+ when Hash
32
+ new client, name, options[:href], options[:method]
33
+ when String
34
+ new client, name, options
35
+ end
36
+ end
37
+
38
+ # A Relation represents an available next action for a resource.
39
+ #
40
+ # @param client [BookingSync::API::Client] The client that made the HTTP
41
+ # request.
42
+ # @param name [Symbol] The name of the relation.
43
+ # @param href [String] The String URL of the location of the next action.
44
+ # @param method [Symbol] The Symbol HTTP method. Default: :get
45
+ def initialize(client, name, href, method = nil)
46
+ @client = client
47
+ @name = name.to_sym
48
+ @href = href
49
+ @href_template = Addressable::Template.new(href.to_s)
50
+ @method = (method || :get).to_sym
51
+ @available_methods = Set.new methods || [@method]
52
+ end
53
+
54
+ # Make an API request with the curent Relation using GET.
55
+ #
56
+ # @param options [Hash] Options to configure the API request.
57
+ # @option options [Hash] headers: Hash of API headers to set.
58
+ # @option options [Hash] query: Hash of URL query params to set.
59
+ # @option options [Symbol] method: Symbol HTTP method.
60
+ # @return [BookingSync::API::Response] A response
61
+ def get(options = nil)
62
+ options ||= {}
63
+ options[:method] = :get
64
+ call options
65
+ end
66
+
67
+ def href(options = nil)
68
+ return @href if @href_template.nil?
69
+ @href_template.expand(options || {}).to_s
70
+ end
71
+
72
+ # Make an API request with the curent Relation.
73
+ #
74
+ # @param data [Hash|String] The Optional Hash or Resource body to be sent.
75
+ # :get or :head requests can have no body, so this can be the options Hash
76
+ # instead.
77
+ # @param options [Hash] A Hash of option to configure the API request.
78
+ # @option options [Hash] headers: A Hash of API headers to set.
79
+ # @option options [Hash] query: Hash of URL query params to set.
80
+ # @option options [Symbol] method: Symbol HTTP method.
81
+ # @return [BookingSync::API::Response]
82
+ def call(data = nil, options = nil)
83
+ m = options && options[:method]
84
+ @client.call m || @method, @href_template, data, options || {}
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,58 @@
1
+ require "hashie"
2
+
3
+ module BookingSync::API
4
+ class Resource < Hash
5
+ include Hashie::Extensions::MethodAccess
6
+ attr_reader :_client, :_rels, :_links, :_resources_key
7
+
8
+ # Initialize a Resource with the given links and data.
9
+ #
10
+ # @param client [BookingSync::API::Client] The client that made the API request.
11
+ # @param data [Hash] Hash of key/value properties.
12
+ # @param links [Hash] Hash of link templates for this resource.
13
+ # @param resources_key [Symbol|String] Key in response body under which
14
+ def initialize(client, data = {}, links = {}, resources_key = nil)
15
+ @_links = links
16
+ @_client = client
17
+ @_resources_key = resources_key
18
+ data.each do |key, value|
19
+ self[key.to_sym] = process_value(value)
20
+ end
21
+ @_rels = Relation.from_links(client, links)
22
+ end
23
+
24
+ # Process an individual value of this resource. Hashes get exploded
25
+ # into another Resource, and Arrays get their values processed too.
26
+ #
27
+ # @param value [Object] An Object value of a Resource's data.
28
+ # @return [Object] An Object to set as the value of a Resource key.
29
+ def process_value(value)
30
+ case value
31
+ when Hash then self.class.new(@_client, value, @_links)
32
+ when Array then value.map { |v| process_value(v) }
33
+ else value
34
+ end
35
+ end
36
+
37
+ # Make associations accessible
38
+ #
39
+ # @param method [Symbol] Name of association
40
+ # @param args [Array] Array of additional arguments
41
+ def method_missing(method, *args)
42
+ association_key = :"#{@_resources_key}.#{method}"
43
+ if self[:links] && self[:links].has_key?(method)
44
+ ids = self[:links][method]
45
+ return [] if !ids or ids.empty?
46
+ options = {uri: {association_key => ids}}
47
+ options.merge!(query: args.first) if args.first.is_a?(Hash)
48
+ @_rels[association_key].get(options).resources
49
+ else
50
+ super
51
+ end
52
+ end
53
+
54
+ def to_s
55
+ id.to_s
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,79 @@
1
+ require "addressable/template"
2
+
3
+ module BookingSync::API
4
+ class Response
5
+ SPECIAL_JSONAPI_FIELDS = %w(links linked meta)
6
+ attr_reader :client, :status, :headers, :data, :rels, :body
7
+
8
+ # Build a Response after a completed request.
9
+ #
10
+ # @param client [BookingSync::API::Client] The client that is
11
+ # managing the API connection.
12
+ # @param res [Faraday::Response] Faraday response object
13
+ def initialize(client, res)
14
+ @client = client
15
+ @status = res.status
16
+ @headers = res.headers
17
+ @env = res.env
18
+ @body = res.body
19
+ end
20
+
21
+ # Turn parsed contents from an API response into a Resource or
22
+ # collection of Resources.
23
+ #
24
+ # @param hash [Hash] A Hash of resources parsed from JSON.
25
+ # @return [Array] An Array of Resources.
26
+ def process_data(hash, links)
27
+ Array(hash).map do |hash|
28
+ Resource.new(client, hash, links, resources_key)
29
+ end
30
+ end
31
+
32
+ # Return name of the key in the response body hash
33
+ # where fetched resources are, like bookings or rentals
34
+ #
35
+ # @return [Symbol] Key name in the body hash
36
+ def resources_key
37
+ decoded_body.keys.delete_if { |k|
38
+ SPECIAL_JSONAPI_FIELDS.include?(k)
39
+ }.pop
40
+ end
41
+
42
+ # Return an array of Resources from the response body
43
+ #
44
+ # @return [Array<BookingSync::API::Resource>]
45
+ def resources
46
+ @resources ||= process_data(decoded_body[resources_key], links)
47
+ end
48
+
49
+ # Return an array of links templates from the response body,
50
+ # it's the contents of links hash
51
+ # {'links': {'rentals.photos':'https://www.bookingsync.com/api/v3/photos/{rentals.photos}'}}
52
+ #
53
+ # @return [Hash] Hash of links to associated resources
54
+ def links
55
+ @links ||= decoded_body[:links]
56
+ end
57
+
58
+ # Return link relations from 'Link' response header
59
+ #
60
+ # @return [Array] An array of Relations
61
+ def rels
62
+ @rels ||= process_rels
63
+ end
64
+
65
+ private
66
+
67
+ def decoded_body
68
+ @decoded_body ||= @client.decode_body(body) || {}
69
+ end
70
+
71
+ def process_rels
72
+ links = ( @headers["Link"] || "" ).split(', ').map do |link|
73
+ href, name = link.match(/<(.*?)>; rel="(\w+)"/).captures
74
+ [name.to_sym, Relation.from_link(@client, name, :href => href)]
75
+ end
76
+ Hash[*links.flatten]
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,100 @@
1
+ require 'date'
2
+ require 'time'
3
+ require 'json'
4
+
5
+ module BookingSync::API
6
+ class Serializer
7
+ # Public: Wraps a serialization format for Sawyer. Nested objects are
8
+ # prepared for serialization (such as changing Times to ISO 8601 Strings).
9
+ # Any serialization format that responds to #dump and #load will work.
10
+ def initialize(dump_method_name = nil, load_method_name = nil)
11
+ @format = JSON
12
+ @dump = @format.method(dump_method_name || :dump)
13
+ @load = @format.method(load_method_name || :load)
14
+ end
15
+
16
+ # Public: Encodes an Object (usually a Hash or Array of Hashes).
17
+ #
18
+ # data - Object to be encoded.
19
+ #
20
+ # Returns an encoded String.
21
+ def encode(data)
22
+ @dump.call(encode_object(data))
23
+ end
24
+
25
+ alias dump encode
26
+
27
+ # Public: Decodes a String into an Object (usually a Hash or Array of
28
+ # Hashes).
29
+ #
30
+ # data - An encoded String.
31
+ #
32
+ # Returns a decoded Object.
33
+ def decode(data)
34
+ return nil if data.nil? || data.empty?
35
+ decode_object(@load.call(data))
36
+ end
37
+
38
+ alias load decode
39
+
40
+ def encode_object(data)
41
+ case data
42
+ when Hash then encode_hash(data)
43
+ when Array then data.map { |o| encode_object(o) }
44
+ else data
45
+ end
46
+ end
47
+
48
+ def encode_hash(hash)
49
+ hash.keys.each do |key|
50
+ case value = hash[key]
51
+ when Date then hash[key] = value.to_time.utc.xmlschema
52
+ when Time then hash[key] = value.utc.xmlschema
53
+ when Hash then hash[key] = encode_hash(value)
54
+ end
55
+ end
56
+ hash
57
+ end
58
+
59
+ def decode_object(data)
60
+ case data
61
+ when Hash then decode_hash(data)
62
+ when Array then data.map { |o| decode_object(o) }
63
+ else data
64
+ end
65
+ end
66
+
67
+ def decode_hash(hash)
68
+ hash.keys.each do |key|
69
+ hash[key.to_sym] = decode_hash_value(key, hash.delete(key))
70
+ end
71
+ hash
72
+ end
73
+
74
+ def decode_hash_value(key, value)
75
+ if time_field?(key, value)
76
+ if value.is_a?(String)
77
+ begin
78
+ Time.parse(value)
79
+ rescue ArgumentError
80
+ value
81
+ end
82
+ elsif value.is_a?(Integer) || value.is_a?(Float)
83
+ Time.at(value)
84
+ else
85
+ value
86
+ end
87
+ elsif value.is_a?(Hash)
88
+ decode_hash(value)
89
+ elsif value.is_a?(Array)
90
+ value.map { |o| decode_hash_value(key, o) }
91
+ else
92
+ value
93
+ end
94
+ end
95
+
96
+ def time_field?(key, value)
97
+ value && (key =~ /_(at|on)\z/ || key =~ /(\A|_)date\z/)
98
+ end
99
+ end
100
+ end