recurly 2.17.11 → 4.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (283) hide show
  1. checksums.yaml +4 -4
  2. data/.bumpversion.cfg +15 -0
  3. data/.changelog_config.yaml +11 -0
  4. data/.github/ISSUE_TEMPLATE/bug-report.md +30 -0
  5. data/.github/ISSUE_TEMPLATE/question-or-other.md +10 -0
  6. data/.github/workflows/ci.yml +29 -0
  7. data/.github/workflows/docs.yml +28 -0
  8. data/.gitignore +15 -0
  9. data/.rspec +2 -0
  10. data/.yardopts +2 -0
  11. data/CHANGELOG.md +295 -0
  12. data/CODE_OF_CONDUCT.md +130 -0
  13. data/CONTRIBUTING.md +106 -0
  14. data/GETTING_STARTED.md +330 -0
  15. data/Gemfile +4 -0
  16. data/LICENSE.txt +21 -0
  17. data/README.md +9 -148
  18. data/Rakefile +6 -0
  19. data/benchmark.rb +16 -0
  20. data/lib/data/ca-certificates.crt +3466 -0
  21. data/lib/recurly/client/operations.rb +4079 -0
  22. data/lib/recurly/client.rb +400 -0
  23. data/lib/recurly/connection_pool.rb +42 -0
  24. data/lib/recurly/errors/api_errors.rb +90 -0
  25. data/lib/recurly/errors/network_errors.rb +7 -0
  26. data/lib/recurly/errors.rb +51 -0
  27. data/lib/recurly/http.rb +50 -0
  28. data/lib/recurly/pager.rb +136 -0
  29. data/lib/recurly/request.rb +31 -0
  30. data/lib/recurly/requests/account_acquisition_cost.rb +18 -0
  31. data/lib/recurly/requests/account_acquisition_update.rb +26 -0
  32. data/lib/recurly/requests/account_create.rb +98 -0
  33. data/lib/recurly/requests/account_purchase.rb +98 -0
  34. data/lib/recurly/requests/account_update.rb +86 -0
  35. data/lib/recurly/requests/add_on_create.rb +102 -0
  36. data/lib/recurly/requests/add_on_pricing.rb +26 -0
  37. data/lib/recurly/requests/add_on_update.rb +78 -0
  38. data/lib/recurly/requests/address.rb +38 -0
  39. data/lib/recurly/requests/billing_info_create.rb +134 -0
  40. data/lib/recurly/requests/billing_info_verify.rb +14 -0
  41. data/lib/recurly/requests/coupon_bulk_create.rb +14 -0
  42. data/lib/recurly/requests/coupon_create.rb +102 -0
  43. data/lib/recurly/requests/coupon_pricing.rb +18 -0
  44. data/lib/recurly/requests/coupon_redemption_create.rb +22 -0
  45. data/lib/recurly/requests/coupon_update.rb +34 -0
  46. data/lib/recurly/requests/custom_field.rb +18 -0
  47. data/lib/recurly/requests/dunning_campaigns_bulk_update.rb +18 -0
  48. data/lib/recurly/requests/external_refund.rb +22 -0
  49. data/lib/recurly/requests/external_transaction.rb +26 -0
  50. data/lib/recurly/requests/invoice_address.rb +54 -0
  51. data/lib/recurly/requests/invoice_collect.rb +22 -0
  52. data/lib/recurly/requests/invoice_create.rb +42 -0
  53. data/lib/recurly/requests/invoice_refund.rb +34 -0
  54. data/lib/recurly/requests/invoice_update.rb +34 -0
  55. data/lib/recurly/requests/item_create.rb +58 -0
  56. data/lib/recurly/requests/item_update.rb +58 -0
  57. data/lib/recurly/requests/line_item_create.rb +86 -0
  58. data/lib/recurly/requests/line_item_refund.rb +22 -0
  59. data/lib/recurly/requests/measured_unit_create.rb +22 -0
  60. data/lib/recurly/requests/measured_unit_update.rb +22 -0
  61. data/lib/recurly/requests/percentage_tier.rb +18 -0
  62. data/lib/recurly/requests/percentage_tiers_by_currency.rb +18 -0
  63. data/lib/recurly/requests/plan_create.rb +102 -0
  64. data/lib/recurly/requests/plan_hosted_pages.rb +26 -0
  65. data/lib/recurly/requests/plan_pricing.rb +26 -0
  66. data/lib/recurly/requests/plan_update.rb +94 -0
  67. data/lib/recurly/requests/pricing.rb +22 -0
  68. data/lib/recurly/requests/purchase_create.rb +78 -0
  69. data/lib/recurly/requests/shipping_address_create.rb +62 -0
  70. data/lib/recurly/requests/shipping_address_update.rb +66 -0
  71. data/lib/recurly/requests/shipping_fee_create.rb +22 -0
  72. data/lib/recurly/requests/shipping_method_create.rb +26 -0
  73. data/lib/recurly/requests/shipping_method_update.rb +26 -0
  74. data/lib/recurly/requests/shipping_purchase.rb +22 -0
  75. data/lib/recurly/requests/subscription_add_on_create.rb +46 -0
  76. data/lib/recurly/requests/subscription_add_on_percentage_tier.rb +18 -0
  77. data/lib/recurly/requests/subscription_add_on_tier.rb +26 -0
  78. data/lib/recurly/requests/subscription_add_on_update.rb +50 -0
  79. data/lib/recurly/requests/subscription_cancel.rb +14 -0
  80. data/lib/recurly/requests/subscription_change_billing_info_create.rb +14 -0
  81. data/lib/recurly/requests/subscription_change_create.rb +74 -0
  82. data/lib/recurly/requests/subscription_change_shipping_create.rb +30 -0
  83. data/lib/recurly/requests/subscription_create.rb +114 -0
  84. data/lib/recurly/requests/subscription_pause.rb +14 -0
  85. data/lib/recurly/requests/subscription_purchase.rb +70 -0
  86. data/lib/recurly/requests/subscription_shipping_create.rb +30 -0
  87. data/lib/recurly/requests/subscription_shipping_purchase.rb +22 -0
  88. data/lib/recurly/requests/subscription_shipping_update.rb +22 -0
  89. data/lib/recurly/requests/subscription_update.rb +70 -0
  90. data/lib/recurly/requests/tier.rb +22 -0
  91. data/lib/recurly/requests/tier_pricing.rb +22 -0
  92. data/lib/recurly/requests/usage_create.rb +26 -0
  93. data/lib/recurly/requests.rb +8 -0
  94. data/lib/recurly/resource.rb +23 -1092
  95. data/lib/recurly/resources/account.rb +138 -0
  96. data/lib/recurly/resources/account_acquisition.rb +46 -0
  97. data/lib/recurly/resources/account_acquisition_cost.rb +18 -0
  98. data/lib/recurly/resources/account_balance.rb +26 -0
  99. data/lib/recurly/resources/account_balance_amount.rb +22 -0
  100. data/lib/recurly/resources/account_mini.rb +50 -0
  101. data/lib/recurly/resources/account_note.rb +34 -0
  102. data/lib/recurly/resources/add_on.rb +122 -0
  103. data/lib/recurly/resources/add_on_mini.rb +54 -0
  104. data/lib/recurly/resources/add_on_pricing.rb +26 -0
  105. data/lib/recurly/resources/address.rb +38 -0
  106. data/lib/recurly/resources/address_with_name.rb +46 -0
  107. data/lib/recurly/resources/billing_info.rb +74 -0
  108. data/lib/recurly/resources/billing_info_updated_by.rb +18 -0
  109. data/lib/recurly/resources/binary_file.rb +14 -0
  110. data/lib/recurly/resources/coupon.rb +126 -0
  111. data/lib/recurly/resources/coupon_discount.rb +26 -0
  112. data/lib/recurly/resources/coupon_discount_pricing.rb +18 -0
  113. data/lib/recurly/resources/coupon_discount_trial.rb +18 -0
  114. data/lib/recurly/resources/coupon_mini.rb +42 -0
  115. data/lib/recurly/resources/coupon_redemption.rb +54 -0
  116. data/lib/recurly/resources/coupon_redemption_mini.rb +34 -0
  117. data/lib/recurly/resources/credit_payment.rb +66 -0
  118. data/lib/recurly/resources/custom_field.rb +18 -0
  119. data/lib/recurly/resources/custom_field_definition.rb +50 -0
  120. data/lib/recurly/resources/dunning_campaign.rb +50 -0
  121. data/lib/recurly/resources/dunning_campaigns_bulk_update_response.rb +18 -0
  122. data/lib/recurly/resources/dunning_cycle.rb +58 -0
  123. data/lib/recurly/resources/dunning_interval.rb +18 -0
  124. data/lib/recurly/resources/error.rb +22 -0
  125. data/lib/recurly/resources/error_may_have_transaction.rb +26 -0
  126. data/lib/recurly/resources/export_dates.rb +18 -0
  127. data/lib/recurly/resources/export_file.rb +22 -0
  128. data/lib/recurly/resources/export_files.rb +18 -0
  129. data/lib/recurly/resources/fraud_info.rb +22 -0
  130. data/lib/recurly/resources/invoice.rb +162 -0
  131. data/lib/recurly/resources/invoice_address.rb +54 -0
  132. data/lib/recurly/resources/invoice_collection.rb +22 -0
  133. data/lib/recurly/resources/invoice_mini.rb +30 -0
  134. data/lib/recurly/resources/invoice_template.rb +34 -0
  135. data/lib/recurly/resources/item.rb +82 -0
  136. data/lib/recurly/resources/item_mini.rb +34 -0
  137. data/lib/recurly/resources/line_item.rb +206 -0
  138. data/lib/recurly/resources/measured_unit.rb +46 -0
  139. data/lib/recurly/resources/payment_method.rb +70 -0
  140. data/lib/recurly/resources/percentage_tier.rb +18 -0
  141. data/lib/recurly/resources/percentage_tiers_by_currency.rb +18 -0
  142. data/lib/recurly/resources/plan.rb +122 -0
  143. data/lib/recurly/resources/plan_hosted_pages.rb +26 -0
  144. data/lib/recurly/resources/plan_mini.rb +26 -0
  145. data/lib/recurly/resources/plan_pricing.rb +26 -0
  146. data/lib/recurly/resources/pricing.rb +22 -0
  147. data/lib/recurly/resources/settings.rb +22 -0
  148. data/lib/recurly/resources/shipping_address.rb +82 -0
  149. data/lib/recurly/resources/shipping_method.rb +46 -0
  150. data/lib/recurly/resources/shipping_method_mini.rb +26 -0
  151. data/lib/recurly/resources/site.rb +54 -0
  152. data/lib/recurly/resources/subscription.rb +198 -0
  153. data/lib/recurly/resources/subscription_add_on.rb +78 -0
  154. data/lib/recurly/resources/subscription_add_on_percentage_tier.rb +18 -0
  155. data/lib/recurly/resources/subscription_add_on_tier.rb +26 -0
  156. data/lib/recurly/resources/subscription_change.rb +82 -0
  157. data/lib/recurly/resources/subscription_change_billing_info.rb +14 -0
  158. data/lib/recurly/resources/subscription_shipping.rb +26 -0
  159. data/lib/recurly/resources/tax_detail.rb +26 -0
  160. data/lib/recurly/resources/tax_info.rb +26 -0
  161. data/lib/recurly/resources/tier.rb +22 -0
  162. data/lib/recurly/resources/tier_pricing.rb +22 -0
  163. data/lib/recurly/resources/transaction.rb +162 -0
  164. data/lib/recurly/resources/transaction_error.rb +38 -0
  165. data/lib/recurly/resources/transaction_payment_gateway.rb +26 -0
  166. data/lib/recurly/resources/unique_coupon_code.rb +50 -0
  167. data/lib/recurly/resources/unique_coupon_code_params.rb +26 -0
  168. data/lib/recurly/resources/usage.rb +78 -0
  169. data/lib/recurly/resources/user.rb +42 -0
  170. data/lib/recurly/resources.rb +18 -0
  171. data/lib/recurly/schema/file_parser.rb +13 -0
  172. data/lib/recurly/schema/json_parser.rb +72 -0
  173. data/lib/recurly/schema/request_caster.rb +60 -0
  174. data/lib/recurly/schema/resource_caster.rb +46 -0
  175. data/lib/recurly/schema/schema_factory.rb +48 -0
  176. data/lib/recurly/schema/schema_validator.rb +144 -0
  177. data/lib/recurly/schema.rb +156 -0
  178. data/lib/recurly/version.rb +1 -15
  179. data/lib/recurly.rb +15 -141
  180. data/openapi/api.yaml +22879 -0
  181. data/recurly.gemspec +39 -0
  182. data/scripts/build +5 -0
  183. data/scripts/clean +6 -0
  184. data/scripts/format +12 -0
  185. data/scripts/prepare-release +50 -0
  186. data/scripts/release +17 -0
  187. data/scripts/test +15 -0
  188. metadata +217 -220
  189. data/lib/recurly/account.rb +0 -189
  190. data/lib/recurly/account_acquisition.rb +0 -19
  191. data/lib/recurly/account_balance.rb +0 -21
  192. data/lib/recurly/add_on.rb +0 -30
  193. data/lib/recurly/address.rb +0 -25
  194. data/lib/recurly/adjustment.rb +0 -76
  195. data/lib/recurly/api/errors.rb +0 -208
  196. data/lib/recurly/api/net_http_adapter.rb +0 -111
  197. data/lib/recurly/api.rb +0 -101
  198. data/lib/recurly/billing_info.rb +0 -82
  199. data/lib/recurly/coupon.rb +0 -134
  200. data/lib/recurly/credit_payment.rb +0 -32
  201. data/lib/recurly/custom_field.rb +0 -15
  202. data/lib/recurly/delivery.rb +0 -19
  203. data/lib/recurly/error.rb +0 -13
  204. data/lib/recurly/gift_card.rb +0 -82
  205. data/lib/recurly/helper.rb +0 -51
  206. data/lib/recurly/invoice.rb +0 -273
  207. data/lib/recurly/invoice_collection.rb +0 -14
  208. data/lib/recurly/js.rb +0 -14
  209. data/lib/recurly/juris_detail.rb +0 -14
  210. data/lib/recurly/measured_unit.rb +0 -16
  211. data/lib/recurly/money.rb +0 -120
  212. data/lib/recurly/note.rb +0 -14
  213. data/lib/recurly/plan.rb +0 -40
  214. data/lib/recurly/purchase.rb +0 -234
  215. data/lib/recurly/redemption.rb +0 -46
  216. data/lib/recurly/resource/association.rb +0 -16
  217. data/lib/recurly/resource/errors.rb +0 -20
  218. data/lib/recurly/resource/pager.rb +0 -313
  219. data/lib/recurly/shipping_address.rb +0 -26
  220. data/lib/recurly/shipping_fee.rb +0 -17
  221. data/lib/recurly/shipping_method.rb +0 -13
  222. data/lib/recurly/subscription/add_ons.rb +0 -77
  223. data/lib/recurly/subscription.rb +0 -330
  224. data/lib/recurly/subscription_add_on.rb +0 -50
  225. data/lib/recurly/tax_detail.rb +0 -14
  226. data/lib/recurly/tax_type.rb +0 -12
  227. data/lib/recurly/transaction/errors.rb +0 -115
  228. data/lib/recurly/transaction.rb +0 -129
  229. data/lib/recurly/usage.rb +0 -28
  230. data/lib/recurly/webhook/account_notification.rb +0 -10
  231. data/lib/recurly/webhook/billing_info_updated_notification.rb +0 -6
  232. data/lib/recurly/webhook/canceled_account_notification.rb +0 -6
  233. data/lib/recurly/webhook/canceled_subscription_notification.rb +0 -6
  234. data/lib/recurly/webhook/closed_credit_invoice_notification.rb +0 -6
  235. data/lib/recurly/webhook/closed_invoice_notification.rb +0 -6
  236. data/lib/recurly/webhook/credit_payment_notification.rb +0 -12
  237. data/lib/recurly/webhook/dunning_notification.rb +0 -14
  238. data/lib/recurly/webhook/expired_subscription_notification.rb +0 -6
  239. data/lib/recurly/webhook/failed_charge_invoice_notification.rb +0 -6
  240. data/lib/recurly/webhook/failed_payment_notification.rb +0 -6
  241. data/lib/recurly/webhook/gift_card_notification.rb +0 -8
  242. data/lib/recurly/webhook/invoice_notification.rb +0 -12
  243. data/lib/recurly/webhook/low_balance_gift_card_notification.rb +0 -6
  244. data/lib/recurly/webhook/new_account_notification.rb +0 -6
  245. data/lib/recurly/webhook/new_charge_invoice_notification.rb +0 -6
  246. data/lib/recurly/webhook/new_credit_invoice_notification.rb +0 -6
  247. data/lib/recurly/webhook/new_credit_payment_notification.rb +0 -6
  248. data/lib/recurly/webhook/new_dunning_event_notification.rb +0 -6
  249. data/lib/recurly/webhook/new_invoice_notification.rb +0 -6
  250. data/lib/recurly/webhook/new_subscription_notification.rb +0 -6
  251. data/lib/recurly/webhook/new_usage_notification.rb +0 -8
  252. data/lib/recurly/webhook/notification.rb +0 -18
  253. data/lib/recurly/webhook/paid_charge_invoice_notification.rb +0 -6
  254. data/lib/recurly/webhook/past_due_charge_invoice_notification.rb +0 -6
  255. data/lib/recurly/webhook/past_due_invoice_notification.rb +0 -6
  256. data/lib/recurly/webhook/processing_charge_invoice_notification.rb +0 -6
  257. data/lib/recurly/webhook/processing_credit_invoice_notification.rb +0 -6
  258. data/lib/recurly/webhook/processing_invoice_notification.rb +0 -6
  259. data/lib/recurly/webhook/processing_payment_notification.rb +0 -6
  260. data/lib/recurly/webhook/purchased_gift_card_notification.rb +0 -7
  261. data/lib/recurly/webhook/reactivated_account_notification.rb +0 -6
  262. data/lib/recurly/webhook/redeemed_gift_card_notification.rb +0 -7
  263. data/lib/recurly/webhook/renewed_subscription_notification.rb +0 -6
  264. data/lib/recurly/webhook/reopened_charge_invoice_notification.rb +0 -6
  265. data/lib/recurly/webhook/reopened_credit_invoice_notification.rb +0 -6
  266. data/lib/recurly/webhook/scheduled_payment_notification.rb +0 -6
  267. data/lib/recurly/webhook/subscription_notification.rb +0 -12
  268. data/lib/recurly/webhook/successful_payment_notification.rb +0 -6
  269. data/lib/recurly/webhook/successful_refund_notification.rb +0 -6
  270. data/lib/recurly/webhook/transaction_authorized_notification.rb +0 -6
  271. data/lib/recurly/webhook/transaction_notification.rb +0 -12
  272. data/lib/recurly/webhook/transaction_status_updated_notification.rb +0 -6
  273. data/lib/recurly/webhook/updated_account_notification.rb +0 -6
  274. data/lib/recurly/webhook/updated_balance_gift_card_notification.rb +0 -7
  275. data/lib/recurly/webhook/updated_invoice_notification.rb +0 -6
  276. data/lib/recurly/webhook/updated_subscription_notification.rb +0 -6
  277. data/lib/recurly/webhook/void_payment_notification.rb +0 -6
  278. data/lib/recurly/webhook/voided_credit_invoice_notification.rb +0 -6
  279. data/lib/recurly/webhook/voided_credit_payment_notification.rb +0 -6
  280. data/lib/recurly/webhook.rb +0 -91
  281. data/lib/recurly/xml/nokogiri.rb +0 -60
  282. data/lib/recurly/xml/rexml.rb +0 -52
  283. data/lib/recurly/xml.rb +0 -122
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,106 @@
1
+ # Contributing Guide
2
+
3
+ 👍🎉 First off, thanks for taking the time to contribute! 🎉👍
4
+
5
+ Filing an Issue or a Pull Request is often the best way to address a problem with this library;
6
+ however, we may not get to these right away. Although we try to be quick, our primary, daily focus is
7
+ writing code. If you want a timely response (especially if you have an emergency), we recommend
8
+ you contact our [official support team](https://support.recurly.com/).
9
+
10
+ ## Code of Conduct
11
+
12
+ Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
13
+
14
+ #### Table Of Contents
15
+
16
+ * [I don't want to read this whole thing, I just have a question!!!](#i-dont-want-to-read-this-whole-thing-i-just-have-a-question)
17
+ * [I think something is wrong with this library](#i-think-something-is-wrong-with-this-library)
18
+ * [I know what's wrong and I want to submit a code change](#i-know-whats-wrong-and-i-want-to-submit-a-code-change)
19
+ * [Development Dependencies](#development-dependencies)
20
+ * [Building and Testing](#building-and-testing)
21
+ * [Formatting Code](#formatting-code)
22
+ * [Generated Code](#generated-code)
23
+
24
+
25
+ ## I don't want to read this whole thing I just have a question!!!
26
+
27
+ The best way to get a question answered is through our [official support channel](https://support.recurly.com/). If you
28
+ have a specific question related to this library and cannot find an answer, feel free to post an issue with the question.
29
+
30
+ ## I think something is wrong with this library
31
+
32
+ Are you getting an exception or seeing some unexpected behavior from the library? An issue is the way to go.
33
+ Submit an issue and make sure you provide as much detail as possible. Some things you'll want to include:
34
+
35
+ * Your dependency versions (client version, language version, OS, etc)
36
+ * A stack trace if available
37
+ * A [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example)
38
+
39
+ The more information you give us, the quicker and easier the response will be. Keep in mind that issues should be scoped
40
+ to a problem in this library and we may often redirect you to our official support for problems originating from
41
+ upstream systems.
42
+
43
+ ## I know what's wrong and I want to submit a code change
44
+
45
+ So, you are sure you want to submit a change to the code? We appreciate the help!
46
+ Before you do, consider opening a discussion in the form of an issue. This accomplish a few things:
47
+
48
+ 1. We can give you advice to implement the change
49
+ 2. We can give you an idea of our openness to the change
50
+
51
+ **Note**: Sending code without a discussion is *always* fine. Discussion on the PR is often easier anyway. Just understand that we may
52
+ not accept the code if we don't think it's best for everyone using the library.
53
+
54
+ The rest of this section describes what you'll need to know.
55
+
56
+ ### Development Dependencies
57
+
58
+ You're going to first need a supported version of the language toolchain. The best way to find which versions are supported are by checking
59
+ the [Travis File](.travis.yml) which is used to run our tests. We try to test against every supported version of the language. The [README](README.md)
60
+ may also have something to say about supported dependencies.
61
+
62
+ ### Building and Testing
63
+
64
+ All of our client libraries contain a `scripts` folder which houses a set of bash scripts for doing common
65
+ development tasks. These scripts follow the same naming conventions so this can act as a kind of "Bash API"
66
+ for manipulating the libraries.
67
+
68
+ **Note**: If you are on a system without bash (such as some Windows systems), you should find the scripts only consist of a
69
+ few commands which can easily be run in your terminal or editor directly.
70
+
71
+ Start by running the `build` script to setup deps, compile (if applicable), build docs, etc:
72
+
73
+ ```bash
74
+ ./scripts/build
75
+ ```
76
+
77
+ Use the `test` script to run the tests:
78
+
79
+ ```bash
80
+ ./scripts/test
81
+ ```
82
+
83
+ Make sure the tests pass locally before submitting your change.
84
+
85
+ ### Formatting Code
86
+
87
+ The PR (and often the tests) will fail if you have not properly formatted the code. Instead of having a style-guide, we've provided
88
+ an auto-formatter. To use it, run the `format` script:
89
+
90
+ ```bash
91
+ ./scripts/format
92
+ ```
93
+
94
+ ### Generated Code
95
+
96
+ Some files in this codebase are generated by a non-public, proprietary program. Because they are regularly generated and updated as the
97
+ API and docs change, we won't accept any PRs that modify these files. Each of these files has a disclaimer on the top saying that they cannot
98
+ be edited by hand. By convention, they relate to things that are specific to the Recurly API that may change. For example:
99
+
100
+ * Response Schemas (Resources)
101
+ * Request Schemas (Requests)
102
+ * API endpoints (Operations)
103
+ * Errors
104
+
105
+ If you feel like you need one of these to change, please file an issue and we can discuss getting the change upstreamed.
106
+
@@ -0,0 +1,330 @@
1
+ This repository houses the official ruby client for Recurly's V3 API.
2
+
3
+ # Installing
4
+
5
+ In your Gemfile, add `recurly` as a dependency.
6
+
7
+ ```ruby
8
+ gem 'recurly', '~> 4.18'
9
+ ```
10
+
11
+ > *Note*: We try to follow [semantic versioning](https://semver.org/) and will only apply breaking changes to major versions.
12
+
13
+ # Creating a client
14
+
15
+ A client represents a connection to the Recurly servers. Every call
16
+ to the server exists as a method on this class. To initialize, you only need the private API key
17
+ which can be obtained on the [API Credentials Page](https://app.recurly.com/go/integrations/api_keys).
18
+
19
+ ```ruby
20
+ API_KEY = '83749879bbde395b5fe0cc1a5abf8e5'
21
+ client = Recurly::Client.new(api_key: API_KEY)
22
+ sub = client.get_subscription(subscription_id: 'abcd123456')
23
+ ```
24
+
25
+ To access Recurly API in Europe, you will need to specify the EU Region in the argument region.
26
+
27
+ ```ruby
28
+ API_KEY = '83749879bbde395b5fe0cc1a5abf8e5'
29
+ client = Recurly::Client.new(api_key: API_KEY, region: :eu)
30
+ sub = client.get_subscription(subscription_id: 'abcd123456')
31
+ ```
32
+
33
+ You can also pass the initializer a block. This will give you a client scoped for just that block:
34
+
35
+ ```ruby
36
+ Recurly::Client.new(api_key: API_KEY) do |client|
37
+ sub = client.get_subscription(subscription_id: 'abcd123456')
38
+ end
39
+ ```
40
+
41
+ If you plan on using the client for more than one site, you should initialize a new client for each site.
42
+
43
+ ```ruby
44
+ client = Recurly::Client.new(api_key: API_KEY1)
45
+ sub = client.get_subscription(subscription_id: 'abcd123456')
46
+
47
+ # you should create a new client to connect to another site
48
+ client = Recurly::Client.new(api_key: API_KEY2)
49
+ sub = client.get_subscription(subscription_id: 'abcd7890')
50
+ ```
51
+
52
+ ## Logging
53
+
54
+ The client constructor optionally accepts a logger provided by the programmer. The logger you pass should be an instance of ruby stdlib's [Logger](https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html)
55
+ or follow the same interface. By default, the client creates a logger to `STDOUT` with level `WARN`.
56
+
57
+ ```ruby
58
+ require 'logger'
59
+
60
+ # Create a logger to STDOUT
61
+ logger = Logger.new(STDOUT)
62
+ logger.level = Logger::INFO
63
+
64
+ # You could also use an existing logger
65
+ # If you are using Rails you may want to use your application's logger
66
+ logger = Rails.logger
67
+
68
+ client = Recurly::Client.new(api_key: API_KEY, logger: logger)
69
+ ```
70
+
71
+ > *SECURITY WARNING*: The log level should never be set to DEBUG in production. This could potentially result in sensitive data in your logging system.
72
+
73
+ # Operations
74
+
75
+ The {Recurly::Client} contains every `operation` you can perform on the site as a list of methods. Each method is documented explaining
76
+ the types and descriptions for each input and return type. You can view all available operations by looking at the `Instance Methods Summary` list
77
+ on the {Recurly::Client} documentation page. Clicking a method will give you detailed information about its inputs and returns. Take the `create_account`
78
+ operation as an example: {Recurly::Client#create_account}.
79
+
80
+ # Pagination
81
+
82
+ Pagination is done by the class {Recurly::Pager}. All `list_*` methods on the client return an instance of this class.
83
+ The pager has an `each` method which accepts a block for each object in the entire list. Each page is fetched automatically
84
+ for you presenting the elements as a single enumerable.
85
+
86
+ ```ruby
87
+ plans = client.list_plans()
88
+ plans.each do |plan|
89
+ puts "Plan: #{plan.id}"
90
+ end
91
+ ```
92
+
93
+ You may also paginate in chunks with `each_page`.
94
+
95
+ ```ruby
96
+ plans = client.list_plans()
97
+ plans.each_page do |data|
98
+ data.each do |plan|
99
+ puts "Plan: #{plan.id}"
100
+ end
101
+ end
102
+ ```
103
+
104
+ Both {Pager#each} and {Pager#each_page} return Enumerators if a block is not given. This allows you to use other Enumerator methods
105
+ such as `map` or `each_with_index`.
106
+
107
+ ```ruby
108
+ plans = client.list_plans()
109
+ plans.each_page.each_with_index do |data, page_num|
110
+ puts "Page Number #{page_num}"
111
+ data.each do |plan|
112
+ puts "Plan: #{plan.id}"
113
+ end
114
+ end
115
+ ```
116
+
117
+ Pagination endpoints take a number of options to sort and filter the results. They can be passed in as a hash provided by the `:params` keyword argument.
118
+ The names, types, and descriptions of these arguments are listed in the rubydocs for each method:
119
+
120
+ ```ruby
121
+ options = {
122
+ params: {
123
+ limit: 200, # number of items per page
124
+ state: :active, # only active plans
125
+ sort: :updated_at,
126
+ order: :asc,
127
+ begin_time: DateTime.new(2017,1,1), # January 1st 2017,
128
+ end_time: DateTime.now
129
+ }
130
+ }
131
+
132
+ plans = client.list_plans(**options)
133
+ plans.each do |plan|
134
+ puts "Plan: #{plan.id}"
135
+ end
136
+ ```
137
+
138
+ **A note on `limit`**:
139
+
140
+ `limit` defaults to 20 items per page and can be set from 1 to 200. Choosing a lower limit means more network requests but smaller payloads.
141
+ We recommend keeping the default for most cases but increasing the limit if you are planning on iterating through many pages of items (e.g. all transactions in your site).
142
+
143
+ ## Efficiently Fetch the First or Last Resource
144
+
145
+ The Pager class implements a first method which allows you to fetch just the first or last resource from the server. On top of being a convenient abstraction, this is implemented efficiently by only asking the server for the 1 item you want.
146
+
147
+ ```ruby
148
+ accounts = client.list_accounts(
149
+ subscriber: true,
150
+ order: :desc
151
+ )
152
+
153
+ last_subscriber = accounts.first
154
+ ```
155
+
156
+ If you want to fetch the last account in this scenario, invert the order from descending `desc` to ascending `asc`:
157
+
158
+ ```ruby
159
+ accounts = client.list_accounts(
160
+ subscriber: true,
161
+ order: :asc
162
+ )
163
+
164
+ first_subscriber = accounts.first
165
+ ```
166
+
167
+ ## Counting Resources
168
+
169
+ The Pager class implements a `count` method which allows you to count the resources the pager would return. It does so by calling the endpoint with `HEAD` and parsing and returning the `Recurly-Total-Records` header. This method respects any filtering parameters you apply to the pager, but the sorting parameters will have no effect.
170
+
171
+ ```ruby
172
+ accounts = client.list_accounts(
173
+ subscriber: true,
174
+ begin_time: DateTime.new(2017,1,1)
175
+ )
176
+
177
+ # Calling count here will return an integer indicating
178
+ # the number of subscribers since 2017
179
+ count = accounts.count
180
+ # => 573
181
+ ```
182
+
183
+ # Creating Resources
184
+
185
+ Currently, resources are created by passing in a `body` keyword argument in the form of a `Hash`.
186
+ This Hash must follow the schema of the documented request type. For example, the `create_plan` operation
187
+ takes a request of type {Recurly::Requests::PlanCreate}. Failing to conform to this schema will result in an argument
188
+ error.
189
+
190
+ ```ruby
191
+ require 'securerandom'
192
+
193
+ code = SecureRandom.uuid
194
+ plan_data = {
195
+ code: code,
196
+ interval_length: 1,
197
+ interval_unit: 'months',
198
+ name: code,
199
+ currencies: [
200
+ {
201
+ currency: 'USD',
202
+ setup_fee: 800,
203
+ unit_amount: 10
204
+ }
205
+ ]
206
+ }
207
+
208
+ plan = client.create_plan(body: plan_data)
209
+ ```
210
+
211
+ # Error Handling
212
+
213
+ All errors thrown by this library are based off of the `Recurly::Errors::APIError`. There
214
+
215
+ This library throws one main type of exception, `Recurly::Errors::APIError`. There exists an additional hierarchy of errors to facilitate the process of rescuing various classes of errors. More detail can be found in the [Api Errors Module](./lib/recurly/errors/api_errors.rb).
216
+
217
+ You can catch specific or generic versions of these exceptions. Example:
218
+
219
+ ```ruby
220
+ begin
221
+ client = Recurly::Client.new(api_key: API_KEY)
222
+ code = "iexistalready"
223
+ plan_data = {
224
+ code: code,
225
+ interval_length: 1,
226
+ interval_unit: 'months',
227
+ name: code,
228
+ currencies: [
229
+ {
230
+ currency: 'USD',
231
+ setup_fee: 800,
232
+ unit_amount: 10
233
+ }
234
+ ]
235
+ }
236
+
237
+ plan = client.create_plan(body: plan_data)
238
+ rescue Recurly::Errors::ValidationError => ex
239
+ puts ex.inspect
240
+ #=> #<Recurly::ValidationError: Recurly::ValidationError: Code 'iexistalready' already exists>
241
+ puts ex.recurly_error.inspect
242
+ #=> #<Recurly::Error:0x007fbbdf8a32c8 @attributes={:type=>"validation", :message=>"Code 'iexistalready' already exists", :params=>[{"param"=>"code", "message"=>"'iexistalready' already exists"}]}>
243
+ puts ex.status_code
244
+ #=> 422
245
+ rescue Recurly::Errors::TimeoutError => ex
246
+ # catch a specific server error
247
+ rescue Recurly::Errors::ServerError => ex
248
+ # catch a generic server error
249
+ rescue Recurly::Errors::APIError => ex
250
+ # catch a generic api error
251
+ end
252
+ ```
253
+
254
+ `Recurly::Errors::APIError` instances provide access to the response via the `#get_response` method.
255
+
256
+ # HTTP Metadata
257
+
258
+ Sometimes you might want to get some additional information about the underlying HTTP request and response. Instead of
259
+ returning this information directly and forcing the programmer to unwrap it, we inject this metadata into the top level
260
+ resource that was returned. You can access the {Recurly::HTTP::Response} by calling `#get_response` on any {Recurly::Resource}.
261
+
262
+ **Warning**: Do not log or render whole requests or responses as they may contain PII or sensitive data.
263
+
264
+ ```ruby
265
+ account = @client.get_account(account_id: "code-benjamin")
266
+ response = account.get_response
267
+ response.rate_limit_remaining #=> 1985
268
+ response.request_id #=> "0av50sm5l2n2gkf88ehg"
269
+ response.request.path #=> "/sites/subdomain-mysite/accounts/code-benjamin"
270
+ response.request.body #=> None
271
+ ```
272
+
273
+ This also works on {Recurly::Resources::Empty} responses:
274
+
275
+ ```ruby
276
+ response = @client.remove_line_item(
277
+ line_item_id: "a959576b2b10b012"
278
+ ).get_response
279
+ ```
280
+ And it can be captured on exceptions through the {Recurly::APIError} object:
281
+
282
+ ```ruby
283
+ begin
284
+ account = client.get_account(account_id: "code-benjamin")
285
+ rescue Recurly::Errors::NotFoundError => e
286
+ response = e.get_response()
287
+ puts "Give this request id to Recurly Support: #{response.request_id}"
288
+ end
289
+ ```
290
+
291
+ # Webhooks
292
+
293
+ Recurly can send webhooks to any publicly accessible server.
294
+ When an event in Recurly triggers a webhook (e.g., an account is opened),
295
+ Recurly will attempt to send this notification to the endpoint(s) you specify.
296
+ You can specify up to 10 endpoints through the application. All notifications will
297
+ be sent to all configured endpoints for your site.
298
+
299
+ See our [product docs](https://docs.recurly.com/docs/webhooks) to learn more about webhooks
300
+ and see our [dev docs](https://developers.recurly.com/pages/webhooks.html) to learn about what payloads
301
+ are available.
302
+
303
+ Although our API is now JSON, our webhook payloads are still formatted as XML for the time being.
304
+ This library is not yet responsible for handling webhooks. If you do need webhooks, we recommend using a simple
305
+ XML to Hash parser.
306
+
307
+ If you are using Rails, we'd recommend [Hash.from_xml](https://apidock.com/rails/Hash/from_xml/class).
308
+
309
+ ```ruby
310
+ notification = Hash.from_xml <<-XML
311
+ <?xml version="1.0" encoding="UTF-8"?>
312
+ <new_account_notification>
313
+ <account>
314
+ <account_code>1</account_code>
315
+ <username nil="true"></username>
316
+ <email>verena@example.com</email>
317
+ <first_name>Verena</first_name>
318
+ <last_name>Example</last_name>
319
+ <company_name nil="true"></company_name>
320
+ </account>
321
+ </new_account_notification>
322
+ XML
323
+
324
+ code = notification["new_account_notification"]["account"]["account_code"]
325
+ puts "New Account with code #{code} created."
326
+ ```
327
+
328
+ If you are not using Rails, we recommend you use [nokogiri](https://nokogiri.org/); however, heed security warnings
329
+ about parse options. Although the XML should only be coming from Recurly, you should parse it as untrusted to be safe.
330
+ Read more about the security implications of parsing untrusted XML in [this OWASP cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_Security_Cheat_Sheet.html).
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in recurly.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Recurly Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md CHANGED
@@ -1,156 +1,17 @@
1
- # Recurly [![Build Status](https://secure.travis-ci.org/recurly/recurly-client-ruby.png?branch=master)](http://travis-ci.org/recurly/recurly-client-ruby) [![Gem Version](https://badge.fury.io/rb/recurly.svg)](http://badge.fury.io/rb/recurly)
1
+ # Recurly
2
2
 
3
- <https://github.com/recurly/recurly-client-ruby>
3
+ [![Rubygems](https://img.shields.io/static/v1?label=rubygems&message=recurly&color=purple)](https://rubygems.org/gems/recurly)
4
+ [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v2.0%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md)
4
5
 
5
- [Recurly](https://recurly.com/)'s Ruby client library is an interface to its
6
- [REST API](https://dev.recurly.com/docs/getting-started).
6
+ This repository houses the official ruby client for Recurly's V3 API.
7
7
 
8
- You can also look at [rubydocs](http://www.rubydoc.info/github/recurly/recurly-client-ruby/master)
9
- to see documentation on the classes and methods available.
8
+ > *Note*:
9
+ > If you were looking for the V2 client, see the [v2 branch](https://github.com/recurly/recurly-client-ruby/tree/v2).
10
10
 
11
- ## Installation
11
+ ## Reference Documentation
12
12
 
13
- Recurly is packaged as a Ruby gem. We recommend you install it with
14
- [Bundler](http://gembundler.com/) by adding the following line to your Gemfile:
15
-
16
- ``` ruby
17
- gem 'recurly', '~> 2.17'
18
- ```
19
-
20
- Recurly will automatically use [Nokogiri](http://nokogiri.org/) (for a nice
21
- speed boost) if it's available and loaded in your app's environment.
22
-
23
- ## Configuration
24
-
25
- Use the following template to configure Recurly:
26
-
27
- ``` ruby
28
- Recurly.subdomain = ENV['RECURLY_SUBDOMAIN']
29
- Recurly.api_key = ENV['RECURLY_API_KEY']
30
- ```
31
-
32
- > Note: In Rails, these would be added in an initializer `config/initializers/recurly.rb`.
33
-
34
- Configure the client library with
35
- [your API credentials](https://app.recurly.com/go/developer/api_access).
36
-
37
- * `RECURLY_SUBDOMAIN` should contain subdomain for your recurly account.
38
- * `RECURLY_API_KEY` is your "Private API Key" which can be found under "API Credentials" on the `api_access` admin page.
39
-
40
- The default currency is USD. To override with a different code:
41
-
42
- ``` ruby
43
- Recurly.default_currency = 'EUR' # Assign nil to disable the default entirely.
44
- ```
45
-
46
- If you are using [Recurly.js](https://js.recurly.com) you can store "Public API Key" (which can be found
47
- under "API Credentials" on the `api_access` admin page):
48
-
49
- ``` ruby
50
- Recurly.js.public_key = ENV['RECURLY_PUBLIC_API_KEY']
51
- ```
52
-
53
- Then, in your Rails project you can create `recurly_service.js.erb` file and
54
- [configure](https://docs.recurly.com/js/#configure) recurly.js with public key this way:
55
-
56
- ``` js
57
- recurly.configure({ publicKey: '<%= Recurly.js.public_key %>'});
58
- ```
59
-
60
- The client library currently uses a Net::HTTP adapter. If you need to
61
- configure the settings passed to Net::HTTP (e.g., an SSL certificates path or timeout lengths),
62
- make sure you assign them when initializing the library:
63
-
64
- ``` ruby
65
- Recurly::API.net_http = {
66
- ca_path: "/etc/ssl/certs",
67
- open_timeout: 5, # 5 seconds (defaults to 60)
68
- read_timeout: 45 # 45 seconds (defaults to 60)
69
- }
70
- ```
71
-
72
- To see which keys are supported for this Hash, see the `Attributes` section
73
- of the [Net::HTTP documentation](http://ruby-doc.org/stdlib-2.4.1/libdoc/net/http/rdoc/Net/HTTP.html) for your ruby version.
74
-
75
- ## Multi-Threaded Configuration
76
- If you are using the client in a multi-threaded environment and require a different configuration per
77
- thread you can use the following within the thread's context:
78
-
79
- ``` ruby
80
- Recurly.config({
81
- subdomain: ENV['RECURLY_SUBDOMAIN']
82
- api_key: ENV['RECURLY_API_KEY'],
83
- default_currency: "US"
84
- })
85
- ```
86
-
87
- Any configuration items you do not include in the above config call will be defaulted to the standard
88
- configuration items. For example if you do not define default_currency then Recurly.default_currency
89
- will be used.
90
-
91
- ## Supported Ruby Versions
92
-
93
- We are currently supporting ruby language versions `2.3` and above. `1.9`, `2.0`, `2.1`, and `2.2` may still work but are not officially supported.
94
-
95
- If you are still using one of these rubies, you should know that support for them ended in
96
- 2015 (1.9), 2016 (2.0), 2017 (2.1), 2018 (2.2) and continuing to use them is a security risk.
97
-
98
- - https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/
99
- - https://www.ruby-lang.org/en/news/2016/02/24/support-plan-of-ruby-2-0-0-and-2-1/
100
- - https://www.ruby-lang.org/en/news/2017/04/01/support-of-ruby-2-1-has-ended/
101
- - https://www.ruby-lang.org/en/news/2018/06/20/support-of-ruby-2-2-has-ended/
102
-
103
- ## Nokogiri Support
104
-
105
- For now, we are still running the tests on 2.0 and below but without `nokogiri` and only `rexml`. Nokogiri is
106
- no longer supported on 1.9 or 2.0 and has patched known vulnerabilities since dropping support.
107
- If you must run one of these rubies (this includes jruby1.7), you must use rexml and not nokogiri.
108
-
109
- ## Usage
110
-
111
- Instructions and examples are available on
112
- [Recurly's documentation site](https://dev.recurly.com/docs/getting-started).
113
-
114
- Recurly's gem API is available
115
- [here](http://rubydoc.info/gems/recurly/frames/Recurly).
116
-
117
- ## Support
118
-
119
- - [https://support.recurly.com](https://support.recurly.com)
120
- - [stackoverflow](http://stackoverflow.com/questions/tagged/recurly)
13
+ Getting Started Guide and reference documentation can be found on [Github Pages](https://recurly.github.io/recurly-client-ruby/).
121
14
 
122
15
  ## Contributing
123
16
 
124
- Developing for the Recurly gem is easy with [Bundler](http://gembundler.com/).
125
-
126
- Fork and clone the repository, `cd` into the directory, and, with a Ruby of your choice
127
- (1.9.3 or greater), set up your environment.
128
-
129
- If you don't have Bundler installed, install it with the following command:
130
-
131
- ``` bash
132
- $ [sudo] gem install bundler
133
- ```
134
-
135
- And bundle:
136
-
137
- ``` bash
138
- $ bundle --path=vendor/bundle
139
- ```
140
-
141
- You should now be able to run the test suite with Rake:
142
-
143
- ``` bash
144
- $ bundle exec rake
145
- ```
146
-
147
- To run the suite using Nokogiri:
148
-
149
- ``` bash
150
- $ XML=nokogiri bundle exec rake
151
- ```
152
-
153
- If you plan on submitting a patch, please write tests for it (we use
154
- [MiniTest::Spec](http://bfts.rubyforge.org/minitest/MiniTest/Expectations.html)).
155
-
156
- If everything looks good, submit a pull request on GitHub and we'll bring in your changes.
17
+ Please see our [Contributing Guide](CONTRIBUTING.md).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/benchmark.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "rubygems"
2
+ require "bundler/setup"
3
+ require "recurly"
4
+ require "benchmark"
5
+
6
+ N = 1_000
7
+
8
+ account_body = "{\"id\":\"ljvmmbjchtgs\",\"object\":\"account\",\"code\":\"9ebd49f7288@example.com\",\"parent_account_id\":null,\"bill_to\":\"self\",\"state\":\"active\",\"username\":null,\"email\":null,\"cc_emails\":null,\"preferred_locale\":null,\"first_name\":\"Benjamin\",\"last_name\":\"Du Monde\",\"company\":null,\"vat_number\":null,\"tax_exempt\":false,\"exemption_certificate\":null,\"address\":null,\"billing_info\":null,\"shipping_addresses\":[{\"object\":\"shipping_address\",\"first_name\":\"Benjamin\",\"last_name\":\"Du Monde\",\"company\":null,\"phone\":null,\"street1\":\"1 Tchoupitoulas St\",\"street2\":null,\"city\":\"New Orleans\",\"region\":\"LA\",\"postal_code\":\"70115\",\"country\":\"US\",\"nickname\":\"Home\",\"email\":null,\"vat_number\":null,\"id\":\"ljvmmbk9e1as\",\"account_id\":\"ljvmmbjchtgs\",\"created_at\":\"2019-09-19T22:45:59Z\",\"updated_at\":\"2019-09-19T22:45:59Z\"}],\"custom_fields\":[],\"hosted_login_token\":\"PSvcHow5H4HGEGKTfHXadLNoDcRaDVMK\",\"created_at\":\"2019-09-19T22:45:59Z\",\"updated_at\":\"2019-09-19T22:45:59Z\",\"deleted_at\":null}"
9
+
10
+ Benchmark.bm do |benchmark|
11
+ benchmark.report("JSON parsing and casting\n") do
12
+ N.times do
13
+ _account = Recurly::JSONParser.parse(nil, account_body)
14
+ end
15
+ end
16
+ end