contentful 2.10.1 → 2.11.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4411b6feaa1a20d23b04be5850b00c6bc4d3b97f009c94d5b3a2f647c49d08c5
4
- data.tar.gz: 4b8e2a124c217803421cf8fd4dedaaec8cb7fc0eba5d62b55610005dbb6f205a
3
+ metadata.gz: 4119a15a3968b909e9128d54c7a1daefe677940a9b9a4fb0665daba4717887c0
4
+ data.tar.gz: dce1c341f2e1826c5ef7116d4cbe81f03ceb833e925aaa452e844075a1586fdb
5
5
  SHA512:
6
- metadata.gz: 2c706107331d0135a2908945f9b7edc6d66e7aacf7746170a07ed2fb9c24a0d55ed72723660dfc3641a89402652d285d9f4506ab5ed936413787587f24579dc6
7
- data.tar.gz: bfe4e04fa103f7137e0e79dbadedf3778ac5efb27844dd3f2e658bdc2ed0ae96d0c4cfefd085ceb4424006ce66aa1ac7632e3d35f035cfe9a75ac29b498c8edd
6
+ metadata.gz: e18f6f53144ad186ca24fe6f8305bb1c432d3d691068e7181232ea7996bd6625048cbeae61fd931b2ce7948bc34b1b12c905fc93afe927f21f52c1005b0733e0
7
+ data.tar.gz: 69a2cf198c6ec8e1972c99cb887daa23d11338a2249a585c81cf52d3dacb263bbef8e58161532de933872e2b1d05328ea0b63e877b4bea6e585cd3229facf05e
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.11.0
6
+ ### Added
7
+ * Added `:raise_for_empty_fields` configuration option. [#190](https://github.com/contentful/contentful.rb/issues/190)
8
+
9
+ ### Fixed
10
+ * Links in `RichText` fields, that are published but unreachable, due to not having enough include depth on the request, are now returned as `Link` objects.
11
+
12
+ ### Changed
13
+ * Included resources for embedded entries and assets in Rich Text fields are now properly serialized to `data.target` instead of the top level `data`.
14
+
5
15
  ## 2.10.1
6
16
  ### Fixed
7
17
  * Fixed `Marshal.load` for entries with unpublished related entries.
data/README.md CHANGED
@@ -229,6 +229,11 @@ client = Contentful::Client.new(
229
229
  <td><code>true</code></td>
230
230
  <td>Determines whether errors are raised or returned.</td>
231
231
  </tr>
232
+ <tr>
233
+ <td><code>raise_for_empty_fields</code></td>
234
+ <td><code>true</code></td>
235
+ <td>Determines whether <code>EmptyFieldError</code> is raised when empty fields are requested on an entry or <code>nil</code> is returned.</td>
236
+ </tr>
232
237
  <tr>
233
238
  <td><code>dynamic_entries</code></td>
234
239
  <td><code>:manual</code></td>
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_development_dependency'term-ansicolor', '~> 1.3.0'
22
22
  gem.add_development_dependency 'public_suffix', '< 1.5'
23
23
  else
24
- gem.add_dependency 'http', '> 0.8', '< 3.0'
24
+ gem.add_dependency 'http', '> 0.8', '< 4.0'
25
25
  end
26
26
 
27
27
  gem.add_dependency 'multi_json', '~> 1'
@@ -39,6 +39,6 @@ Gem::Specification.new do |gem|
39
39
  gem.add_development_dependency 'rr'
40
40
  gem.add_development_dependency 'vcr'
41
41
  gem.add_development_dependency 'simplecov'
42
- gem.add_development_dependency 'webmock', '~> 1', '>= 1.17.3'
42
+ gem.add_development_dependency 'webmock'
43
43
  gem.add_development_dependency 'tins', '~> 1.6.0'
44
44
  end
@@ -17,6 +17,7 @@ module Contentful
17
17
  DEFAULT_CONFIGURATION = {
18
18
  secure: true,
19
19
  raise_errors: true,
20
+ raise_for_empty_fields: true,
20
21
  dynamic_entries: :manual,
21
22
  api_url: 'cdn.contentful.com',
22
23
  api_version: 1,
@@ -76,6 +77,7 @@ module Contentful
76
77
  # @option given_configuration [false, ::Logger] :logger
77
78
  # @option given_configuration [::Logger::DEBUG, ::Logger::INFO, ::Logger::WARN, ::Logger::ERROR] :log_level
78
79
  # @option given_configuration [Boolean] :raise_errors
80
+ # @option given_configuration [Boolean] :raise_for_empty_fields
79
81
  # @option given_configuration [::Array<String>] :dynamic_entries
80
82
  # @option given_configuration [::Hash<String, Contentful::Resource>] :resource_mapping
81
83
  # @option given_configuration [::Hash<String, Contentful::Resource>] :entry_mapping
@@ -1,4 +1,5 @@
1
1
  require_relative 'location'
2
+ require_relative 'link'
2
3
 
3
4
  module Contentful
4
5
  # Basic Coercion
@@ -127,7 +128,7 @@ module Contentful
127
128
  link = coerce_link(node, configuration)
128
129
 
129
130
  if !link.nil?
130
- node['data'] = link
131
+ node['data']['target'] = link
131
132
  else
132
133
  invalid_nodes << index
133
134
  end
@@ -158,6 +159,9 @@ module Contentful
158
159
  configuration[:includes_for_single]
159
160
  )
160
161
 
162
+ # Resource is valid but unreachable
163
+ return Link.new(node['data']['target'], configuration) if resource.nil?
164
+
161
165
  ResourceBuilder.new(
162
166
  resource,
163
167
  configuration,
@@ -1,3 +1,4 @@
1
+ require_relative 'error'
1
2
  require_relative 'fields_resource'
2
3
  require_relative 'content_type_cache'
3
4
  require_relative 'resource_references'
@@ -89,8 +90,34 @@ module Contentful
89
90
  (object.is_a?(Contentful::Entry) || object.is_a?(Contentful::Asset))
90
91
  end
91
92
 
93
+ def method_missing(name, *args, &block)
94
+ return empty_field_error(name) if content_type_field?(name)
95
+
96
+ super
97
+ end
98
+
99
+ def respond_to_missing?(name, include_private = false)
100
+ content_type_field?(name) || super
101
+ end
102
+
92
103
  protected
93
104
 
105
+ def content_type_field?(name)
106
+ content_type = ContentTypeCache.cache_get(
107
+ sys[:space].id,
108
+ sys[:content_type].id
109
+ )
110
+
111
+ return false if content_type.nil?
112
+
113
+ !content_type.field_for(name).nil?
114
+ end
115
+
116
+ def empty_field_error(name)
117
+ return nil unless @configuration[:raise_for_empty_fields]
118
+ fail EmptyFieldError, name
119
+ end
120
+
94
121
  def repr_name
95
122
  content_type_key = Support.snakify('contentType', @configuration[:use_camel_case]).to_sym
96
123
  "#{super}[#{sys[content_type_key].id}]"
@@ -201,4 +201,11 @@ module Contentful
201
201
 
202
202
  # Raised when response is not parsable as a Contentful::Resource
203
203
  class UnparsableResource < StandardError; end
204
+
205
+ # Raised when an undefined field is requested
206
+ class EmptyFieldError < StandardError
207
+ def initialize(name)
208
+ super("The field '#{name}' is empty and unavailable in the response")
209
+ end
210
+ end
204
211
  end
@@ -1,5 +1,5 @@
1
1
  # Contentful Namespace
2
2
  module Contentful
3
3
  # Gem Version
4
- VERSION = '2.10.1'
4
+ VERSION = '2.11.0'
5
5
  end
@@ -540,6 +540,45 @@ describe Contentful::Entry do
540
540
  end
541
541
  end
542
542
 
543
+ describe 'empty fields' do
544
+ it 'raises an exception by default' do
545
+ vcr('entries/empty_fields') {
546
+ entry = create_client(
547
+ space: 'z4ssexir3p93',
548
+ access_token: 'e157fdaf7b325b71d07a94b7502807d4cfbbb1a34e69b7856838e25b92777bc6',
549
+ dynamic_entries: :auto
550
+ ).entry('2t1x77MgUA4SM2gMiaUcsy')
551
+
552
+ expect { entry.title }.to raise_error Contentful::EmptyFieldError
553
+ }
554
+ end
555
+
556
+ it 'returns nil if raise_for_empty_fields is false' do
557
+ vcr('entries/empty_fields') {
558
+ entry = create_client(
559
+ space: 'z4ssexir3p93',
560
+ access_token: 'e157fdaf7b325b71d07a94b7502807d4cfbbb1a34e69b7856838e25b92777bc6',
561
+ dynamic_entries: :auto,
562
+ raise_for_empty_fields: false
563
+ ).entry('2t1x77MgUA4SM2gMiaUcsy')
564
+
565
+ expect(entry.title).to be_nil
566
+ }
567
+ end
568
+
569
+ it 'will properly raise NoMethodError for non-fields' do
570
+ vcr('entries/empty_fields') {
571
+ entry = create_client(
572
+ space: 'z4ssexir3p93',
573
+ access_token: 'e157fdaf7b325b71d07a94b7502807d4cfbbb1a34e69b7856838e25b92777bc6',
574
+ dynamic_entries: :auto
575
+ ).entry('2t1x77MgUA4SM2gMiaUcsy')
576
+
577
+ expect { entry.unexisting_field }.to raise_error NoMethodError
578
+ }
579
+ end
580
+ end
581
+
543
582
  describe 'rich text support' do
544
583
  it 'properly serializes and resolves includes' do
545
584
  vcr('entries/rich_text') {
@@ -555,8 +594,8 @@ describe Contentful::Entry do
555
594
  embedded_entry_index = 1
556
595
  entry.body['content'].each do |content|
557
596
  if content['nodeType'] == 'embedded-entry-block'
558
- expect(content['data']).to be_a Contentful::Entry
559
- expect(content['data'].body).to eq "Embedded #{embedded_entry_index}"
597
+ expect(content['data']['target']).to be_a Contentful::Entry
598
+ expect(content['data']['target'].body).to eq "Embedded #{embedded_entry_index}"
560
599
  expected_entry_occurrances -= 1
561
600
  embedded_entry_index += 1
562
601
  end
@@ -605,10 +644,25 @@ describe Contentful::Entry do
605
644
  ).entry('6NGLswCREsGA28kGouScyY')
606
645
 
607
646
  expect(entry.body['content'][3]['nodeType']).to eq('unordered-list')
608
- expect(entry.body['content'][3]['content'][2]['content'][0]['data'].is_a?(Contentful::Entry)).to be_truthy
647
+ expect(entry.body['content'][3]['content'][2]['content'][0]['data']['target'].is_a?(Contentful::Entry)).to be_truthy
609
648
 
610
649
  expect(entry.body['content'][4]['nodeType']).to eq('ordered-list')
611
- expect(entry.body['content'][4]['content'][2]['content'][0]['data'].is_a?(Contentful::Entry)).to be_truthy
650
+ expect(entry.body['content'][4]['content'][2]['content'][0]['data']['target'].is_a?(Contentful::Entry)).to be_truthy
651
+ }
652
+ end
653
+
654
+ it 'returns a link when resource is valid but unreachable' do
655
+ vcr('entries/rich_text_unresolved_relationships') {
656
+ parent = create_client(
657
+ space: 'jd7yc4wnatx3',
658
+ access_token: '6256b8ef7d66805ca41f2728271daf27e8fa6055873b802a813941a0fe696248',
659
+ raise_errors: true,
660
+ dynamic_entries: :auto,
661
+ gzip_encoded: false
662
+ ).entry('4fvSwl5Ob6UEWKg6MQicuC')
663
+
664
+ entry = parent.rich_text_child
665
+ expect(entry.body['content'][19]['data']['target'].is_a?(Contentful::Link)).to be_truthy
612
666
  }
613
667
  end
614
668
  end
@@ -0,0 +1,246 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://cdn.contentful.com/spaces/z4ssexir3p93/environments/master/content_types?limit=1000
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ X-Contentful-User-Agent:
11
+ - sdk contentful.rb/2.10.1; platform ruby/2.5.1; os macOS/16;
12
+ Authorization:
13
+ - Bearer e157fdaf7b325b71d07a94b7502807d4cfbbb1a34e69b7856838e25b92777bc6
14
+ Content-Type:
15
+ - application/vnd.contentful.delivery.v1+json
16
+ Accept-Encoding:
17
+ - gzip
18
+ Connection:
19
+ - close
20
+ Host:
21
+ - cdn.contentful.com
22
+ User-Agent:
23
+ - http.rb/2.2.2
24
+ response:
25
+ status:
26
+ code: 200
27
+ message: OK
28
+ headers:
29
+ Access-Control-Allow-Headers:
30
+ - Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization,X-Contentful-Skip-Transformation,X-Contentful-User-Agent,X-Contentful-Enable-Alpha-Feature
31
+ Access-Control-Allow-Methods:
32
+ - GET,HEAD,OPTIONS
33
+ Access-Control-Allow-Origin:
34
+ - "*"
35
+ Access-Control-Expose-Headers:
36
+ - Etag
37
+ Access-Control-Max-Age:
38
+ - '86400'
39
+ Cache-Control:
40
+ - max-age=0
41
+ Content-Type:
42
+ - application/vnd.contentful.delivery.v1+json
43
+ Contentful-Api:
44
+ - cda_cached
45
+ Etag:
46
+ - '"736965822f777aebb01c9ee4ac6d1b2a"'
47
+ Server:
48
+ - Contentful
49
+ X-Content-Type-Options:
50
+ - nosniff
51
+ X-Contentful-Region:
52
+ - us-east-1
53
+ X-Contentful-Request-Id:
54
+ - 43dd26ec0162d8b206895bf92ec3cb7c
55
+ Content-Length:
56
+ - '945'
57
+ Accept-Ranges:
58
+ - bytes
59
+ Date:
60
+ - Thu, 08 Nov 2018 13:19:20 GMT
61
+ Via:
62
+ - 1.1 varnish
63
+ Age:
64
+ - '11024'
65
+ Connection:
66
+ - close
67
+ X-Served-By:
68
+ - cache-fra19123-FRA
69
+ X-Cache:
70
+ - HIT
71
+ X-Cache-Hits:
72
+ - '1'
73
+ Vary:
74
+ - Accept-Encoding
75
+ body:
76
+ encoding: ASCII-8BIT
77
+ string: |
78
+ {
79
+ "sys": {
80
+ "type": "Array"
81
+ },
82
+ "total": 1,
83
+ "skip": 0,
84
+ "limit": 1000,
85
+ "items": [
86
+ {
87
+ "sys": {
88
+ "space": {
89
+ "sys": {
90
+ "type": "Link",
91
+ "linkType": "Space",
92
+ "id": "z4ssexir3p93"
93
+ }
94
+ },
95
+ "id": "test",
96
+ "type": "ContentType",
97
+ "createdAt": "2018-11-08T10:14:31.609Z",
98
+ "updatedAt": "2018-11-08T10:14:31.609Z",
99
+ "environment": {
100
+ "sys": {
101
+ "id": "master",
102
+ "type": "Link",
103
+ "linkType": "Environment"
104
+ }
105
+ },
106
+ "revision": 1
107
+ },
108
+ "displayField": "title",
109
+ "name": "Test",
110
+ "description": "",
111
+ "fields": [
112
+ {
113
+ "id": "title",
114
+ "name": "Title",
115
+ "type": "Symbol",
116
+ "localized": false,
117
+ "required": false,
118
+ "disabled": false,
119
+ "omitted": false
120
+ }
121
+ ]
122
+ }
123
+ ]
124
+ }
125
+ http_version:
126
+ recorded_at: Thu, 08 Nov 2018 13:19:20 GMT
127
+ - request:
128
+ method: get
129
+ uri: https://cdn.contentful.com/spaces/z4ssexir3p93/environments/master/entries?sys.id=2t1x77MgUA4SM2gMiaUcsy
130
+ body:
131
+ encoding: US-ASCII
132
+ string: ''
133
+ headers:
134
+ X-Contentful-User-Agent:
135
+ - sdk contentful.rb/2.10.1; platform ruby/2.5.1; os macOS/16;
136
+ Authorization:
137
+ - Bearer e157fdaf7b325b71d07a94b7502807d4cfbbb1a34e69b7856838e25b92777bc6
138
+ Content-Type:
139
+ - application/vnd.contentful.delivery.v1+json
140
+ Accept-Encoding:
141
+ - gzip
142
+ Connection:
143
+ - close
144
+ Host:
145
+ - cdn.contentful.com
146
+ User-Agent:
147
+ - http.rb/2.2.2
148
+ response:
149
+ status:
150
+ code: 200
151
+ message: OK
152
+ headers:
153
+ Access-Control-Allow-Headers:
154
+ - Accept,Accept-Language,Authorization,Cache-Control,Content-Length,Content-Range,Content-Type,DNT,Destination,Expires,If-Match,If-Modified-Since,If-None-Match,Keep-Alive,Last-Modified,Origin,Pragma,Range,User-Agent,X-Http-Method-Override,X-Mx-ReqToken,X-Requested-With,X-Contentful-Version,X-Contentful-Content-Type,X-Contentful-Organization,X-Contentful-Skip-Transformation,X-Contentful-User-Agent,X-Contentful-Enable-Alpha-Feature
155
+ Access-Control-Allow-Methods:
156
+ - GET,HEAD,OPTIONS
157
+ Access-Control-Allow-Origin:
158
+ - "*"
159
+ Access-Control-Expose-Headers:
160
+ - Etag
161
+ Access-Control-Max-Age:
162
+ - '86400'
163
+ Cache-Control:
164
+ - max-age=0
165
+ Content-Type:
166
+ - application/vnd.contentful.delivery.v1+json
167
+ Contentful-Api:
168
+ - cda_cached
169
+ Etag:
170
+ - '"08908121582750c6cc9ba9d71bfd6e0f"'
171
+ Server:
172
+ - Contentful
173
+ X-Content-Type-Options:
174
+ - nosniff
175
+ X-Contentful-Region:
176
+ - us-east-1
177
+ X-Contentful-Request-Id:
178
+ - 0e4aaa81032e63c7a619be69843ff267
179
+ Content-Length:
180
+ - '842'
181
+ Accept-Ranges:
182
+ - bytes
183
+ Date:
184
+ - Thu, 08 Nov 2018 13:19:20 GMT
185
+ Via:
186
+ - 1.1 varnish
187
+ Age:
188
+ - '0'
189
+ Connection:
190
+ - close
191
+ X-Served-By:
192
+ - cache-fra19146-FRA
193
+ X-Cache:
194
+ - MISS
195
+ X-Cache-Hits:
196
+ - '0'
197
+ Vary:
198
+ - Accept-Encoding
199
+ body:
200
+ encoding: ASCII-8BIT
201
+ string: |
202
+ {
203
+ "sys": {
204
+ "type": "Array"
205
+ },
206
+ "total": 1,
207
+ "skip": 0,
208
+ "limit": 100,
209
+ "items": [
210
+ {
211
+ "sys": {
212
+ "space": {
213
+ "sys": {
214
+ "type": "Link",
215
+ "linkType": "Space",
216
+ "id": "z4ssexir3p93"
217
+ }
218
+ },
219
+ "id": "2t1x77MgUA4SM2gMiaUcsy",
220
+ "type": "Entry",
221
+ "createdAt": "2018-11-08T10:14:42.223Z",
222
+ "updatedAt": "2018-11-08T10:14:42.223Z",
223
+ "environment": {
224
+ "sys": {
225
+ "id": "master",
226
+ "type": "Link",
227
+ "linkType": "Environment"
228
+ }
229
+ },
230
+ "revision": 1,
231
+ "contentType": {
232
+ "sys": {
233
+ "type": "Link",
234
+ "linkType": "ContentType",
235
+ "id": "test"
236
+ }
237
+ },
238
+ "locale": "en-US"
239
+ },
240
+ "fields": {}
241
+ }
242
+ ]
243
+ }
244
+ http_version:
245
+ recorded_at: Thu, 08 Nov 2018 13:19:21 GMT
246
+ recorded_with: VCR 4.0.0