gecko-ruby 0.9.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
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