goods 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.
@@ -0,0 +1,87 @@
1
+ require "spec_helper"
2
+
3
+ describe Goods::Offer do
4
+ let(:books) { Goods::Category.new(id: "1", name: "Books") }
5
+ let(:rur) { Goods::Currency.new(id: "RUR", rate: 1, plus: 0) }
6
+ let(:valid_description) do
7
+ {id: "1", name: "The Lord of The Rings", category_id: "1", currency_id: "RUR", price: 10}
8
+ end
9
+ let(:valid_offer) do
10
+ offer = Goods::Offer.new(valid_description)
11
+ offer.category = books
12
+ offer.currency = rur
13
+ offer
14
+ end
15
+
16
+ it_should_behave_like "containable" do
17
+ let(:element) { valid_offer }
18
+ end
19
+
20
+ describe "#valid?" do
21
+ context "invalid cases" do
22
+ let(:invalid_offer) { Goods::Offer.new({}) }
23
+
24
+ [:id, :category_id, :currency_id, :price].each do |field|
25
+ it "should reject offers without #{field}" do
26
+ expect(invalid_offer).not_to be_valid
27
+ expect(invalid_offer.invalid_fields).to include(field)
28
+ end
29
+ end
30
+
31
+ it "should reject offers with non-positive price" do
32
+ invalid_offer = Goods::Offer.new(price: -5.0)
33
+ expect(invalid_offer).not_to be_valid
34
+ expect(invalid_offer.invalid_fields).to include(:price)
35
+ end
36
+ end
37
+
38
+ context "valid cases" do
39
+ it "should accept offer when it has id, category, currency and price" do
40
+ expect(valid_offer).to be_valid
41
+ end
42
+ end
43
+ end
44
+
45
+ [:available, :description, :model, :name, :picture, :vendor].each do |field|
46
+ it "should have #{field}" do
47
+ expect(valid_offer).to respond_to(field)
48
+ end
49
+ end
50
+
51
+ it "should have floting point price" do
52
+ expect(Goods::Offer.new(price: 5).price).to be_kind_of(Float)
53
+ end
54
+
55
+ describe "#convert_currency" do
56
+ let(:usd) { Goods::Currency.new(id: "USD", rate: 30, plus: 0) }
57
+
58
+ it "should change currency" do
59
+ valid_offer.convert_currency(usd)
60
+ expect(valid_offer.currency).to be(usd)
61
+ end
62
+
63
+ it "should leave offer valid" do
64
+ valid_offer.convert_currency(usd)
65
+ expect(valid_offer).to be_valid
66
+ end
67
+
68
+ it "should change price according to rate" do
69
+ valid_offer.convert_currency(usd)
70
+ expect(valid_offer.price).to eql(1.0/3)
71
+ end
72
+ end
73
+
74
+ describe "#change_category" do
75
+ let(:printers) { Goods::Category.new(id: "print", name: "Printers") }
76
+
77
+ it "should change category to specified one" do
78
+ valid_offer.change_category(printers)
79
+ expect(valid_offer.category).to be(printers)
80
+ end
81
+
82
+ it "should leave offer valid" do
83
+ valid_offer.change_category(printers)
84
+ expect(valid_offer).to be_valid
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Goods::OffersList do
4
+ let(:categories) { Goods::CategoriesList.new([{id: "1", name: "Category"}]) }
5
+ let(:currencies) { Goods::CurrenciesList.new([{id: "RUR", rate: 1, plus: 0}]) }
6
+ let(:offers) { Goods::OffersList.new(categories, currencies) }
7
+ let(:subject) { offers }
8
+
9
+ it_should_behave_like "a container",
10
+ Goods::Offer,
11
+ Goods::Offer.new(id: "1", url: "url.com", category_id: "1", currency_id: "RUR", price: 10) do
12
+ let(:subject) { offers }
13
+ end
14
+
15
+ describe "#add" do
16
+ it "should setup category and currency for offer" do
17
+ offer = Goods::Offer.new(id: "1", url: "url.com", category_id: "1", currency_id: "RUR", price: 10)
18
+ subject.add(offer)
19
+
20
+ expect(offer.category).to be(categories.find("1"))
21
+ expect(offer.currency).to be(currencies.find("RUR"))
22
+ end
23
+ end
24
+
25
+ describe "#prune_categories" do
26
+ let(:categories) do
27
+ list = Goods::CategoriesList.new [
28
+ {id: "1", name: "root"},
29
+ {id: "11", name: "root", parent_id: "1"},
30
+ {id: "12", name: "root", parent_id: "11"}
31
+ ]
32
+ list
33
+ end
34
+ let(:offers) do
35
+ list = Goods::OffersList.new categories, currencies, [
36
+ {id: "1", category_id: "1", currency_id: "RUR", price: 1},
37
+ {id: "2", category_id: "11", currency_id: "RUR", price: 1},
38
+ {id: "3", category_id: "12", currency_id: "RUR", price: 1}
39
+ ]
40
+ list
41
+ end
42
+
43
+ it "should raise error if level < 0" do
44
+ expect{ offers.prune_categories }.to raise_error(ArgumentError)
45
+ end
46
+
47
+ it "should replace deep categories with their parents on specified level" do
48
+ offers.prune_categories(1)
49
+ expect(offers.find("3").category).to be(categories.find("11"))
50
+ end
51
+
52
+ it "should not affect offers with categories having lower level" do
53
+ offers.prune_categories(1)
54
+ expect(offers.find("1").category).to be(categories.find("1"))
55
+ end
56
+ end
57
+
58
+ describe "#convert_currency" do
59
+ let(:currencies) do
60
+ Goods::CurrenciesList.new([
61
+ {id: "RUR", rate: 1, plus: 0},
62
+ {id: "USD", rate: 30, plus: 0},
63
+ {id: "GBP", rate: 50, plus: 0}
64
+ ])
65
+ end
66
+ let(:offers) do
67
+ list = Goods::OffersList.new categories, currencies, [
68
+ {id: "1", category_id: "1", currency_id: "USD", price: 1},
69
+ {id: "2", category_id: "1", currency_id: "GBP", price: 1}
70
+ ]
71
+ list
72
+ end
73
+
74
+ it "should convert currency for all offers" do
75
+ expect(offers.find("1")).to receive(:convert_currency)
76
+ expect(offers.find("2")).to receive(:convert_currency)
77
+ offers.convert_currency(currencies.find("RUR"))
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+
3
+ describe Goods::XML::Validator do
4
+ let(:valid_document) { File.read(File.expand_path("../../../fixtures/simple_catalog.xml", __FILE__)) }
5
+ let(:invalid_document) { File.read(File.expand_path("../../../fixtures/empty_catalog.xml", __FILE__)) }
6
+
7
+ describe "#valid?" do
8
+ it "should return true if document is valid according to dtd" do
9
+ validator = Goods::XML::Validator.new
10
+ expect(validator.valid? valid_document).to eql(true)
11
+ expect(validator.error).to be_nil
12
+ end
13
+
14
+ it "should return false if document is not valid" do
15
+ validator = Goods::XML::Validator.new
16
+ expect(validator.valid? invalid_document).to eql(false)
17
+ end
18
+
19
+ it "should have non-empty errors if document is not valid" do
20
+ validator = Goods::XML::Validator.new
21
+ validator.valid? invalid_document
22
+ expect(validator.error).not_to be_nil
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,178 @@
1
+ require 'spec_helper'
2
+
3
+ describe Goods::XML do
4
+ let(:simple_catalog_data) do
5
+ File.read(File.expand_path('../../fixtures/simple_catalog.xml', __FILE__))
6
+ end
7
+ let(:simple_catalog) { Goods::XML.new(simple_catalog_data) }
8
+ SIMPLE_CATALOG_CATEGORIES_COUNT = 9
9
+ SIMPLE_CATALOG_CURRENCIES_COUNT = 3
10
+ SIMPLE_CATALOG_OFFERS_COUNT = 2
11
+
12
+ describe "#initialize" do
13
+ it 'should use Nokogiri for parsing' do
14
+ params = ["string", "url", "encoding"]
15
+ expect(Nokogiri::XML::Document).to receive(:parse).with(*params)
16
+
17
+ Goods::XML.new(*params)
18
+ end
19
+
20
+ it 'should parse valid document' do
21
+ expect(simple_catalog.instance_variable_get("@xml_source")).to be_kind_of(Nokogiri::XML::Document)
22
+ end
23
+ end
24
+
25
+ describe "#categories" do
26
+ let(:categories) { simple_catalog.categories }
27
+
28
+ it "should extract all categories" do
29
+ expect(categories.count).to eq(SIMPLE_CATALOG_CATEGORIES_COUNT)
30
+ end
31
+
32
+ context "category format" do
33
+ let(:root_category) { categories[0] }
34
+ let(:child_category) { categories[1] }
35
+
36
+ it "should have an id" do
37
+ expect(root_category[:id]).to eq("1")
38
+ end
39
+
40
+ it "should have a name" do
41
+ expect(root_category[:name]).to eq("Оргтехника")
42
+ end
43
+
44
+ it "should have nil parent_id for root category" do
45
+ expect(root_category[:parent_id]).to be_nil
46
+ end
47
+
48
+ it "should have non-nil parent_id for child_category" do
49
+ expect(child_category[:parent_id]).to eq("1")
50
+ end
51
+ end
52
+
53
+ it 'should call #extract_categories only at the first invocation' do
54
+ expect_any_instance_of(Goods::XML).to receive(:extract_categories).once.and_call_original
55
+ 2.times { simple_catalog.categories }
56
+ end
57
+ end
58
+
59
+ describe "#currencies" do
60
+ it "should extract all currencies" do
61
+ expect(simple_catalog.currencies.count).to eq(SIMPLE_CATALOG_CURRENCIES_COUNT)
62
+ end
63
+
64
+ context "currency format" do
65
+ let(:rur) { simple_catalog.currencies[0] }
66
+ let(:usd) { simple_catalog.currencies[1] }
67
+ let(:kzt) { simple_catalog.currencies[2] }
68
+
69
+ it "should have an id" do
70
+ expect(rur[:id]).to eq("RUR")
71
+ end
72
+
73
+ it "should have a rate" do
74
+ expect(rur[:rate]).to eq("1")
75
+ end
76
+
77
+ it "should have a custom rate" do
78
+ expect(usd[:rate]).to eq("30")
79
+ end
80
+
81
+ it "should have a default rate" do
82
+ expect(kzt[:rate]).to eq("1")
83
+ end
84
+
85
+ it "should have a plus" do
86
+ expect(rur[:plus]).to eq("0")
87
+ end
88
+
89
+ it "should have a default plus" do
90
+ expect(kzt[:plus]).to eq("0")
91
+ end
92
+ end
93
+
94
+ it 'should call #extract_currencies only at the first invocation' do
95
+ expect_any_instance_of(Goods::XML).to receive(:extract_currencies).once.and_call_original
96
+ 2.times { simple_catalog.currencies }
97
+ end
98
+ end
99
+
100
+ describe "#offers" do
101
+ it 'should extract all offers' do
102
+ expect(simple_catalog.offers.count).to eq(SIMPLE_CATALOG_OFFERS_COUNT)
103
+ end
104
+
105
+ context "offer format" do
106
+ let(:printer) { simple_catalog.offers[0] }
107
+ let(:book) { simple_catalog.offers[1] }
108
+
109
+ it "should have an id" do
110
+ expect(printer[:id]).to eq("123")
111
+ end
112
+
113
+ it "should have availability status" do
114
+ expect(book[:available]).to eq(false)
115
+ end
116
+
117
+ it "should have default availability status" do
118
+ expect(printer[:available]).to eq(true)
119
+ end
120
+
121
+ it "should have a URL which is not empty" do
122
+ expect(printer[:url]).to eq("http://magazin.ru/product_page.asp?pid=14344")
123
+ end
124
+
125
+ it "should have a nil URL if offer doesn't have one" do
126
+ expect(book[:url]).to be_nil
127
+ end
128
+
129
+ it "should have a price" do
130
+ expect(printer[:price]).to eq(15000.00)
131
+ end
132
+
133
+ it "should have a currency_id" do
134
+ expect(printer[:currency_id]).to eq("RUR")
135
+ end
136
+
137
+ it "should use first category_id" do
138
+ expect(printer[:category_id]).to eq("100")
139
+ end
140
+
141
+ it "should use first picture if there at least one" do
142
+ expect(printer[:picture]).to eq("http://magazin.ru/img/device1.jpg")
143
+ end
144
+
145
+ it "should have a nil picture if offer doesn't have one" do
146
+ expect(book[:picture]).to be_nil
147
+ end
148
+
149
+ it "should have a description" do
150
+ expect(printer[:description]).to eq("A4, 64Mb, 600x600 dpi, USB 2.0, 29стр/мин ч/б / 15стр/мин цв, лотки на 100л и 250л, плотность до 175г/м, до 60000 стр/месяц")
151
+ end
152
+
153
+ it "should have a non-empty name" do
154
+ expect(book[:name]).to eq("Все не так. В 2 томах. Том 1")
155
+ end
156
+
157
+ it "should have a nil name if offer doesn't have one" do
158
+ expect(printer[:name]).to be_nil
159
+ end
160
+
161
+ it "should have a non-empty vendor" do
162
+ expect(printer[:vendor]).to eq("НP")
163
+ end
164
+
165
+ it "should have a nil vendor if offer doesn't have one" do
166
+ expect(book[:vendor]).to be_nil
167
+ end
168
+
169
+ it "should have a non-empty model" do
170
+ expect(printer[:model]).to eq("Color LaserJet 3000")
171
+ end
172
+
173
+ it "should have a nil model if offer doesn't have one" do
174
+ expect(book[:model]).to be_nil
175
+ end
176
+ end
177
+ end
178
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe Goods do
4
+ it 'should have a version number' do
5
+ expect(Goods::VERSION).to_not be_nil
6
+ end
7
+
8
+ describe ".from_string" do
9
+ let(:valid_document) { File.read(File.expand_path("../fixtures/simple_catalog.xml", __FILE__)) }
10
+ let(:invalid_document) { File.read(File.expand_path("../fixtures/empty_catalog.xml", __FILE__)) }
11
+
12
+ it "should return catalog if valid xml file is passed" do
13
+ expect(Goods::Catalog).to receive(:new).
14
+ with({string: valid_document, url: "url", encoding: "UTF-8"})
15
+ Goods.from_string(valid_document, "url", "UTF-8")
16
+ end
17
+
18
+ it "should raise error if invalid file is passed" do
19
+ expect { Goods.from_string(invalid_document) }.to raise_error(Goods::XML::InvalidFormatError)
20
+ end
21
+ end
22
+
23
+ describe ".from_file" do
24
+ it "should load file and call .from_string" do
25
+ params = {
26
+ file: "file", string: "string", url: nil, encoding: "UTF-8"
27
+ }
28
+ expect(Goods).to receive(:load).with(params[:file]) { params[:string] }
29
+ expect(Goods).to receive(:from_string).with(params[:string], nil, params[:encoding])
30
+ Goods.from_file params[:file], params[:encoding]
31
+ end
32
+ end
33
+
34
+ describe ".from_url" do
35
+ it "should load remote page and call .from_string" do
36
+ params = {
37
+ string: "string", url: "url", encoding: "UTF-8"
38
+ }
39
+ expect(Goods).to receive(:load).with(params[:url]) { params[:string] }
40
+ expect(Goods).to receive(:from_string).with(params[:string], params[:url], params[:encoding])
41
+ Goods.from_url params[:url], params[:encoding]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,22 @@
1
+ require 'bundler/setup'
2
+ require 'goods'
3
+
4
+ Dir[File.expand_path("../support/**/*.rb", __FILE__)].each { |f| require f }
5
+
6
+ RSpec.configure do |config|
7
+ # Limit the spec run to only specs with the focus metadata. If no specs have
8
+ # the filtering metadata and `run_all_when_everything_filtered = true` then
9
+ # all specs will run.
10
+ config.filter_run :focus
11
+
12
+ # Run all specs when none match the provided filter. This works well in
13
+ # conjunction with `config.filter_run :focus`, as it will run the entire
14
+ # suite when no specs have `:filter` metadata.
15
+ config.run_all_when_everything_filtered = true
16
+
17
+ # Run specs in random order to surface order dependencies. If you find an
18
+ # order dependency and want to debug it, you can fix the order by providing
19
+ # the seed, which is printed after each run.
20
+ # --seed 1234
21
+ #config.order = 'random'
22
+ end
@@ -0,0 +1,16 @@
1
+ shared_examples "containable" do
2
+ [:description, :id, :invalid_fields].each do |prop|
3
+ it "should give access to #{prop}" do
4
+ expect(element).to respond_to(prop)
5
+ end
6
+ end
7
+
8
+ describe "#reset_validation" do
9
+ it "should clear invalid_fields" do
10
+ element.instance_variable_set("@invalid_fields", [:a, :b])
11
+ expect(element.invalid_fields.size).to eql(2)
12
+ element.send :reset_validation
13
+ expect(element.invalid_fields).to be_empty
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,43 @@
1
+ shared_examples "a container" do |containable_class, element|
2
+ describe "#add" do
3
+ context "when hash is passed" do
4
+ it "should at first create an object" do
5
+ expect(containable_class).to receive(:new) { element }
6
+ subject.add({})
7
+ end
8
+ end
9
+
10
+ context "when object is passed" do
11
+ it "should not create new object" do
12
+ expect(containable_class).to_not receive(:new)
13
+ subject.add element
14
+ end
15
+
16
+ it "should add to list valid elements" do
17
+ expect { subject.add(element) }.to change(subject, :size).by(1)
18
+ end
19
+
20
+ it "should remember invalid elements" do
21
+ allow(element).to receive(:valid?).and_return(false)
22
+ expect { subject.add(element) }.to change(subject.defectives, :size).by(1)
23
+ end
24
+ end
25
+ end
26
+
27
+ describe "#find" do
28
+ [:one, :two].each do |el|
29
+ let(el) {
30
+ el = containable_class.new({})
31
+ allow(el).to receive(:valid?) { true }
32
+ allow(el).to receive(:id) { el.to_s.upcase }
33
+ el
34
+ }
35
+ end
36
+
37
+ it "should return element with correct id" do
38
+ subject.add(one); subject.add(two)
39
+ expect(subject.size).to eq(2)
40
+ expect(subject.find(one.id)).to eq(one)
41
+ end
42
+ end
43
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: goods
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Artem Pyanykh
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 3.0.0.beta1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0.beta1
55
+ - !ruby/object:Gem::Dependency
56
+ name: libxml-ruby
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: nokogiri
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: |2
84
+ The purpose of this gem is to provide simple, yet reliable solution for parsing
85
+ YML (Yandex Market Language) files, with clean and convenient interface,
86
+ and extra capabilites, such as categories prunning.
87
+ email:
88
+ - artem.pyanykh@gmail.com
89
+ executables: []
90
+ extensions: []
91
+ extra_rdoc_files: []
92
+ files:
93
+ - .gitignore
94
+ - .rspec
95
+ - Gemfile
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - goods.gemspec
100
+ - lib/goods.rb
101
+ - lib/goods/catalog.rb
102
+ - lib/goods/categories_list.rb
103
+ - lib/goods/category.rb
104
+ - lib/goods/containable.rb
105
+ - lib/goods/container.rb
106
+ - lib/goods/currencies_list.rb
107
+ - lib/goods/currency.rb
108
+ - lib/goods/offer.rb
109
+ - lib/goods/offers_list.rb
110
+ - lib/goods/version.rb
111
+ - lib/goods/xml.rb
112
+ - lib/goods/xml/validator.rb
113
+ - lib/support/shops.dtd
114
+ - spec/fixtures/empty_catalog.xml
115
+ - spec/fixtures/simple_catalog.xml
116
+ - spec/goods/catalog_spec.rb
117
+ - spec/goods/categories_list_spec.rb
118
+ - spec/goods/category_spec.rb
119
+ - spec/goods/currencies_list_spec.rb
120
+ - spec/goods/currency_spec.rb
121
+ - spec/goods/offer_spec.rb
122
+ - spec/goods/offers_list_spec.rb
123
+ - spec/goods/xml/validator_spec.rb
124
+ - spec/goods/xml_spec.rb
125
+ - spec/goods_spec.rb
126
+ - spec/spec_helper.rb
127
+ - spec/support/shared_examples_for_containable.rb
128
+ - spec/support/shared_examples_for_container.rb
129
+ homepage: https://github.com/ArtemPyanykh/goods
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.1.11
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Simple parser for YML (Yandex Market Language) files with a few twists.
153
+ test_files:
154
+ - spec/fixtures/empty_catalog.xml
155
+ - spec/fixtures/simple_catalog.xml
156
+ - spec/goods/catalog_spec.rb
157
+ - spec/goods/categories_list_spec.rb
158
+ - spec/goods/category_spec.rb
159
+ - spec/goods/currencies_list_spec.rb
160
+ - spec/goods/currency_spec.rb
161
+ - spec/goods/offer_spec.rb
162
+ - spec/goods/offers_list_spec.rb
163
+ - spec/goods/xml/validator_spec.rb
164
+ - spec/goods/xml_spec.rb
165
+ - spec/goods_spec.rb
166
+ - spec/spec_helper.rb
167
+ - spec/support/shared_examples_for_containable.rb
168
+ - spec/support/shared_examples_for_container.rb