dustbag 0.0.1

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.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +92 -0
  4. data/lib/dustbag.rb +47 -0
  5. data/lib/dustbag/accessories.rb +7 -0
  6. data/lib/dustbag/accessory.rb +6 -0
  7. data/lib/dustbag/arguments.rb +8 -0
  8. data/lib/dustbag/availability_attributes.rb +9 -0
  9. data/lib/dustbag/browse_node.rb +15 -0
  10. data/lib/dustbag/browse_nodes.rb +7 -0
  11. data/lib/dustbag/common.rb +7 -0
  12. data/lib/dustbag/customer_reviews.rb +11 -0
  13. data/lib/dustbag/dimension.rb +13 -0
  14. data/lib/dustbag/dimensions.rb +10 -0
  15. data/lib/dustbag/editorial_review.rb +11 -0
  16. data/lib/dustbag/editorial_reviews.rb +7 -0
  17. data/lib/dustbag/http_headers.rb +8 -0
  18. data/lib/dustbag/image.rb +5 -0
  19. data/lib/dustbag/image_set.rb +9 -0
  20. data/lib/dustbag/image_sets.rb +7 -0
  21. data/lib/dustbag/item.rb +21 -0
  22. data/lib/dustbag/item_attributes.rb +79 -0
  23. data/lib/dustbag/item_link.rb +9 -0
  24. data/lib/dustbag/item_links.rb +7 -0
  25. data/lib/dustbag/item_search_request.rb +7 -0
  26. data/lib/dustbag/item_search_response.rb +8 -0
  27. data/lib/dustbag/items.rb +14 -0
  28. data/lib/dustbag/language.rb +7 -0
  29. data/lib/dustbag/languages.rb +7 -0
  30. data/lib/dustbag/offer.rb +52 -0
  31. data/lib/dustbag/offer_summary.rb +12 -0
  32. data/lib/dustbag/offers.rb +7 -0
  33. data/lib/dustbag/operation_request.rb +13 -0
  34. data/lib/dustbag/parser.rb +26 -0
  35. data/lib/dustbag/parser/collection_node.rb +37 -0
  36. data/lib/dustbag/parser/map_collection_node.rb +19 -0
  37. data/lib/dustbag/parser/node.rb +112 -0
  38. data/lib/dustbag/price.rb +13 -0
  39. data/lib/dustbag/request.rb +11 -0
  40. data/lib/dustbag/similar_product.rb +6 -0
  41. data/lib/dustbag/similar_products.rb +7 -0
  42. data/lib/dustbag/simple_product.rb +9 -0
  43. data/lib/dustbag/variation_attribute.rb +7 -0
  44. data/lib/dustbag/variation_attributes.rb +7 -0
  45. data/lib/dustbag/variation_summary.rb +13 -0
  46. data/lib/dustbag/variations.rb +18 -0
  47. data/lib/dustbag/version.rb +3 -0
  48. data/spec/dustbag/accessories_spec.rb +9 -0
  49. data/spec/dustbag/accessory_spec.rb +10 -0
  50. data/spec/dustbag/arguments_spec.rb +9 -0
  51. data/spec/dustbag/availability_attributes_spec.rb +21 -0
  52. data/spec/dustbag/browse_node_spec.rb +33 -0
  53. data/spec/dustbag/browse_nodes_spec.rb +9 -0
  54. data/spec/dustbag/customer_reviews_spec.rb +17 -0
  55. data/spec/dustbag/dimension_spec.rb +17 -0
  56. data/spec/dustbag/dimensions_spec.rb +29 -0
  57. data/spec/dustbag/editorial_review_spec.rb +21 -0
  58. data/spec/dustbag/editorial_reviews_spec.rb +9 -0
  59. data/spec/dustbag/http_headers_spec.rb +11 -0
  60. data/spec/dustbag/image_set_spec.rb +13 -0
  61. data/spec/dustbag/image_sets_spec.rb +9 -0
  62. data/spec/dustbag/image_spec.rb +9 -0
  63. data/spec/dustbag/item_attributes_spec.rb +188 -0
  64. data/spec/dustbag/item_link_spec.rb +17 -0
  65. data/spec/dustbag/item_links_spec.rb +9 -0
  66. data/spec/dustbag/item_search_request_spec.rb +21 -0
  67. data/spec/dustbag/item_search_response_spec.rb +13 -0
  68. data/spec/dustbag/item_spec.rb +110 -0
  69. data/spec/dustbag/items_spec.rb +25 -0
  70. data/spec/dustbag/language_spec.rb +17 -0
  71. data/spec/dustbag/languages_spec.rb +9 -0
  72. data/spec/dustbag/offer_spec.rb +43 -0
  73. data/spec/dustbag/offer_summary_spec.rb +30 -0
  74. data/spec/dustbag/offers_spec.rb +9 -0
  75. data/spec/dustbag/operation_request_spec.rb +27 -0
  76. data/spec/dustbag/parser_spec.rb +23 -0
  77. data/spec/dustbag/price_spec.rb +18 -0
  78. data/spec/dustbag/request_spec.rb +25 -0
  79. data/spec/dustbag/similar_product_spec.rb +18 -0
  80. data/spec/dustbag/similar_products_spec.rb +9 -0
  81. data/spec/dustbag/variation_attribute_spec.rb +17 -0
  82. data/spec/dustbag/variation_attributes_spec.rb +9 -0
  83. data/spec/dustbag/variation_summary_spec.rb +19 -0
  84. data/spec/dustbag/variations_spec.rb +22 -0
  85. data/spec/fixtures/accessories.xml +23 -0
  86. data/spec/fixtures/accessory.xml +4 -0
  87. data/spec/fixtures/arguments.xml +11 -0
  88. data/spec/fixtures/availability_attributes.xml +5 -0
  89. data/spec/fixtures/book_item_attributes.xml +61 -0
  90. data/spec/fixtures/browse_node.xml +23 -0
  91. data/spec/fixtures/browse_nodes.xml +25 -0
  92. data/spec/fixtures/customer_reviews.xml +5 -0
  93. data/spec/fixtures/dimension.xml +1 -0
  94. data/spec/fixtures/dimensions.xml +6 -0
  95. data/spec/fixtures/editorial_review.xml +5 -0
  96. data/spec/fixtures/editorial_reviews.xml +7 -0
  97. data/spec/fixtures/http_headers.xml +3 -0
  98. data/spec/fixtures/image.xml +5 -0
  99. data/spec/fixtures/image_set.xml +32 -0
  100. data/spec/fixtures/image_sets.xml +34 -0
  101. data/spec/fixtures/invalid_request.xml +8 -0
  102. data/spec/fixtures/item.xml +40 -0
  103. data/spec/fixtures/item_attributes.xml +58 -0
  104. data/spec/fixtures/item_large.xml +500 -0
  105. data/spec/fixtures/item_link.xml +4 -0
  106. data/spec/fixtures/item_links.xml +30 -0
  107. data/spec/fixtures/item_medium.xml +123 -0
  108. data/spec/fixtures/item_search_request.xml +5 -0
  109. data/spec/fixtures/item_search_response.xml +433 -0
  110. data/spec/fixtures/item_small.xml +40 -0
  111. data/spec/fixtures/item_with_accessories.xml +122 -0
  112. data/spec/fixtures/item_with_variation_attributes.xml +264 -0
  113. data/spec/fixtures/item_with_variations.xml +1016 -0
  114. data/spec/fixtures/items.xml +411 -0
  115. data/spec/fixtures/language.xml +4 -0
  116. data/spec/fixtures/languages.xml +6 -0
  117. data/spec/fixtures/movie_item_attributes.xml +30 -0
  118. data/spec/fixtures/offer.xml +26 -0
  119. data/spec/fixtures/offer_summary.xml +11 -0
  120. data/spec/fixtures/offers.xml +31 -0
  121. data/spec/fixtures/operation_request.xml +18 -0
  122. data/spec/fixtures/price.xml +5 -0
  123. data/spec/fixtures/request.xml +8 -0
  124. data/spec/fixtures/root_browse_node.xml +11 -0
  125. data/spec/fixtures/similar_product.xml +4 -0
  126. data/spec/fixtures/similar_products.xml +18 -0
  127. data/spec/fixtures/variation_attribute.xml +4 -0
  128. data/spec/fixtures/variation_attributes.xml +6 -0
  129. data/spec/fixtures/variation_summary.xml +12 -0
  130. data/spec/fixtures/variations.xml +1000 -0
  131. data/spec/shared_examples/collection_node.rb +15 -0
  132. data/spec/shared_examples/common_response.rb +7 -0
  133. data/spec/shared_examples/map_collection_node.rb +13 -0
  134. data/spec/shared_examples/node.rb +9 -0
  135. data/spec/shared_examples/node_context.rb +6 -0
  136. data/spec/shared_examples/simple_product.rb +4 -0
  137. data/spec/spec_helper.rb +16 -0
  138. metadata +356 -0
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe ItemLink do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#description' do
10
+ it { expect(subject.description).to eq 'Technical Details' }
11
+ end
12
+
13
+ describe '#url' do
14
+ it { expect(subject.url).to eq 'http://www.amazon.com/Motorola-Moto-3rd-Generation-Unlocked/dp/tech-data/B00ZQVSKS2%3FSubscriptionId%3DMyAccessKeyId%26tag%3Daffiliate-tag%26linkCode%3Dxm2%26camp%3D2025%26creative%3D386001%26creativeASIN%3DB00ZQVSKS2' }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe ItemLinks do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a collection node of', ItemLink
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe ItemSearchRequest do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#keywords' do
10
+ it { expect(subject.keywords).to eq 'moto g' }
11
+ end
12
+
13
+ describe '#response_group' do
14
+ it { expect(subject.response_group).to eq 'Small' }
15
+ end
16
+
17
+ describe '#search_index' do
18
+ it { expect(subject.search_index).to eq 'All' }
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe ItemSearchResponse do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a common response'
8
+
9
+ describe '#items' do
10
+ it { expect(subject.items).to be_a_kind_of Items }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Item do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#asin' do
10
+ it { expect(subject.asin).to eq 'B00ZQVSKS2' }
11
+ end
12
+
13
+ describe '#parent_asin' do
14
+ it { expect(subject.parent_asin).to eq 'B0127MKEAE' }
15
+ end
16
+
17
+ describe '#detail_page_url' do
18
+ it { expect(subject.detail_page_url).to eq 'http://www.amazon.com/Motorola-Moto-3rd-Generation-Unlocked/dp/B00ZQVSKS2%3Fpsc%3D1%26SubscriptionId%3DMyAccessKeyId%26tag%3Daffiliate-tag%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB00ZQVSKS2' }
19
+ end
20
+
21
+ describe '#item_links' do
22
+ it { expect(subject.item_links).to be_a_kind_of ItemLinks }
23
+ end
24
+
25
+ describe '#item_attributes' do
26
+ it { expect(subject.item_attributes).to be_a_kind_of ItemAttributes }
27
+ end
28
+
29
+ context 'item response for the medium response group' do
30
+ include_context 'load xml from fixture', 'item_medium'
31
+
32
+ describe '#small_image' do
33
+ it { expect(subject.small_image).to be_a_kind_of Image }
34
+ end
35
+
36
+ describe '#medium_image' do
37
+ it { expect(subject.medium_image).to be_a_kind_of Image }
38
+ end
39
+
40
+ describe '#large_image' do
41
+ it { expect(subject.large_image).to be_a_kind_of Image }
42
+ end
43
+
44
+ describe '#image_sets' do
45
+ it { expect(subject.image_sets).to be_a_kind_of ImageSets }
46
+ end
47
+
48
+ describe '#offer_summary' do
49
+ it { expect(subject.offer_summary).to be_a_kind_of OfferSummary }
50
+ end
51
+ end
52
+
53
+ context 'item response for the large response group' do
54
+ include_context 'load xml from fixture', 'item_large'
55
+
56
+ describe '#sales_rank' do
57
+ it { expect(subject.sales_rank).to eq 399 }
58
+ end
59
+
60
+ describe '#offers' do
61
+ it { expect(subject.offers).to be_a_kind_of Offers }
62
+ end
63
+
64
+ describe '#customer_reviews' do
65
+ it { expect(subject.customer_reviews).to be_a_kind_of CustomerReviews }
66
+ end
67
+
68
+ describe '#editorial_reviews' do
69
+ it { expect(subject.editorial_reviews).to be_a_kind_of EditorialReviews }
70
+ end
71
+
72
+ describe '#similar_products' do
73
+ it { expect(subject.similar_products).to be_a_kind_of SimilarProducts }
74
+ end
75
+
76
+ describe '#browse_nodes' do
77
+ it { expect(subject.browse_nodes).to be_a_kind_of BrowseNodes }
78
+ end
79
+ end
80
+
81
+ context 'item with accessories' do
82
+ include_context 'load xml from fixture', 'item_with_accessories'
83
+
84
+ describe '#accessories' do
85
+ it { expect(subject.accessories).to be_a_kind_of(Accessories) }
86
+ it { expect(subject.accessories).to_not be_empty }
87
+ end
88
+ end
89
+
90
+ context 'item with variations' do
91
+ include_context 'load xml from fixture', 'item_with_variations'
92
+
93
+ describe '#variation_summary' do
94
+ it { expect(subject.variation_summary).to be_a_kind_of VariationSummary }
95
+ end
96
+
97
+ describe '#variations' do
98
+ it { expect(subject.variations).to be_a_kind_of Variations }
99
+ it { expect(subject.variations).to_not be_empty }
100
+ end
101
+ end
102
+
103
+ context 'item with variation attributes' do
104
+ include_context 'load xml from fixture', 'item_with_variation_attributes'
105
+
106
+ it { expect(subject.variation_attributes).to_not be_empty }
107
+ it { expect(subject.variation_attributes).to be_a_kind_of VariationAttributes }
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Items do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a collection node of', Item
8
+
9
+ describe '#request' do
10
+ it { expect(subject.request).to be_a_kind_of Request }
11
+ end
12
+
13
+ describe '#total_results' do
14
+ it { expect(subject.total_results).to eq 1630787 }
15
+ end
16
+
17
+ describe '#total_pages' do
18
+ it { expect(subject.total_pages).to eq 163079 }
19
+ end
20
+
21
+ describe '#more_search_results_url' do
22
+ it { expect(subject.more_search_results_url).to eq 'http://www.amazon.com/gp/redirect.html?linkCode=xm2&SubscriptionId=MyAccessKeyId&location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Fsearch%3Fkeywords%3Dmoto%2Bg%26url%3Dsearch-alias%253Daws-amazon-aps&tag=affiliate-tag&creative=386001&camp=2025' }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Language do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#name' do
10
+ it { expect(subject.name).to eq('English') }
11
+ end
12
+
13
+ describe '#type' do
14
+ it { expect(subject.type).to eq('Subtitled') }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Languages do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a collection node of', Language
8
+ end
9
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Offer do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#condition' do
10
+ it { expect(subject.condition).to eq 'New' }
11
+ end
12
+
13
+ describe '#id' do
14
+ it { expect(subject.id).to eq 'DZEJaOVZkxOW3bnN9SFvLNIEVwWDB3Y0HBG5zgBQ7jwJI9gANnOgNkJYiwRiuWUAx8GXFAWOjSrH4nrN4grN4gmtpEZHnkVZy4bHkNzvMu2G18d6bykCLQ%3D%3D' }
15
+ end
16
+
17
+ describe '#price' do
18
+ it { expect(subject.price).to be_a_kind_of Money }
19
+ it { expect(subject.price.format).to eq '$179.62' }
20
+ end
21
+
22
+ describe '#amount_saved' do
23
+ it { expect(subject.amount_saved).to be_a_kind_of Money }
24
+ it { expect(subject.amount_saved.format).to eq '$0.37' }
25
+ end
26
+
27
+ describe '#availability' do
28
+ it { expect(subject.availability).to eq 'Usually ships in 24 hours' }
29
+ end
30
+
31
+ describe '#availability_attributes' do
32
+ it { expect(subject.availability_attributes).to be_a_kind_of AvailabilityAttributes }
33
+ end
34
+
35
+ describe '#eligible_for_super_saver_shipping?' do
36
+ it { expect(subject.eligible_for_super_saver_shipping?).to be_truthy }
37
+ end
38
+
39
+ describe '#eligible_for_prime?' do
40
+ it { expect(subject.eligible_for_prime?).to be_truthy }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe OfferSummary do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#lowest_new_price' do
10
+ it { expect(subject.lowest_new_price).to be_a_kind_of Money }
11
+ it { expect(subject.lowest_new_price.format).to eq '$14.99' }
12
+ end
13
+
14
+ describe '#total_new' do
15
+ it { expect(subject.total_new).to eq 1 }
16
+ end
17
+
18
+ describe '#total_used' do
19
+ it { expect(subject.total_used).to eq 0 }
20
+ end
21
+
22
+ describe '#total_collectible' do
23
+ it { expect(subject.total_collectible).to eq 0 }
24
+ end
25
+
26
+ describe '#total_refurbished' do
27
+ it { expect(subject.total_refurbished).to eq 0 }
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Offers do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a collection node of', Offer
8
+ end
9
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe OperationRequest do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#request_id' do
10
+ it { expect(subject.request_id).to eq '0adda2e2-434e-44f4-a216-dbdf4c593d1b' }
11
+ end
12
+
13
+ describe '#arguments' do
14
+ it { expect(subject.arguments).to be_a_kind_of Arguments }
15
+ it { expect(subject.arguments).to_not be_empty }
16
+ end
17
+
18
+ describe '#http_headers' do
19
+ it { expect(subject.http_headers).to be_a_kind_of HttpHeaders }
20
+ it { expect(subject.http_headers).to_not be_empty }
21
+ end
22
+
23
+ describe '#request_processing_time' do
24
+ it { expect(subject.request_processing_time).to eq '0.2921170000000000' }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ context 'an ItemSearchResponse' do
5
+ let(:response) { File.read('spec/fixtures/item_search_response.xml') }
6
+
7
+ it { expect{ Dustbag::Parser.parse(response) }.to_not raise_exception }
8
+
9
+ it { expect(Dustbag::Parser.parse(response)).to be_a_kind_of ItemSearchResponse }
10
+ end
11
+
12
+ context 'a not implemented response type' do
13
+ let(:response) { '<?xml version="1.0" ?><foo>Foo</foo>' }
14
+
15
+ it { expect{ Dustbag::Parser.parse(response) }.to raise_exception('foo is not implemented!') }
16
+ end
17
+
18
+ context 'not a xml response' do
19
+ let(:response) { '' }
20
+
21
+ it { expect{ Dustbag::Parser.parse(response) }.to raise_exception('Not a Ox::Document') }
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Price do
5
+ let(:xml) { Ox.parse(File.read('spec/fixtures/price.xml')) }
6
+
7
+ describe '#parse' do
8
+ it { expect(subject.parse(xml)).to be_a_kind_of Money }
9
+ it { expect(subject.parse(xml).to_s).to eq '179.99' }
10
+ it { expect(subject.parse(xml).currency).to be_a_kind_of Money::Currency }
11
+ it { expect(subject.parse(xml).currency.iso_code).to eq 'USD' }
12
+
13
+ context 'when xml is nil' do
14
+ it { expect(subject.parse(nil)).to be_nil }
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe Request do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+
9
+ describe '#valid?' do
10
+ context 'when request is valid' do
11
+ it { expect(subject.valid?).to be_truthy }
12
+ end
13
+
14
+ context 'when request is not valid' do
15
+ include_context 'load xml from fixture', 'invalid_request'
16
+
17
+ it { expect(subject.valid?).to be_falsy }
18
+ end
19
+ end
20
+
21
+ describe '#item_search_request' do
22
+ it { expect(subject.item_search_request).to be_a_kind_of ItemSearchRequest }
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,18 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe SimilarProduct do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a node'
8
+ it_behaves_like 'a simple product'
9
+
10
+ describe '#asin' do
11
+ it { expect(subject.asin).to eq 'B0146PPAG8' }
12
+ end
13
+
14
+ describe '#title' do
15
+ it { expect(subject.title).to eq "Moto G (3rd Gen) Tempered Glass Screen Protector, PLESON Motorola Moto G 3rd Generation Screen Protector [Lifetime No-Hassle Warranty] 0.3mm Premium HD Clear Glass Screen Protector for Moto G3" }
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ module Dustbag
4
+ describe SimilarProducts do
5
+ include_context 'load xml from fixture'
6
+
7
+ it_behaves_like 'a collection node of', SimilarProduct
8
+ end
9
+ end