gocardless-pro 0.1.0

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 (91) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +2 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +132 -0
  6. data/circle.yml +18 -0
  7. data/demo.rb +10 -0
  8. data/gocardless-pro.gemspec +27 -0
  9. data/lib/gocardless-pro.rb +243 -0
  10. data/lib/gocardless-pro/api_service.rb +57 -0
  11. data/lib/gocardless-pro/error.rb +42 -0
  12. data/lib/gocardless-pro/error/gocardless_error.rb +5 -0
  13. data/lib/gocardless-pro/error/invalid_api_usage_error.rb +5 -0
  14. data/lib/gocardless-pro/error/invalid_state_error.rb +5 -0
  15. data/lib/gocardless-pro/error/validation_error.rb +5 -0
  16. data/lib/gocardless-pro/list_response.rb +34 -0
  17. data/lib/gocardless-pro/paginator.rb +37 -0
  18. data/lib/gocardless-pro/request.rb +69 -0
  19. data/lib/gocardless-pro/resources/api_key.rb +62 -0
  20. data/lib/gocardless-pro/resources/creditor.rb +83 -0
  21. data/lib/gocardless-pro/resources/creditor_bank_account.rb +78 -0
  22. data/lib/gocardless-pro/resources/customer.rb +72 -0
  23. data/lib/gocardless-pro/resources/customer_bank_account.rb +80 -0
  24. data/lib/gocardless-pro/resources/event.rb +75 -0
  25. data/lib/gocardless-pro/resources/helper.rb +29 -0
  26. data/lib/gocardless-pro/resources/mandate.rb +70 -0
  27. data/lib/gocardless-pro/resources/payment.rb +86 -0
  28. data/lib/gocardless-pro/resources/payout.rb +66 -0
  29. data/lib/gocardless-pro/resources/publishable_api_key.rb +51 -0
  30. data/lib/gocardless-pro/resources/redirect_flow.rb +104 -0
  31. data/lib/gocardless-pro/resources/refund.rb +70 -0
  32. data/lib/gocardless-pro/resources/role.rb +101 -0
  33. data/lib/gocardless-pro/resources/subscription.rb +152 -0
  34. data/lib/gocardless-pro/resources/user.rb +60 -0
  35. data/lib/gocardless-pro/response.rb +77 -0
  36. data/lib/gocardless-pro/services/api_key_service.rb +130 -0
  37. data/lib/gocardless-pro/services/base_service.rb +29 -0
  38. data/lib/gocardless-pro/services/creditor_bank_account_service.rb +122 -0
  39. data/lib/gocardless-pro/services/creditor_service.rb +112 -0
  40. data/lib/gocardless-pro/services/customer_bank_account_service.rb +153 -0
  41. data/lib/gocardless-pro/services/customer_service.rb +112 -0
  42. data/lib/gocardless-pro/services/event_service.rb +80 -0
  43. data/lib/gocardless-pro/services/helper_service.rb +97 -0
  44. data/lib/gocardless-pro/services/mandate_service.rb +170 -0
  45. data/lib/gocardless-pro/services/payment_service.rb +164 -0
  46. data/lib/gocardless-pro/services/payout_service.rb +80 -0
  47. data/lib/gocardless-pro/services/publishable_api_key_service.rb +130 -0
  48. data/lib/gocardless-pro/services/redirect_flow_service.rb +96 -0
  49. data/lib/gocardless-pro/services/refund_service.rb +126 -0
  50. data/lib/gocardless-pro/services/role_service.rb +127 -0
  51. data/lib/gocardless-pro/services/subscription_service.rb +133 -0
  52. data/lib/gocardless-pro/services/user_service.rb +148 -0
  53. data/lib/gocardless-pro/version.rb +8 -0
  54. data/spec/api_service_spec.rb +69 -0
  55. data/spec/client_spec.rb +29 -0
  56. data/spec/error_spec.rb +44 -0
  57. data/spec/resources/api_key_spec.rb +85 -0
  58. data/spec/resources/creditor_bank_account_spec.rb +109 -0
  59. data/spec/resources/creditor_spec.rb +125 -0
  60. data/spec/resources/customer_bank_account_spec.rb +109 -0
  61. data/spec/resources/customer_spec.rb +127 -0
  62. data/spec/resources/event_spec.rb +113 -0
  63. data/spec/resources/helper_spec.rb +23 -0
  64. data/spec/resources/mandate_spec.rb +97 -0
  65. data/spec/resources/payment_spec.rb +129 -0
  66. data/spec/resources/payout_spec.rb +89 -0
  67. data/spec/resources/publishable_api_key_spec.rb +63 -0
  68. data/spec/resources/redirect_flow_spec.rb +97 -0
  69. data/spec/resources/refund_spec.rb +77 -0
  70. data/spec/resources/role_spec.rb +63 -0
  71. data/spec/resources/subscription_spec.rb +157 -0
  72. data/spec/resources/user_spec.rb +85 -0
  73. data/spec/response_spec.rb +79 -0
  74. data/spec/services/api_key_service_spec.rb +362 -0
  75. data/spec/services/creditor_bank_account_service_spec.rb +365 -0
  76. data/spec/services/creditor_service_spec.rb +339 -0
  77. data/spec/services/customer_bank_account_service_spec.rb +404 -0
  78. data/spec/services/customer_service_spec.rb +365 -0
  79. data/spec/services/event_service_spec.rb +172 -0
  80. data/spec/services/helper_service_spec.rb +123 -0
  81. data/spec/services/mandate_service_spec.rb +449 -0
  82. data/spec/services/payment_service_spec.rb +497 -0
  83. data/spec/services/payout_service_spec.rb +172 -0
  84. data/spec/services/publishable_api_key_service_spec.rb +336 -0
  85. data/spec/services/redirect_flow_service_spec.rb +208 -0
  86. data/spec/services/refund_service_spec.rb +279 -0
  87. data/spec/services/role_service_spec.rb +336 -0
  88. data/spec/services/subscription_service_spec.rb +488 -0
  89. data/spec/services/user_service_spec.rb +433 -0
  90. data/spec/spec_helper.rb +91 -0
  91. metadata +255 -0
@@ -0,0 +1,164 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # WARNING: Do not edit by hand, this file was generated by Crank:
6
+ #
7
+ # https://github.com/gocardless/crank
8
+
9
+ module GoCardless
10
+ module Services
11
+ # Service for making requests to the Payment endpoints
12
+ class PaymentService < BaseService
13
+ # <a name="mandate_is_inactive"></a>Creates a new payment object.
14
+ #
15
+ # This
16
+ # fails with a `mandate_is_inactive` error if the linked
17
+ # [mandate](https://developer.gocardless.com/pro/#api-endpoints-mandates) is
18
+ # cancelled. Payments can be created against `pending_submission` mandates, but
19
+ # they will not be submitted until the mandate becomes active.
20
+ # Example URL: /payments
21
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
22
+ # Else, they will be the body of the request.
23
+ def create(options = {}, custom_headers = {})
24
+ path = '/payments'
25
+ new_options = {}
26
+ new_options[envelope_key] = options
27
+ options = new_options
28
+ response = make_request(:post, path, options, custom_headers)
29
+
30
+ Resources::Payment.new(unenvelope_body(response.body))
31
+ end
32
+
33
+ # Returns a
34
+ # [cursor-paginated](https://developer.gocardless.com/pro/#overview-cursor-pagination)
35
+ # list of your payments.
36
+ # Example URL: /payments
37
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
38
+ # Else, they will be the body of the request.
39
+ def list(options = {}, custom_headers = {})
40
+ path = '/payments'
41
+
42
+ response = make_request(:get, path, options, custom_headers)
43
+ ListResponse.new(
44
+ raw_response: response,
45
+ unenveloped_body: unenvelope_body(response.body),
46
+ resource_class: Resources::Payment
47
+ )
48
+ end
49
+
50
+ # Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
51
+ #
52
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
53
+ # Otherwise they will be the body of the request.
54
+ def all(options = {})
55
+ Paginator.new(
56
+ service: self,
57
+ path: '/payments',
58
+ options: options
59
+ ).enumerator
60
+ end
61
+
62
+ # Retrieves the details of a single existing payment.
63
+ # Example URL: /payments/:identity
64
+ #
65
+ # @param identity # Unique identifier, beginning with "PM"
66
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
67
+ # Else, they will be the body of the request.
68
+ def get(identity, options = {}, custom_headers = {})
69
+ path = sub_url('/payments/:identity', 'identity' => identity)
70
+
71
+ response = make_request(:get, path, options, custom_headers)
72
+
73
+ Resources::Payment.new(unenvelope_body(response.body))
74
+ end
75
+
76
+ # Updates a payment object. This accepts only the metadata parameter.
77
+ # Example URL: /payments/:identity
78
+ #
79
+ # @param identity # Unique identifier, beginning with "PM"
80
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
81
+ # Else, they will be the body of the request.
82
+ def update(identity, options = {}, custom_headers = {})
83
+ path = sub_url('/payments/:identity', 'identity' => identity)
84
+
85
+ new_options = {}
86
+ new_options[envelope_key] = options
87
+ options = new_options
88
+ response = make_request(:put, path, options, custom_headers)
89
+
90
+ Resources::Payment.new(unenvelope_body(response.body))
91
+ end
92
+
93
+ # Cancels the payment if it has not already been submitted to the banks. Any
94
+ # metadata supplied to this endpoint will be stored on the payment cancellation
95
+ # event it causes.
96
+ #
97
+ # This will fail with a `cancellation_failed` error unless
98
+ # the payment's status is `pending_submission`.
99
+ # Example URL: /payments/:identity/actions/cancel
100
+ #
101
+ # @param identity # Unique identifier, beginning with "PM"
102
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
103
+ # Else, they will be the body of the request.
104
+ def cancel(identity, options = {}, custom_headers = {})
105
+ path = sub_url('/payments/:identity/actions/cancel', 'identity' => identity)
106
+
107
+ new_options = {}
108
+ new_options['data'] = options
109
+ options = new_options
110
+ response = make_request(:post, path, options, custom_headers)
111
+
112
+ Resources::Payment.new(unenvelope_body(response.body))
113
+ end
114
+
115
+ # <a name="retry_failed"></a>Retries a failed payment if the underlying mandate
116
+ # is active. You will receive a `resubmission_requested` webhook, but after that
117
+ # retrying the payment follows the same process as its initial creation, so you
118
+ # will receive a `submitted` webhook, followed by a `confirmed` or `failed`
119
+ # event. Any metadata supplied to this endpoint will be stored against the
120
+ # payment submission event it causes.
121
+ #
122
+ # This will return a `retry_failed`
123
+ # error if the payment has not failed.
124
+ # Example URL: /payments/:identity/actions/retry
125
+ #
126
+ # @param identity # Unique identifier, beginning with "PM"
127
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
128
+ # Else, they will be the body of the request.
129
+ def retry(identity, options = {}, custom_headers = {})
130
+ path = sub_url('/payments/:identity/actions/retry', 'identity' => identity)
131
+
132
+ new_options = {}
133
+ new_options['data'] = options
134
+ options = new_options
135
+ response = make_request(:post, path, options, custom_headers)
136
+
137
+ Resources::Payment.new(unenvelope_body(response.body))
138
+ end
139
+
140
+ # Unenvelope the response of the body using the service's `envelope_key`
141
+ #
142
+ # @param body [Hash]
143
+ def unenvelope_body(body)
144
+ body[envelope_key] || body['data']
145
+ end
146
+
147
+ private
148
+
149
+ # return the key which API responses will envelope data under
150
+ def envelope_key
151
+ 'payments'
152
+ end
153
+
154
+ # take a URL with placeholder params and substitute them out for the acutal value
155
+ # @param url [String] the URL with placeholders in
156
+ # @param param_map [Hash] a hash of placeholders and their actual values
157
+ def sub_url(url, param_map)
158
+ param_map.reduce(url) do |new_url, (param, value)|
159
+ new_url.gsub(":#{param}", value)
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,80 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # WARNING: Do not edit by hand, this file was generated by Crank:
6
+ #
7
+ # https://github.com/gocardless/crank
8
+
9
+ module GoCardless
10
+ module Services
11
+ # Service for making requests to the Payout endpoints
12
+ class PayoutService < BaseService
13
+ # Returns a
14
+ # [cursor-paginated](https://developer.gocardless.com/pro/#overview-cursor-pagination)
15
+ # list of your payouts.
16
+ # Example URL: /payouts
17
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
18
+ # Else, they will be the body of the request.
19
+ def list(options = {}, custom_headers = {})
20
+ path = '/payouts'
21
+
22
+ response = make_request(:get, path, options, custom_headers)
23
+ ListResponse.new(
24
+ raw_response: response,
25
+ unenveloped_body: unenvelope_body(response.body),
26
+ resource_class: Resources::Payout
27
+ )
28
+ end
29
+
30
+ # Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
31
+ #
32
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
33
+ # Otherwise they will be the body of the request.
34
+ def all(options = {})
35
+ Paginator.new(
36
+ service: self,
37
+ path: '/payouts',
38
+ options: options
39
+ ).enumerator
40
+ end
41
+
42
+ # Retrieves the details of a single payout.
43
+ # Example URL: /payouts/:identity
44
+ #
45
+ # @param identity # Unique identifier, beginning with "PO"
46
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
47
+ # Else, they will be the body of the request.
48
+ def get(identity, options = {}, custom_headers = {})
49
+ path = sub_url('/payouts/:identity', 'identity' => identity)
50
+
51
+ response = make_request(:get, path, options, custom_headers)
52
+
53
+ Resources::Payout.new(unenvelope_body(response.body))
54
+ end
55
+
56
+ # Unenvelope the response of the body using the service's `envelope_key`
57
+ #
58
+ # @param body [Hash]
59
+ def unenvelope_body(body)
60
+ body[envelope_key] || body['data']
61
+ end
62
+
63
+ private
64
+
65
+ # return the key which API responses will envelope data under
66
+ def envelope_key
67
+ 'payouts'
68
+ end
69
+
70
+ # take a URL with placeholder params and substitute them out for the acutal value
71
+ # @param url [String] the URL with placeholders in
72
+ # @param param_map [Hash] a hash of placeholders and their actual values
73
+ def sub_url(url, param_map)
74
+ param_map.reduce(url) do |new_url, (param, value)|
75
+ new_url.gsub(":#{param}", value)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,130 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # WARNING: Do not edit by hand, this file was generated by Crank:
6
+ #
7
+ # https://github.com/gocardless/crank
8
+
9
+ module GoCardless
10
+ module Services
11
+ # Service for making requests to the PublishableApiKey endpoints
12
+ class PublishableApiKeyService < BaseService
13
+ # Creates a publishable API key object.
14
+ # Example URL: /publishable_api_keys
15
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
16
+ # Else, they will be the body of the request.
17
+ def create(options = {}, custom_headers = {})
18
+ path = '/publishable_api_keys'
19
+ new_options = {}
20
+ new_options[envelope_key] = options
21
+ options = new_options
22
+ response = make_request(:post, path, options, custom_headers)
23
+
24
+ Resources::PublishableApiKey.new(unenvelope_body(response.body))
25
+ end
26
+
27
+ # Returns a
28
+ # [cursor-paginated](https://developer.gocardless.com/pro/#overview-cursor-pagination)
29
+ # list of your publishable API keys
30
+ # Example URL: /publishable_api_keys
31
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
32
+ # Else, they will be the body of the request.
33
+ def list(options = {}, custom_headers = {})
34
+ path = '/publishable_api_keys'
35
+
36
+ response = make_request(:get, path, options, custom_headers)
37
+ ListResponse.new(
38
+ raw_response: response,
39
+ unenveloped_body: unenvelope_body(response.body),
40
+ resource_class: Resources::PublishableApiKey
41
+ )
42
+ end
43
+
44
+ # Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
45
+ #
46
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
47
+ # Otherwise they will be the body of the request.
48
+ def all(options = {})
49
+ Paginator.new(
50
+ service: self,
51
+ path: '/publishable_api_keys',
52
+ options: options
53
+ ).enumerator
54
+ end
55
+
56
+ # Returns all details about a single publishable API key
57
+ # Example URL: /publishable_api_keys/:identity
58
+ #
59
+ # @param identity # Unique identifier, beginning with "PK"
60
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
61
+ # Else, they will be the body of the request.
62
+ def get(identity, options = {}, custom_headers = {})
63
+ path = sub_url('/publishable_api_keys/:identity', 'identity' => identity)
64
+
65
+ response = make_request(:get, path, options, custom_headers)
66
+
67
+ Resources::PublishableApiKey.new(unenvelope_body(response.body))
68
+ end
69
+
70
+ # Updates a publishable API key. Only the `name` fields are supported. Any other
71
+ # fields passed will be ignored.
72
+ # Example URL: /publishable_api_keys/:identity
73
+ #
74
+ # @param identity # Unique identifier, beginning with "PK"
75
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
76
+ # Else, they will be the body of the request.
77
+ def update(identity, options = {}, custom_headers = {})
78
+ path = sub_url('/publishable_api_keys/:identity', 'identity' => identity)
79
+
80
+ new_options = {}
81
+ new_options[envelope_key] = options
82
+ options = new_options
83
+ response = make_request(:put, path, options, custom_headers)
84
+
85
+ Resources::PublishableApiKey.new(unenvelope_body(response.body))
86
+ end
87
+
88
+ # Disables a publishable API key. Once disabled, the publishable API key will
89
+ # not be usable to authenticate any requests.
90
+ # Example URL: /publishable_api_keys/:identity/actions/disable
91
+ #
92
+ # @param identity # Unique identifier, beginning with "PK"
93
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
94
+ # Else, they will be the body of the request.
95
+ def disable(identity, options = {}, custom_headers = {})
96
+ path = sub_url('/publishable_api_keys/:identity/actions/disable', 'identity' => identity)
97
+
98
+ new_options = {}
99
+ new_options['data'] = options
100
+ options = new_options
101
+ response = make_request(:post, path, options, custom_headers)
102
+
103
+ Resources::PublishableApiKey.new(unenvelope_body(response.body))
104
+ end
105
+
106
+ # Unenvelope the response of the body using the service's `envelope_key`
107
+ #
108
+ # @param body [Hash]
109
+ def unenvelope_body(body)
110
+ body[envelope_key] || body['data']
111
+ end
112
+
113
+ private
114
+
115
+ # return the key which API responses will envelope data under
116
+ def envelope_key
117
+ 'publishable_api_keys'
118
+ end
119
+
120
+ # take a URL with placeholder params and substitute them out for the acutal value
121
+ # @param url [String] the URL with placeholders in
122
+ # @param param_map [Hash] a hash of placeholders and their actual values
123
+ def sub_url(url, param_map)
124
+ param_map.reduce(url) do |new_url, (param, value)|
125
+ new_url.gsub(":#{param}", value)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,96 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # WARNING: Do not edit by hand, this file was generated by Crank:
6
+ #
7
+ # https://github.com/gocardless/crank
8
+
9
+ module GoCardless
10
+ module Services
11
+ # Service for making requests to the RedirectFlow endpoints
12
+ class RedirectFlowService < BaseService
13
+ # Creates a redirect flow object which can then be used to redirect your
14
+ # customer to the GoCardless Pro hosted payment pages.
15
+ # Example URL: /redirect_flows
16
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
17
+ # Else, they will be the body of the request.
18
+ def create(options = {}, custom_headers = {})
19
+ path = '/redirect_flows'
20
+ new_options = {}
21
+ new_options[envelope_key] = options
22
+ options = new_options
23
+ response = make_request(:post, path, options, custom_headers)
24
+
25
+ Resources::RedirectFlow.new(unenvelope_body(response.body))
26
+ end
27
+
28
+ # Returns all details about a single redirect flow
29
+ # Example URL: /redirect_flows/:identity
30
+ #
31
+ # @param identity # Unique identifier, beginning with "RE"
32
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
33
+ # Else, they will be the body of the request.
34
+ def get(identity, options = {}, custom_headers = {})
35
+ path = sub_url('/redirect_flows/:identity', 'identity' => identity)
36
+
37
+ response = make_request(:get, path, options, custom_headers)
38
+
39
+ Resources::RedirectFlow.new(unenvelope_body(response.body))
40
+ end
41
+
42
+ # This creates a
43
+ # [customer](https://developer.gocardless.com/pro/#api-endpoints-customers),
44
+ # [customer bank
45
+ # account](https://developer.gocardless.com/pro/#api-endpoints-customer-bank-account),
46
+ # and [mandate](https://developer.gocardless.com/pro/#api-endpoints-mandates)
47
+ # using the details supplied by your customer and returns the ID of the created
48
+ # mandate.
49
+ #
50
+ # This will return a `redirect_flow_incomplete` error if your
51
+ # customer has not yet been redirected back to your site, and a
52
+ # `redirect_flow_already_completed` error if your integration has already
53
+ # completed this flow. It will return a `bad_request` error if the
54
+ # `session_token` differs to the one supplied when the redirect flow was
55
+ # created.
56
+ # Example URL: /redirect_flows/:identity/actions/complete
57
+ #
58
+ # @param identity # Unique identifier, beginning with "RE"
59
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
60
+ # Else, they will be the body of the request.
61
+ def complete(identity, options = {}, custom_headers = {})
62
+ path = sub_url('/redirect_flows/:identity/actions/complete', 'identity' => identity)
63
+
64
+ new_options = {}
65
+ new_options['data'] = options
66
+ options = new_options
67
+ response = make_request(:post, path, options, custom_headers)
68
+
69
+ Resources::RedirectFlow.new(unenvelope_body(response.body))
70
+ end
71
+
72
+ # Unenvelope the response of the body using the service's `envelope_key`
73
+ #
74
+ # @param body [Hash]
75
+ def unenvelope_body(body)
76
+ body[envelope_key] || body['data']
77
+ end
78
+
79
+ private
80
+
81
+ # return the key which API responses will envelope data under
82
+ def envelope_key
83
+ 'redirect_flows'
84
+ end
85
+
86
+ # take a URL with placeholder params and substitute them out for the acutal value
87
+ # @param url [String] the URL with placeholders in
88
+ # @param param_map [Hash] a hash of placeholders and their actual values
89
+ def sub_url(url, param_map)
90
+ param_map.reduce(url) do |new_url, (param, value)|
91
+ new_url.gsub(":#{param}", value)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end