gandi_v5 0.2.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.rubocop.yml +13 -3
  4. data/.travis.yml +15 -1
  5. data/CHANGELOG.md +63 -0
  6. data/FUNDING.yml +10 -0
  7. data/LICENSE.md +2 -6
  8. data/README.md +16 -21
  9. data/gandi_v5.gemspec +3 -2
  10. data/lib/gandi_v5.rb +64 -24
  11. data/lib/gandi_v5/billing.rb +0 -2
  12. data/lib/gandi_v5/billing/info.rb +0 -2
  13. data/lib/gandi_v5/data.rb +1 -4
  14. data/lib/gandi_v5/data/converter.rb +0 -4
  15. data/lib/gandi_v5/data/converter/integer.rb +26 -0
  16. data/lib/gandi_v5/domain.rb +167 -28
  17. data/lib/gandi_v5/domain/availability.rb +0 -3
  18. data/lib/gandi_v5/domain/availability/product.rb +0 -3
  19. data/lib/gandi_v5/domain/live_dns.rb +42 -0
  20. data/lib/gandi_v5/domain/renewal_information.rb +0 -3
  21. data/lib/gandi_v5/domain/sharing_space.rb +10 -2
  22. data/lib/gandi_v5/email.rb +0 -4
  23. data/lib/gandi_v5/email/forward.rb +102 -0
  24. data/lib/gandi_v5/email/mailbox.rb +57 -13
  25. data/lib/gandi_v5/email/slot.rb +11 -3
  26. data/lib/gandi_v5/error.rb +0 -2
  27. data/lib/gandi_v5/live_dns.rb +0 -16
  28. data/lib/gandi_v5/live_dns/domain.rb +221 -80
  29. data/lib/gandi_v5/live_dns/domain/dnssec_key.rb +115 -0
  30. data/lib/gandi_v5/live_dns/domain/record.rb +81 -0
  31. data/lib/gandi_v5/live_dns/domain/snapshot.rb +107 -0
  32. data/lib/gandi_v5/live_dns/domain/tsig_key.rb +71 -0
  33. data/lib/gandi_v5/organization.rb +38 -5
  34. data/lib/gandi_v5/organization/customer.rb +90 -0
  35. data/lib/gandi_v5/version.rb +1 -1
  36. data/spec/.rubocop.yml +9 -2
  37. data/spec/fixtures/bodies/GandiV5_Billing/{info.yaml → info.yml} +0 -0
  38. data/spec/fixtures/bodies/GandiV5_Domain/{get.yaml → fetch.yml} +8 -0
  39. data/spec/fixtures/bodies/GandiV5_Domain/{fetch_contacts.yaml → fetch_contacts.yml} +0 -0
  40. data/spec/fixtures/bodies/GandiV5_Domain/fetch_glue_records.yml +7 -0
  41. data/spec/fixtures/bodies/GandiV5_Domain/fetch_livedns.yml +6 -0
  42. data/spec/fixtures/bodies/GandiV5_Domain/fetch_name_servers.yml +2 -0
  43. data/spec/fixtures/bodies/GandiV5_Domain/{renewal_info.yaml → fetch_renewal_info.yml} +0 -3
  44. data/spec/fixtures/bodies/GandiV5_Domain/{restore_info.yaml → fetch_restore_info.yml} +0 -0
  45. data/spec/fixtures/bodies/GandiV5_Domain/{list.yaml → list.yml} +1 -0
  46. data/spec/fixtures/bodies/GandiV5_Domain_Availability/{fetch.yaml → fetch.yml} +0 -0
  47. data/spec/fixtures/bodies/GandiV5_Domain_TLD/{fetch.yaml → fetch.yml} +0 -0
  48. data/spec/fixtures/bodies/GandiV5_Domain_TLD/{list.yaml → list.yml} +0 -0
  49. data/spec/fixtures/bodies/GandiV5_Email_Forward/list.yml +6 -0
  50. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/{get.yaml → fetch.yml} +0 -0
  51. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/{list.yaml → list.yml} +0 -0
  52. data/spec/fixtures/bodies/GandiV5_Email_Slot/{get.yaml → fetch.yml} +0 -0
  53. data/spec/fixtures/bodies/GandiV5_Email_Slot/{list.yaml → list.yml} +0 -0
  54. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/fetch.yml +3 -0
  55. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/{list.yaml → list.yml} +0 -0
  56. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list_tsig.yml +3 -0
  57. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/nameservers.yml +3 -0
  58. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/fetch.yml +12 -0
  59. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/list.yml +9 -0
  60. data/spec/fixtures/bodies/{GandiV5_LiveDNS_Zone_Snapshot/fetch.yaml → GandiV5_LiveDNS_Domain_Snapshot/fetch.yml} +4 -3
  61. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_Snapshot/list.yml +5 -0
  62. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/fetch.yml +9 -0
  63. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/list.yml +4 -0
  64. data/spec/fixtures/bodies/GandiV5_Organization/{get.yaml → fetch.yml} +0 -0
  65. data/spec/fixtures/bodies/GandiV5_Organization/list.yml +7 -0
  66. data/spec/fixtures/bodies/GandiV5_Organization_Customer/list.yml +8 -0
  67. data/spec/spec_helper.rb +2 -2
  68. data/spec/units/gandi_v5/billing_spec.rb +2 -2
  69. data/spec/units/gandi_v5/data/converter/integer_spec.rb +16 -0
  70. data/spec/units/gandi_v5/domain/availability_spec.rb +1 -1
  71. data/spec/units/gandi_v5/domain/live_dns_spec.rb +45 -0
  72. data/spec/units/gandi_v5/domain/tld_spec.rb +2 -2
  73. data/spec/units/gandi_v5/domain_spec.rb +294 -65
  74. data/spec/units/gandi_v5/email/forward_spec.rb +92 -0
  75. data/spec/units/gandi_v5/email/mailbox_spec.rb +122 -40
  76. data/spec/units/gandi_v5/email/slot_spec.rb +13 -5
  77. data/spec/units/gandi_v5/live_dns/domain/dnssec_key_spec.rb +128 -0
  78. data/spec/units/gandi_v5/live_dns/{record_set_spec.rb → domain/record_spec.rb} +1 -1
  79. data/spec/units/gandi_v5/live_dns/domain/snapshot_spec.rb +101 -0
  80. data/spec/units/gandi_v5/live_dns/domain/tsig_key_spec.rb +78 -0
  81. data/spec/units/gandi_v5/live_dns/domain_spec.rb +299 -120
  82. data/spec/units/gandi_v5/live_dns_spec.rb +0 -12
  83. data/spec/units/gandi_v5/organization/customer_spec.rb +81 -0
  84. data/spec/units/gandi_v5/organization_spec.rb +52 -1
  85. data/spec/units/gandi_v5_spec.rb +139 -30
  86. metadata +68 -95
  87. data/doc/GandiV5.html +0 -1183
  88. data/doc/GandiV5/Billing.html +0 -293
  89. data/doc/GandiV5/Billing/Info.html +0 -641
  90. data/doc/GandiV5/Billing/Info/Prepaid.html +0 -817
  91. data/doc/GandiV5/Data.html +0 -785
  92. data/doc/GandiV5/Data/ClassMethods.html +0 -223
  93. data/doc/GandiV5/Data/Converter.html +0 -433
  94. data/doc/GandiV5/Data/Converter/ArrayOf.html +0 -413
  95. data/doc/GandiV5/Data/Converter/Symbol.html +0 -322
  96. data/doc/GandiV5/Data/Converter/Time.html +0 -330
  97. data/doc/GandiV5/Domain.html +0 -16847
  98. data/doc/GandiV5/Domain/AutoRenew.html +0 -1237
  99. data/doc/GandiV5/Domain/Availability.html +0 -1020
  100. data/doc/GandiV5/Domain/Availability/Product.html +0 -988
  101. data/doc/GandiV5/Domain/Availability/Product/Period.html +0 -220
  102. data/doc/GandiV5/Domain/Availability/Product/Price.html +0 -1031
  103. data/doc/GandiV5/Domain/Availability/Tax.html +0 -440
  104. data/doc/GandiV5/Domain/Contact.html +0 -4459
  105. data/doc/GandiV5/Domain/Contract.html +0 -520
  106. data/doc/GandiV5/Domain/Dates.html +0 -1313
  107. data/doc/GandiV5/Domain/RenewalInformation.html +0 -1147
  108. data/doc/GandiV5/Domain/RestoreInformation.html +0 -339
  109. data/doc/GandiV5/Domain/SharingSpace.html +0 -437
  110. data/doc/GandiV5/Domain/TLD.html +0 -1565
  111. data/doc/GandiV5/Email.html +0 -144
  112. data/doc/GandiV5/Email/Mailbox.html +0 -6307
  113. data/doc/GandiV5/Email/Mailbox/Responder.html +0 -1560
  114. data/doc/GandiV5/Email/Offer.html +0 -514
  115. data/doc/GandiV5/Email/Slot.html +0 -4244
  116. data/doc/GandiV5/Error.html +0 -151
  117. data/doc/GandiV5/Error/GandiError.html +0 -270
  118. data/doc/GandiV5/LiveDNS.html +0 -300
  119. data/doc/GandiV5/LiveDNS/Domain.html +0 -2984
  120. data/doc/GandiV5/LiveDNS/RecordSet.html +0 -1593
  121. data/doc/GandiV5/LiveDNS/Zone.html +0 -8891
  122. data/doc/GandiV5/LiveDNS/Zone/Snapshot.html +0 -1556
  123. data/doc/GandiV5/Organization.html +0 -2341
  124. data/doc/_index.html +0 -474
  125. data/doc/class_list.html +0 -51
  126. data/doc/css/common.css +0 -1
  127. data/doc/css/full_list.css +0 -58
  128. data/doc/css/style.css +0 -496
  129. data/doc/file.README.html +0 -175
  130. data/doc/file_list.html +0 -56
  131. data/doc/frames.html +0 -17
  132. data/doc/index.html +0 -175
  133. data/doc/js/app.js +0 -303
  134. data/doc/js/full_list.js +0 -216
  135. data/doc/js/jquery.js +0 -4
  136. data/doc/method_list.html +0 -2427
  137. data/doc/top-level-namespace.html +0 -110
  138. data/lib/gandi_v5/live_dns/record_set.rb +0 -79
  139. data/lib/gandi_v5/live_dns/zone.rb +0 -305
  140. data/lib/gandi_v5/live_dns/zone/snapshot.rb +0 -81
  141. data/spec/features/domain_spec.rb +0 -45
  142. data/spec/features/livedns_domain_spec.rb +0 -8
  143. data/spec/features/livedns_zone_spec.rb +0 -45
  144. data/spec/features/mailbox_spec.rb +0 -18
  145. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/get.yaml +0 -4
  146. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/get.yaml +0 -11
  147. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yaml +0 -11
  148. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yaml +0 -3
  149. data/spec/fixtures/vcr/Domain_features/List_domains.yml +0 -54
  150. data/spec/fixtures/vcr/Domain_features/Renew_domain.yml +0 -133
  151. data/spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml +0 -32
  152. data/spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml +0 -42
  153. data/spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml +0 -72
  154. data/spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml +0 -28
  155. data/spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml +0 -39
  156. data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +0 -66
  157. data/spec/units/gandi_v5/live_dns/zone_spec.rb +0 -347
@@ -13,18 +13,6 @@ describe GandiV5::LiveDNS do
13
13
  expect(described_class.domains).to be returns
14
14
  end
15
15
 
16
- it '.zone' do
17
- returns = double GandiV5::LiveDNS::Zone
18
- expect(GandiV5::LiveDNS::Zone).to receive(:fetch).with('zone-uuid').and_return(returns)
19
- expect(described_class.zone('zone-uuid')).to be returns
20
- end
21
-
22
- it '.zones' do
23
- returns = double Array
24
- expect(GandiV5::LiveDNS::Zone).to receive(:list).and_return(returns)
25
- expect(described_class.zones).to be returns
26
- end
27
-
28
16
  describe '.require_valid_record_type' do
29
17
  it 'Does nothing for valid type' do
30
18
  expect { described_class.require_valid_record_type 'A' }.to_not raise_error
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe GandiV5::Organization::Customer do
4
+ let(:body_fixtures) { File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Organization_Customer')) }
5
+
6
+ describe '.create' do
7
+ let(:url) { 'https://api.gandi.net/v5/organization/organizations/uuid/customers' }
8
+ let(:attrs) do
9
+ {
10
+ city: 'Ci',
11
+ country: 'Co',
12
+ email: 'a@e',
13
+ firstname: 'f',
14
+ lastname: 'l',
15
+ phone: '0',
16
+ streetaddr: 'sa',
17
+ type: :individual
18
+ }
19
+ end
20
+
21
+ it 'Success' do
22
+ response = double RestClient::Response, headers: { location: '' }
23
+ expect(GandiV5).to receive(:post).with(url, attrs.to_json).and_return([response, nil])
24
+ expect(described_class.create('uuid', **attrs)).to be nil
25
+ end
26
+
27
+ describe 'Checks for required attributes' do
28
+ %i[city country email firstname lastname phone streetaddr type].each do |attr|
29
+ it attr do
30
+ attrs.delete attr
31
+ expect { described_class.new('org_uuid', **attrs) }.to raise_exception ArgumentError
32
+ end
33
+ end
34
+ end
35
+
36
+ it 'Invalid type' do
37
+ attrs[:type] = :invalid
38
+ expect { described_class.new('org_uuid', **attrs) }.to raise_exception ArgumentError
39
+ end
40
+ end
41
+
42
+ describe '.list' do
43
+ describe 'With default values' do
44
+ subject { described_class.list('uuid') }
45
+
46
+ before :each do
47
+ url = 'https://api.gandi.net/v5/organization/organizations/uuid/customers'
48
+ expect(GandiV5).to receive(:get).with(url, params: {})
49
+ .and_return([nil, YAML.load_file(File.join(body_fixtures, 'list.yml'))])
50
+ end
51
+
52
+ its('count') { should eq 1 }
53
+ its('first.uuid') { should eq 'customer-uuid' }
54
+ its('first.name') { should eq 'FirstLast' }
55
+ its('first.first_name') { should eq 'First' }
56
+ its('first.last_name') { should eq 'Last' }
57
+ its('first.email') { should eq 'first.last@example.com' }
58
+ its('first.type') { should eq :individual }
59
+ its('first.org_name') { should eq 'Org' }
60
+ end
61
+
62
+ describe 'Passes optional query params' do
63
+ let(:url) { 'https://api.gandi.net/v5/organization/organizations/org_uuid/customers' }
64
+
65
+ it 'name' do
66
+ expect(GandiV5).to receive(:get).with(url, params: { '~name' => '5' })
67
+ .and_return([nil, []])
68
+ expect(described_class.list('org_uuid', name: '5')).to eq []
69
+ end
70
+
71
+ %i[permission sort_by].each do |param|
72
+ it param.to_s do
73
+ headers = { param => 5 }
74
+ expect(GandiV5).to receive(:get).with(url, params: headers)
75
+ .and_return([nil, []])
76
+ expect(described_class.list('org_uuid', **headers)).to eq []
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -3,11 +3,48 @@
3
3
  describe GandiV5::Organization do
4
4
  let(:body_fixtures) { File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Organization')) }
5
5
 
6
+ describe '.list' do
7
+ describe 'With default values' do
8
+ subject { described_class.list }
9
+
10
+ before :each do
11
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/organization/organizations', params: {})
12
+ .and_return([nil, YAML.load_file(File.join(body_fixtures, 'list.yml'))])
13
+ end
14
+
15
+ its('count') { should eq 1 }
16
+ its('first.uuid') { should eq 'organization-uuid' }
17
+ its('first.name') { should eq 'FirstLast' }
18
+ its('first.first_name') { should eq 'First' }
19
+ its('first.last_name') { should eq 'Last' }
20
+ end
21
+
22
+ describe 'Passes optional query params' do
23
+ it 'name' do
24
+ expect(GandiV5).to receive(:get).with(
25
+ 'https://api.gandi.net/v5/organization/organizations',
26
+ params: { '~name' => '5' }
27
+ )
28
+ .and_return([nil, []])
29
+ expect(described_class.list(name: '5')).to eq []
30
+ end
31
+
32
+ %i[type permission sort_by].each do |param|
33
+ it param.to_s do
34
+ headers = { param => 5 }
35
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/organization/organizations', params: headers)
36
+ .and_return([nil, []])
37
+ expect(described_class.list(**headers)).to eq []
38
+ end
39
+ end
40
+ end
41
+ end
42
+
6
43
  describe '.fetch' do
7
44
  subject { described_class.fetch }
8
45
  before :each do
9
46
  expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/organization/user-info')
10
- .and_return([nil, YAML.load_file(File.join(body_fixtures, 'get.yaml'))])
47
+ .and_return([nil, YAML.load_file(File.join(body_fixtures, 'fetch.yml'))])
11
48
  end
12
49
 
13
50
  its('uuid') { should eq 'organization-uuid' }
@@ -27,4 +64,18 @@ describe GandiV5::Organization do
27
64
  its('security_email_validated') { should eq true }
28
65
  its('security_email_validation_deadline') { should eq Time.new(2017, 11, 22, 17, 13, 33) }
29
66
  end
67
+
68
+ it '#customers' do
69
+ subject = described_class.new uuid: 'org_uuid'
70
+ returns = double Array
71
+ expect(GandiV5::Organization::Customer).to receive(:list).with('org_uuid', param: :value).and_return(returns)
72
+ expect(subject.customers('org_uuid', param: :value)).to be returns
73
+ end
74
+
75
+ it '#create_customer' do
76
+ subject = described_class.new uuid: 'org_uuid'
77
+ returns = double Object
78
+ expect(GandiV5::Organization::Customer).to receive(:create).with('org_uuid', param: :value).and_return(returns)
79
+ expect(subject.create_customer('org_uuid', param: :value)).to be returns
80
+ end
30
81
  end
@@ -47,41 +47,47 @@ describe GandiV5 do
47
47
  end
48
48
 
49
49
  describe 'Uses RestClient' do
50
+ let(:response) do
51
+ double RestClient::Response, body: 'Hello world!', headers: { content_type: 'text/plain' }
52
+ end
53
+
50
54
  %i[get delete].each do |method|
51
55
  describe ":#{method}" do
52
56
  it 'As JSON' do
53
57
  response_data = { 'hello' => 'world' }
54
58
  response = double RestClient::Response, body: response_data.to_json, headers: { content_type: 'application/json' }
55
59
  expect(described_class).to receive(:prepare_headers)
56
- expect(RestClient).to receive(method).with('url', hash_including(accept: 'application/json')).and_return(response)
57
- expect(described_class.send(method, 'url', accept: 'application/json')).to match_array [response, response_data]
60
+ expect(RestClient).to receive(method).with('url', hash_including(accept: 'application/json'))
61
+ .and_return(response)
62
+ expect(described_class.send(method, 'url', accept: 'application/json'))
63
+ .to match_array [response, response_data]
58
64
  end
59
65
 
60
66
  it 'As text' do
61
- response_data = 'Hello world!'
62
- response = double RestClient::Response, body: response_data, headers: { content_type: 'text/plain' }
63
67
  expect(described_class).to receive(:prepare_headers)
64
68
  expect(RestClient).to receive(method).with('url', hash_including(accept: 'text/plain')).and_return(response)
65
- expect(described_class.send(method, 'url', accept: 'text/plain')).to match_array [response, response_data]
69
+ expect(described_class.send(method, 'url', accept: 'text/plain')).to match_array [response, 'Hello world!']
66
70
  end
67
71
 
68
72
  it 'Passes request headers' do
69
73
  expect(described_class).to receive(:prepare_headers)
70
74
  expect(described_class).to receive(:parse_response)
71
- expect(RestClient).to receive(method).with(anything, header: 'value')
72
- expect(described_class.send(method, 'url', header: 'value')).to match_array [nil, nil]
75
+ expect(RestClient).to receive(method).with(anything, header: 'value').and_return(response)
76
+ expect(described_class.send(method, 'url', header: 'value')).to match_array [response, nil]
73
77
  end
74
78
 
75
79
  it 'Adds authentication header' do
76
- expect(RestClient).to receive(method).with(anything, hash_including(Authorization: 'Apikey abdce12345'))
80
+ expect(RestClient).to receive(method).with(anything, hash_including(authorization: 'Apikey abdce12345'))
81
+ .and_return(response)
77
82
  expect(described_class).to receive(:parse_response)
78
- expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [nil, nil]
83
+ expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [response, nil]
79
84
  end
80
85
 
81
86
  it 'Default accept header' do
82
87
  expect(RestClient).to receive(method).with(any_args, hash_including(accept: 'application/json'))
88
+ .and_return(response)
83
89
  expect(described_class).to receive(:parse_response)
84
- expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [nil, nil]
90
+ expect(described_class.send(method, 'https://api.gandi.net/v5/')).to match_array [response, nil]
85
91
  end
86
92
 
87
93
  it 'Converts a 406 (bad request) exception' do
@@ -92,6 +98,13 @@ describe GandiV5 do
92
98
  end
93
99
  end
94
100
 
101
+ it ':delete handles no content-type' do
102
+ response = double RestClient::Response, headers: {}
103
+ expect(described_class).to receive(:prepare_headers)
104
+ expect(RestClient).to receive(:delete).with('url', hash_including(accept: 'text/plain')).and_return(response)
105
+ expect(described_class.delete('url', accept: 'text/plain')).to match_array [response, nil]
106
+ end
107
+
95
108
  %i[patch post put].each do |method|
96
109
  describe ":#{method}" do
97
110
  let(:payload) { '{"say":"hello world"}' }
@@ -107,26 +120,25 @@ describe GandiV5 do
107
120
  end
108
121
 
109
122
  it 'As text' do
110
- response_data = 'hello world'
111
- response = double RestClient::Response, body: response_data, headers: { content_type: 'text/plain' }
112
123
  expect(described_class).to receive(:prepare_headers)
113
124
  expect(RestClient).to receive(method).with('url', payload, hash_including(accept: 'text/plain'))
114
125
  .and_return(response)
115
- expect(described_class.send(method, 'url', payload, accept: 'text/plain')).to match_array [response, response_data]
126
+ array = [response, 'Hello world!']
127
+ expect(described_class.send(method, 'url', payload, accept: 'text/plain')).to match_array array
116
128
  end
117
129
 
118
130
  it 'Passes payload' do
119
131
  expect(described_class).to receive(:prepare_headers)
120
132
  expect(described_class).to receive(:parse_response)
121
- expect(RestClient).to receive(method).with(anything, payload, any_args)
122
- expect(described_class.send(method, 'url', payload)).to match_array [nil, nil]
133
+ expect(RestClient).to receive(method).with(anything, payload, any_args).and_return(response)
134
+ expect(described_class.send(method, 'url', payload)).to match_array [response, nil]
123
135
  end
124
136
 
125
137
  it 'Passes request headers' do
126
138
  expect(described_class).to receive(:prepare_headers)
127
139
  expect(described_class).to receive(:parse_response)
128
- expect(RestClient).to receive(method).with(any_args, hash_including(header: 'value'))
129
- expect(described_class.send(method, 'url', payload, header: 'value')).to match_array [nil, nil]
140
+ expect(RestClient).to receive(method).with(any_args, hash_including(header: 'value')).and_return(response)
141
+ expect(described_class.send(method, 'url', payload, header: 'value')).to match_array [response, nil]
130
142
  end
131
143
 
132
144
  it 'Adds content type header' do
@@ -136,15 +148,17 @@ describe GandiV5 do
136
148
  end
137
149
 
138
150
  it 'Adds authentication header' do
139
- expect(RestClient).to receive(method).with(any_args, hash_including(Authorization: 'Apikey abdce12345'))
151
+ expect(RestClient).to receive(method).with(any_args, hash_including(authorization: 'Apikey abdce12345'))
152
+ .and_return(response)
140
153
  expect(described_class).to receive(:parse_response)
141
- expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [nil, nil]
154
+ expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [response, nil]
142
155
  end
143
156
 
144
157
  it 'Default accept header' do
145
158
  expect(RestClient).to receive(method).with(any_args, hash_including(accept: 'application/json'))
159
+ .and_return(response)
146
160
  expect(described_class).to receive(:parse_response)
147
- expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [nil, nil]
161
+ expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to match_array [response, nil]
148
162
  end
149
163
 
150
164
  it 'Converts a 406 (bad request) exception' do
@@ -156,20 +170,23 @@ describe GandiV5 do
156
170
  end
157
171
  end
158
172
 
159
- describe 'Generates correct authorisation header' do
160
- it 'When requesting from main V5 API' do
161
- expect(described_class.send(:authorisation_header, 'https://api.gandi.net/v5/example'))
162
- .to eq(Authorization: "Apikey #{api_key}")
173
+ describe 'Prepares headers' do
174
+ it 'Sets accept it not present' do
175
+ headers = {}
176
+ described_class.send(:prepare_headers, headers, GandiV5::BASE)
177
+ expect(headers[:accept]).to eq 'application/json'
163
178
  end
164
179
 
165
- it 'When requesting from main LiveDNS V5 API' do
166
- expect(described_class.send(:authorisation_header, 'https://dns.api.gandi.net/api/v5/example'))
167
- .to eq('X-Api-Key': api_key)
180
+ it 'Leaves accept alone if present' do
181
+ headers = { accept: 'leave/alone' }
182
+ described_class.send(:prepare_headers, headers, GandiV5::BASE)
183
+ expect(headers[:accept]).to eq 'leave/alone'
168
184
  end
169
185
 
170
- it 'Raises ArgumentError when requesting an unknown url' do
171
- expect { described_class.send(:authorisation_header, 'https://unknown.example.com') }
172
- .to raise_error ArgumentError, 'Don\'t know how to authorise for url: https://unknown.example.com'
186
+ it 'Sets authorization' do
187
+ headers = {}
188
+ described_class.send(:prepare_headers, headers, GandiV5::BASE)
189
+ expect(headers[:authorization]).to eq "Apikey #{api_key}"
173
190
  end
174
191
  end
175
192
 
@@ -226,4 +243,96 @@ describe GandiV5 do
226
243
  .to raise_error GandiV5::Error::GandiError, 'field: message'
227
244
  end
228
245
  end
246
+
247
+ describe '.paginated_get' do
248
+ let(:url) { "#{GandiV5::BASE}test/url" }
249
+ let(:do_nothing) { ->(_this_data) { nil } }
250
+
251
+ it 'Keeps fetching until getting a partial list' do
252
+ headers1 = { params: { 'page' => 1, 'per_page' => 2 } }
253
+ headers2 = { params: { 'page' => 2, 'per_page' => 2 } }
254
+ expect(GandiV5).to receive(:get).with(url, headers1)
255
+ .ordered
256
+ .and_return([nil, %i[a b]])
257
+ expect(GandiV5).to receive(:get).with(url, headers2)
258
+ .ordered
259
+ .and_return([nil, %i[c]])
260
+
261
+ described_class.paginated_get(url, (1..2), 2, &do_nothing)
262
+ end
263
+
264
+ it 'Keeps fetching until getting an empty list' do
265
+ headers1 = { params: { 'page' => 1, 'per_page' => 2 } }
266
+ headers2 = { params: { 'page' => 2, 'per_page' => 2 } }
267
+ expect(GandiV5).to receive(:get).with(url, headers1)
268
+ .ordered
269
+ .and_return([nil, %i[a b]])
270
+ expect(GandiV5).to receive(:get).with(url, headers2)
271
+ .ordered
272
+ .and_return([nil, []])
273
+
274
+ described_class.paginated_get(url, (1..2), 2, &do_nothing)
275
+ end
276
+
277
+ it 'Passes per_page option' do
278
+ headers = { params: { 'page' => 1, 'per_page' => 100 } }
279
+ expect(GandiV5).to receive(:get).with(url, headers)
280
+ .and_return([nil, []])
281
+ described_class.paginated_get(url, 1, 100, &do_nothing)
282
+ end
283
+
284
+ it 'Passes on other params' do
285
+ headers = { params: { 'page' => 1, 'per_page' => 100, 'custom' => 'value' } }
286
+ expect(GandiV5).to receive(:get).with(url, headers)
287
+ .and_return([nil, []])
288
+ described_class.paginated_get(url, 1, 100, params: { custom: 'value' }, &do_nothing)
289
+ end
290
+
291
+ it 'Passes on other headers' do
292
+ headers = { params: { 'page' => 1, 'per_page' => 100 }, custom: :value }
293
+ expect(GandiV5).to receive(:get).with(url, headers)
294
+ .and_return([nil, []])
295
+ described_class.paginated_get(url, 1, 100, custom: :value, &do_nothing)
296
+ end
297
+
298
+ describe 'Honors passed pages' do
299
+ it 'Has an each method' do
300
+ headers1 = { params: { 'page' => 1, 'per_page' => 2 } }
301
+ headers2 = { params: { 'page' => 2, 'per_page' => 2 } }
302
+ expect(GandiV5).to receive(:get).with(url, headers1)
303
+ .ordered
304
+ .and_return([nil, %i[a b]])
305
+ expect(GandiV5).to receive(:get).with(url, headers2)
306
+ .ordered
307
+ .and_return([nil, %i[c d]])
308
+
309
+ described_class.paginated_get(url, (1..2), 2, &do_nothing)
310
+ end
311
+
312
+ it 'Positive integer' do
313
+ headers = { params: { 'page' => 3, 'per_page' => 2 } }
314
+ expect(GandiV5).to receive(:get).with(url, headers)
315
+ .ordered
316
+ .and_return([nil, %i[a b c]])
317
+ described_class.paginated_get(url, 3, 2, &do_nothing)
318
+ end
319
+
320
+ it 'Nonpositive integer' do
321
+ expect { described_class.paginated_get(url, -3, 2, &do_nothing) }.to \
322
+ raise_error ArgumentError, 'page must be positive'
323
+ end
324
+ end
325
+
326
+ it 'Relies on caller to build their list' do
327
+ this_data = [:a]
328
+ expect(GandiV5).to receive(:get).and_return([nil, this_data])
329
+ expect { |b| described_class.paginated_get(url, 1, 100, &b) }.to yield_with_args(this_data)
330
+ end
331
+
332
+ it 'Requires a block' do
333
+ allow(GandiV5).to receive(:get).and_return([nil, [:a]])
334
+
335
+ expect { described_class.paginated_get(url) }.to raise_error LocalJumpError
336
+ end
337
+ end
229
338
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gandi_v5
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Gauld
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-22 00:00:00.000000000 Z
11
+ date: 2020-07-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -44,20 +44,34 @@ dependencies:
44
44
  - - "<"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '3'
47
+ - !ruby/object:Gem::Dependency
48
+ name: zeitwerk
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.1'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.1'
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: coveralls
49
63
  requirement: !ruby/object:Gem::Requirement
50
64
  requirements:
51
65
  - - "~>"
52
66
  - !ruby/object:Gem::Version
53
- version: '0.7'
67
+ version: '0.8'
54
68
  type: :development
55
69
  prerelease: false
56
70
  version_requirements: !ruby/object:Gem::Requirement
57
71
  requirements:
58
72
  - - "~>"
59
73
  - !ruby/object:Gem::Version
60
- version: '0.7'
74
+ version: '0.8'
61
75
  - !ruby/object:Gem::Dependency
62
76
  name: guard
63
77
  requirement: !ruby/object:Gem::Requirement
@@ -258,14 +272,14 @@ dependencies:
258
272
  requirements:
259
273
  - - "~>"
260
274
  - !ruby/object:Gem::Version
261
- version: '3.5'
275
+ version: '3.6'
262
276
  type: :development
263
277
  prerelease: false
264
278
  version_requirements: !ruby/object:Gem::Requirement
265
279
  requirements:
266
280
  - - "~>"
267
281
  - !ruby/object:Gem::Version
268
- version: '3.5'
282
+ version: '3.6'
269
283
  description:
270
284
  email:
271
285
  - robert@robertgauld.co.uk
@@ -279,63 +293,13 @@ files:
279
293
  - ".rubocop.yml"
280
294
  - ".travis.yml"
281
295
  - CHANGELOG.md
296
+ - FUNDING.yml
282
297
  - Gemfile
283
298
  - Guardfile
284
299
  - LICENSE.md
285
300
  - README.md
286
301
  - Rakefile
287
302
  - bin/console
288
- - doc/GandiV5.html
289
- - doc/GandiV5/Billing.html
290
- - doc/GandiV5/Billing/Info.html
291
- - doc/GandiV5/Billing/Info/Prepaid.html
292
- - doc/GandiV5/Data.html
293
- - doc/GandiV5/Data/ClassMethods.html
294
- - doc/GandiV5/Data/Converter.html
295
- - doc/GandiV5/Data/Converter/ArrayOf.html
296
- - doc/GandiV5/Data/Converter/Symbol.html
297
- - doc/GandiV5/Data/Converter/Time.html
298
- - doc/GandiV5/Domain.html
299
- - doc/GandiV5/Domain/AutoRenew.html
300
- - doc/GandiV5/Domain/Availability.html
301
- - doc/GandiV5/Domain/Availability/Product.html
302
- - doc/GandiV5/Domain/Availability/Product/Period.html
303
- - doc/GandiV5/Domain/Availability/Product/Price.html
304
- - doc/GandiV5/Domain/Availability/Tax.html
305
- - doc/GandiV5/Domain/Contact.html
306
- - doc/GandiV5/Domain/Contract.html
307
- - doc/GandiV5/Domain/Dates.html
308
- - doc/GandiV5/Domain/RenewalInformation.html
309
- - doc/GandiV5/Domain/RestoreInformation.html
310
- - doc/GandiV5/Domain/SharingSpace.html
311
- - doc/GandiV5/Domain/TLD.html
312
- - doc/GandiV5/Email.html
313
- - doc/GandiV5/Email/Mailbox.html
314
- - doc/GandiV5/Email/Mailbox/Responder.html
315
- - doc/GandiV5/Email/Offer.html
316
- - doc/GandiV5/Email/Slot.html
317
- - doc/GandiV5/Error.html
318
- - doc/GandiV5/Error/GandiError.html
319
- - doc/GandiV5/LiveDNS.html
320
- - doc/GandiV5/LiveDNS/Domain.html
321
- - doc/GandiV5/LiveDNS/RecordSet.html
322
- - doc/GandiV5/LiveDNS/Zone.html
323
- - doc/GandiV5/LiveDNS/Zone/Snapshot.html
324
- - doc/GandiV5/Organization.html
325
- - doc/_index.html
326
- - doc/class_list.html
327
- - doc/css/common.css
328
- - doc/css/full_list.css
329
- - doc/css/style.css
330
- - doc/file.README.html
331
- - doc/file_list.html
332
- - doc/frames.html
333
- - doc/index.html
334
- - doc/js/app.js
335
- - doc/js/full_list.js
336
- - doc/js/jquery.js
337
- - doc/method_list.html
338
- - doc/top-level-namespace.html
339
303
  - gandi_v5.gemspec
340
304
  - lib/gandi_v5.rb
341
305
  - lib/gandi_v5/billing.rb
@@ -344,6 +308,7 @@ files:
344
308
  - lib/gandi_v5/data.rb
345
309
  - lib/gandi_v5/data/converter.rb
346
310
  - lib/gandi_v5/data/converter/array_of.rb
311
+ - lib/gandi_v5/data/converter/integer.rb
347
312
  - lib/gandi_v5/data/converter/symbol.rb
348
313
  - lib/gandi_v5/data/converter/time.rb
349
314
  - lib/gandi_v5/domain.rb
@@ -356,11 +321,13 @@ files:
356
321
  - lib/gandi_v5/domain/contact.rb
357
322
  - lib/gandi_v5/domain/contract.rb
358
323
  - lib/gandi_v5/domain/dates.rb
324
+ - lib/gandi_v5/domain/live_dns.rb
359
325
  - lib/gandi_v5/domain/renewal_information.rb
360
326
  - lib/gandi_v5/domain/restore_information.rb
361
327
  - lib/gandi_v5/domain/sharing_space.rb
362
328
  - lib/gandi_v5/domain/tld.rb
363
329
  - lib/gandi_v5/email.rb
330
+ - lib/gandi_v5/email/forward.rb
364
331
  - lib/gandi_v5/email/mailbox.rb
365
332
  - lib/gandi_v5/email/mailbox/responder.rb
366
333
  - lib/gandi_v5/email/offer.rb
@@ -369,49 +336,51 @@ files:
369
336
  - lib/gandi_v5/error/gandi_error.rb
370
337
  - lib/gandi_v5/live_dns.rb
371
338
  - lib/gandi_v5/live_dns/domain.rb
372
- - lib/gandi_v5/live_dns/record_set.rb
373
- - lib/gandi_v5/live_dns/zone.rb
374
- - lib/gandi_v5/live_dns/zone/snapshot.rb
339
+ - lib/gandi_v5/live_dns/domain/dnssec_key.rb
340
+ - lib/gandi_v5/live_dns/domain/record.rb
341
+ - lib/gandi_v5/live_dns/domain/snapshot.rb
342
+ - lib/gandi_v5/live_dns/domain/tsig_key.rb
375
343
  - lib/gandi_v5/organization.rb
344
+ - lib/gandi_v5/organization/customer.rb
376
345
  - lib/gandi_v5/version.rb
377
346
  - spec/.rubocop.yml
378
- - spec/features/domain_spec.rb
379
- - spec/features/livedns_domain_spec.rb
380
- - spec/features/livedns_zone_spec.rb
381
- - spec/features/mailbox_spec.rb
382
- - spec/fixtures/bodies/GandiV5_Billing/info.yaml
383
- - spec/fixtures/bodies/GandiV5_Domain/fetch_contacts.yaml
384
- - spec/fixtures/bodies/GandiV5_Domain/get.yaml
385
- - spec/fixtures/bodies/GandiV5_Domain/list.yaml
386
- - spec/fixtures/bodies/GandiV5_Domain/renewal_info.yaml
387
- - spec/fixtures/bodies/GandiV5_Domain/restore_info.yaml
388
- - spec/fixtures/bodies/GandiV5_Domain_Availability/fetch.yaml
389
- - spec/fixtures/bodies/GandiV5_Domain_TLD/fetch.yaml
390
- - spec/fixtures/bodies/GandiV5_Domain_TLD/list.yaml
391
- - spec/fixtures/bodies/GandiV5_Email_Mailbox/get.yaml
392
- - spec/fixtures/bodies/GandiV5_Email_Mailbox/list.yaml
393
- - spec/fixtures/bodies/GandiV5_Email_Slot/get.yaml
394
- - spec/fixtures/bodies/GandiV5_Email_Slot/list.yaml
395
- - spec/fixtures/bodies/GandiV5_LiveDNS_Domain/get.yaml
396
- - spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list.yaml
397
- - spec/fixtures/bodies/GandiV5_LiveDNS_Zone/get.yaml
398
- - spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yaml
399
- - spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/fetch.yaml
400
- - spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/list.yaml
401
- - spec/fixtures/bodies/GandiV5_Organization/get.yaml
402
- - spec/fixtures/vcr/Domain_features/List_domains.yml
403
- - spec/fixtures/vcr/Domain_features/Renew_domain.yml
404
- - spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml
405
- - spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml
406
- - spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml
407
- - spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml
408
- - spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml
347
+ - spec/fixtures/bodies/GandiV5_Billing/info.yml
348
+ - spec/fixtures/bodies/GandiV5_Domain/fetch.yml
349
+ - spec/fixtures/bodies/GandiV5_Domain/fetch_contacts.yml
350
+ - spec/fixtures/bodies/GandiV5_Domain/fetch_glue_records.yml
351
+ - spec/fixtures/bodies/GandiV5_Domain/fetch_livedns.yml
352
+ - spec/fixtures/bodies/GandiV5_Domain/fetch_name_servers.yml
353
+ - spec/fixtures/bodies/GandiV5_Domain/fetch_renewal_info.yml
354
+ - spec/fixtures/bodies/GandiV5_Domain/fetch_restore_info.yml
355
+ - spec/fixtures/bodies/GandiV5_Domain/list.yml
356
+ - spec/fixtures/bodies/GandiV5_Domain_Availability/fetch.yml
357
+ - spec/fixtures/bodies/GandiV5_Domain_TLD/fetch.yml
358
+ - spec/fixtures/bodies/GandiV5_Domain_TLD/list.yml
359
+ - spec/fixtures/bodies/GandiV5_Email_Forward/list.yml
360
+ - spec/fixtures/bodies/GandiV5_Email_Mailbox/fetch.yml
361
+ - spec/fixtures/bodies/GandiV5_Email_Mailbox/list.yml
362
+ - spec/fixtures/bodies/GandiV5_Email_Slot/fetch.yml
363
+ - spec/fixtures/bodies/GandiV5_Email_Slot/list.yml
364
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain/fetch.yml
365
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list.yml
366
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list_tsig.yml
367
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain/nameservers.yml
368
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/fetch.yml
369
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain_DnssecKey/list.yml
370
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain_Snapshot/fetch.yml
371
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain_Snapshot/list.yml
372
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/fetch.yml
373
+ - spec/fixtures/bodies/GandiV5_LiveDNS_Domain_TsigKey/list.yml
374
+ - spec/fixtures/bodies/GandiV5_Organization/fetch.yml
375
+ - spec/fixtures/bodies/GandiV5_Organization/list.yml
376
+ - spec/fixtures/bodies/GandiV5_Organization_Customer/list.yml
409
377
  - spec/spec_helper.rb
410
378
  - spec/test.env
411
379
  - spec/units/gandi_v5/billing/info/prepaid_spec.rb
412
380
  - spec/units/gandi_v5/billing/info_spec.rb
413
381
  - spec/units/gandi_v5/billing_spec.rb
414
382
  - spec/units/gandi_v5/data/converter/array_of_spec.rb
383
+ - spec/units/gandi_v5/data/converter/integer_spec.rb
415
384
  - spec/units/gandi_v5/data/converter/symbol_spec.rb
416
385
  - spec/units/gandi_v5/data/converter/time_spec.rb
417
386
  - spec/units/gandi_v5/data/converter_spec.rb
@@ -425,22 +394,26 @@ files:
425
394
  - spec/units/gandi_v5/domain/contact_spec.rb
426
395
  - spec/units/gandi_v5/domain/contract_spec.rb
427
396
  - spec/units/gandi_v5/domain/dates_spec.rb
397
+ - spec/units/gandi_v5/domain/live_dns_spec.rb
428
398
  - spec/units/gandi_v5/domain/renewal_information_spec.rb
429
399
  - spec/units/gandi_v5/domain/restore_information_spec.rb
430
400
  - spec/units/gandi_v5/domain/sharing_space_spec.rb
431
401
  - spec/units/gandi_v5/domain/tld_spec.rb
432
402
  - spec/units/gandi_v5/domain_spec.rb
403
+ - spec/units/gandi_v5/email/forward_spec.rb
433
404
  - spec/units/gandi_v5/email/mailbox/responder_spec.rb
434
405
  - spec/units/gandi_v5/email/mailbox_spec.rb
435
406
  - spec/units/gandi_v5/email/offer_spec.rb
436
407
  - spec/units/gandi_v5/email/slot_spec.rb
437
408
  - spec/units/gandi_v5/error/gandi_error_spec.rb
438
409
  - spec/units/gandi_v5/error_spec.rb
410
+ - spec/units/gandi_v5/live_dns/domain/dnssec_key_spec.rb
411
+ - spec/units/gandi_v5/live_dns/domain/record_spec.rb
412
+ - spec/units/gandi_v5/live_dns/domain/snapshot_spec.rb
413
+ - spec/units/gandi_v5/live_dns/domain/tsig_key_spec.rb
439
414
  - spec/units/gandi_v5/live_dns/domain_spec.rb
440
- - spec/units/gandi_v5/live_dns/record_set_spec.rb
441
- - spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb
442
- - spec/units/gandi_v5/live_dns/zone_spec.rb
443
415
  - spec/units/gandi_v5/live_dns_spec.rb
416
+ - spec/units/gandi_v5/organization/customer_spec.rb
444
417
  - spec/units/gandi_v5/organization_spec.rb
445
418
  - spec/units/gandi_v5_spec.rb
446
419
  homepage: https://github.com/robertgauld/gandi_v5
@@ -462,7 +435,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
462
435
  - !ruby/object:Gem::Version
463
436
  version: 2.6.14
464
437
  requirements: []
465
- rubygems_version: 3.0.3
438
+ rubygems_version: 3.1.2
466
439
  signing_key:
467
440
  specification_version: 4
468
441
  summary: Make use of Gandi's V5 API.