active_merge 1.0.0 → 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9f04e96b337986ab01516a571764953292c4cf46
4
+ data.tar.gz: e51483094adf87e9f17596876c74feda706dddad
5
+ SHA512:
6
+ metadata.gz: b1c2930d0ffb8c6c0e996fb2aeef7701d211031dfcad1ff6e90f0ef117620de45f676028347c1763785f2a51acab8311b26592873ccd483ea982972f449aecc2
7
+ data.tar.gz: a4365f27dd04f85929042e8f07a25837386af8bfc0c96d12dd5f7c0ddaca69d867a74b50c5853c319f8dd503cd86399fc2b59269a5f13b265a5b56a69a52d9f2
@@ -67,99 +67,67 @@ module ActiveMerge
67
67
  # то объединения не произойдет!
68
68
  #
69
69
  class Service
70
+ include ActiveModel::Validations
70
71
 
71
72
  def initialize(list = [])
72
- list = _extract_from list
73
+ list = extract_from list
73
74
  @item, @items = list.first, Array(list[1..-1])
74
75
  end
75
76
 
76
77
  attr_reader :item, :items, :klass, :klasses
77
-
78
- # Возвращает класс объединяемых объектов
79
- def klass
80
- @klass ||= item.class
81
- end
82
-
83
- # Возвращает хэш, в котором ключами выступают связи has_many,
84
- # а значениями - foreign keys
85
- def klasses
86
- @klasses ||= klass.reflect_on_all_associations(:has_many).
87
- inject({}){ |hash, item| hash.merge(item.name => item.foreign_key) }
88
- end
78
+ validates :items, presence: true
89
79
 
90
80
  # Объединяет все записи из переменной #items с записью в переменной #item
91
81
  #
92
82
  # При этом:
93
- # * все ссылки на записи из массива #items (связь has_many) перепривязываются к #item
83
+ # * все ссылки на записи из массива #items перепривязываются к #item
94
84
  # * все записи #items удаляются
95
85
  #
96
86
  # При любой ошибке все сделанные изменения отменяются.
97
87
  #
98
88
  def provide
99
89
  ActiveRecord::Base.transaction requires_new: true do
100
- _raise :blank if items.blank?
101
- items.each{ |item| _merge_one(item) }
90
+ raise unless valid?
91
+ items.each{ |item| merge self.item, item }
102
92
  end
103
93
  end
104
94
 
105
95
  private
106
96
 
107
- # Вызывает исключение указанного типа с переданными парамертами
108
- def _raise(type, item = nil)
109
- options = item ? { type: item.class.name.underscore, id: item.id } : {}
110
- options.merge! scope: %w(active_merge errors service)
111
- raise I18n.t(type, options)
112
- end
113
-
114
97
  # Извлекает из списка только сохраненные объекты ActiveRecord
115
98
  # Если список содержит элементы ActiveRecord разных классов, возвращает
116
99
  # пустой массив.
117
- def _extract_from(list)
100
+ def extract_from(list)
118
101
  begin
119
- list = list.select{ |item| _valid? item }
120
- klass = list.first.class
121
- list.each { |item| raise unless item.class == klass }
122
- list.sort_by { |item| item.id }
102
+ list = select_active_records_from list
103
+ list = select_by_class_from list
123
104
  rescue
124
105
  []
125
106
  end
126
107
  end
127
108
 
128
- # Проверяет, что объект является сохраненным объектом ActiveRecord
129
- def _valid?(item)
130
- begin
109
+ # Выбирает сохраненные объекты ActiveRecord
110
+ def select_active_records_from(list)
111
+ list.select do |item|
131
112
  item.class.ancestors.include?(ActiveRecord::Base) && item.persisted?
132
- rescue
133
- false
134
- end
135
- end
136
-
137
- # Объединяет указанный объект с объектом из переменной #item
138
- # * Перепривязывает ссылки на объект #item
139
- # * Удаляет объект, переданный в аргументе
140
- def _merge_one(item)
141
- klasses.each do |list, foreign_key|
142
- item.send(list).each { |ref| _rebind! ref, foreign_key }
143
113
  end
144
- _destroy! item
145
114
  end
146
115
 
147
- # Перепривязывает запись к первому объединяемому объекту
148
- def _rebind!(item, foreign_key)
149
- begin
150
- item.send "#{ foreign_key }=", self.item.id
151
- item.save!
152
- rescue
153
- _raise :rebind, item
154
- end
116
+ # Выбирает объекты того же класса, что и у первой записи списка
117
+ def select_by_class_from(list)
118
+ klass = list.first.class
119
+ list.each { |item| raise unless item.class == klass }
120
+ list.sort_by { |item| item.id }
155
121
  end
156
122
 
157
- # Удаляет запись, сохраняя ошибки
158
- def _destroy!(item)
123
+ # Объединяет две записи.
124
+ # Переносит ошибки в текущий объект.
125
+ def merge(first, second)
126
+ service = ActiveMerge::SimpleService.new(first, second)
159
127
  begin
160
- item.destroy!
128
+ service.provide
161
129
  rescue
162
- _raise :destroy, item
130
+ service.errors.each{ |key, val| errors.add key, val } and raise
163
131
  end
164
132
  end
165
133
  end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+ module ActiveMerge
3
+
4
+ # Сервисный объект (паттерн Service Object), отвечающий за объединение
5
+ # двух записей ActiveRecord
6
+ #
7
+ # В ходе объединения все ссылки на вторую запись перепривязываются к первой,
8
+ # затем вторая запись удаляется
9
+ #
10
+ # В случае любой ошибки вызывается исключение, а ошибка добавляется в массив
11
+ # <tt>errors</tt>
12
+ #
13
+ class SimpleService
14
+ include ActiveModel::Validations
15
+
16
+ def initialize(first, second)
17
+
18
+ if first.class.ancestors.include?(ActiveRecord::Base) && first.persisted?
19
+ @first = first
20
+ end
21
+
22
+ if @first && (second.class == @first.class) && second.persisted?
23
+ @second = second
24
+ end
25
+ end
26
+ attr_reader :first, :second
27
+
28
+ validates :second, presence: true
29
+
30
+ def provide
31
+ ActiveRecord::Base.transaction requires_new: true do
32
+ raise unless valid?
33
+ refs.each{ |item, key| rebind(item, key) }
34
+ destroy
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ # Возвращает хэш, в котором ключами выступают связи has_many,
41
+ # а значениями - foreign keys
42
+ def klasses
43
+ second.class.reflect_on_all_associations(:has_many).
44
+ inject({}){ |hash, item| hash.merge(item.name => item.foreign_key) }
45
+ end
46
+
47
+ # Возвращает хэш, в котором ключами выступают объекты, ссылающихся на
48
+ # #second, а значениями - методы присвоения ссылки на #first.
49
+ def refs
50
+ @refs = {}
51
+ klasses.each do |list, key|
52
+ second.send(list).each{ |item| @refs[item] = "#{ key }=" }
53
+ end
54
+ return @refs
55
+ end
56
+
57
+ # Выполняет перепривязку указанного объекта к первому аргументу
58
+ # Ошибки накапливаются в массиве <tt>errors</tt>
59
+ def rebind(item, key)
60
+ begin
61
+ item.send key, first.id
62
+ item.save!
63
+ rescue
64
+ item.errors.each{ |key, val| errors.add key, val } and raise
65
+ end
66
+ end
67
+
68
+ # Удаляет объединяемый объект
69
+ def destroy
70
+ begin
71
+ second.destroy!
72
+ rescue
73
+ second.errors.each{ |key, val| errors.add key, val } and raise
74
+ end
75
+ end
76
+ end
77
+ end
@@ -1,4 +1,4 @@
1
1
  module ActiveMerge
2
2
  # Текущая версия плагина
3
- VERSION = "1.0.0"
3
+ VERSION = "1.0.1"
4
4
  end
data/lib/active_merge.rb CHANGED
@@ -7,6 +7,8 @@
7
7
  #
8
8
  module ActiveMerge
9
9
  extend ActiveSupport::Autoload
10
+
11
+ autoload :SimpleService
10
12
  autoload :Service
11
13
 
12
14
  # Объединение указанных записей.
metadata CHANGED
@@ -1,94 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_merge
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
5
- prerelease:
4
+ version: 1.0.1
6
5
  platform: ruby
7
6
  authors:
8
7
  - Andrew Kozin
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-03-08 00:00:00.000000000 Z
11
+ date: 2014-03-17 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rails
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: 4.0.3
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: 4.0.3
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: sqlite3
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - ">="
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - ">="
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: rspec
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - ">="
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
52
+ - - ">="
60
53
  - !ruby/object:Gem::Version
61
54
  version: '0'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: yard
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ! '>='
59
+ - - ">="
68
60
  - !ruby/object:Gem::Version
69
61
  version: '0'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ! '>='
66
+ - - ">="
76
67
  - !ruby/object:Gem::Version
77
68
  version: '0'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: database_cleaner
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ! '>='
73
+ - - ">="
84
74
  - !ruby/object:Gem::Version
85
75
  version: '0'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ! '>='
80
+ - - ">="
92
81
  - !ruby/object:Gem::Version
93
82
  version: '0'
94
83
  description: Declares the ActiveMerge module with the 'merge!' class method.
@@ -98,36 +87,36 @@ executables: []
98
87
  extensions: []
99
88
  extra_rdoc_files: []
100
89
  files:
101
- - lib/active_merge/service.rb
102
- - lib/active_merge/version.rb
103
- - lib/active_merge.rb
104
90
  - MIT-LICENSE
105
- - Rakefile
106
91
  - README.rdoc
92
+ - Rakefile
93
+ - lib/active_merge.rb
94
+ - lib/active_merge/service.rb
95
+ - lib/active_merge/simple_service.rb
96
+ - lib/active_merge/version.rb
107
97
  homepage: https://github.com/nepalez/active_merge
108
98
  licenses:
109
99
  - MIT
100
+ metadata: {}
110
101
  post_install_message:
111
102
  rdoc_options: []
112
103
  require_paths:
113
104
  - lib
114
105
  required_ruby_version: !ruby/object:Gem::Requirement
115
- none: false
116
106
  requirements:
117
- - - ! '>='
107
+ - - ">="
118
108
  - !ruby/object:Gem::Version
119
109
  version: '0'
120
110
  required_rubygems_version: !ruby/object:Gem::Requirement
121
- none: false
122
111
  requirements:
123
- - - ! '>='
112
+ - - ">="
124
113
  - !ruby/object:Gem::Version
125
114
  version: '0'
126
115
  requirements: []
127
116
  rubyforge_project:
128
- rubygems_version: 1.8.24
117
+ rubygems_version: 2.2.2
129
118
  signing_key:
130
- specification_version: 3
119
+ specification_version: 4
131
120
  summary: Merges instances of an ActiveRecord class.
132
121
  test_files: []
133
122
  has_rdoc: