contentful 1.2.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -0
  3. data/LICENSE.txt +1 -0
  4. data/README.md +8 -0
  5. data/contentful.gemspec +2 -1
  6. data/examples/custom_classes.rb +23 -26
  7. data/examples/raise_errors.rb +2 -2
  8. data/lib/contentful.rb +0 -1
  9. data/lib/contentful/array.rb +27 -19
  10. data/lib/contentful/array_like.rb +51 -0
  11. data/lib/contentful/asset.rb +43 -11
  12. data/lib/contentful/base_resource.rb +87 -0
  13. data/lib/contentful/client.rb +43 -34
  14. data/lib/contentful/coercions.rb +116 -0
  15. data/lib/contentful/content_type.rb +23 -8
  16. data/lib/contentful/content_type_cache.rb +26 -0
  17. data/lib/contentful/deleted_asset.rb +2 -5
  18. data/lib/contentful/deleted_entry.rb +2 -5
  19. data/lib/contentful/entry.rb +55 -33
  20. data/lib/contentful/error.rb +1 -1
  21. data/lib/contentful/field.rb +37 -9
  22. data/lib/contentful/fields_resource.rb +115 -0
  23. data/lib/contentful/file.rb +7 -8
  24. data/lib/contentful/link.rb +3 -6
  25. data/lib/contentful/locale.rb +6 -6
  26. data/lib/contentful/location.rb +7 -5
  27. data/lib/contentful/resource_builder.rb +72 -226
  28. data/lib/contentful/space.rb +16 -6
  29. data/lib/contentful/support.rb +41 -3
  30. data/lib/contentful/sync_page.rb +17 -10
  31. data/lib/contentful/version.rb +1 -1
  32. data/spec/array_spec.rb +4 -8
  33. data/spec/client_class_spec.rb +12 -23
  34. data/spec/client_configuration_spec.rb +13 -23
  35. data/spec/content_type_spec.rb +0 -5
  36. data/spec/entry_spec.rb +130 -125
  37. data/spec/error_requests_spec.rb +1 -1
  38. data/spec/field_spec.rb +0 -5
  39. data/spec/file_spec.rb +0 -5
  40. data/spec/fixtures/vcr_cassettes/entry.yml +54 -64
  41. data/spec/fixtures/vcr_cassettes/entry/include_resolution.yml +101 -0
  42. data/spec/fixtures/vcr_cassettes/entry/marshall.yml +227 -251
  43. data/spec/fixtures/vcr_cassettes/entry/raw.yml +88 -124
  44. data/spec/fixtures/vcr_cassettes/entry_locales.yml +56 -74
  45. data/spec/fixtures/vcr_cassettes/human.yml +63 -40
  46. data/spec/fixtures/vcr_cassettes/location.yml +99 -211
  47. data/spec/fixtures/vcr_cassettes/multi_locale_array_reference.yml +12 -16
  48. data/spec/fixtures/vcr_cassettes/not_found.yml +26 -21
  49. data/spec/fixtures/vcr_cassettes/nyancat.yml +53 -63
  50. data/spec/fixtures/vcr_cassettes/ratelimit.yml +1 -1
  51. data/spec/fixtures/vcr_cassettes/reloaded_entry.yml +54 -64
  52. data/spec/fixtures/vcr_cassettes/unauthorized.yml +1 -1
  53. data/spec/fixtures/vcr_cassettes/unavailable.yml +27 -15
  54. data/spec/link_spec.rb +3 -2
  55. data/spec/locale_spec.rb +0 -5
  56. data/spec/location_spec.rb +1 -6
  57. data/spec/request_spec.rb +3 -2
  58. data/spec/resource_building_spec.rb +10 -7
  59. data/spec/response_spec.rb +1 -1
  60. data/spec/space_spec.rb +0 -5
  61. data/spec/spec_helper.rb +3 -0
  62. data/spec/support/json_responses.rb +3 -3
  63. data/spec/sync_page_spec.rb +1 -6
  64. data/spec/sync_spec.rb +11 -7
  65. metadata +69 -20
  66. data/examples/dynamic_entries.rb +0 -124
  67. data/examples/resource_mapping.rb +0 -32
  68. data/lib/contentful/constants.rb +0 -504
  69. data/lib/contentful/dynamic_entry.rb +0 -57
  70. data/lib/contentful/resource.rb +0 -239
  71. data/lib/contentful/resource/array_like.rb +0 -39
  72. data/lib/contentful/resource/asset_fields.rb +0 -58
  73. data/lib/contentful/resource/custom_resource.rb +0 -29
  74. data/lib/contentful/resource/fields.rb +0 -73
  75. data/lib/contentful/resource/system_properties.rb +0 -55
  76. data/spec/coercions_spec.rb +0 -23
  77. data/spec/dynamic_entry_spec.rb +0 -75
  78. data/spec/resource_spec.rb +0 -79
@@ -58,5 +58,5 @@ module Contentful
58
58
  class UnparsableJson < Error; end
59
59
 
60
60
  # Raised when response is not parsable as a Contentful::Resource
61
- class UnparsableResource < Error; end
61
+ class UnparsableResource < StandardError; end
62
62
  end
@@ -1,17 +1,45 @@
1
- require_relative 'resource'
1
+ require_relative 'location'
2
+ require_relative 'coercions'
2
3
 
3
4
  module Contentful
4
5
  # A ContentType's field schema
5
6
  # See https://www.contentful.com/developers/documentation/content-management-api/#resources-content-types-fields
6
7
  class Field
7
- include Contentful::Resource
8
+ # Coercions from Contentful Types to Ruby native types
9
+ KNOWN_TYPES = {
10
+ 'String' => StringCoercion,
11
+ 'Text' => TextCoercion,
12
+ 'Symbol' => SymbolCoercion,
13
+ 'Integer' => IntegerCoercion,
14
+ 'Float' => FloatCoercion,
15
+ 'Boolean' => BooleanCoercion,
16
+ 'Date' => DateCoercion,
17
+ 'Location' => LocationCoercion,
18
+ 'Object' => ObjectCoercion,
19
+ 'Array' => ArrayCoercion,
20
+ 'Link' => LinkCoercion
21
+ }
8
22
 
9
- property :id, :string
10
- property :name, :string
11
- property :type, :string
12
- property :linkType, :string
13
- property :items, Field
14
- property :required, :boolean
15
- property :localized, :boolean
23
+ attr_reader :raw, :id, :name, :type, :link_type, :items, :required, :localized
24
+
25
+ def initialize(json)
26
+ @raw = json
27
+ @id = json.fetch('id', nil)
28
+ @name = json.fetch('name', nil)
29
+ @type = json.fetch('type', nil)
30
+ @link_type = json.fetch('linkType', nil)
31
+ @items = json.key?('items') ? Field.new(json.fetch('items', {})) : nil
32
+ @required = json.fetch('required', false)
33
+ @localized = json.fetch('localized', false)
34
+ end
35
+
36
+ # Coerces value to proper type
37
+ def coerce(value)
38
+ return value if type.nil?
39
+
40
+ options = {}
41
+ options[:coercion_class] = KNOWN_TYPES[items.type] unless items.nil?
42
+ KNOWN_TYPES[type].new(value, options).coerce
43
+ end
16
44
  end
17
45
  end
@@ -0,0 +1,115 @@
1
+ require_relative 'support'
2
+ require_relative 'base_resource'
3
+
4
+ module Contentful
5
+ # Base definition of a Contentful Resource containing Field properties
6
+ class FieldsResource < BaseResource
7
+ def initialize(item, _configuration, localized = false, includes = [], *)
8
+ super
9
+
10
+ @fields = hydrate_fields(localized, includes)
11
+
12
+ define_fields_methods!
13
+ end
14
+
15
+ # Returns all fields of the asset
16
+ #
17
+ # @return [Hash] fields for Resource on selected locale
18
+ def fields(wanted_locale = nil)
19
+ wanted_locale = internal_resource_locale if wanted_locale.nil?
20
+ @fields.fetch(wanted_locale.to_s, {})
21
+ end
22
+
23
+ # Returns all fields of the asset with locales nested by field
24
+ #
25
+ # @return [Hash] fields for Resource grouped by field name
26
+ def fields_with_locales
27
+ remapped_fields = {}
28
+ locales.each do |locale|
29
+ fields(locale).each do |name, value|
30
+ remapped_fields[name] ||= {}
31
+ remapped_fields[name][locale.to_sym] = value
32
+ end
33
+ end
34
+
35
+ remapped_fields
36
+ end
37
+
38
+ # Provides a list of the available locales for a Resource
39
+ def locales
40
+ @fields.keys
41
+ end
42
+
43
+ # @private
44
+ def marshal_dump
45
+ raw_with_links
46
+ end
47
+
48
+ # @private
49
+ def marshal_load(raw_object)
50
+ super(raw_object)
51
+ localized = raw_object.fetch('fields', {}).all? { |_, v| v.is_a?(Hash) }
52
+ @fields = hydrate_fields(localized, [])
53
+ define_fields_methods!
54
+ end
55
+
56
+ # @private
57
+ def raw_with_links
58
+ links = fields.keys.select { |property| known_link?(property) }
59
+ processed_raw = raw.clone
60
+ raw['fields'].each do |k, v|
61
+ processed_raw['fields'][k] = links.include?(Support.snakify(k).to_sym) ? send(Support.snakify(k)) : v
62
+ end
63
+
64
+ processed_raw
65
+ end
66
+
67
+ private
68
+
69
+ def define_fields_methods!
70
+ fields.each do |k, v|
71
+ define_singleton_method k do
72
+ v
73
+ end
74
+ end
75
+ end
76
+
77
+ def hydrate_fields(localized, includes)
78
+ return {} unless raw.key?('fields')
79
+
80
+ locale = internal_resource_locale
81
+ result = { locale => {} }
82
+
83
+ if localized
84
+ raw['fields'].each do |name, locales|
85
+ locales.each do |loc, value|
86
+ result[loc] ||= {}
87
+ result[loc][Support.snakify(name).to_sym] = coerce(
88
+ Support.snakify(name),
89
+ value,
90
+ localized,
91
+ includes
92
+ )
93
+ end
94
+ end
95
+ else
96
+ raw['fields'].each do |name, value|
97
+ result[locale][Support.snakify(name).to_sym] = coerce(
98
+ Support.snakify(name),
99
+ value,
100
+ localized,
101
+ includes
102
+ )
103
+ end
104
+ end
105
+
106
+ result
107
+ end
108
+
109
+ protected
110
+
111
+ def coerce(_field_id, value, _localized, _includes)
112
+ value
113
+ end
114
+ end
115
+ end
@@ -1,13 +1,12 @@
1
- require_relative 'resource'
2
-
3
1
  module Contentful
4
2
  # An Assets's file info
5
3
  class File
6
- include Contentful::Resource
7
-
8
- property :fileName, :string
9
- property :contentType, :string
10
- property :details
11
- property :url, :string
4
+ attr_reader :file_name, :content_type, :details, :url
5
+ def initialize(json)
6
+ @file_name = json.fetch('fileName', nil)
7
+ @content_type = json.fetch('contentType', nil)
8
+ @details = json.fetch('details', nil)
9
+ @url = json.fetch('url', nil)
10
+ end
12
11
  end
13
12
  end
@@ -1,15 +1,12 @@
1
- require_relative 'resource'
1
+ require_relative 'base_resource'
2
2
 
3
3
  module Contentful
4
4
  # Resource Class for Links
5
5
  # https://www.contentful.com/developers/documentation/content-delivery-api/#links
6
- class Link
7
- include Contentful::Resource
8
- include Contentful::Resource::SystemProperties
9
-
6
+ class Link < BaseResource
10
7
  # Queries contentful for the Resource the Link is refering to
11
8
  # Takes an optional query hash
12
- def resolve(query = {})
9
+ def resolve(client, query = {})
13
10
  id_and_query = [(id unless link_type == 'Space')].compact + [query]
14
11
  client.public_send(
15
12
  Contentful::Support.snakify(link_type).to_sym,
@@ -1,13 +1,13 @@
1
- require_relative 'resource'
2
-
3
1
  module Contentful
4
2
  # A Locale definition as included in Space
5
3
  # Read more about Localization at https://www.contentful.com/developers/documentation/content-delivery-api/#i18n
6
4
  class Locale
7
- include Contentful::Resource
5
+ attr_reader :code, :name, :default
8
6
 
9
- property :code, :string
10
- property :name, :string
11
- property :default, :boolean
7
+ def initialize(json)
8
+ @code = json.fetch('code', nil)
9
+ @name = json.fetch('name', nil)
10
+ @default = json.fetch('default', false)
11
+ end
12
12
  end
13
13
  end
@@ -1,12 +1,14 @@
1
- require_relative 'resource'
2
-
3
1
  module Contentful
4
2
  # Location Field Type
5
3
  # You can directly query for them: https://www.contentful.com/developers/documentation/content-delivery-api/#search-filter-geo
6
4
  class Location
7
- include Contentful::Resource
5
+ attr_reader :lat, :lon
6
+ alias latitude lat
7
+ alias longitude lon
8
8
 
9
- property :lat, :float
10
- property :lon, :float
9
+ def initialize(json)
10
+ @lat = json.fetch('lat', nil)
11
+ @lon = json.fetch('lon', nil)
12
+ end
11
13
  end
12
14
  end
@@ -1,9 +1,7 @@
1
1
  require_relative 'error'
2
- require_relative 'resource'
3
2
  require_relative 'space'
4
3
  require_relative 'content_type'
5
4
  require_relative 'entry'
6
- require_relative 'dynamic_entry'
7
5
  require_relative 'asset'
8
6
  require_relative 'array'
9
7
  require_relative 'link'
@@ -19,9 +17,9 @@ module Contentful
19
17
  DEFAULT_RESOURCE_MAPPING = {
20
18
  'Space' => Space,
21
19
  'ContentType' => ContentType,
22
- 'Entry' => :find_entry_class,
20
+ 'Entry' => Entry,
23
21
  'Asset' => Asset,
24
- 'Array' => :array_or_sync_page,
22
+ 'Array' => Array,
25
23
  'Link' => Link,
26
24
  'DeletedEntry' => DeletedEntry,
27
25
  'DeletedAsset' => DeletedAsset
@@ -30,271 +28,119 @@ module Contentful
30
28
  # @see _ README for more information on Entry Mapping
31
29
  DEFAULT_ENTRY_MAPPING = {}
32
30
 
33
- attr_reader :client, :response, :resource_mapping, :entry_mapping, :resource
31
+ attr_reader :json, :default_locale, :endpoint, :depth, :localized, :resource_mapping, :entry_mapping, :resource
34
32
 
35
- def initialize(client,
36
- response,
37
- resource_mapping = {},
38
- entry_mapping = {},
39
- default_locale = Contentful::Client::DEFAULT_CONFIGURATION[:default_locale])
40
- @response = response
41
- @client = client
42
- @included_resources = {}
43
- @known_resources = Hash.new { |h, k| h[k] = {} }
44
- @default_locale = default_locale
45
- @resource_mapping = default_resource_mapping.merge(resource_mapping)
46
- @entry_mapping = default_entry_mapping.merge(entry_mapping)
33
+ def initialize(json, configuration = {}, localized = false, depth = 0, endpoint = nil)
34
+ @json = json
35
+ @default_locale = configuration.fetch(:default_locale, ::Contentful::Client::DEFAULT_CONFIGURATION[:default_locale])
36
+ @resource_mapping = default_resource_mapping.merge(configuration.fetch(:resource_mapping, {}))
37
+ @entry_mapping = default_entry_mapping.merge(configuration.fetch(:entry_mapping, {}))
38
+ @includes_for_single = configuration.fetch(:includes_for_single, [])
39
+ @localized = localized
40
+ @depth = depth
41
+ @endpoint = endpoint
42
+ @configuration = configuration
47
43
  end
48
44
 
49
45
  # Starts the parsing process.
46
+ #
50
47
  # @return [Contentful::Resource, Contentful::Error]
51
48
  def run
52
- if response.status == :ok
53
- create_all_resources!
54
- else
55
- response.object
56
- end
57
- end
58
-
59
- # PARSING MECHANISM
60
- # - raise error if response not valid
61
- # - look for included objects and parse them to resources
62
- # - parse main object to resource
63
- # - replace links in included resources with known resources
64
- # - replace links in main resource with known resources
65
- # - return main resource
66
- def create_all_resources!
67
- create_included_resources! response.object['includes']
68
- @resource = create_resource(response.object)
69
-
70
- unless @included_resources.empty?
71
- replace_links_in_included_resources_with_known_resources
72
- end
73
-
74
- replace_links_with_known_resources @resource
75
-
76
- @resource
49
+ return build_array if array?
50
+ build_single
77
51
  rescue UnparsableResource => error
78
52
  error
79
53
  end
80
54
 
81
- # Creates a single resource from the response object
82
- def create_resource(object)
83
- res_class = detect_resource_class(object)
84
- res = res_class.new(object, response.request, client, @default_locale)
85
-
86
- add_to_known_resources res
87
- replace_children res, object
88
- replace_child_array res.items if res.array?
89
-
90
- res
91
- end
92
-
93
- # Checks in a custom class for an entry was defined in entry_mapping
94
- def find_entry_class(object)
95
- entry_mapping[content_type_id_for_entry(object)] || try_dynamic_entry(object)
96
- end
97
-
98
- # Automatically converts Entry to DynamicEntry if in cache
99
- def try_dynamic_entry(object)
100
- get_dynamic_entry(object) || Entry
101
- end
102
-
103
- # Finds the proper DynamicEntry class for an entry
104
- def get_dynamic_entry(object)
105
- content_id = content_type_id_for_entry(object)
106
- client.dynamic_entry_cache[content_id.to_sym] if content_id
107
- end
108
-
109
- # Returns the id of the related ContentType, if there is one
110
- def content_type_id_for_entry(object)
111
- object['sys'] &&
112
- object['sys']['contentType'] &&
113
- object['sys']['contentType']['sys'] &&
114
- object['sys']['contentType']['sys']['id']
115
- end
116
-
117
- # Detects if a resource is an Contentful::Array or a SyncPage
118
- def array_or_sync_page(object)
119
- if object['nextPageUrl'] || object['nextSyncUrl']
120
- SyncPage
121
- else
122
- Array
123
- end
124
- end
125
-
126
- # Uses the resource mapping to find the proper Resource class to initialize
127
- # for this Response object type
128
- #
129
- # The mapping value can be a
130
- # - Class
131
- # - Proc: Will be called, expected to return the proper Class
132
- # - Symbol: Will be called as method of the ResourceBuilder itself
133
- def detect_resource_class(object)
134
- type = object['sys'] && object['sys']['type']
135
-
136
- case res_class = resource_mapping[type]
137
- when Symbol
138
- public_send(res_class, object)
139
- when Proc
140
- res_class[object]
141
- when nil
142
- fail UnparsableResource, response
143
- else
144
- res_class
145
- end
146
- end
147
-
148
- # The default mapping for #detect_resource_class
149
- def default_resource_mapping
150
- DEFAULT_RESOURCE_MAPPING.dup
151
- end
152
-
153
- # The default entry mapping
154
- def default_entry_mapping
155
- DEFAULT_ENTRY_MAPPING.dup
156
- end
157
-
158
55
  private
159
56
 
160
- def detect_child_objects(object)
161
- if object.is_a? Hash
162
- object.select { |_, v| v.is_a?(Hash) && v.key?('sys') }
163
- else
164
- {}
57
+ def build_array
58
+ includes = fetch_includes
59
+ result = json['items'].map do |item|
60
+ build_item(item, includes)
165
61
  end
62
+ array_class = fetch_array_class
63
+ array_class.new(json.dup.merge('items' => result), default_locale, endpoint)
166
64
  end
167
65
 
168
- def detect_child_arrays(object)
169
- if object.is_a? Hash
170
- object.select do |_, v|
171
- v.is_a?(::Array) &&
172
- v.first &&
173
- v.first.is_a?(Hash) &&
174
- v.first.key?('sys')
175
- end
176
- else
177
- {}
178
- end
66
+ def build_single
67
+ includes = @includes_for_single
68
+ build_item(json, includes)
179
69
  end
180
70
 
181
- def add_to_known_resources(res)
182
- @known_resources[res.type][res.id] = res if res.sys && res.id && res.type != 'Link'
183
- end
71
+ def build_item(item, includes = [])
72
+ buildables = %w(Entry Asset ContentType Space DeletedEntry DeletedAsset)
73
+ item_type = buildables.detect { |b| b.to_s == item['sys']['type'] }
74
+ fail UnparsableResource, 'Item type is not known, could not parse' if item_type.nil?
75
+ item_class = resource_class(item)
184
76
 
185
- def localized_entry?(object, property_name, potential_objects)
186
- object['sys']['type'] == 'Entry' &&
187
- property_name == 'fields' &&
188
- potential_objects.is_a?(::Hash) &&
189
- potential_objects.any? { |_, p| Support.localized?(p) }
77
+ item_class.new(item, @configuration, localized?, includes, depth)
190
78
  end
191
79
 
192
- def replace_children(res, object)
193
- object.each do |name, potential_objects|
194
- replace_localized_children(res, object, name, potential_objects)
195
-
196
- detect_child_objects(potential_objects).each do |child_name, child_object|
197
- res.public_send(name)[child_name.to_sym] = create_resource(child_object)
198
- end
199
- next if name == 'includes'
200
- detect_child_arrays(potential_objects).each do |child_name, _child_array|
201
- replace_child_array res.public_send(name)[child_name.to_sym]
80
+ def fetch_includes
81
+ includes = json['items'].dup
82
+ %w(Entry Asset).each do |type|
83
+ if json.fetch('includes', {}).key?(type)
84
+ includes.concat(json['includes'].fetch(type, []))
202
85
  end
203
86
  end
87
+ includes
204
88
  end
205
89
 
206
- def replace_localized_children(result, object, property_name, potential_objects)
207
- return unless localized_entry?(object, property_name, potential_objects)
208
-
209
- localized_objects = potential_objects.select { |_, p| Support.localized?(p) }
210
- localized_objects.each do |field_name, localized_object|
211
- detect_child_objects(localized_object).each do |locale, child_object|
212
- result.public_send(property_name, locale)[field_name.to_sym] = create_resource(child_object)
213
- end
214
- detect_child_arrays(localized_object).each do |locale, _child_array|
215
- replace_child_array result.public_send(property_name, locale)[field_name.to_sym]
216
- end
217
- end
90
+ def resource_class(item)
91
+ return fetch_custom_resource_class(item) if %w(Entry Asset).include?(item['sys']['type'])
92
+ resource_mapping[item['sys']['type']]
218
93
  end
219
94
 
220
- def replace_child_array(child_array)
221
- child_array.map! { |resource_object| create_resource(resource_object) }
222
- end
95
+ def fetch_custom_resource_class(item)
96
+ case item['sys']['type']
97
+ when 'Entry'
98
+ resource_class = entry_mapping[item['sys']['contentType']['sys']['id']]
99
+ return resource_class unless resource_class.nil?
223
100
 
224
- def create_included_resources!(included_objects)
225
- if included_objects
226
- included_objects.each do |type, objects|
227
- @included_resources[type] = Hash[
228
- objects.map do |object|
229
- res = create_resource(object)
230
- [res.id, res]
231
- end
232
- ]
233
- end
101
+ return fetch_custom_resource_mapping(item, 'Entry', Entry)
102
+ when 'Asset'
103
+ return fetch_custom_resource_mapping(item, 'Asset', Asset)
234
104
  end
235
105
  end
236
106
 
237
- def replace_links_with_known_resources(res, seen_resource_ids = [])
238
- seen_resource_ids << res.id
239
-
240
- property_containers = [:properties, :sys].map do |property_container_name|
241
- res.public_send(property_container_name)
242
- end
243
-
244
- if res.is_a?(Entry)
245
- res.locales.each do |locale|
246
- property_containers << res.fields(locale)
247
- end
248
- else
249
- property_containers << res.fields
250
- end
107
+ def fetch_custom_resource_mapping(item, type, default_class)
108
+ resources = resource_mapping[type]
109
+ return default_class if resources.nil?
251
110
 
252
- property_containers.compact!
111
+ return resources if resources.is_a?(Class)
112
+ return resources[item] if resources.respond_to?(:call)
253
113
 
254
- property_containers.each do |property_container|
255
- replace_links_in_properties(property_container, seen_resource_ids)
256
- end
114
+ default_class
115
+ end
257
116
 
258
- replace_links_in_array res.items, seen_resource_ids if res.array?
117
+ def fetch_array_class
118
+ return SyncPage if sync?
119
+ ::Contentful::Array
259
120
  end
260
121
 
261
- def replace_links_in_properties(property_container, seen_resource_ids)
262
- property_container.each do |property_name, property_value|
263
- if property_value.is_a? ::Array
264
- replace_links_in_array property_value, seen_resource_ids
265
- else
266
- replace_link_or_check_recursively property_value, property_container, property_name, seen_resource_ids
267
- end
268
- end
122
+ def localized?
123
+ return true if @localized
124
+ return true if array? && sync?
125
+ false
269
126
  end
270
127
 
271
- def replace_links_in_array(property_container, seen_resource_ids)
272
- property_container.each.with_index do |child_property, property_index|
273
- replace_link_or_check_recursively child_property, property_container, property_index, seen_resource_ids
274
- end
128
+ def array?
129
+ json.fetch('sys', {}).fetch('type', '') == 'Array'
275
130
  end
276
131
 
277
- def replace_link_or_check_recursively(property_value, property_container, property_name, seen_resource_ids)
278
- if property_value.is_a? Link
279
- maybe_replace_link(property_value, property_container, property_name)
280
- elsif property_value.is_a?(Resource) && property_value.sys && !seen_resource_ids.include?(property_value.id)
281
- replace_links_with_known_resources(property_value, seen_resource_ids)
282
- end
132
+ def sync?
133
+ json.fetch('nextSyncUrl', nil) || json.fetch('nextPageUrl', nil)
283
134
  end
284
135
 
285
- def maybe_replace_link(link, parent, key)
286
- if @known_resources[link.link_type] &&
287
- @known_resources[link.link_type].key?(link.id)
288
- parent[key] = @known_resources[link.link_type][link.id]
289
- end
136
+ # The default mapping for #detect_resource_class
137
+ def default_resource_mapping
138
+ DEFAULT_RESOURCE_MAPPING.dup
290
139
  end
291
140
 
292
- def replace_links_in_included_resources_with_known_resources
293
- @included_resources.each do |_, for_type|
294
- for_type.each do |_, res|
295
- replace_links_with_known_resources(res)
296
- end
297
- end
141
+ # The default entry mapping
142
+ def default_entry_mapping
143
+ DEFAULT_ENTRY_MAPPING.dup
298
144
  end
299
145
  end
300
146
  end