yml_builder 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b10e44faa9d509c11bbe34e4e0add97bb5956f15
4
+ data.tar.gz: 9e7634b0d218b487480bb242a404e9705d5a7991
5
+ SHA512:
6
+ metadata.gz: 14847041d19be93067fb9f0c2ca4cab96030115071191841b55bfcd0fbe0057c90b598140be1db47fad77018bb5551568271881b182f1a276559425d2b217f8f
7
+ data.tar.gz: 1239542340171ddf325f154722a8678787e06d50e19731c699c656ad4180c200522545b05d23043599b37424a32d7ae0e7c817a73624f78d7979378848a7e7df
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ ## 0.1.0 (2015-05-11)
2
+
3
+ * Начальная версия
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Stan Zhuravlev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,300 @@
1
+ # YmlBuilder
2
+
3
+ Библиотека YmlBuilder предназначена для формирования прайс-листов в формате Яндекс.Маркет. Библиотека обеспечивает формирвоание
4
+ прайс-листов с учетом правил Yandex (названия секций, ключей, порядок следования ключей и пр.), а также валидацию
5
+ большинства ошибок, связанных с генерацией прайс-листов.
6
+
7
+ ## Установка
8
+
9
+ Добавить в Gemfile:
10
+
11
+ ```ruby
12
+ gem 'yml_builder'
13
+ ```
14
+
15
+ Установить гем cредствами Bundler:
16
+
17
+ $ bundle
18
+
19
+ Или установить его отдельно:
20
+
21
+ $ gem install yml_builder
22
+
23
+ # Зависимости
24
+
25
+ Для работы гема требуется Ruby не младше версии 2.2.1. Также для работы необходим гем StTools (https://github.com/StanZhuravlev/st_tools).
26
+
27
+ ## Использование
28
+
29
+ Библиотека работает с кодировкой UTF-8, однако формирование прайс-листа осуществляется в соответствии с рекомендациями,
30
+ в кодировке windows-1251. Все работа строится на базе двух основных классов - YmlBuilder::Yml и YmlBuilder::Offer.
31
+ Остальные классы являются вспомогательными, и в пользовательских приложениях использоваться не должны. Использование
32
+ классов продемонстрировано ниже на базе примеров. Все примеры можно найти в папке /test
33
+
34
+ В соответствии со спецификацией Yandex.Market, все значения в прайс-листе делятся на две группы: обязательные и опциональные.
35
+ Если при формировании прайс-листа не заданы какие-либо обязательные параметры, то будет вызвано исключение с детальным
36
+ описанием причин.
37
+
38
+ _Ограничения библиотеки: поскольку она писалась под конкретный проект, в ней реализован только один тип товара - упрощенный.
39
+ В библиотеке заложены возможности расширения под дугие типы, но такое расширение будет создаваться только по необходимости.
40
+ Пишите, если требуется подержка других карточек, сделаю_
41
+
42
+ ### Пример 1 - Создание прайс-листа и настройка магазина
43
+
44
+ Первым шагом необходимо создать прайс-лист, и настроить параметры Интернет-магазина.
45
+
46
+ ```ruby
47
+ price = YmlBuilder::Yml.new
48
+ price.shop.name = 'Магазин ТЕСТ'
49
+ price.shop.company = "ООО 'Рога & Копыта'"
50
+ price.shop.url = 'http://example-site.ru'
51
+ price.shop.phone = '+7 (123) 456-7890'
52
+ price.shop.platform = 'OpenCart'
53
+ price.shop.version = '2.0'
54
+ puts price.to_yml
55
+ ```
56
+
57
+ Результатом данного кода будет являться сгенерированная XML-сруктура следующего вида.
58
+
59
+ ```xml
60
+ <?xml version="1.0" encoding="windows-1251"?>
61
+ <!DOCTYPE yml_catalog SYSTEM "shops.dtd">
62
+ <yml_catalog date="2015-05-11 14:07">
63
+ <shop>
64
+ <name>Магазин ТЕСТ</name>
65
+ <company>ООО &apos;Рога &amp; Копыта&apos;</company>
66
+ <url>http://example-site.ru</url>
67
+ <phone>+7 (123) 456-7890</phone>
68
+ <platform>OpenCart</platform>
69
+ <version>2.0</version>
70
+ <currencies>
71
+ </currencies>
72
+ <categories>
73
+ </categories>
74
+ <offers>
75
+ </offers>
76
+ </shop>
77
+ </yml_catalog>
78
+ ```
79
+
80
+ Также будет сгенерировано два предупреждения
81
+
82
+ ```txt
83
+ Предупреждение: не указано ни одной валюты в секции 'currencies'
84
+ Предупреждение: не указано ни одной категории в секции 'categories'
85
+ ```
86
+
87
+ ### Пример 2 - Добавление валют и категорий
88
+
89
+ На втором шаге, осуществляется добавление необходимых валют из числа поддерживаемых Яндекс.Маркет, а также категорий
90
+ в которых будут размещены товары.
91
+
92
+ ```ruby
93
+ price = YmlBuilder::Yml.new
94
+ price.shop.name = 'Магазин ТЕСТ'
95
+ price.shop.company = "ООО 'Рога & Копыта'"
96
+ price.shop.url = 'http://example-site.ru'
97
+ price.shop.phone = '+7 (123) 456-7890'
98
+ price.shop.platform = 'OpenCart'
99
+ price.shop.version = '2.0'
100
+
101
+ price.currencies.rub = 1
102
+ price.currencies.usd = 55.04
103
+ price.currencies.eur = :cbrf
104
+
105
+ price.categories.add(id: 1, name: "Игрушки")
106
+ price.categories.add(id: 2, name: "Одежда")
107
+ price.categories.add(id: 4, name: "Игрушки для девочек", parent_id: 1)
108
+ price.categories.add(id: 5, name: "Игрушки для мальчиков", parent_id: 1)
109
+ price.categories.add(id: 3, name: "Книги")
110
+
111
+ puts price.to_yml
112
+ ```
113
+
114
+ Результатом данного кода будет являться сгенерированная XML-сруктура следующего вида.
115
+
116
+ ```xml
117
+ <?xml version="1.0" encoding="windows-1251"?>
118
+ <!DOCTYPE yml_catalog SYSTEM "shops.dtd">
119
+ <yml_catalog date="2015-05-11 14:28">
120
+ <shop>
121
+ <name>Магазин ТЕСТ</name>
122
+ <company>ООО &apos;Рога &amp; Копыта&apos;</company>
123
+ <url>http://example-site.ru</url>
124
+ <phone>+7 (123) 456-7890</phone>
125
+ <platform>OpenCart</platform>
126
+ <version>2.0</version>
127
+ <currencies>
128
+ <currency id="RUB" rate="1"/>
129
+ <currency id="USD" rate="55.04"/>
130
+ <currency id="EUR" rate="CBRF"/>
131
+ </currencies>
132
+ <categories>
133
+ <category id="1">Игрушки</category>
134
+ <category id="2">Одежда</category>
135
+ <category id="3">Книги</category>
136
+ <category id="4" parentId="1">Игрушки для девочек</category>
137
+ <category id="5" parentId="1">Игрушки для мальчиков</category>
138
+ </categories>
139
+ <offers>
140
+ </offers>
141
+ </shop>
142
+ </yml_catalog>
143
+ ```
144
+
145
+ ### Пример 3 - Добавление товаров
146
+
147
+ Затем необходимо сформировать информацию о оферах, и добавить их в список товаров (offers). Офферы создаются через вызов
148
+ отдельного класса - YmlBuilder.Offer. На самом деле, это "рамочный" класс, который на самом деле вернет экземпляры
149
+ классов, соответствующих типам товаров Yandex.Market. Напрмиер, ```ruby YmlBuilder::Offer.new('simple')``` создает
150
+ описание урощенной карточки товара. Если вместо simple указать любой другой тип, то в данной версии библиотеки
151
+ будет вызвано исключение.
152
+
153
+ Кроме того, через вызов ```ruby offer.add_picture``` добавляются ссылки на картинки, описывающие товар. Каждый вызов метода
154
+ добавляет ссылку на фотографю товара в конце списка picture. При этом контролируется, чтобы размер списка изображений
155
+ не превышал 10. При превышении массив фотографий всегда обрезается до 10. Чтобы добавить основную фотографию товара
156
+ необходимо вызвать метод ```ruby offer.add_cover_picture```. Данный метод просто добавляет картинку в начало списка
157
+ фотографий. Если вызвать данный метод два раза, то список фотографий будет выглядеть как две основные фотографии.
158
+
159
+ Через вызов ```ruby offer.add_param``` добавляются различные вспомогательные параметры - вес, продолжительность записи,
160
+ размеры одежды и прочая информация.
161
+
162
+ ```ruby
163
+ item = YmlBuilder::Offer.new('simple')
164
+ item.id = 6
165
+ item.available = true
166
+ item.currency_id = 'RUR'
167
+ item.delivery = true
168
+ item.category_id = 1
169
+ item.name = 'Товар №6'
170
+ item.url = 'http://example-site.ru/items/6'
171
+ item.price = 300.90
172
+ item.add_picture('http://example-site.ru/image1')
173
+ item.add_picture('http://example-site.ru/image2')
174
+ item.add_cover_picture('http://example-site.ru/image_cover')
175
+ item.add_param(name: 'Обложка', value: 'Мягкая')
176
+ item.add_param(name: 'Страниц', value: 10, unit: 'шт.')
177
+
178
+ price.offers.add(item)
179
+
180
+ item = YmlBuilder::Offer.new('simple')
181
+ item.id = 3
182
+ item.available = false
183
+ item.currency_id = 'RUR'
184
+ item.delivery = true
185
+ item.category_id = 2
186
+ item.name = 'Товар №3'
187
+ item.url = 'http://example-site.ru/items/3'
188
+ item.price = 100
189
+ item.add_picture('http://example-site.ru/image1')
190
+ item.add_picture('http://example-site.ru/image2')
191
+ item.add_cover_picture('http://example-site.ru/image_cover')
192
+ item.add_param(name: 'Обложка', value: 'Мягкая')
193
+ item.add_param(name: 'Страниц', value: 10, unit: 'шт.')
194
+
195
+ price.offers.add(item)
196
+ ```
197
+
198
+ Результатом данного кода будет являться сгенерированная XML-сруктура следующего вида.
199
+
200
+ ```xml
201
+ <?xml version="1.0" encoding="windows-1251"?>
202
+ <!DOCTYPE yml_catalog SYSTEM "shops.dtd">
203
+ <yml_catalog date="2015-05-11 14:40">
204
+ <shop>
205
+ <name>Магазин ТЕСТ</name>
206
+ <company>ООО &apos;Рога &amp; Копыта&apos;</company>
207
+ <url>http://example-site.ru</url>
208
+ <phone>+7 (123) 456-7890</phone>
209
+ <platform>OpenCart</platform>
210
+ <version>2.0</version>
211
+ <currencies>
212
+ <currency id="RUB" rate="1"/>
213
+ <currency id="USD" rate="55.04"/>
214
+ <currency id="EUR" rate="CBRF"/>
215
+ </currencies>
216
+ <categories>
217
+ <category id="1">Игрушки</category>
218
+ <category id="2">Одежда</category>
219
+ <category id="3">Книги</category>
220
+ <category id="4" parentId="1">Игрушки для девочек</category>
221
+ <category id="5" parentId="1">Игрушки для мальчиков</category>
222
+ </categories>
223
+ <offers>
224
+ <offer id="3" available="false">
225
+ <url>http://nosite/items/3</url>
226
+ <price>100</price>
227
+ <currencyId>RUR</currencyId>
228
+ <categoryId>2</categoryId>
229
+ <picture>http://example-site.ru/image_cover</picture>
230
+ <picture>http://example-site.ru/image1</picture>
231
+ <picture>http://example-site.ru/image2</picture>
232
+ <delivery>true</delivery>
233
+ <name>Товар №3</name>
234
+ <param name="Обложка">Мягкая</param>
235
+ <param name="Страниц" unit="шт.">10</param>
236
+ </offer>
237
+ <offer id="6" available="true">
238
+ <url>http://nosite/items/6</url>
239
+ <price>300.9</price>
240
+ <currencyId>RUR</currencyId>
241
+ <categoryId>1</categoryId>
242
+ <picture>http://example-site.ru/image_cover</picture>
243
+ <picture>http://example-site.ru/image1</picture>
244
+ <picture>http://example-site.ru/image2</picture>
245
+ <delivery>true</delivery>
246
+ <name>Товар №6</name>
247
+ <param name="Обложка">Мягкая</param>
248
+ <param name="Страниц" unit="шт.">10</param>
249
+ </offer>
250
+ </offers>
251
+ </shop>
252
+ </yml_catalog>
253
+ ```
254
+
255
+ ### Дополнительные возможности
256
+
257
+ В ряде случаев (размещение в тематических прайс-агрегаторах, ограничение показа товаров в Яндекс.Маркет) необходимо
258
+ генерировать различные прайс-листы. При использовании бибилиотеки YmlBuild это можно сделать через указание допустимых
259
+ категорий в методе filter. Вызов данного метода должен быть осуществлен до добавления первой категории или товара.
260
+
261
+ ```ruby
262
+ price.categories.filter = [1, 10, 12, 20]
263
+ ```
264
+
265
+ Для указания в соответствии с требованиями Yandex цены доставки в место локации магазина, необходимо использовать
266
+ метод local_delivery_cost.
267
+
268
+ ```ruby
269
+ price.local_delivery_cost = 300
270
+ ```
271
+
272
+ Метод to_yml формирует выходную строку в формате utf-8. Для записи прайс-листа рекомендуется использовать метод save,
273
+ передава ему имя файла для записи.
274
+
275
+ ```ruby
276
+ price.save('price.xml')
277
+ ```
278
+
279
+ Узнать статистику по экпорту прайс-листа (общее число товаров, число товаров в наличии, общая стоимость товаров в
280
+ наличии (без учета количества)) можно через вызов метода ```ruby price.stats```. Результатом работы метода является
281
+ структура следующего вида
282
+
283
+ ```ruby
284
+ {
285
+ :categories => 5,
286
+ :total => 2,
287
+ :available => 1,
288
+ :price => 300.9
289
+ }
290
+ ```
291
+
292
+
293
+
294
+ ## Contributing
295
+
296
+ 1. Fork it ( https://github.com/StanZhuravlev/yml_builder/fork )
297
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
298
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
299
+ 4. Push to the branch (`git push origin my-new-feature`)
300
+ 5. Create a new Pull Request
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "yml_builder"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,72 @@
1
+ module YmlBuilder
2
+ class Categories
3
+ # Переменная содержит список id категорий, для которых необходимо формировать прайс-лист.
4
+ # Если переменная пуста, то включаются все категории
5
+ attr_reader :filter
6
+
7
+ def initialize(stats)
8
+ @stats = stats
9
+ init_class
10
+ end
11
+
12
+ def add(opts = {})
13
+ return false unless can_add?(opts[:id])
14
+ allow = [:id, :parent_id, :name]
15
+ raise "Ошибка: для добавления категории используйте ключи #{allow.inspect}" if (opts.keys - allow).count > 0
16
+ raise "Ошибка: не указан 'id' для добавления категории" if opts[:id].nil?
17
+ raise "Ошибка: не указан 'name' для добавления категории" if opts[:name].nil?
18
+ @params[opts[:id]] = { parent_id: opts[:parent_id], name: opts[:name] }
19
+ @params = Hash[ @params.sort_by { |id, data| id } ]
20
+ @stats.add(:categories, 1)
21
+ true
22
+ end
23
+
24
+ # Метод проверяет необходимость добавления категории или товара в прайс-лист
25
+ # с учетом выставленных в значении filter настроек.
26
+ #
27
+ # @param [Object] id идентифкатор категории товара
28
+ # @return [Boolean] true, если данный id категории указан в filter как допустимый для включения в прайс-лист
29
+ def can_add?(id)
30
+ @filter.count == 0 ? true : @filter.include?(id)
31
+ end
32
+
33
+ # Метод позволяет огарничить формирование прайс-листа только категориями, указанными в данном поле
34
+ # Filter может принимать значения nil или [], тогда считается, что допустимо включение в прайс-лист
35
+ # всех товаров.
36
+ # @param [Array] allow массив id категорий, который должны попадать в результирующий прайс-лист
37
+ def filter=(allow)
38
+ @filter = allow || Array.new
39
+ end
40
+
41
+ # Метод формирует фрагмент YML файла каталога Яндекс.Маркет, содержащий список категорий
42
+ #
43
+ # @param [Integer] ident отступ от левого края в символах
44
+ # @return [String] фрагмент YML файла каталога Яндекс.Маркет, содержащий список категорий
45
+ def to_yml(ident = 4)
46
+ out = Array.new
47
+ out << '<categories>'
48
+
49
+ @params.each do |id, value|
50
+ if value[:parent_id].nil?
51
+ out << " <category id=#{id.to_s.inspect}>#{::YmlBuilder::Common.encode_special_chars(value[:name])}</category>"
52
+ else
53
+ out << " <category id=#{id.to_s.inspect} parentId=#{value[:parent_id].to_s.inspect}>#{::YmlBuilder::Common.encode_special_chars(value[:name])}</category>"
54
+ end
55
+ end
56
+ warn "Предупреждение: не указано ни одной категории в секции 'categories'" if out.count == 1
57
+
58
+ out << '</categories>'
59
+
60
+ out.map! { |line| line = ' '.rjust(ident, ' ') + line }
61
+ out.join("\n")
62
+ end
63
+
64
+ private
65
+
66
+ def init_class
67
+ @params = Hash.new
68
+ self.filter = nil
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,19 @@
1
+ module YmlBuilder
2
+ class Common
3
+
4
+ def self.encode_special_chars(out)
5
+ return out.to_s.gsub(/[\"\&\>\<\']/, '"' => '&quot;',
6
+ '&' => '&amp;',
7
+ '>' => '&gt;',
8
+ '<' => '&lt;',
9
+ "'" => '&apos;')
10
+ end
11
+
12
+ def self.convert_key(key)
13
+ return 'currencyId' if key == :currency_id
14
+ return 'categoryId' if key == :category_id
15
+ key.to_s
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,135 @@
1
+ module YmlBuilder
2
+ class CommonOffer
3
+ attr_accessor :id
4
+ attr_accessor :type
5
+ attr_accessor :available
6
+ attr_accessor :bid
7
+
8
+ attr_accessor :mandatories
9
+
10
+ def initialize
11
+ init_class
12
+ end
13
+
14
+ def init_class
15
+ @params = Hash.new
16
+ @meta = Hash.new
17
+ @picture = Array.new
18
+
19
+ @id = 0
20
+ @type = 'unknown'
21
+ @available = false
22
+ @bid = nil
23
+
24
+ @mandatories = Array.new
25
+ end
26
+
27
+ def add_picture(url)
28
+ @picture << url
29
+ @picture.uniq!
30
+ warn "Предупреждение: число картинок превышает 10 (offer_id=#{@id}). Сокращаем до 10" if @picture.count > 10
31
+ @picture = @picture[0,9]
32
+ end
33
+
34
+ def add_cover_picture(url)
35
+ @picture.unshift(url)
36
+ @picture.uniq!
37
+ warn "Предупреждение: число картинок превышает 10 (offer_id=#{@id}). Сокращаем до 10" if @picture.count > 10
38
+ @picture = @picture[0,9]
39
+ end
40
+
41
+ def add_param(name:, unit: nil, value:)
42
+ @meta[name] = { unit: unit, value: value}
43
+ end
44
+
45
+ def method_missing(method_sym, *arguments, &block)
46
+ if @params.include?(method_sym.to_s.gsub(/=$/, '').to_sym)
47
+ processing_method(method_sym, arguments.first)
48
+ else
49
+ super
50
+ end
51
+ end
52
+
53
+ def processing_method(method_sym, value)
54
+ if method_sym.to_s.match(/=$/)
55
+ key = method_sym.to_s.gsub(/=$/, '')
56
+ warn "Предупреждение: url не должен превышать 512 символов" if key == 'url' && value.length > 512
57
+ warn "Предупреждение: price не может быть равен нулю" if key == 'price' && value.to_f == 0
58
+ warn "Предупреждение: weight не может быть равен нулю" if key == 'weight' && value.to_f == 0
59
+ @params[key.to_sym] = value
60
+ else
61
+ @params[method_sym.to_s.gsub(/=$/, '').to_sym]
62
+ end
63
+ end
64
+
65
+ def header_line
66
+ out = Array.new
67
+ out << "id=#{@id.to_s.inspect}"
68
+ out << "type=#{@type.to_s.inspect}" if @type != 'simple'
69
+ out << "available=\"#{@available.inspect}\""
70
+ out << "bid=#{@bid.inspect}" unless @bid.nil?
71
+ "<offer #{out.join (' ')}>"
72
+ end
73
+
74
+ def footer_line
75
+ '</offer>'
76
+ end
77
+
78
+ def param_line(name, data)
79
+ if data[:unit].nil?
80
+ "<param name=#{::YmlBuilder::Common.encode_special_chars(name.to_s).inspect}>#{::YmlBuilder::Common.encode_special_chars(data[:value].to_s)}</param>"
81
+ else
82
+ "<param name=#{::YmlBuilder::Common.encode_special_chars(name.to_s).inspect} unit=#{::YmlBuilder::Common.encode_special_chars(data[:unit]).inspect}>#{::YmlBuilder::Common.encode_special_chars(data[:value].to_s)}</param>"
83
+ end
84
+ end
85
+
86
+ def to_yml_subsections(key)
87
+ out = Array.new
88
+
89
+ if key == :picture
90
+ @picture.each do |url|
91
+ out << " <picture>#{url}</picture>"
92
+ end
93
+ else
94
+ @meta.each do |name, data|
95
+ out << " #{param_line(name, data)}"
96
+ end
97
+ end
98
+
99
+ out
100
+ end
101
+
102
+ def to_yml_mandatories(key, value)
103
+ raise "Ошибка секции 'offer': не заполнено обязательное значение #{key.to_s.inspect}" if (value.nil? || value.to_s == '')
104
+ key_xml = ::YmlBuilder::Common.convert_key(key)
105
+ " <#{key_xml}>#{::YmlBuilder::Common.encode_special_chars(value)}</#{key_xml}>"
106
+ end
107
+
108
+ def to_yml_optional(key, value)
109
+ return nil if value.nil?
110
+ key_xml = ::YmlBuilder::Common.convert_key(key)
111
+ " <#{key_xml}>#{::YmlBuilder::Common.encode_special_chars(value)}</#{key_xml}>"
112
+ end
113
+
114
+ def to_yml(ident = 4)
115
+ out = Array.new
116
+ out << header_line
117
+
118
+ @params.each do |key, value|
119
+ if [:picture, :param].include?(key)
120
+ out += to_yml_subsections(key)
121
+ elsif @mandatories.include?(key)
122
+ out << to_yml_mandatories(key, value)
123
+ else
124
+ out << to_yml_optional(key, value)
125
+ end
126
+ end
127
+ out.compact!
128
+
129
+ out << footer_line
130
+ out.map! { |line| ' '.rjust(ident, ' ') + line }
131
+ out.join("\n")
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,63 @@
1
+ module YmlBuilder
2
+ class Currencies
3
+
4
+ def initialize
5
+ init_class
6
+ end
7
+
8
+ def init_class
9
+ @params = Hash.new
10
+
11
+ @params[:rur] = nil
12
+ @params[:rub] = nil
13
+ @params[:usd] = nil
14
+ @params[:eur] = nil
15
+ @params[:uah] = nil
16
+ @params[:kzt] = nil
17
+ end
18
+
19
+ def method_missing(method_sym, *arguments, &block)
20
+ if @params.include?(method_sym.to_s.gsub(/=$/, '').to_sym)
21
+ processing_method(method_sym, arguments.first)
22
+ else
23
+ super
24
+ end
25
+ end
26
+
27
+ def valid?(method_sym, allow, value)
28
+ return true if value.to_s.match(/^\s*[+-]?((\d+_?)*\d+(\.(\d+_?)*\d+)?|\.(\d+_?)*\d+)(\s*|([eE][+-]?(\d+_?)*\d+)\s*)$/)
29
+ return true if allow.include?(value)
30
+ warn "Предупреждение: значение валюты #{method_sym.to_s.upcase} может быть цифрой или значением из #{allow.inspect}"
31
+ false
32
+ end
33
+
34
+ def processing_method(method_sym, value)
35
+ if method_sym.to_s.match(/=$/)
36
+ key = method_sym.to_s.gsub(/=$/, '')
37
+ allow = [:cbrf, :nbu, :nbk, :cb]
38
+ valid?(key.to_s, allow, value)
39
+
40
+ @params[key.to_sym] = value
41
+ else
42
+ @params[method_sym.to_s.gsub(/=$/, '').to_sym]
43
+ end
44
+ end
45
+
46
+ def to_yml(ident = 4)
47
+ out = Array.new
48
+ out << '<currencies>'
49
+
50
+ @params.each do |key, value|
51
+ out << " <currency id=#{key.to_s.upcase.inspect} rate=#{value.to_s.upcase.inspect}/>" unless value.nil?
52
+ end
53
+ warn "Предупреждение: не указано ни одной валюты в секции 'currencies'" if out.count == 1
54
+
55
+ out << '</currencies>'
56
+
57
+ out.map! { |line| line = ' '.rjust(ident, ' ') + line }
58
+
59
+ out.join("\n")
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,14 @@
1
+ module YmlBuilder
2
+ class Offer
3
+
4
+ def self.new(type)
5
+ case type.downcase
6
+ when 'simple'
7
+ ::YmlBuilder::OfferSimple.new
8
+ else
9
+ raise "Ошибка: неизвестный тип оффера (#{type})"
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,33 @@
1
+ module YmlBuilder
2
+ class OfferSimple < YmlBuilder::CommonOffer
3
+
4
+ def initialize
5
+ super
6
+ @type = 'simple'
7
+
8
+ @params = Hash.new
9
+ @params[:url] = nil
10
+ @params[:price] = nil
11
+ @params[:currency_id] = nil
12
+ @params[:category_id] = nil
13
+ @params[:market_category] = nil
14
+ @params[:picture] = nil
15
+ @params[:store] = nil
16
+ @params[:pickup] = nil
17
+ @params[:delivery] = nil
18
+ @params[:local_delivery_cost] = nil
19
+ @params[:name] = nil
20
+ @params[:vendor] = nil
21
+ @params[:vendor_code] = nil
22
+ @params[:description] = nil
23
+ @params[:country_of_origin] = nil
24
+ @params[:adult] = nil
25
+ @params[:param] = nil
26
+ @params[:weight] = nil
27
+ @params[:dimensions] = nil
28
+
29
+ @mandatories = [:url, :price, :currency_id, :category_id, :delivery, :name]
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,32 @@
1
+ module YmlBuilder # :nodoc:
2
+ class OfferVendorModel < YmlBuilder::CommonOffer
3
+
4
+ def initialize
5
+ super
6
+
7
+ @type = 'vendor.model'
8
+
9
+ @params[:m] = Hash.new
10
+ @params[:m][:url] = nil
11
+ @params[:m][:price] = nil
12
+ @params[:m][:currency_id] = nil
13
+ @params[:m][:category_id] = nil
14
+ @params[:m][:delivery] = nil
15
+ @params[:m][:vendor] = nil
16
+ @params[:m][:model] = nil
17
+
18
+ @params[:o] = Hash.new
19
+ @params[:o][:local_delivery_cost] = nil
20
+ @params[:o][:type_prefix] = nil
21
+ @params[:o][:vendor_code] = nil
22
+ @params[:o][:description] = nil
23
+ @params[:o][:manufacturer_warranty] = nil
24
+ @params[:o][:country_of_origin] = nil
25
+ @params[:o][:available] = nil
26
+ @params[:o][:sales_notes] = nil
27
+ @params[:o][:downloadable] = nil
28
+ @params[:o][:adult] = nil
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,42 @@
1
+ module YmlBuilder
2
+ class Offers
3
+
4
+ def initialize(stats, categories)
5
+ @stats = stats
6
+ @categories = categories
7
+ init_class
8
+ end
9
+
10
+ def init_class
11
+ @offers = Hash.new
12
+ end
13
+
14
+ def add(offer)
15
+ return false unless @categories.can_add?(offer.category_id)
16
+ @offers[offer.id] = offer
17
+
18
+ # Формируем статистику
19
+ @stats.add(:total, 1)
20
+ if offer.available
21
+ @stats.add(:available, 1)
22
+ @stats.add(:price, (offer.price || 0))
23
+ end
24
+ true
25
+ end
26
+
27
+ def to_yml(ident = 4)
28
+ @offers = @offers.sort_by { |id, offer| id }
29
+
30
+ out = Array.new
31
+ out << "<offers>"
32
+ @offers.each do |id, offer|
33
+ out += offer.to_yml(2).split(/[\n\r]/)
34
+ end
35
+ out << "</offers>"
36
+
37
+ out.map! { |line| ' '.rjust(ident, ' ') + line }
38
+ out.join("\n")
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,71 @@
1
+ module YmlBuilder
2
+ class Shop
3
+
4
+ def initialize
5
+ init_class
6
+ end
7
+
8
+ def init_class
9
+ @params = Hash.new
10
+
11
+ @params[:m] = Hash.new
12
+ @params[:m][:name] = ''
13
+ @params[:m][:company] = ''
14
+ @params[:m][:url] = ''
15
+
16
+ @params[:o] = Hash.new
17
+ @params[:o][:phone] = nil
18
+ @params[:o][:platform] = nil
19
+ @params[:o][:version] = nil
20
+ @params[:o][:agency] = nil
21
+ @params[:o][:email] = nil
22
+ @params[:o][:adult] = nil
23
+ @params[:o][:cpa] = nil
24
+ end
25
+
26
+ def method_missing(method_sym, *arguments, &block)
27
+ if @params[:m].include?(method_sym.to_s.gsub(/=$/, '').to_sym)
28
+ processing_method(:m, method_sym, arguments.first)
29
+ elsif @params[:o].include?(method_sym.to_s.gsub(/=$/, '').to_sym)
30
+ processing_method(:o, method_sym, arguments.first)
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def processing_method(part, method_sym, value)
37
+ if method_sym.to_s.match(/=$/)
38
+ key = method_sym.to_s.gsub(/=$/, '')
39
+ warn "Предупреждение: название магазина не должно быть больше 20 символов" if key == 'name' && value.length > 20
40
+ @params[part][key.to_sym] = value
41
+ else
42
+ @params[part][method_sym.to_s.gsub(/=$/, '').to_sym]
43
+ end
44
+ end
45
+
46
+ def to_yml
47
+ out = Array.new
48
+ out << ' <shop>'
49
+
50
+ @params[:m].each do |key, value|
51
+ raise "Ошибка секции 'company': не заполнено значение для обязательного ключа #{key.to_s.inspect}" if value == ''
52
+ out << " <#{key}>#{::YmlBuilder::Common.encode_special_chars(value)}</#{key}>"
53
+ end
54
+
55
+ @params[:o].each do |key, value|
56
+ unless value.nil?
57
+ out << " <#{key}>#{::YmlBuilder::Common.encode_special_chars(value)}</#{key}>"
58
+ end
59
+ end
60
+
61
+ out << ' {replace_currencies}'
62
+ out << ' {replace_categories}'
63
+ out << ' {replace_local_delivery_cost}'
64
+ out << ' {replace_offers}'
65
+ out << ' </shop>'
66
+ out.join("\n")
67
+ end
68
+
69
+
70
+ end
71
+ end
@@ -0,0 +1,22 @@
1
+ module YmlBuilder # :nodoc:
2
+ class Stats
3
+ attr_reader :stats
4
+
5
+ def initialize
6
+ init_class
7
+ end
8
+
9
+ def init_class
10
+ @stats = Hash.new
11
+ @stats[:categories] = 0
12
+ @stats[:total] = 0
13
+ @stats[:available] = 0
14
+ @stats[:price] = 0
15
+ end
16
+
17
+ def add(key, value)
18
+ @stats[key] += value
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module YmlBuilder # :nodoc:
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,83 @@
1
+ # Базовый класс для управления формированием прайс-листа. Содержит ссылки на различные секции:
2
+ # shop, currencies, categories, offers
3
+
4
+ module YmlBuilder
5
+ class Yml
6
+ # Ссылка на класс, описывающий контакты Интернет-магазина
7
+ attr_reader :shop
8
+ # Ссылка на класс, описывающий категории
9
+ attr_reader :categories
10
+ # Ссылка на класс, описывающий валюты
11
+ attr_reader :currencies
12
+ # Ссылка на класс, управляющий товарами (офферами)
13
+ attr_reader :offers
14
+ # Переменая, хранящая стоимость доставки в локации расположения Интернет-магазина
15
+ attr_reader :local_delivery_cost
16
+
17
+
18
+ def initialize
19
+ @stats = ::YmlBuilder::Stats.new
20
+ @shop = ::YmlBuilder::Shop.new
21
+ @currencies = ::YmlBuilder::Currencies.new
22
+ @categories = ::YmlBuilder::Categories.new(@stats)
23
+ @offers = ::YmlBuilder::Offers.new(@stats, @categories)
24
+ @local_delivery_cost = nil
25
+ end
26
+
27
+ # Метод устанавливает стоимость доставки в месте локации магазина. Например, если магазин находится в Москве,
28
+ # то при указанни данной стоимости, она будет показана покупателям в этом же районе.
29
+ #
30
+ # @param [Float] value стоимость доставки в месте локации магазина
31
+ # @return [None] нет
32
+ def local_delivery_cost=(value)
33
+ @local_delivery_cost = value
34
+ end
35
+
36
+ # Метод возвращает статистику по результатам генерации прайс-листа: всего товаров, товаров в наличии, стоимость
37
+ # товаров в наличии (без учета количества)
38
+ #
39
+ # @return [None] нет
40
+ def stats
41
+ @stats.stats
42
+ end
43
+
44
+ # Метод возвращает текстовую строку с прайс-листом в формате Яндекс.Маркет
45
+ #
46
+ # @return [String] строка с прайс-листом в формате utf-8
47
+ def to_yml
48
+ out = @shop.to_yml
49
+ out.gsub!(/^\s{0,100}\{replace\_currencies\}/, @currencies.to_yml)
50
+ out.gsub!(/^\s{0,100}\{replace\_categories\}/, @categories.to_yml)
51
+ out.gsub!(/^\s{0,100}\{replace\_local\_delivery\_cost\}[\n\r]/, lds_to_yml)
52
+ out.gsub!(/^\s{0,100}\{replace\_offers\}/, @offers.to_yml)
53
+
54
+ add_header_footer(out)
55
+ end
56
+
57
+ # Метод для записи прайслиста в файл. Запись осущесствится в кодировке windows-1251
58
+ #
59
+ # @param [String] filename название файла для записи прайс-листа
60
+ # @return [None] нет
61
+ def save(filename)
62
+ File.open(filename, 'w:windows-1251') {|f| f.write(to_yml) }
63
+ end
64
+
65
+ private
66
+
67
+ def add_header_footer(text)
68
+ out = Array.new
69
+ out << "<?xml version=\"1.0\" encoding=\"windows-1251\"?>"
70
+ out << "<!DOCTYPE yml_catalog SYSTEM \"shops.dtd\">"
71
+ out << "<yml_catalog date=#{::Time.now.strftime("%Y-%m-%d %H:%M").inspect}>"
72
+ out << text
73
+ out << "</yml_catalog>"
74
+ out.join("\n")
75
+ end
76
+
77
+ def lds_to_yml(ident = 4)
78
+ return "" if @local_delivery_cost.nil?
79
+ ' '.rjust(ident, ' ') + "<local_delivery_cost>#{@local_delivery_cost}</local_delivery_cost>\n"
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('..', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "yml_builder/version"
5
+
6
+ module YmlBuilder # :nodoc:
7
+ require "yml_builder/stats"
8
+ require "yml_builder/common"
9
+ require "yml_builder/shop"
10
+ require "yml_builder/currencies"
11
+ require "yml_builder/categories"
12
+ require "yml_builder/common_offer"
13
+ require "yml_builder/offer_simple"
14
+ require "yml_builder/offer_vendor_model"
15
+ require "yml_builder/offers"
16
+ require "yml_builder/offer"
17
+ require "yml_builder/yml"
18
+ end
@@ -0,0 +1,17 @@
1
+ require 'rspec'
2
+ require 'yml_builder'
3
+
4
+ describe 'Пример 1 - Инициация прайс-листа и магазина' do
5
+
6
+ it 'Test' do
7
+ price = YmlBuilder::Yml.new
8
+ price.shop.name = 'Магазин ТЕСТ'
9
+ price.shop.company = "ООО 'Рога & Копыта'"
10
+ price.shop.url = 'http://example-site.ru'
11
+ price.shop.phone = '+7 (123) 456-7890'
12
+ price.shop.platform = 'OpenCart'
13
+ price.shop.version = '2.0'
14
+ puts price.to_yml
15
+
16
+ end
17
+ end
@@ -0,0 +1,28 @@
1
+ require 'rspec'
2
+ require 'yml_builder'
3
+
4
+ describe 'Пример 2 - Валюта и категории' do
5
+
6
+ it 'Test' do
7
+ price = YmlBuilder::Yml.new
8
+ price.shop.name = 'Магазин ТЕСТ'
9
+ price.shop.company = "ООО 'Рога & Копыта'"
10
+ price.shop.url = 'http://example-site.ru'
11
+ price.shop.phone = '+7 (123) 456-7890'
12
+ price.shop.platform = 'OpenCart'
13
+ price.shop.version = '2.0'
14
+
15
+ price.currencies.rub = 1
16
+ price.currencies.usd = 55.04
17
+ price.currencies.eur = :cbrf
18
+
19
+ price.categories.add(id: 1, name: "Игрушки")
20
+ price.categories.add(id: 2, name: "Одежда")
21
+ price.categories.add(id: 4, name: "Игрушки для девочек", parent_id: 1)
22
+ price.categories.add(id: 5, name: "Игрушки для мальчиков", parent_id: 1)
23
+ price.categories.add(id: 3, name: "Книги")
24
+
25
+ puts price.to_yml
26
+
27
+ end
28
+ end
@@ -0,0 +1,64 @@
1
+ require 'rspec'
2
+ require 'yml_builder'
3
+
4
+ describe 'Пример 3 - Добавление товара' do
5
+
6
+ it 'Test' do
7
+ price = YmlBuilder::Yml.new
8
+ price.shop.name = 'Магазин ТЕСТ'
9
+ price.shop.company = "ООО 'Рога & Копыта'"
10
+ price.shop.url = 'http://example-site.ru'
11
+ price.shop.phone = '+7 (123) 456-7890'
12
+ price.shop.platform = 'OpenCart'
13
+ price.shop.version = '2.0'
14
+
15
+ price.currencies.rub = 1
16
+ price.currencies.usd = 55.04
17
+ price.currencies.eur = :cbrf
18
+
19
+ price.categories.add(id: 1, name: "Игрушки")
20
+ price.categories.add(id: 2, name: "Одежда")
21
+ price.categories.add(id: 4, name: "Игрушки для девочек", parent_id: 1)
22
+ price.categories.add(id: 5, name: "Игрушки для мальчиков", parent_id: 1)
23
+ price.categories.add(id: 3, name: "Книги")
24
+
25
+ item = YmlBuilder::Offer.new('simple')
26
+ item.id = 6
27
+ item.type = 'simple'
28
+ item.available = true
29
+ item.currency_id = 'RUR'
30
+ item.delivery = true
31
+ item.category_id = 1
32
+ item.name = 'Товар №6'
33
+ item.url = 'http://example-site.ru/items/6'
34
+ item.price = 300.90
35
+ item.add_picture('http://example-site.ru/image1')
36
+ item.add_picture('http://example-site.ru/image2')
37
+ item.add_cover_picture('http://example-site.ru/image_cover')
38
+ item.add_param(name: 'Обложка', value: 'Мягкая')
39
+ item.add_param(name: 'Страниц', value: 10, unit: 'шт.')
40
+
41
+ price.offers.add(item)
42
+
43
+ item = YmlBuilder::Offer.new('simple')
44
+ item.id = 3
45
+ item.type = 'simple'
46
+ item.available = false
47
+ item.currency_id = 'RUR'
48
+ item.delivery = true
49
+ item.category_id = 2
50
+ item.name = 'Товар №3'
51
+ item.url = 'http://example-site.ru/items/3'
52
+ item.price = 100
53
+ item.add_picture('http://example-site.ru/image1')
54
+ item.add_picture('http://example-site.ru/image2')
55
+ item.add_cover_picture('http://example-site.ru/image_cover')
56
+ item.add_param(name: 'Обложка', value: 'Мягкая')
57
+ item.add_param(name: 'Страниц', value: 10, unit: 'шт.')
58
+
59
+ price.offers.add(item)
60
+
61
+ puts price.to_yml
62
+
63
+ end
64
+ end
@@ -0,0 +1,68 @@
1
+ require 'rspec'
2
+ require 'yml_builder'
3
+
4
+ describe 'Проверка формирования файла' do
5
+
6
+ it 'Test' do
7
+ price = YmlBuilder::Yml.new
8
+ price.shop.name = 'Магазин ТЕСТ'
9
+ price.shop.company = "ООО 'Рога & Копыта'"
10
+ price.shop.url = 'http://nosite.ru'
11
+ price.shop.phone = '+7 (123) 456-7890'
12
+ price.shop.platform = 'OpenCart'
13
+ price.shop.version = '2.0'
14
+
15
+ price.currencies.rub = 1
16
+ price.currencies.usd = 55.04
17
+ price.currencies.eur = :cbrf
18
+
19
+ price.categories.add(id: 1, name: "Игрушки")
20
+ price.categories.add(id: 2, name: "Одежда")
21
+ price.categories.add(id: 4, name: "Игрушки для девочек", parent_id: 1)
22
+ price.categories.add(id: 5, name: "Игрушки для мальчиков", parent_id: 1)
23
+ price.categories.add(id: 3, name: "Книги")
24
+
25
+ price.local_delivery_cost = 350
26
+
27
+ item = YmlBuilder::Offer.new('simple')
28
+ item.id = 6
29
+ item.type = 'simple'
30
+ item.available = true
31
+ item.currency_id = 'RUR'
32
+ item.delivery = true
33
+ item.category_id = 1
34
+ item.name = 'Товар №6'
35
+ item.url = 'http://nosite/items/6'
36
+ item.price = 300.90
37
+ item.add_picture('http://nosite.ru/image1')
38
+ item.add_picture('http://nosite.ru/image2')
39
+ item.add_cover_picture('http://nosite.ru/image_cover')
40
+ item.add_param(name: 'Обложка', value: 'Мягкая')
41
+ item.add_param(name: 'Страниц', value: 10, unit: 'шт.')
42
+
43
+ price.offers.add(item)
44
+
45
+ item = YmlBuilder::Offer.new('simple')
46
+ item.id = 3
47
+ item.type = 'simple'
48
+ item.available = false
49
+ item.currency_id = 'RUR'
50
+ item.delivery = true
51
+ item.category_id = 2
52
+ item.name = 'Товар №3'
53
+ item.url = 'http://nosite/items/3'
54
+ item.price = 100
55
+ item.add_picture('http://nosite.ru/image1')
56
+ item.add_picture('http://nosite.ru/image2')
57
+ item.add_cover_picture('http://nosite.ru/image_cover')
58
+ item.add_param(name: 'Обложка', value: 'Мягкая')
59
+ item.add_param(name: 'Страниц', value: 10, unit: 'шт.')
60
+
61
+ price.offers.add(item)
62
+
63
+ puts price.to_yml
64
+ price.save('test_yml.yml')
65
+ puts price.stats.inspect
66
+
67
+ end
68
+ end
data/test/test_yml.yml ADDED
@@ -0,0 +1,53 @@
1
+ <?xml version="1.0" encoding="windows-1251"?>
2
+ <!DOCTYPE yml_catalog SYSTEM "shops.dtd">
3
+ <yml_catalog date="2015-05-11 14:57">
4
+ <shop>
5
+ <name>������� ����</name>
6
+ <company>��� &apos;���� &amp; ������&apos;</company>
7
+ <url>http://nosite.ru</url>
8
+ <phone>+7 (123) 456-7890</phone>
9
+ <platform>OpenCart</platform>
10
+ <version>2.0</version>
11
+ <currencies>
12
+ <currency id="RUB" rate="1"/>
13
+ <currency id="USD" rate="55.04"/>
14
+ <currency id="EUR" rate="CBRF"/>
15
+ </currencies>
16
+ <categories>
17
+ <category id="1">�������</category>
18
+ <category id="2">������</category>
19
+ <category id="3">�����</category>
20
+ <category id="4" parentId="1">������� ��� �������</category>
21
+ <category id="5" parentId="1">������� ��� ���������</category>
22
+ </categories>
23
+ <local_delivery_cost>350</local_delivery_cost>
24
+ <offers>
25
+ <offer id="3" available="false">
26
+ <url>http://nosite/items/3</url>
27
+ <price>100</price>
28
+ <currencyId>RUR</currencyId>
29
+ <categoryId>2</categoryId>
30
+ <picture>http://nosite.ru/image_cover</picture>
31
+ <picture>http://nosite.ru/image1</picture>
32
+ <picture>http://nosite.ru/image2</picture>
33
+ <delivery>true</delivery>
34
+ <name>����� �3</name>
35
+ <param name="�������">������</param>
36
+ <param name="�������" unit="��.">10</param>
37
+ </offer>
38
+ <offer id="6" available="true">
39
+ <url>http://nosite/items/6</url>
40
+ <price>300.9</price>
41
+ <currencyId>RUR</currencyId>
42
+ <categoryId>1</categoryId>
43
+ <picture>http://nosite.ru/image_cover</picture>
44
+ <picture>http://nosite.ru/image1</picture>
45
+ <picture>http://nosite.ru/image2</picture>
46
+ <delivery>true</delivery>
47
+ <name>����� �6</name>
48
+ <param name="�������">������</param>
49
+ <param name="�������" unit="��.">10</param>
50
+ </offer>
51
+ </offers>
52
+ </shop>
53
+ </yml_catalog>
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: yml_builder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stan Zhuravlev
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-05-11 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.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: |-
42
+ Библиотека содержит набор классов для формирования и валидации прайс-листов
43
+ в формате Яндекс YAML (Яндекс.Маркет).
44
+ Текущая версия поддерживает только упрощенные товарные карточки.
45
+ email:
46
+ - stan@post-api.ru
47
+ executables: []
48
+ extensions: []
49
+ extra_rdoc_files: []
50
+ files:
51
+ - CHANGELOG.md
52
+ - LICENSE.txt
53
+ - README.md
54
+ - bin/console
55
+ - bin/setup
56
+ - lib/yml_builder.rb
57
+ - lib/yml_builder/categories.rb
58
+ - lib/yml_builder/common.rb
59
+ - lib/yml_builder/common_offer.rb
60
+ - lib/yml_builder/currencies.rb
61
+ - lib/yml_builder/offer.rb
62
+ - lib/yml_builder/offer_simple.rb
63
+ - lib/yml_builder/offer_vendor_model.rb
64
+ - lib/yml_builder/offers.rb
65
+ - lib/yml_builder/shop.rb
66
+ - lib/yml_builder/stats.rb
67
+ - lib/yml_builder/version.rb
68
+ - lib/yml_builder/yml.rb
69
+ - test/example_1_spec.rb
70
+ - test/example_2_spec.rb
71
+ - test/example_3_spec.rb
72
+ - test/example_full_spec.rb
73
+ - test/test_yml.yml
74
+ homepage: https://github.com/StanZhuravlev/yml_builder
75
+ licenses:
76
+ - MIT
77
+ metadata:
78
+ allowed_push_host: https://rubygems.org
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ - lib/yml_builder
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: 2.2.1
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.5
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: "Набор классов для формирования прайс-листов в формате Яндекс YAML"
100
+ test_files: []