kontent-delivery-sdk-ruby 2.0.22 → 2.0.24

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.md +21 -21
  3. data/README.md +603 -602
  4. data/bin/console +14 -14
  5. data/bin/setup +8 -8
  6. data/lib/delivery/builders/image_transformation_builder.rb +272 -272
  7. data/lib/delivery/builders/url_builder.rb +123 -123
  8. data/lib/delivery/client/delivery_client.rb +184 -184
  9. data/lib/delivery/client/delivery_query.rb +302 -302
  10. data/lib/delivery/client/request_manager.rb +126 -127
  11. data/lib/delivery/models/content_item.rb +153 -153
  12. data/lib/delivery/models/content_type.rb +41 -41
  13. data/lib/delivery/models/language.rb +29 -29
  14. data/lib/delivery/models/pagination.rb +22 -22
  15. data/lib/delivery/models/taxonomy_group.rb +39 -39
  16. data/lib/delivery/query_parameters/filters.rb +201 -201
  17. data/lib/delivery/query_parameters/parameter_base.rb +56 -56
  18. data/lib/delivery/query_parameters/query_string.rb +78 -78
  19. data/lib/delivery/resolvers/content_link_resolver.rb +102 -102
  20. data/lib/delivery/resolvers/inline_content_item_resolver.rb +75 -75
  21. data/lib/delivery/resolvers/linked_item_resolver.rb +43 -37
  22. data/lib/delivery/responses/delivery_element_response.rb +34 -34
  23. data/lib/delivery/responses/delivery_item_listing_response.rb +54 -54
  24. data/lib/delivery/responses/delivery_item_response.rb +40 -40
  25. data/lib/delivery/responses/delivery_items_feed_response.rb +58 -58
  26. data/lib/delivery/responses/delivery_language_listing_response.rb +44 -44
  27. data/lib/delivery/responses/delivery_taxonomy_listing_response.rb +47 -47
  28. data/lib/delivery/responses/delivery_taxonomy_response.rb +33 -33
  29. data/lib/delivery/responses/delivery_type_listing_response.rb +46 -46
  30. data/lib/delivery/responses/delivery_type_response.rb +32 -32
  31. data/lib/delivery/responses/response_base.rb +39 -39
  32. data/lib/delivery/tests/401.json +5 -5
  33. data/lib/delivery/tests/429.json +4 -4
  34. data/lib/delivery/tests/fake_responder.rb +99 -105
  35. data/lib/delivery/tests/filtering/items_with_count.json +5384 -5384
  36. data/lib/delivery/tests/filtering/pagination.json +761 -761
  37. data/lib/delivery/tests/generic/items.json +5383 -5383
  38. data/lib/delivery/tests/generic/items/about_us.json +276 -276
  39. data/lib/delivery/tests/generic/items/aeropress_filters.json +155 -155
  40. data/lib/delivery/tests/generic/items/coffee_processing_techniques.json +565 -565
  41. data/lib/delivery/tests/generic/items/where_does_coffee_come_from_.json +598 -598
  42. data/lib/delivery/tests/generic/languages.json +23 -23
  43. data/lib/delivery/tests/generic/taxonomies.json +203 -203
  44. data/lib/delivery/tests/generic/taxonomies/manufacturer.json +29 -29
  45. data/lib/delivery/tests/generic/types.json +835 -835
  46. data/lib/delivery/tests/generic/types/brewer.json +88 -88
  47. data/lib/delivery/tests/generic/types/brewer/elements/product_status.json +5 -5
  48. data/lib/delivery/tests/items_feed/articles_feed_1.json +39 -39
  49. data/lib/delivery/tests/items_feed/articles_feed_2.json +78 -78
  50. data/lib/delivery/tests/items_feed/articles_feed_3.json +104 -104
  51. data/lib/kontent-delivery-sdk-ruby.rb +22 -22
  52. metadata +13 -32
@@ -1,128 +1,127 @@
1
- require 'rest-client'
2
- require 'dotenv/load'
3
-
4
- module Kentico
5
- module Kontent
6
- module Delivery
7
- class RequestManager
8
- class << self
9
- MAX_ATTEMPTS = 6
10
- MAX_DELAY_SECONDS = 30
11
- INITIAL_DELAY = 1
12
- RETRY_WHEN_CODE = [408, 429, 500, 502, 503, 504].freeze
13
- CODES_WITH_POSSIBLE_RETRY_HEADER = [429, 503].freeze
14
-
15
- def start(query, headers)
16
- @query = query
17
- @headers = headers
18
- @times_run = 1
19
- @delay = INITIAL_DELAY
20
- @url = @query.provide_url
21
- @total_delay = 0
22
- continue
23
- end
24
-
25
- private
26
-
27
- def should_retry(potential_response)
28
- return potential_response if @times_run == MAX_ATTEMPTS ||
29
- !RETRY_WHEN_CODE.include?(potential_response.http_code) ||
30
- !@query.with_retry_policy ||
31
- @total_delay >= MAX_DELAY_SECONDS
32
-
33
- next_delay
34
- sleep(@delay)
35
- @total_delay += @delay
36
- continue
37
- end
38
-
39
- # Generates a random delay based on times_run, then increases times_run
40
- def next_delay
41
- min = 0.8 * INITIAL_DELAY
42
- max = (1.2 * INITIAL_DELAY) * (2**@times_run)
43
- @delay = rand(min..max)
44
- @times_run += 1
45
- end
46
-
47
- def continue
48
- if ENV['TEST'] == '1'
49
- resp = Kentico::Kontent::Delivery::Tests::FakeResponder.get_response @query, @url, @headers
50
- return should_retry(resp) if resp.is_a? Kentico::Kontent::Delivery::Responses::ResponseBase
51
-
52
- make_response resp # resp is pure JSON
53
- else
54
- begin
55
- resp = RestClient.get @url, @headers
56
- rescue RestClient::ExceptionWithResponse => err
57
- should_retry Kentico::Kontent::Delivery::Responses::ResponseBase.new err.http_code, err.response
58
- rescue RestClient::SSLCertificateNotVerified => err
59
- should_retry Kentico::Kontent::Delivery::Responses::ResponseBase.new 500, err
60
- rescue SocketError => err
61
- should_retry Kentico::Kontent::Delivery::Responses::ResponseBase.new 500, err.message
62
- else
63
- make_response resp
64
- end
65
- end
66
- end
67
-
68
- # Converts a standard REST response based on the type of query.
69
- #
70
- # * *Returns*:
71
- # - An object derived from the Kentico::Kontent::Delivery::Responses::ResponseBase class
72
- def make_response(response)
73
- case @query.query_type
74
- when Kentico::Kontent::Delivery::QUERY_TYPE_ITEMS_FEED
75
- Kentico::Kontent::Delivery::Responses::DeliveryItemsFeedResponse.new(
76
- response.headers,
77
- response.body,
78
- @query
79
- )
80
- when Kentico::Kontent::Delivery::QUERY_TYPE_ITEMS
81
- respond_item response
82
- when Kentico::Kontent::Delivery::QUERY_TYPE_TYPES
83
- respond_type response
84
- when Kentico::Kontent::Delivery::QUERY_TYPE_TAXONOMIES
85
- respond_taxonomy response
86
- when Kentico::Kontent::Delivery::QUERY_TYPE_ELEMENT
87
- Kentico::Kontent::Delivery::Responses::DeliveryElementResponse.new response.headers, response.body
88
- when Kentico::Kontent::Delivery::QUERY_TYPE_LANGUAGES
89
- Kentico::Kontent::Delivery::Responses::DeliveryLanguageListingResponse.new response.headers, response.body
90
- end
91
- end
92
-
93
- def respond_type(response)
94
- if @query.code_name.nil?
95
- Kentico::Kontent::Delivery::Responses::DeliveryTypeListingResponse.new response.headers, response.body
96
- else
97
- Kentico::Kontent::Delivery::Responses::DeliveryTypeResponse.new response.headers, response.body
98
- end
99
- end
100
-
101
- def respond_taxonomy(response)
102
- if @query.code_name.nil?
103
- Kentico::Kontent::Delivery::Responses::DeliveryTaxonomyListingResponse.new response.headers, response.body
104
- else
105
- Kentico::Kontent::Delivery::Responses::DeliveryTaxonomyResponse.new response.headers, response.body
106
- end
107
- end
108
-
109
- def respond_item(response)
110
- if @query.code_name.nil?
111
- Kentico::Kontent::Delivery::Responses::DeliveryItemListingResponse.new(
112
- response.headers,
113
- response.body,
114
- @query
115
- )
116
- else
117
- Kentico::Kontent::Delivery::Responses::DeliveryItemResponse.new(
118
- response.headers,
119
- response.body,
120
- @query
121
- )
122
- end
123
- end
124
- end
125
- end
126
- end
127
- end
1
+ require 'rest-client'
2
+
3
+ module Kentico
4
+ module Kontent
5
+ module Delivery
6
+ class RequestManager
7
+ class << self
8
+ MAX_ATTEMPTS = 6
9
+ MAX_DELAY_SECONDS = 30
10
+ INITIAL_DELAY = 1
11
+ RETRY_WHEN_CODE = [408, 429, 500, 502, 503, 504].freeze
12
+ CODES_WITH_POSSIBLE_RETRY_HEADER = [429, 503].freeze
13
+
14
+ def start(query, headers)
15
+ @query = query
16
+ @headers = headers
17
+ @times_run = 1
18
+ @delay = INITIAL_DELAY
19
+ @url = @query.provide_url
20
+ @total_delay = 0
21
+ continue
22
+ end
23
+
24
+ private
25
+
26
+ def should_retry(potential_response)
27
+ return potential_response if @times_run == MAX_ATTEMPTS ||
28
+ !RETRY_WHEN_CODE.include?(potential_response.http_code) ||
29
+ !@query.with_retry_policy ||
30
+ @total_delay >= MAX_DELAY_SECONDS
31
+
32
+ next_delay
33
+ sleep(@delay)
34
+ @total_delay += @delay
35
+ continue
36
+ end
37
+
38
+ # Generates a random delay based on times_run, then increases times_run
39
+ def next_delay
40
+ min = 0.8 * INITIAL_DELAY
41
+ max = (1.2 * INITIAL_DELAY) * (2**@times_run)
42
+ @delay = rand(min..max)
43
+ @times_run += 1
44
+ end
45
+
46
+ def continue
47
+ if ENV['TEST'] == '1'
48
+ resp = Kentico::Kontent::Delivery::Tests::FakeResponder.get_response @query, @url, @headers
49
+ return should_retry(resp) if resp.is_a? Kentico::Kontent::Delivery::Responses::ResponseBase
50
+
51
+ make_response resp # resp is pure JSON
52
+ else
53
+ begin
54
+ resp = RestClient.get @url, @headers
55
+ rescue RestClient::ExceptionWithResponse => err
56
+ should_retry Kentico::Kontent::Delivery::Responses::ResponseBase.new err.http_code, err.response
57
+ rescue RestClient::SSLCertificateNotVerified => err
58
+ should_retry Kentico::Kontent::Delivery::Responses::ResponseBase.new 500, err
59
+ rescue SocketError => err
60
+ should_retry Kentico::Kontent::Delivery::Responses::ResponseBase.new 500, err.message
61
+ else
62
+ make_response resp
63
+ end
64
+ end
65
+ end
66
+
67
+ # Converts a standard REST response based on the type of query.
68
+ #
69
+ # * *Returns*:
70
+ # - An object derived from the Kentico::Kontent::Delivery::Responses::ResponseBase class
71
+ def make_response(response)
72
+ case @query.query_type
73
+ when Kentico::Kontent::Delivery::QUERY_TYPE_ITEMS_FEED
74
+ Kentico::Kontent::Delivery::Responses::DeliveryItemsFeedResponse.new(
75
+ response.headers,
76
+ response.body,
77
+ @query
78
+ )
79
+ when Kentico::Kontent::Delivery::QUERY_TYPE_ITEMS
80
+ respond_item response
81
+ when Kentico::Kontent::Delivery::QUERY_TYPE_TYPES
82
+ respond_type response
83
+ when Kentico::Kontent::Delivery::QUERY_TYPE_TAXONOMIES
84
+ respond_taxonomy response
85
+ when Kentico::Kontent::Delivery::QUERY_TYPE_ELEMENT
86
+ Kentico::Kontent::Delivery::Responses::DeliveryElementResponse.new response.headers, response.body
87
+ when Kentico::Kontent::Delivery::QUERY_TYPE_LANGUAGES
88
+ Kentico::Kontent::Delivery::Responses::DeliveryLanguageListingResponse.new response.headers, response.body
89
+ end
90
+ end
91
+
92
+ def respond_type(response)
93
+ if @query.code_name.nil?
94
+ Kentico::Kontent::Delivery::Responses::DeliveryTypeListingResponse.new response.headers, response.body
95
+ else
96
+ Kentico::Kontent::Delivery::Responses::DeliveryTypeResponse.new response.headers, response.body
97
+ end
98
+ end
99
+
100
+ def respond_taxonomy(response)
101
+ if @query.code_name.nil?
102
+ Kentico::Kontent::Delivery::Responses::DeliveryTaxonomyListingResponse.new response.headers, response.body
103
+ else
104
+ Kentico::Kontent::Delivery::Responses::DeliveryTaxonomyResponse.new response.headers, response.body
105
+ end
106
+ end
107
+
108
+ def respond_item(response)
109
+ if @query.code_name.nil?
110
+ Kentico::Kontent::Delivery::Responses::DeliveryItemListingResponse.new(
111
+ response.headers,
112
+ response.body,
113
+ @query
114
+ )
115
+ else
116
+ Kentico::Kontent::Delivery::Responses::DeliveryItemResponse.new(
117
+ response.headers,
118
+ response.body,
119
+ @query
120
+ )
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
128
127
  end
@@ -1,153 +1,153 @@
1
- require 'ostruct'
2
- require 'nokogiri'
3
-
4
- module Kentico
5
- module Kontent
6
- module Delivery
7
- class ContentItem
8
- attr_accessor :content_link_url_resolver,
9
- :inline_content_item_resolver
10
-
11
- # Parses the 'elements' JSON object as a dynamic OpenStruct object.
12
- #
13
- # * *Returns*:
14
- # - +OpenStruct+ The elements of the content item
15
- def elements
16
- @elements unless @elements.nil?
17
- @elements = JSON.parse(
18
- JSON.generate(@source['elements']),
19
- object_class: OpenStruct
20
- )
21
- end
22
-
23
- # Parses the 'system' JSON object as a dynamic OpenStruct object.
24
- #
25
- # * *Returns*:
26
- # - +OpenStruct+ The system properties of the content item
27
- def system
28
- @system unless @system.nil?
29
- @system = JSON.parse(
30
- JSON.generate(@source['system']),
31
- object_class: OpenStruct
32
- )
33
- end
34
-
35
- # Constructor.
36
- #
37
- # * *Args*:
38
- # - *source* (+JSON+) The response from a REST request for content items. The item may be on the root or under the 'item' node
39
- # - *content_link_url_resolver* ( Kentico::Kontent::Delivery::Resolvers::ContentLinkResolver )
40
- # - *inline_content_item_resolver* ( Kentico::Kontent::Delivery::Resolvers::InlineContentItemResolver )
41
- # - *linked_items_resolver* ( Kentico::Kontent::Delivery::Resolvers::LinkedItemResolver )
42
- def initialize(source, content_link_url_resolver, inline_content_item_resolver, linked_items_resolver)
43
- @source =
44
- if source['item'].nil?
45
- source
46
- else
47
- source['item']
48
- end
49
- @linked_items_resolver = linked_items_resolver
50
- self.content_link_url_resolver = content_link_url_resolver
51
- self.inline_content_item_resolver = inline_content_item_resolver
52
- end
53
-
54
- # Gets a string representation of the data stored in the element. Using this
55
- # method instead of directly accessing the +elements+ collection causes
56
- # the content to be resolved using the resolvers passed during instantiation.
57
- # See https://github.com/Kentico/kontent-delivery-sdk-ruby#resolving-links
58
- #
59
- # * *Args*:
60
- # - *code_name* (+string+) The code name of the desired element
61
- #
62
- # * *Returns*:
63
- # - +string+ The data converted to a string, resolved if the element is a 'rich_text' element
64
- def get_string(code_name)
65
- element = get_element code_name
66
- content = element['value']
67
-
68
- if element['type'] == 'rich_text'
69
- content = content_link_url_resolver.resolve content, element['links'] if should_resolve_links element
70
- inline_items = get_inline_items code_name
71
- content = inline_content_item_resolver.resolve content, inline_items if should_resolve_inline_content element
72
- end
73
- content.to_s
74
- end
75
-
76
- # Returns an array of assets inserted into the specified element of the
77
- # 'asset' type.
78
- #
79
- # * *Args*:
80
- # - *code_name* (+string+) The code name of the desired element
81
- #
82
- # * *Returns*:
83
- # - +Array+ The element's assets parsed as +OpenStruct+ objects
84
- def get_assets(code_name)
85
- element = get_element code_name
86
- element['value'].map { |n| OpenStruct.new(n) }
87
- end
88
-
89
- # Returns an array of ContentItems that are linked in a 'modular_content'
90
- # element.
91
- #
92
- # * *Args*:
93
- # - *code_name* (+string+) The code name of the desired element
94
- #
95
- # * *Returns*:
96
- # - +Array+ The element's linked items parsed as +ContentItem+ objects
97
- def get_links(code_name)
98
- element = get_element code_name
99
- get_linked_items element['value']
100
- end
101
-
102
- # Returns an array of ContentItems that are inserted as inline content
103
- # items or componenets of a 'rich_text' element.
104
- #
105
- # * *Args*:
106
- # - *code_name* (+string+) The code name of the desired element
107
- #
108
- # * *Returns*:
109
- # - +Array+ The element's inline content items parsed as +ContentItem+ objects
110
- def get_inline_items(code_name)
111
- element = get_element code_name
112
- get_linked_items element['modular_content']
113
- end
114
-
115
- private
116
-
117
- def should_resolve_links(element)
118
- !element['links'].nil? && !content_link_url_resolver.nil?
119
- end
120
-
121
- def should_resolve_inline_content(element)
122
- !element['modular_content'].nil? && !inline_content_item_resolver.nil?
123
- end
124
-
125
- # Gets the JSON object from the 'elements' collection with the specified key
126
- #
127
- # * *Args*:
128
- # - *code_name* (+string+, +symbol+) The code name or symbol of the desired element
129
- #
130
- # * *Returns*:
131
- # - +JSON+ The element as a JSON object
132
- #
133
- # * *Raises*:
134
- # - +ArgumentError+ if +code_name+ is +nil+
135
- def get_element(code_name)
136
- raise ArgumentError, "Argument 'code_name' cannot be null" if code_name.nil?
137
-
138
- code_name = code_name.to_s if code_name.is_a? Symbol
139
- @source['elements'][code_name]
140
- end
141
-
142
- def get_linked_items(codenames)
143
- return [] unless codenames.class == Array
144
-
145
- codenames.each_with_object([]) do |codename, items|
146
- item = @linked_items_resolver.resolve codename
147
- items << item if item
148
- end
149
- end
150
- end
151
- end
152
- end
153
- end
1
+ require 'ostruct'
2
+ require 'nokogiri'
3
+
4
+ module Kentico
5
+ module Kontent
6
+ module Delivery
7
+ class ContentItem
8
+ attr_accessor :content_link_url_resolver,
9
+ :inline_content_item_resolver
10
+
11
+ # Parses the 'elements' JSON object as a dynamic OpenStruct object.
12
+ #
13
+ # * *Returns*:
14
+ # - +OpenStruct+ The elements of the content item
15
+ def elements
16
+ @elements unless @elements.nil?
17
+ @elements = JSON.parse(
18
+ JSON.generate(@source['elements']),
19
+ object_class: OpenStruct
20
+ )
21
+ end
22
+
23
+ # Parses the 'system' JSON object as a dynamic OpenStruct object.
24
+ #
25
+ # * *Returns*:
26
+ # - +OpenStruct+ The system properties of the content item
27
+ def system
28
+ @system unless @system.nil?
29
+ @system = JSON.parse(
30
+ JSON.generate(@source['system']),
31
+ object_class: OpenStruct
32
+ )
33
+ end
34
+
35
+ # Constructor.
36
+ #
37
+ # * *Args*:
38
+ # - *source* (+JSON+) The response from a REST request for content items. The item may be on the root or under the 'item' node
39
+ # - *content_link_url_resolver* ( Kentico::Kontent::Delivery::Resolvers::ContentLinkResolver )
40
+ # - *inline_content_item_resolver* ( Kentico::Kontent::Delivery::Resolvers::InlineContentItemResolver )
41
+ # - *linked_items_resolver* ( Kentico::Kontent::Delivery::Resolvers::LinkedItemResolver )
42
+ def initialize(source, content_link_url_resolver, inline_content_item_resolver, linked_items_resolver)
43
+ @source =
44
+ if source['item'].nil?
45
+ source
46
+ else
47
+ source['item']
48
+ end
49
+ @linked_items_resolver = linked_items_resolver
50
+ self.content_link_url_resolver = content_link_url_resolver
51
+ self.inline_content_item_resolver = inline_content_item_resolver
52
+ end
53
+
54
+ # Gets a string representation of the data stored in the element. Using this
55
+ # method instead of directly accessing the +elements+ collection causes
56
+ # the content to be resolved using the resolvers passed during instantiation.
57
+ # See https://github.com/Kentico/kontent-delivery-sdk-ruby#resolving-links
58
+ #
59
+ # * *Args*:
60
+ # - *code_name* (+string+) The code name of the desired element
61
+ #
62
+ # * *Returns*:
63
+ # - +string+ The data converted to a string, resolved if the element is a 'rich_text' element
64
+ def get_string(code_name)
65
+ element = get_element code_name
66
+ content = element['value']
67
+
68
+ if element['type'] == 'rich_text'
69
+ content = content_link_url_resolver.resolve content, element['links'] if should_resolve_links element
70
+ inline_items = get_inline_items code_name
71
+ content = inline_content_item_resolver.resolve content, inline_items if should_resolve_inline_content element
72
+ end
73
+ content.to_s
74
+ end
75
+
76
+ # Returns an array of assets inserted into the specified element of the
77
+ # 'asset' type.
78
+ #
79
+ # * *Args*:
80
+ # - *code_name* (+string+) The code name of the desired element
81
+ #
82
+ # * *Returns*:
83
+ # - +Array+ The element's assets parsed as +OpenStruct+ objects
84
+ def get_assets(code_name)
85
+ element = get_element code_name
86
+ element['value'].map { |n| OpenStruct.new(n) }
87
+ end
88
+
89
+ # Returns an array of ContentItems that are linked in a 'modular_content'
90
+ # element.
91
+ #
92
+ # * *Args*:
93
+ # - *code_name* (+string+) The code name of the desired element
94
+ #
95
+ # * *Returns*:
96
+ # - +Array+ The element's linked items parsed as +ContentItem+ objects
97
+ def get_links(code_name)
98
+ element = get_element code_name
99
+ get_linked_items element['value']
100
+ end
101
+
102
+ # Returns an array of ContentItems that are inserted as inline content
103
+ # items or componenets of a 'rich_text' element.
104
+ #
105
+ # * *Args*:
106
+ # - *code_name* (+string+) The code name of the desired element
107
+ #
108
+ # * *Returns*:
109
+ # - +Array+ The element's inline content items parsed as +ContentItem+ objects
110
+ def get_inline_items(code_name)
111
+ element = get_element code_name
112
+ get_linked_items element['modular_content']
113
+ end
114
+
115
+ private
116
+
117
+ def should_resolve_links(element)
118
+ !element['links'].nil? && !content_link_url_resolver.nil?
119
+ end
120
+
121
+ def should_resolve_inline_content(element)
122
+ !element['modular_content'].nil? && !inline_content_item_resolver.nil?
123
+ end
124
+
125
+ # Gets the JSON object from the 'elements' collection with the specified key
126
+ #
127
+ # * *Args*:
128
+ # - *code_name* (+string+, +symbol+) The code name or symbol of the desired element
129
+ #
130
+ # * *Returns*:
131
+ # - +JSON+ The element as a JSON object
132
+ #
133
+ # * *Raises*:
134
+ # - +ArgumentError+ if +code_name+ is +nil+
135
+ def get_element(code_name)
136
+ raise ArgumentError, "Argument 'code_name' cannot be null" if code_name.nil?
137
+
138
+ code_name = code_name.to_s if code_name.is_a? Symbol
139
+ @source['elements'][code_name]
140
+ end
141
+
142
+ def get_linked_items(codenames)
143
+ return [] unless codenames.class == Array
144
+
145
+ codenames.each_with_object([]) do |codename, items|
146
+ item = @linked_items_resolver.resolve codename
147
+ items << item if item
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end