bitrix_on_rails 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +20 -0
- data/LICENSE.txt +20 -0
- data/README +0 -0
- data/README.rdoc +86 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/app/models/iblock.rb +87 -0
- data/app/models/iblock_element.rb +108 -0
- data/app/models/iblock_element_property.rb +6 -0
- data/app/models/iblock_field.rb +6 -0
- data/app/models/iblock_group.rb +6 -0
- data/app/models/iblock_property.rb +32 -0
- data/app/models/iblock_property_enum.rb +6 -0
- data/app/models/iblock_section.rb +30 -0
- data/app/models/iblock_section_element.rb +8 -0
- data/app/models/iblock_type.rb +5 -0
- data/bitrix_on_rails.gemspec +77 -0
- data/init.rb +1 -0
- data/lib/active_record/connection_adapters/mysql2_downcase_adapter.rb +76 -0
- data/lib/bitrix_on_rails.rb +21 -0
- data/lib/bitrix_on_rails/active_record.rb +28 -0
- data/lib/bitrix_on_rails/engine.rb +4 -0
- data/lib/bitrix_on_rails/iblock_element_prop_m.rb +64 -0
- data/lib/bitrix_on_rails/iblock_element_prop_s.rb +119 -0
- data/test/helper.rb +18 -0
- data/test/test_bitrix_on_rails.rb +7 -0
- metadata +125 -0
data/.document
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem "shoulda", ">= 0"
|
10
|
+
gem "bundler", "~> 1.0.0"
|
11
|
+
gem "jeweler", "~> 1.6.4"
|
12
|
+
gem "rcov", ">= 0"
|
13
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
git (1.2.5)
|
5
|
+
jeweler (1.6.4)
|
6
|
+
bundler (~> 1.0)
|
7
|
+
git (>= 1.2.5)
|
8
|
+
rake
|
9
|
+
rake (0.9.2)
|
10
|
+
rcov (0.9.9)
|
11
|
+
shoulda (2.11.3)
|
12
|
+
|
13
|
+
PLATFORMS
|
14
|
+
ruby
|
15
|
+
|
16
|
+
DEPENDENCIES
|
17
|
+
bundler (~> 1.0.0)
|
18
|
+
jeweler (~> 1.6.4)
|
19
|
+
rcov
|
20
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Danil Pismenny
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
= bitrix_on_rails
|
2
|
+
|
3
|
+
Приблуды для использования под рельсами базы 1С:Битрикс.
|
4
|
+
|
5
|
+
Для каждого инфоблока что лежит в b_iblock есть своя таблица название которой с номером инфоблока, например b_iblock_element_prop_s7
|
6
|
+
prop_s - для одиночных свойтсв, prop_m - для множестенный.
|
7
|
+
У каждого инфоблока нескоолько секций (iblock_section), в каждой секции несколько элементов (iblock_element) у каждого элемента разные свойства которые лежат в prop_s/_m.
|
8
|
+
Соответсвенно я эти свойства вытащил в одно место - они все доступны из модели IblockElement. Или напрямую; IblockElement.find(123).НАЗВАНИЕ_СВОЙСТВА или через метод properties
|
9
|
+
|
10
|
+
== Что есть:
|
11
|
+
|
12
|
+
=== mysql2_downcase адаптер
|
13
|
+
1. Адаптер mysql2_downcase для автоматической конвертации заглавных наименований полей в прописные.
|
14
|
+
|
15
|
+
=== Инфоблоки
|
16
|
+
|
17
|
+
1. Все модели для таблиц b_iblock_*
|
18
|
+
2. Автоматическая установка свойств из таблиц prop_s*/prop_m* в методы объекта IblockElement.
|
19
|
+
Например IblockElement.find(1).name_emittents, где name_emittent - свойство из prop_s.
|
20
|
+
Все подобные свойства также доступны через метод IblockElement#properties.
|
21
|
+
|
22
|
+
3. IblockElementS*
|
23
|
+
1. Тоже самое и для моделей IblockElementPropertyS*, плюс в них значения полей можно еще и устанавливать:
|
24
|
+
|
25
|
+
p = IblockElementPropertyS3.find(1)
|
26
|
+
p.name_emittents='новое имя'
|
27
|
+
p.save
|
28
|
+
|
29
|
+
2. Поиск по кодовым названиям полей таблицы
|
30
|
+
|
31
|
+
IblockElementPropertyS3.find_by_post_id(123)
|
32
|
+
|
33
|
+
вместо
|
34
|
+
|
35
|
+
.find_by_property_149(123)
|
36
|
+
|
37
|
+
Таким образом если мы знаем что инфоблок S3 связан с таблицей постов и хотим получить все свойства поста 63, делаем:
|
38
|
+
|
39
|
+
IblockElementPropS3.find_by_post_id(63).iblock_element.properties
|
40
|
+
|
41
|
+
3. IblockElement.properties выдает хеш соответсвия кодов свойств и названия их полей в prop_s
|
42
|
+
Автоматическое определение привязки элемента к объекту. Например: если мы спрашиваем iblock_element.post
|
43
|
+
то он ищет ключ :post_id в свойствах элемента, и если находит, то возвращает Post.find_by_id(properties[:post_id])
|
44
|
+
|
45
|
+
4. Все свойства IblockProperty кешируются и доступны через find(id)
|
46
|
+
|
47
|
+
5. В IblockElement автоматически добавляются has_one :iblock_element_prop_s* и has_many :iblock_element_prop_m* при создании соответвующих классов.
|
48
|
+
|
49
|
+
6. Модель можно расширять инфоблоком с помощью:
|
50
|
+
|
51
|
+
class Post << ActiveRecord::Base
|
52
|
+
|
53
|
+
has_infoblock(3, :property_19) # где property_19 поле ссылающееся на Post
|
54
|
+
|
55
|
+
для этой модели автоматически создадутся ассоциации
|
56
|
+
|
57
|
+
:iblock_element - класс PostElement
|
58
|
+
|
59
|
+
Класс PostElement будет иметь ассоциации
|
60
|
+
|
61
|
+
:property_set (он же iblock_element_prop_sNUMBER) и
|
62
|
+
:m_prop_values
|
63
|
+
|
64
|
+
а также default_scope с номером инфоблока, поэтому PostElement.all выдаст только элементы к специфичному инфоблоку
|
65
|
+
|
66
|
+
|
67
|
+
=== Битрикс-авторизация
|
68
|
+
|
69
|
+
== mysql2_downcase
|
70
|
+
|
71
|
+
Подключать просто:
|
72
|
+
|
73
|
+
development:
|
74
|
+
adapter: mysql2_downcase
|
75
|
+
encoding: cp1251
|
76
|
+
...
|
77
|
+
|
78
|
+
== Contributing to bitrix_on_rails
|
79
|
+
|
80
|
+
* С нетерпением жду форков, пулеквестов, замечаний и предложений.
|
81
|
+
|
82
|
+
== Copyright
|
83
|
+
|
84
|
+
Copyright (c) 2011 Danil Pismenny. See LICENSE.txt for
|
85
|
+
further details.
|
86
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "bitrix_on_rails"
|
18
|
+
gem.homepage = "http://github.com/dapi/bitrix_on_rails"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Работа с инфоблоками 1С-Битрикс}
|
21
|
+
gem.description = %Q{Использование инфоблоков 1С-Битрикс в Ruby On Rails проектах}
|
22
|
+
gem.email = "danil@orionet.ru"
|
23
|
+
gem.authors = ["Danil Pismenny"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "bitrix_on_rails #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
class Iblock < ActiveRecord::Base
|
3
|
+
set_table_name :b_iblock
|
4
|
+
|
5
|
+
# version - 1 или 2
|
6
|
+
|
7
|
+
# iblock_type_id это строка, поэтом он срабатывает только если его указывать явано в foreign_key
|
8
|
+
belongs_to :iblock_type, :foreign_key=>'iblock_type_id'
|
9
|
+
|
10
|
+
# Они еще связаны между собой через iblock_section_element
|
11
|
+
has_many :iblock_sections
|
12
|
+
has_many :iblock_elements
|
13
|
+
|
14
|
+
# has_many :iblock_section_elements, :through=>:iblock_sections
|
15
|
+
|
16
|
+
# Список типов свойств по номерам которых создаются поля в
|
17
|
+
# таблицах iblock_element_prop_sN
|
18
|
+
has_many :iblock_properties
|
19
|
+
|
20
|
+
has_many :iblock_fields
|
21
|
+
has_many :iblock_groups
|
22
|
+
|
23
|
+
class << self
|
24
|
+
def s_props_class(id)
|
25
|
+
# raise 'Только для инфоблоков 2-й версии' unless version==2
|
26
|
+
"IblockElementPropS#{id}".constantize
|
27
|
+
end
|
28
|
+
|
29
|
+
def m_props_class(id)
|
30
|
+
# raise 'Только для инфоблоков 2-й версии' unless version==2
|
31
|
+
"IblockElementPropM#{id}".constantize
|
32
|
+
end
|
33
|
+
|
34
|
+
def all
|
35
|
+
@cached_all ||= super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
name
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def init_property_models
|
45
|
+
return unless version==2
|
46
|
+
iblock_id = self.id
|
47
|
+
|
48
|
+
# Создаем классы IblockElementPropSНОМЕР
|
49
|
+
#
|
50
|
+
const_name = "IblockElementPropS#{iblock_id}"
|
51
|
+
unless Kernel.const_defined? const_name
|
52
|
+
e = Class.new(ActiveRecord::Base) do
|
53
|
+
extend BitrixOnRails::IblockElementPropS
|
54
|
+
|
55
|
+
class << self
|
56
|
+
@m_prop_class = nil
|
57
|
+
@m_props = nil
|
58
|
+
|
59
|
+
def m_prop_class
|
60
|
+
Kernel.const_get(@m_prop_class)
|
61
|
+
end
|
62
|
+
|
63
|
+
def m_props
|
64
|
+
@m_props
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
acts_as_iblock_element_prop_s(iblock_id)
|
69
|
+
end
|
70
|
+
Kernel.const_set const_name, e
|
71
|
+
end
|
72
|
+
Kernel.const_get(const_name).init
|
73
|
+
|
74
|
+
# Создаем классы IblockElementPropMНОМЕР
|
75
|
+
#
|
76
|
+
const_name = "IblockElementPropM#{iblock_id}"
|
77
|
+
unless Kernel.const_defined? const_name
|
78
|
+
e = Class.new(ActiveRecord::Base) do
|
79
|
+
extend BitrixOnRails::IblockElementPropM
|
80
|
+
acts_as_iblock_element_prop_m(iblock_id)
|
81
|
+
end
|
82
|
+
Kernel.const_set "IblockElementPropM#{iblock_id}", e
|
83
|
+
end
|
84
|
+
Kernel.const_get(const_name).init
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
class IblockElement < ActiveRecord::Base
|
3
|
+
class << self
|
4
|
+
@block_id = nil
|
5
|
+
@iblock_properties = nil
|
6
|
+
|
7
|
+
def iblock_id
|
8
|
+
@iblock_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def iblock_properties
|
12
|
+
@iblock_properties
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
set_table_name :b_iblock_element
|
17
|
+
|
18
|
+
belongs_to :iblock
|
19
|
+
belongs_to :iblock_section
|
20
|
+
|
21
|
+
# Применяется только для iblock-ов 1-й версии
|
22
|
+
#
|
23
|
+
has_many :iblock_element_properties
|
24
|
+
|
25
|
+
# Применяется для iblock-ов 2-й версии
|
26
|
+
#
|
27
|
+
has_many :iblock_section_elements
|
28
|
+
has_many :iblock_sections, :through => :iblock_section_elements
|
29
|
+
|
30
|
+
after_find :initialize_properties
|
31
|
+
|
32
|
+
attr_accessor :properties
|
33
|
+
|
34
|
+
def to_s
|
35
|
+
name
|
36
|
+
end
|
37
|
+
|
38
|
+
def s_props
|
39
|
+
# has_one
|
40
|
+
@s_props ||= Iblock.s_props_class(iblock_id).find_by_iblock_element_id( id )
|
41
|
+
end
|
42
|
+
|
43
|
+
def iblock_element_prop_m
|
44
|
+
Iblock.m_props_class(iblock_id).where(:iblock_element_id=>id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def m_props
|
48
|
+
# TODO Cache
|
49
|
+
@m_props={}
|
50
|
+
iblock_element_prop_m.each do |p|
|
51
|
+
@m_props[p.code]||=[]
|
52
|
+
@m_props[p.code] << p.get_value
|
53
|
+
end
|
54
|
+
@m_props
|
55
|
+
end
|
56
|
+
|
57
|
+
# Если мы спрашиваем iblock_element.post
|
58
|
+
# то он ищет ключ :post_id в свойствах элемента
|
59
|
+
# и если находит, то возвращает Post.find_by_id(properties[:post_id])
|
60
|
+
#
|
61
|
+
def method_missing(method, *args)
|
62
|
+
id_name = "#{method}_id".to_sym
|
63
|
+
if properties and properties.include?(id_name)
|
64
|
+
# TODO Проверять на наличие такого класса и то что он ActiveRecord
|
65
|
+
# Кешировать
|
66
|
+
method.to_s.capitalize.constantize.find_by_id(properties[id_name])
|
67
|
+
else
|
68
|
+
super
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.set_iblock_id(id)
|
73
|
+
@iblock_id = id
|
74
|
+
@iblock_properties = IblockProperty.where(:iblock_id => id).inject({}){ |a,e| a[e.code] = e.id; a }
|
75
|
+
|
76
|
+
prop_s_class = "::IblockElementPropS#{id}"
|
77
|
+
prop_m_class = "::IblockElementPropM#{id}"
|
78
|
+
|
79
|
+
has_one :property_set, :class_name => prop_s_class, :foreign_key => 'iblock_element_id', :autosave => true
|
80
|
+
has_many :m_prop_values, :class_name => prop_m_class, :foreign_key => 'iblock_element_id'
|
81
|
+
|
82
|
+
default_scope where(:iblock_id => id, :active => 'Y')
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def initialize_properties
|
88
|
+
# TODO Могу повторяться именя в m_props, ругаться чтоли
|
89
|
+
@properties = (s_props ? s_props.properties : {}).merge m_props
|
90
|
+
|
91
|
+
# TODO Переписать на автоматическое определение названия свойства в моделях property_set и m_prop_values
|
92
|
+
# чтобы уйти от хеша @properties (оставить его массивом для дебаггинга)
|
93
|
+
|
94
|
+
# TODO Сделать в элементе автоделегейт
|
95
|
+
@properties.keys.each do |prop|
|
96
|
+
# TODO Перенести на прямой вызов объектов s_props/m_props
|
97
|
+
instance_eval "def #{prop}; @properties[:#{prop}]; end"
|
98
|
+
instance_eval "def #{prop}=(val); @properties[:#{prop}]=property_set.#{prop}=val; end"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Это здесь для того чтобы при перезагрузке в development
|
106
|
+
# режиме заново создавались ассоциации iblock_element_prop_s3
|
107
|
+
# TODO переделать на более элегантное решение
|
108
|
+
Iblock.all.map &:init_property_models
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
class IblockProperty < ActiveRecord::Base
|
3
|
+
set_table_name :b_iblock_property
|
4
|
+
|
5
|
+
belongs_to :iblock
|
6
|
+
|
7
|
+
# TODO Что это за link_iblock?
|
8
|
+
belongs_to :link_iblock, :class_name=>'Iblock'
|
9
|
+
|
10
|
+
has_many :iblock_property_enums, :foreign_key=>:property_id
|
11
|
+
has_many :iblock_element_properties
|
12
|
+
|
13
|
+
cattr_accessor :cache
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def find(id)
|
17
|
+
cache_all unless @@cache
|
18
|
+
@@cache[id] or raise "Не найдено такое свойство iblock_property #{id}"
|
19
|
+
end
|
20
|
+
|
21
|
+
# Запускается в ./lib/bitrix_on_rails при загрузке
|
22
|
+
def cache_all
|
23
|
+
@@cache = IblockProperty.all.inject({}) { |hash, prop| hash[prop.id]=prop; hash }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def code
|
28
|
+
val = read_attribute('code')
|
29
|
+
return nil if val.nil?
|
30
|
+
val.downcase.to_sym
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
class IblockSection < ActiveRecord::Base
|
3
|
+
class << self
|
4
|
+
@iblock_id = nil
|
5
|
+
|
6
|
+
def iblock_id
|
7
|
+
@iblock_id
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
set_table_name :b_iblock_section
|
12
|
+
|
13
|
+
belongs_to :iblock
|
14
|
+
|
15
|
+
default_scope order(:sort)
|
16
|
+
|
17
|
+
has_many :direct_iblock_elements, :class_name=>'IblockElement'
|
18
|
+
|
19
|
+
has_many :iblock_section_elements
|
20
|
+
has_many :iblock_elements, :through => :iblock_section_elements
|
21
|
+
|
22
|
+
def self.set_iblock_id(id)
|
23
|
+
@iblock_id = id
|
24
|
+
default_scope where(:iblock_id => id, :active => 'Y')
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
name
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{bitrix_on_rails}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Danil Pismenny"]
|
12
|
+
s.date = %q{2011-08-02}
|
13
|
+
s.description = %q{Использование инфоблоков 1С-Битрикс в Ruby On Rails проектах}
|
14
|
+
s.email = %q{danil@orionet.ru}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README",
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
"Gemfile",
|
23
|
+
"Gemfile.lock",
|
24
|
+
"LICENSE.txt",
|
25
|
+
"README",
|
26
|
+
"README.rdoc",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"app/models/iblock.rb",
|
30
|
+
"app/models/iblock_element.rb",
|
31
|
+
"app/models/iblock_element_property.rb",
|
32
|
+
"app/models/iblock_field.rb",
|
33
|
+
"app/models/iblock_group.rb",
|
34
|
+
"app/models/iblock_property.rb",
|
35
|
+
"app/models/iblock_property_enum.rb",
|
36
|
+
"app/models/iblock_section.rb",
|
37
|
+
"app/models/iblock_section_element.rb",
|
38
|
+
"app/models/iblock_type.rb",
|
39
|
+
"bitrix_on_rails.gemspec",
|
40
|
+
"init.rb",
|
41
|
+
"lib/active_record/connection_adapters/mysql2_downcase_adapter.rb",
|
42
|
+
"lib/bitrix_on_rails.rb",
|
43
|
+
"lib/bitrix_on_rails/active_record.rb",
|
44
|
+
"lib/bitrix_on_rails/engine.rb",
|
45
|
+
"lib/bitrix_on_rails/iblock_element_prop_m.rb",
|
46
|
+
"lib/bitrix_on_rails/iblock_element_prop_s.rb",
|
47
|
+
"test/helper.rb",
|
48
|
+
"test/test_bitrix_on_rails.rb"
|
49
|
+
]
|
50
|
+
s.homepage = %q{http://github.com/dapi/bitrix_on_rails}
|
51
|
+
s.licenses = ["MIT"]
|
52
|
+
s.require_paths = ["lib"]
|
53
|
+
s.rubygems_version = %q{1.6.2}
|
54
|
+
s.summary = %q{Работа с инфоблоками 1С-Битрикс}
|
55
|
+
|
56
|
+
if s.respond_to? :specification_version then
|
57
|
+
s.specification_version = 3
|
58
|
+
|
59
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
60
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
62
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
63
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
64
|
+
else
|
65
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
66
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
67
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
68
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
69
|
+
end
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
72
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
74
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bitrix_on_rails'
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Just use 'mysql2_downcase' adapter in database.yml
|
3
|
+
#
|
4
|
+
|
5
|
+
require 'active_record/connection_adapters/mysql2_adapter'
|
6
|
+
|
7
|
+
module ActiveRecord
|
8
|
+
class Base
|
9
|
+
# Establishes a connection to the database that's used by all Active Record objects.
|
10
|
+
def self.mysql2_downcase_connection(config)
|
11
|
+
config[:username] = 'root' if config[:username].nil?
|
12
|
+
|
13
|
+
if Mysql2::Client.const_defined? :FOUND_ROWS
|
14
|
+
config[:flags] = Mysql2::Client::FOUND_ROWS
|
15
|
+
end
|
16
|
+
|
17
|
+
client = Mysql2::Client.new(config.symbolize_keys)
|
18
|
+
options = [config[:host], config[:username], config[:password], config[:database], config[:port], config[:socket], 0]
|
19
|
+
ConnectionAdapters::Mysql2DowncaseAdapter.new(client, logger, options, config)
|
20
|
+
# ActiveRecord::Base.mysql2_connection(config)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Result
|
25
|
+
|
26
|
+
# Это выполняется через ActiveRecord::Result.new в mysql2_adapter
|
27
|
+
# при выполнении запроса
|
28
|
+
def initialize(columns, rows)
|
29
|
+
@columns = columns.map { |c| c.downcase }
|
30
|
+
@rows = rows
|
31
|
+
@hash_rows = nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module ConnectionAdapters
|
36
|
+
class Column
|
37
|
+
|
38
|
+
alias_method :old_initialize, :initialize
|
39
|
+
|
40
|
+
# Это выполняется при выборке списка аттрибутов на уровне класса
|
41
|
+
#
|
42
|
+
def initialize(name, default, sql_type = nil, null = true)
|
43
|
+
old_initialize name.downcase, default, sql_type, null
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
class Mysql2DowncaseAdapter < Mysql2Adapter
|
49
|
+
|
50
|
+
ADAPTER_NAME = 'Mysql2Downcase'
|
51
|
+
|
52
|
+
# Надо бы глобально сделать тут:
|
53
|
+
# def execute(sql, name = nil)
|
54
|
+
# debugger
|
55
|
+
# end
|
56
|
+
|
57
|
+
# Это чтобы нормально определся primary_key
|
58
|
+
def pk_and_sequence_for(table)
|
59
|
+
keys = []
|
60
|
+
result = execute("DESCRIBE #{quote_table_name(table)}", 'SCHEMA')
|
61
|
+
result.each(:symbolize_keys => true, :as => :hash) do |row|
|
62
|
+
keys << row[:Field].downcase if row[:Key] == "PRI"
|
63
|
+
end
|
64
|
+
keys.length == 1 ? [keys.first, nil] : nil
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Возможно понадобится исправить этот метод
|
73
|
+
# quote_column_name
|
74
|
+
|
75
|
+
# Хороший пример адаптера - http://virtuoso.rubyforge.org/activerecord-mysql2spatial-adapter/
|
76
|
+
# https://github.com/dazuma/activerecord-mysql2spatial-adapter
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# require 'rails'
|
3
|
+
|
4
|
+
module BitrixOnRails
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'active_record'
|
8
|
+
|
9
|
+
require 'bitrix_on_rails/active_record'
|
10
|
+
require 'bitrix_on_rails/iblock_element_prop_s'
|
11
|
+
require 'bitrix_on_rails/iblock_element_prop_m'
|
12
|
+
# require 'bitrix_on_rails/engine'
|
13
|
+
|
14
|
+
# ActiveRecord::Base.connection.tables
|
15
|
+
|
16
|
+
ActiveRecord::Base.extend BitrixOnRails::ActiveRecord
|
17
|
+
|
18
|
+
# Просто подгружаем модель, тогда в ней появятся ассоциации типа iblock_element_prop_s3
|
19
|
+
IblockElement.class
|
20
|
+
|
21
|
+
# IblockProperty.cache_all
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
IblockElement.class
|
4
|
+
|
5
|
+
module BitrixOnRails
|
6
|
+
module ActiveRecord
|
7
|
+
|
8
|
+
def has_infoblock(iblock_id, property_name, &blk)
|
9
|
+
prop_s_name = "iblock_element_prop_s#{iblock_id}".to_sym
|
10
|
+
has_one prop_s_name, :foreign_key=>property_name, :class_name=>"::IblockElementPropS#{iblock_id}", :autosave => true
|
11
|
+
|
12
|
+
element_class_name = self.name + 'Element'
|
13
|
+
unless Kernel.const_defined?(element_class_name)
|
14
|
+
element_class = Class.new(IblockElement) do
|
15
|
+
set_iblock_id iblock_id
|
16
|
+
end
|
17
|
+
|
18
|
+
if block_given?
|
19
|
+
element_class.instance_eval(&blk)
|
20
|
+
end
|
21
|
+
|
22
|
+
self.const_set(element_class_name, element_class)
|
23
|
+
end
|
24
|
+
|
25
|
+
has_one :iblock_element, :through => prop_s_name, :class_name => element_class_name, :autosave => true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
module BitrixOnRails::IblockElementPropM
|
4
|
+
def acts_as_iblock_element_prop_m(id)
|
5
|
+
extend ClassMethods
|
6
|
+
include InstanceMethods
|
7
|
+
|
8
|
+
# Убираем лишнюю s вконце
|
9
|
+
#set_table_name 'b_'+table_name.chop
|
10
|
+
set_table_name "b_iblock_element_prop_m#{id}"
|
11
|
+
|
12
|
+
# delegate :code, :to=>:property
|
13
|
+
|
14
|
+
belongs_to :iblock_element
|
15
|
+
belongs_to :iblock_property
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def init
|
20
|
+
self.to_s=~/(\d+)/
|
21
|
+
iblock_id = $1.to_i
|
22
|
+
IblockElement.send :has_many, "iblock_element_prop_m#{iblock_id}".to_sym, :class_name=>"::IblockElementPropM#{iblock_id}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module InstanceMethods
|
27
|
+
|
28
|
+
def property
|
29
|
+
# Достаем кешированный вариант
|
30
|
+
IblockProperty.find(iblock_property_id)
|
31
|
+
end
|
32
|
+
|
33
|
+
def code
|
34
|
+
@code||=property.code
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_value
|
38
|
+
case property.property_type
|
39
|
+
when 'S' # String
|
40
|
+
self.value
|
41
|
+
when 'N' # Numeric
|
42
|
+
self.value_num.to_i # Когда BigDecimal - не приятно
|
43
|
+
# when 'E' # Enum?
|
44
|
+
# self.value_enum
|
45
|
+
# when 'L' # WTF?
|
46
|
+
else
|
47
|
+
raise "Не установленный тип (#{iblock_property.property_type}) свойства (#{self.class} #{id})"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
# Table b_iblock_element_prop_m7
|
55
|
+
# ==============================
|
56
|
+
# ID, IBLOCK_ELEMENT_ID, IBLOCK_PROPERTY_ID, VALUE, VALUE_ENUM, VALUE_NUM, DESCRIPTION
|
57
|
+
# ------------------------------
|
58
|
+
# ID int(11) PK
|
59
|
+
# IBLOCK_ELEMENT_ID int(11)
|
60
|
+
# IBLOCK_PROPERTY_ID int(11)
|
61
|
+
# VALUE text
|
62
|
+
# VALUE_ENUM int(11)
|
63
|
+
# VALUE_NUM decimal(18,4)
|
64
|
+
# DESCRIPTION varchar(255)
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
module BitrixOnRails::IblockElementPropS
|
3
|
+
def acts_as_iblock_element_prop_s(id)
|
4
|
+
extend ClassMethods
|
5
|
+
include InstanceMethods
|
6
|
+
|
7
|
+
@m_prop_class = "IblockElementPropM#{id}"
|
8
|
+
# Название свойства сохраняется только для наглядности, чтобы можно было через консоль понять
|
9
|
+
# что за свойство.
|
10
|
+
@m_props = IblockProperty.where(:iblock_id => id).inject({}){ |a,e| a[e.code] = e.id if e.multiple == 'Y'; a }
|
11
|
+
|
12
|
+
# Убираем лишнюю s вконце
|
13
|
+
#set_table_name 'b_'+table_name.chop
|
14
|
+
set_table_name "b_iblock_element_prop_s#{id}"
|
15
|
+
|
16
|
+
belongs_to :iblock_element
|
17
|
+
|
18
|
+
# Хеш соответсвия кодов свойств названию полей: post_id -> property_149
|
19
|
+
cattr_accessor :properties
|
20
|
+
|
21
|
+
# Хеш свойств объекта по кодам
|
22
|
+
attr_accessor :properties
|
23
|
+
|
24
|
+
after_find do
|
25
|
+
self.properties = self.class.properties.keys.inject({}) { |hash, prop| hash[prop] = send prop; hash }
|
26
|
+
end
|
27
|
+
|
28
|
+
before_save do
|
29
|
+
self.class.m_props.each_value { |id|
|
30
|
+
values = m_prop_values(id)
|
31
|
+
self.send("property_#{id}=", PHP.serialize({'VALUE' => values, 'DESCRIPTION' => Array.new(values.size, nil)}))
|
32
|
+
# self.send("property_#{id}=", PhpSerialization.dump({'VALUE' => values, 'DESCRIPTION' => Array.new(values.size, nil)}))
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_element_association
|
39
|
+
IblockElement.send :has_one, "iblock_element_prop_s#{id}".to_sym, :class_name=>"::IblockElementPropS#{id}"
|
40
|
+
end
|
41
|
+
|
42
|
+
module ClassMethods
|
43
|
+
|
44
|
+
# code - врое как кодовое название свойства
|
45
|
+
# name - русское описание
|
46
|
+
|
47
|
+
# Дальше идут пары:
|
48
|
+
# property_120
|
49
|
+
# description_120
|
50
|
+
# ..
|
51
|
+
# определяются они в iblock.iblock_properties
|
52
|
+
|
53
|
+
# Берем список свойств из таблицы iblock_properties
|
54
|
+
# и создаем такие же методы для опроса и установки, чтобы можно было использовать
|
55
|
+
# их напрямую:
|
56
|
+
#
|
57
|
+
# self.кодовое_имя_свойства
|
58
|
+
#
|
59
|
+
# Например:
|
60
|
+
#
|
61
|
+
# self.post_id вместо self.property_120
|
62
|
+
#
|
63
|
+
def init
|
64
|
+
self.to_s=~/(\d+)/
|
65
|
+
iblock_id = $1.to_i
|
66
|
+
|
67
|
+
IblockElement.send :has_one, "iblock_element_prop_s#{iblock_id}".to_sym, :class_name=>"::IblockElementPropS#{iblock_id}"
|
68
|
+
|
69
|
+
self.properties = {}
|
70
|
+
attribute_names.select {|a| a[0,4]=='prop' }.each do |name|
|
71
|
+
prop_id = name.slice(9,5).to_i
|
72
|
+
iblock_property = IblockProperty.find(prop_id)
|
73
|
+
code = iblock_property.code.downcase.to_sym
|
74
|
+
self.properties[code] = name
|
75
|
+
define_method code do
|
76
|
+
val = send name
|
77
|
+
return val.to_i if val.is_a?(BigDecimal)
|
78
|
+
|
79
|
+
# Вот так мы проверяем сериализацию
|
80
|
+
# Есть еще вариант что поле сериализовано если iblock_property.user_type=='HTML'
|
81
|
+
#
|
82
|
+
if val.is_a? String and val.length>5 and val[0,3]=~/[a-z]:\d/
|
83
|
+
res = PHP.unserialize(val)
|
84
|
+
# res = PhpSerialization.load(val)
|
85
|
+
return iblock_property.property_type=='S' && res.is_a?(Hash) && res.include?('TEXT') ? res['TEXT'] : res
|
86
|
+
end
|
87
|
+
val
|
88
|
+
end
|
89
|
+
define_method "#{code}=" do |val|
|
90
|
+
send "#{name}=", val
|
91
|
+
end
|
92
|
+
eval "def self.find_by_#{code}(val); find_by_#{name}(val); end"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
module InstanceMethods
|
98
|
+
|
99
|
+
# Возвращает десериализованное (при необходимости) значение свойства
|
100
|
+
#
|
101
|
+
# prop - код свойства (post_id к примеру)
|
102
|
+
def get_value(prop)
|
103
|
+
send prop
|
104
|
+
end
|
105
|
+
|
106
|
+
def m_prop_values(prop_id)
|
107
|
+
self.class.m_prop_class.where(:iblock_element_id => self.id, :iblock_property_id => prop_id).collect { |e| e.value }
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_m_prop_value(prop_id, value)
|
111
|
+
self.class.m_prop_class.create(:iblock_element_id => self.id, :iblock_property_id => prop_id, :value => value)
|
112
|
+
end
|
113
|
+
|
114
|
+
def destroy_m_prop_value(prop_id, value)
|
115
|
+
m_props = self.class.m_prop_class.where(:iblock_element_id => self.iblock_element_id, :iblock_property_id => prop_id, :value => value)
|
116
|
+
m_props.each { |p| p.destroy } if m_props.any?
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'bitrix_on_rails'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bitrix_on_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Danil Pismenny
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-08-02 00:00:00.000000000 +04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: shoulda
|
17
|
+
requirement: &2155895220 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2155895220
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: bundler
|
28
|
+
requirement: &2155894360 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.0.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2155894360
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: jeweler
|
39
|
+
requirement: &2155893580 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.6.4
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2155893580
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: rcov
|
50
|
+
requirement: &2155892440 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *2155892440
|
59
|
+
description: Использование инфоблоков 1С-Битрикс в Ruby On Rails проектах
|
60
|
+
email: danil@orionet.ru
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files:
|
64
|
+
- LICENSE.txt
|
65
|
+
- README
|
66
|
+
- README.rdoc
|
67
|
+
files:
|
68
|
+
- .document
|
69
|
+
- Gemfile
|
70
|
+
- Gemfile.lock
|
71
|
+
- LICENSE.txt
|
72
|
+
- README
|
73
|
+
- README.rdoc
|
74
|
+
- Rakefile
|
75
|
+
- VERSION
|
76
|
+
- app/models/iblock.rb
|
77
|
+
- app/models/iblock_element.rb
|
78
|
+
- app/models/iblock_element_property.rb
|
79
|
+
- app/models/iblock_field.rb
|
80
|
+
- app/models/iblock_group.rb
|
81
|
+
- app/models/iblock_property.rb
|
82
|
+
- app/models/iblock_property_enum.rb
|
83
|
+
- app/models/iblock_section.rb
|
84
|
+
- app/models/iblock_section_element.rb
|
85
|
+
- app/models/iblock_type.rb
|
86
|
+
- bitrix_on_rails.gemspec
|
87
|
+
- init.rb
|
88
|
+
- lib/active_record/connection_adapters/mysql2_downcase_adapter.rb
|
89
|
+
- lib/bitrix_on_rails.rb
|
90
|
+
- lib/bitrix_on_rails/active_record.rb
|
91
|
+
- lib/bitrix_on_rails/engine.rb
|
92
|
+
- lib/bitrix_on_rails/iblock_element_prop_m.rb
|
93
|
+
- lib/bitrix_on_rails/iblock_element_prop_s.rb
|
94
|
+
- test/helper.rb
|
95
|
+
- test/test_bitrix_on_rails.rb
|
96
|
+
has_rdoc: true
|
97
|
+
homepage: http://github.com/dapi/bitrix_on_rails
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
require_paths:
|
103
|
+
- lib
|
104
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
segments:
|
111
|
+
- 0
|
112
|
+
hash: 3152042687155228433
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
115
|
+
requirements:
|
116
|
+
- - ! '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
requirements: []
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 1.6.2
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: Работа с инфоблоками 1С-Битрикс
|
125
|
+
test_files: []
|