active_merge 1.0.0 → 1.0.1

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: 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: