gecko-ruby 0.9.0 → 0.12.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/config/rubocop_linter_action.yml +7 -0
  3. data/.github/workflows/testing.yml +26 -0
  4. data/.rubocop.yml +23 -16
  5. data/CHANGELOG.md +18 -0
  6. data/Gemfile +2 -0
  7. data/README.md +1 -1
  8. data/Rakefile +3 -1
  9. data/gecko-ruby.gemspec +11 -10
  10. data/generate.thor +4 -1
  11. data/lib/gecko-ruby.rb +2 -0
  12. data/lib/gecko.rb +2 -0
  13. data/lib/gecko/client.rb +16 -14
  14. data/lib/gecko/ext/liquid_compat.rb +11 -9
  15. data/lib/gecko/ext/log_subscriber.rb +6 -6
  16. data/lib/gecko/helpers/association_helper.rb +14 -12
  17. data/lib/gecko/helpers/inspection_helper.rb +4 -2
  18. data/lib/gecko/helpers/record_helper.rb +2 -0
  19. data/lib/gecko/helpers/serialization_helper.rb +5 -1
  20. data/lib/gecko/helpers/validation_helper.rb +3 -1
  21. data/lib/gecko/record/account.rb +3 -1
  22. data/lib/gecko/record/address.rb +2 -0
  23. data/lib/gecko/record/base.rb +5 -3
  24. data/lib/gecko/record/base_adapter.rb +33 -22
  25. data/lib/gecko/record/company.rb +2 -0
  26. data/lib/gecko/record/contact.rb +2 -0
  27. data/lib/gecko/record/currency.rb +2 -0
  28. data/lib/gecko/record/exceptions.rb +2 -0
  29. data/lib/gecko/record/fulfillment.rb +2 -0
  30. data/lib/gecko/record/fulfillment_line_item.rb +2 -1
  31. data/lib/gecko/record/image.rb +13 -8
  32. data/lib/gecko/record/invoice.rb +7 -3
  33. data/lib/gecko/record/invoice_line_item.rb +2 -1
  34. data/lib/gecko/record/location.rb +2 -0
  35. data/lib/gecko/record/note.rb +2 -0
  36. data/lib/gecko/record/order.rb +2 -0
  37. data/lib/gecko/record/order_line_item.rb +3 -0
  38. data/lib/gecko/record/payment_term.rb +2 -1
  39. data/lib/gecko/record/product.rb +4 -0
  40. data/lib/gecko/record/purchase_order.rb +2 -1
  41. data/lib/gecko/record/purchase_order_line_item.rb +2 -1
  42. data/lib/gecko/record/tax_type.rb +2 -1
  43. data/lib/gecko/record/user.rb +3 -1
  44. data/lib/gecko/record/variant.rb +9 -7
  45. data/lib/gecko/record/webhook.rb +3 -1
  46. data/lib/gecko/version.rb +3 -1
  47. data/test/client_test.rb +4 -2
  48. data/test/fixtures/vcr_cassettes/images.yml +1 -1
  49. data/test/gecko_test.rb +2 -0
  50. data/test/helpers/association_helper_test.rb +7 -5
  51. data/test/helpers/inspection_helper_test.rb +6 -4
  52. data/test/helpers/serialization_helper_test.rb +16 -14
  53. data/test/helpers/validation_helper_test.rb +3 -1
  54. data/test/record/account_adapter_test.rb +2 -0
  55. data/test/record/address_adapter_test.rb +2 -0
  56. data/test/record/address_test.rb +2 -0
  57. data/test/record/company_adapter_test.rb +2 -0
  58. data/test/record/company_test.rb +2 -0
  59. data/test/record/contact_adapter_test.rb +2 -0
  60. data/test/record/contact_test.rb +3 -1
  61. data/test/record/currency_adapter_test.rb +2 -0
  62. data/test/record/currency_test.rb +2 -0
  63. data/test/record/fulfillment_adapter_test.rb +2 -0
  64. data/test/record/fulfillment_line_item_adapter_test.rb +2 -0
  65. data/test/record/fulfillment_line_item_test.rb +2 -0
  66. data/test/record/fulfillment_test.rb +4 -2
  67. data/test/record/image_adapter_test.rb +2 -0
  68. data/test/record/image_test.rb +18 -0
  69. data/test/record/invoice_adapter_test.rb +2 -0
  70. data/test/record/invoice_line_item_adapter_test.rb +2 -0
  71. data/test/record/invoice_line_item_test.rb +2 -0
  72. data/test/record/invoice_test.rb +2 -0
  73. data/test/record/location_adapter_test.rb +2 -0
  74. data/test/record/location_test.rb +2 -0
  75. data/test/record/note_test.rb +2 -0
  76. data/test/record/order_adapter_test.rb +2 -0
  77. data/test/record/order_line_item_adapter_test.rb +2 -0
  78. data/test/record/order_line_item_test.rb +2 -0
  79. data/test/record/order_test.rb +2 -0
  80. data/test/record/payment_term_adapter_test.rb +2 -0
  81. data/test/record/payment_term_test.rb +2 -0
  82. data/test/record/product_adapter_test.rb +2 -0
  83. data/test/record/product_test.rb +2 -0
  84. data/test/record/purchase_order_adapter_test.rb +2 -0
  85. data/test/record/purchase_order_line_item_adapter_test.rb +2 -0
  86. data/test/record/purchase_order_line_item_test.rb +2 -0
  87. data/test/record/purchase_order_test.rb +2 -0
  88. data/test/record/tax_type_adapter_test.rb +2 -0
  89. data/test/record/tax_type_test.rb +2 -0
  90. data/test/record/user_adapter_test.rb +2 -0
  91. data/test/record/user_test.rb +2 -0
  92. data/test/record/variant_adapter_test.rb +2 -0
  93. data/test/record/variant_test.rb +6 -4
  94. data/test/record/webhook_test.rb +2 -0
  95. data/test/support/let.rb +2 -0
  96. data/test/support/shared_adapter_examples.rb +35 -31
  97. data/test/support/shared_record_examples.rb +3 -1
  98. data/test/support/shared_sideloaded_data_parsing_examples.rb +2 -1
  99. data/test/support/testing_adapter.rb +2 -0
  100. data/test/support/vcr_support.rb +2 -0
  101. data/test/test_helper.rb +2 -0
  102. metadata +24 -23
  103. data/.travis.yml +0 -8
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gecko
2
4
  module Helpers
3
5
  # Provides serialization to records
@@ -28,6 +30,7 @@ module Gecko
28
30
  attribute_hash = {}
29
31
  attribute_set.each do |attribute|
30
32
  next unless writeable?(attribute)
33
+
31
34
  serialize_attribute(attribute_hash, attribute)
32
35
  end
33
36
 
@@ -46,6 +49,7 @@ module Gecko
46
49
  def writeable?(attribute)
47
50
  return if attribute.options[:readonly]
48
51
  return true unless attribute.options[:writeable_on]
52
+
49
53
  case attribute.options[:writeable_on]
50
54
  when :update
51
55
  persisted?
@@ -75,7 +79,7 @@ module Gecko
75
79
  # @return [String]
76
80
  #
77
81
  # @api private
78
- def _serialize(serialized)
82
+ def _serialize(serialized) # rubocop:disable Metrics/MethodLength
79
83
  if serialized.respond_to?(:serializable_hash)
80
84
  serialized.serializable_hash
81
85
  else
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gecko
2
4
  module Helpers
3
5
  # Provides record validation
@@ -71,7 +73,7 @@ module Gecko
71
73
  #
72
74
  # @api public
73
75
  def empty?
74
- messages.all? { |k, v| v && v.empty? && !v.is_a?(String) }
76
+ messages.all? { |_k, v| v&.empty? && !v.is_a?(String) }
75
77
  end
76
78
 
77
79
  # Parse JSON errors response into the error object
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -52,7 +54,7 @@ module Gecko
52
54
  #
53
55
  # @api public
54
56
  def current
55
- if self.has_record_for_id?(:current)
57
+ if has_record_for_id?(:current)
56
58
  record_for_id(:current)
57
59
  else
58
60
  @identity_map[:current] = find(:current)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/helpers/association_helper'
2
4
  require 'gecko/helpers/inspection_helper'
3
5
  require 'gecko/helpers/serialization_helper'
@@ -24,9 +26,9 @@ module Gecko
24
26
  # @return [undefined]
25
27
  #
26
28
  # @api private
27
- def initialize(client, attributes={})
29
+ def initialize(client, attributes = {})
28
30
  super(attributes)
29
- @client = client
31
+ @client = client
30
32
  end
31
33
 
32
34
  # Whether the record has been persisted
@@ -62,7 +64,7 @@ module Gecko
62
64
  #
63
65
  # @api private
64
66
  def self.demodulized_name
65
- self.name.split('::').last
67
+ name.split('::').last
66
68
  end
67
69
  end
68
70
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gecko
2
4
  module Record
3
5
  class BaseAdapter
@@ -108,8 +110,8 @@ module Gecko
108
110
  # @return [Array<Gecko::Record::Base>] Records via the API
109
111
  #
110
112
  # @api public
111
- def where(params={})
112
- response = @last_response = request(:get, plural_path, params: params)
113
+ def where(params = {})
114
+ response = request(:get, plural_path, params: params)
113
115
  parsed_response = response.parsed
114
116
  set_pagination(response.headers)
115
117
  parse_records(parsed_response)
@@ -149,14 +151,14 @@ module Gecko
149
151
  # @return <Gecko::Record::Base> A record instance
150
152
  #
151
153
  # @api public
152
- def first(params={})
154
+ def first(params = {})
153
155
  where(params.merge(limit: 1)).first
154
156
  end
155
157
 
156
158
  # Fetch the forty-second record for the given parameters
157
159
  #
158
160
  # @api public
159
- def forty_two(params={})
161
+ def forty_two(params = {})
160
162
  where(params.merge(limit: 1, page: 42)).first
161
163
  end
162
164
 
@@ -171,7 +173,7 @@ module Gecko
171
173
  #
172
174
  # @api public
173
175
  def count(params = {})
174
- self.where(params.merge(limit: 0))
176
+ where(params.merge(limit: 0))
175
177
  @pagination['total_records']
176
178
  end
177
179
 
@@ -199,13 +201,13 @@ module Gecko
199
201
  # @return [nil] if no record was found
200
202
  #
201
203
  # @api private
202
- def fetch(id)
204
+ def fetch(id) # rubocop:disable Metrics/MethodLength
203
205
  verify_id_presence!(id)
204
- response = @last_response = request(:get, plural_path + '/' + id.to_s)
206
+ response = request(:get, plural_path + '/' + id.to_s)
205
207
  record_json = extract_record(response.parsed)
206
208
  instantiate_and_register_record(record_json)
207
- rescue OAuth2::Error => ex
208
- case ex.response.status
209
+ rescue OAuth2::Error => e
210
+ case e.response.status
209
211
  when 404
210
212
  record_not_found!(id)
211
213
  else
@@ -257,7 +259,7 @@ module Gecko
257
259
  # @return [Gecko::Record::Base]
258
260
  #
259
261
  # @api public
260
- def build(attributes={})
262
+ def build(attributes = {})
261
263
  model_class.new(@client, attributes)
262
264
  end
263
265
 
@@ -342,7 +344,7 @@ module Gecko
342
344
  # @api private
343
345
  def create_record(record, opts = {})
344
346
  response = request(:post, plural_path, {
345
- body: record.as_json,
347
+ body: record.as_json,
346
348
  raise_errors: false
347
349
  }.merge(headers: headers_from_opts(opts)))
348
350
  handle_response(record, response)
@@ -355,7 +357,7 @@ module Gecko
355
357
  # @api private
356
358
  def update_record(record, opts = {})
357
359
  response = request(:put, plural_path + "/" + record.id.to_s, {
358
- body: record.as_json,
360
+ body: record.as_json,
359
361
  raise_errors: false
360
362
  }.merge(headers: headers_from_opts(opts)))
361
363
  handle_response(record, response)
@@ -368,10 +370,10 @@ module Gecko
368
370
  # @return [OAuth2::Response]
369
371
  #
370
372
  # @api private
371
- def handle_response(record, response)
373
+ def handle_response(record, response) # rubocop:disable Metrics/MethodLength
372
374
  case response.status
373
375
  when 200..299
374
- if response_json = extract_record(response.parsed)
376
+ if (response_json = extract_record(response.parsed))
375
377
  record.attributes = response_json
376
378
  register_record(record)
377
379
  end
@@ -380,7 +382,7 @@ module Gecko
380
382
  record.errors.from_response(response.parsed['errors'])
381
383
  false
382
384
  else
383
- fail OAuth2::Error.new(response)
385
+ fail OAuth2::Error, response
384
386
  end
385
387
  end
386
388
 
@@ -410,6 +412,7 @@ module Gecko
410
412
 
411
413
  record_class = record_type.singularize.classify
412
414
  next unless Gecko::Record.const_defined?(record_class)
415
+
413
416
  adapter = @client.adapter_for(record_class)
414
417
 
415
418
  records.each do |record_json|
@@ -428,16 +431,24 @@ module Gecko
428
431
  # @return [OAuth2::Response]
429
432
  #
430
433
  # @api private
431
- def request(verb, path, options={})
434
+ def request(verb, path, options = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
432
435
  ActiveSupport::Notifications.instrument('request.gecko') do |payload|
433
436
  payload[:verb] = verb
434
437
  payload[:params] = options[:params]
435
438
  payload[:body] = options[:body]
436
439
  payload[:model_class] = model_class
437
440
  payload[:request_path] = path
438
- options[:headers] = options.fetch(:headers, {}).tap { |headers| headers['Content-Type'] = 'application/json' }
439
- options[:body] = options[:body].to_json if options[:body]
440
- payload[:response] = @client.access_token.request(verb, path, options)
441
+
442
+ options[:headers] = options.fetch(:headers, {}).tap do |headers|
443
+ headers['Content-Type'] = 'application/json'
444
+ end
445
+
446
+ options[:body] = options[:body].to_json if options[:body]
447
+
448
+ @client.access_token.request(verb, path, options.merge(raise_errors: false)).tap do |response|
449
+ payload[:response] = @last_response = response
450
+ raise response.error if response.error && options[:raise_errors] != false
451
+ end
441
452
  end
442
453
  end
443
454
 
@@ -450,9 +461,9 @@ module Gecko
450
461
  end
451
462
 
452
463
  def verify_id_presence!(id)
453
- if id.respond_to?(:empty?) ? id.empty? : !id
454
- fail RecordNotFound, "Couldn't find #{model_class.name} without an ID"
455
- end
464
+ return unless id.respond_to?(:empty?) ? id.empty? : !id
465
+
466
+ fail RecordNotFound, "Couldn't find #{model_class.name} without an ID"
456
467
  end
457
468
  end
458
469
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gecko
2
4
  module Record
3
5
  # Generic Gecko::Record exception class.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
  require 'gecko/record/fulfillment_line_item'
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -13,7 +15,6 @@ module Gecko
13
15
  end
14
16
 
15
17
  class FulfillmentLineItemAdapter < BaseAdapter
16
-
17
18
  end
18
19
  end
19
20
  end
@@ -1,12 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
4
6
  module Record
5
7
  class Image < Base
6
- AVAILABLE_SIZES = [:full, :thumbnail]
8
+ AVAILABLE_SIZES = %i[full thumbnail].freeze
9
+
10
+ belongs_to :uploader, class_name: "User", readonly: true
11
+
12
+ belongs_to :product, writeable_on: :create
13
+ has_many :variants, writeable_on: :create, readonly: false
7
14
 
8
- belongs_to :variant
9
- belongs_to :uploader, class_name: "User", readonly: true
10
15
  attribute :name, String
11
16
  attribute :url, String
12
17
  attribute :position, Integer, readonly: true
@@ -31,11 +36,11 @@ module Gecko
31
36
  private
32
37
 
33
38
  def build_url(size)
34
- if size == :full
35
- file_path = file_name
36
- else
37
- file_path = "#{size}_#{file_name}"
38
- end
39
+ file_path = if size == :full
40
+ file_name
41
+ else
42
+ "#{size}_#{file_name}"
43
+ end
39
44
  [base_path, file_path].join("/")
40
45
  end
41
46
  end
@@ -1,16 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
4
6
  module Record
5
7
  class Invoice < Base
6
8
  belongs_to :order, writeable_on: :create
7
- belongs_to :shipping_address
8
- belongs_to :billing_address
9
+ belongs_to :shipping_address, class_name: 'Address'
10
+ belongs_to :billing_address, class_name: 'Address'
9
11
  belongs_to :payment_term
12
+ belongs_to :company, readonly: true
13
+ belongs_to :currency, readonly: true
10
14
 
11
15
  has_many :invoice_line_items, embedded: true
12
16
 
13
17
  attribute :invoice_number, String
18
+ attribute :order_number, String, readonly: true
14
19
  attribute :invoiced_at, Date
15
20
  attribute :due_at, Date
16
21
  attribute :notes, String
@@ -23,7 +28,6 @@ module Gecko
23
28
  end
24
29
 
25
30
  class InvoiceAdapter < BaseAdapter
26
-
27
31
  end
28
32
  end
29
33
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -13,7 +15,6 @@ module Gecko
13
15
  end
14
16
 
15
17
  class InvoiceLineItemAdapter < BaseAdapter
16
-
17
18
  end
18
19
  end
19
20
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -39,6 +41,7 @@ module Gecko
39
41
 
40
42
  def discount_multiplier
41
43
  return 1 unless discount
44
+
42
45
  1 - discount / 100
43
46
  end
44
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -10,7 +12,6 @@ module Gecko
10
12
  end
11
13
 
12
14
  class PaymentTermAdapter < BaseAdapter
13
-
14
15
  end
15
16
  end
16
17
  end
@@ -1,9 +1,13 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
4
6
  module Record
5
7
  class Product < Base
6
8
  has_many :variants
9
+ has_many :images
10
+
7
11
  attribute :name, String
8
12
  attribute :description, String
9
13
  attribute :product_type, String
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'gecko/record/base'
2
4
 
3
5
  module Gecko
@@ -38,7 +40,6 @@ module Gecko
38
40
  end
39
41
 
40
42
  class PurchaseOrderAdapter < BaseAdapter
41
-
42
43
  end
43
44
  end
44
45
  end