bookingsync-api 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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