active_merge 1.0.4 → 1.0.5
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 +4 -4
- data/CHANGELOG.rdoc +16 -0
- data/{MIT-LICENSE → LICENSE} +1 -1
- data/README.rdoc +1 -1
- data/Rakefile +13 -1
- data/lib/active_merge/service.rb +57 -72
- data/lib/active_merge/simple_service.rb +36 -39
- data/lib/active_merge/version.rb +1 -2
- data/lib/active_merge.rb +9 -9
- data/spec/active_merge/service_spec.rb +205 -0
- data/spec/active_merge/simple_service_spec.rb +127 -0
- data/spec/active_merge_spec.rb +21 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/models/domain.rb +3 -0
- data/spec/dummy/app/models/lord.rb +4 -0
- data/spec/dummy/app/models/man.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +30 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +29 -0
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +36 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/ru.yml +7 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/migrate/20140416183029_create_lords.rb +6 -0
- data/spec/dummy/db/migrate/20140416183043_create_men.rb +8 -0
- data/spec/dummy/db/migrate/20140416183059_create_domains.rb +8 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +38 -0
- data/spec/dummy/log/test.log +25184 -0
- data/spec/dummy/public/404.html +58 -0
- data/spec/dummy/public/422.html +58 -0
- data/spec/dummy/public/500.html +57 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/spec_helper.rb +53 -0
- data/spec/support/errors.rb +17 -0
- metadata +125 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9908a773d23bf5b0b67850538549bf130646b257
|
4
|
+
data.tar.gz: e61c2879ca3ff6a256ac575651c69432b97c3c15
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d189fc4e6e22e3806c1bcf7350130718c4e85170c6d9b51924a7b206cbbdbec9ecae588d339a36bec6fc2650b7a75d3883d51d718663159226b94e7cae6b4511
|
7
|
+
data.tar.gz: eccd6bbd86184af049cb31f3229b4c575ab9ba478c7b0b4a7e3ba97af443ec62467424761f25f8e5bd89ea9c3446dc000f3f73b789a787a1c16d13eb961fd1ac
|
data/CHANGELOG.rdoc
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
= Список изменений в версиях
|
2
|
+
|
3
|
+
== v.1.0.4
|
4
|
+
|
5
|
+
* The gem is allowed to use with rails 4.1
|
6
|
+
|
7
|
+
== v.1.0.2
|
8
|
+
|
9
|
+
* Documentation bug fixed. References to the <tt>#merge</tt> changed to the <tt>#merge_all</tt>
|
10
|
+
|
11
|
+
== v.1.0.1
|
12
|
+
|
13
|
+
* The <tt>Service#klass</tt> and <tt>Service#klasses</tt> methods removed
|
14
|
+
* The <tt>Service</tt> class includes <tt>ActiveModels::Validations</tt>
|
15
|
+
* The <tt>Service#valid?</tt> method added
|
16
|
+
* Service object errors collected in the <tt>Service#errors</tt>
|
data/{MIT-LICENSE → LICENSE}
RENAMED
data/README.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -20,10 +20,22 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
20
20
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
21
|
end
|
22
22
|
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
23
26
|
Bundler::GemHelper.install_tasks
|
24
27
|
|
25
28
|
require "bundler/gem_tasks"
|
26
29
|
require 'rspec/core/rake_task'
|
27
30
|
|
28
31
|
RSpec::Core::RakeTask.new(:spec)
|
29
|
-
task default
|
32
|
+
task :default do
|
33
|
+
sh "bundle exec rake db:migrate RAILS_ENV=test"
|
34
|
+
sh "mkdir spec/dummy/tmp" do |ok, res|
|
35
|
+
nunitSuccessFlag = false
|
36
|
+
end
|
37
|
+
sh "mkdir spec/dummy/tmp/cache" do |ok, res|
|
38
|
+
nunitSuccessFlag = false
|
39
|
+
end
|
40
|
+
sh "bundle exec rspec spec"
|
41
|
+
end
|
data/lib/active_merge/service.rb
CHANGED
@@ -1,24 +1,29 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module ActiveMerge
|
3
3
|
|
4
|
-
#
|
5
|
-
#
|
4
|
+
# Service Object responds for merging given ActiveRecord instances into the
|
5
|
+
# first one
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# они должны быть объектами одного класса.
|
7
|
+
# Object initializes either with ActiveRecord::Association or array of objects.
|
8
|
+
# If the argument is an array, then only those items taken into account, that:
|
10
9
|
#
|
11
|
-
#
|
12
|
-
# *
|
13
|
-
# *
|
14
|
-
# * После перепривязки все объекты, кроме первого, удаляются.
|
10
|
+
# * inherited from the <tt>ActiveRecord::Base</tt>
|
11
|
+
# * persisted
|
12
|
+
# * are objects of one class
|
15
13
|
#
|
16
|
-
#
|
17
|
-
# ранее относившиеся к объединяемым записям.
|
14
|
+
# == Merging algorithm
|
18
15
|
#
|
19
|
-
#
|
16
|
+
# * The item with minimal <tt>id</tt> selected from the service argument. It will remaine intact.
|
17
|
+
# * All objects, that the other items links to via "has_many" assotiation, are selected...
|
18
|
+
# * ... and are rebound to the first item
|
19
|
+
# * After rebinding any item from the service argument, except the first one, to be deleted.
|
20
20
|
#
|
21
|
-
#
|
21
|
+
# As a result it is only the first object from the argument remains intact,
|
22
|
+
# and all the instances that belonged to the other ones are now belongs to it.
|
23
|
+
#
|
24
|
+
# == Example:
|
25
|
+
#
|
26
|
+
# # Let any kingdom has many shires and men
|
22
27
|
# class Kingdom < ActiveRecord::Base
|
23
28
|
# has_many :shires
|
24
29
|
# has_many :men
|
@@ -32,102 +37,82 @@ module ActiveMerge
|
|
32
37
|
# belongs_to :kingdom
|
33
38
|
# end
|
34
39
|
#
|
35
|
-
# #
|
40
|
+
# # Britain has 10 shires and 100 thousands men lives there
|
36
41
|
# britain = Kingdom.create!
|
37
|
-
#
|
42
|
+
# 100000.times.each{ britain.men.create! }
|
38
43
|
# 10.times.each{ britain.shires.create! }
|
39
44
|
#
|
40
|
-
# #
|
45
|
+
# # Scotland has 5 shires and 30 thousands living men
|
41
46
|
# scotland = Kingdom.create!
|
42
|
-
#
|
43
|
-
# 5.times.each{
|
47
|
+
# 30000.times.each{ scotland.men.create! }
|
48
|
+
# 5.times.each{ scotland.shires.create! }
|
44
49
|
#
|
45
|
-
# #
|
50
|
+
# # Lets merge all the kingdoms:
|
46
51
|
# Service.new(Kingdom.all).submit!
|
47
52
|
#
|
48
|
-
# #
|
53
|
+
# # Now union Britain (because it is Britain that was created first)
|
54
|
+
# # has all those 15 shires and 130 thousand men
|
55
|
+
# # from both the old good Britain and the old good Scotland.
|
49
56
|
# britain.reload.men.count # => 130000
|
50
57
|
# britain.reload.shires.count # => 15
|
51
58
|
#
|
52
|
-
# #
|
59
|
+
# # And, alas, the Scotland Kingdom doesn't exists any more
|
53
60
|
# Kingdom.find_by(scotland.id) # => nil
|
54
61
|
#
|
55
|
-
# ==
|
62
|
+
# == Warning!
|
56
63
|
#
|
57
|
-
#
|
58
|
-
#
|
64
|
+
# The merge provided as a whole transaction. In case any error occures, all
|
65
|
+
# the changes rolled back.
|
59
66
|
#
|
60
|
-
#
|
61
|
-
# королевству (незыблемость суверенитета):
|
67
|
+
# Let (see the example above) the shire cannot be rebount to another kingdom:
|
62
68
|
#
|
63
69
|
# class Shire
|
64
70
|
# attr_readonly :kingdom_id
|
65
71
|
# end
|
66
72
|
#
|
67
|
-
#
|
73
|
+
# then merging won't be finished.
|
74
|
+
#
|
75
|
+
# Not only shires, but also the scots remain living in their Scotland,
|
76
|
+
# not in the United Kingdom!
|
68
77
|
#
|
69
|
-
class Service
|
78
|
+
class Service < ActivePatterns::BaseService
|
70
79
|
include ActiveModel::Validations
|
71
80
|
|
72
|
-
def initialize(list =
|
73
|
-
list =
|
81
|
+
def initialize(list = nil)
|
82
|
+
list = Items.new list
|
74
83
|
@item, @items = list.first, Array(list[1..-1])
|
75
84
|
end
|
76
85
|
|
77
86
|
attr_reader :item, :items, :klass, :klasses
|
78
87
|
validates :items, presence: true
|
79
88
|
|
80
|
-
#
|
81
|
-
#
|
82
|
-
# При этом:
|
83
|
-
# * все ссылки на записи из массива #items перепривязываются к #item
|
84
|
-
# * все записи #items удаляются
|
85
|
-
#
|
86
|
-
# При любой ошибке все сделанные изменения отменяются.
|
87
|
-
#
|
89
|
+
# Merges all the #items to the #item as a whole transaction
|
88
90
|
def provide
|
89
|
-
|
90
|
-
|
91
|
-
|
91
|
+
transaction do
|
92
|
+
items.each do |item|
|
93
|
+
service = SimpleService.new(self.item, item)
|
94
|
+
change(service) { service.provide }
|
95
|
+
end
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
95
99
|
private
|
96
100
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
list = select_by_class_from list
|
104
|
-
rescue
|
105
|
-
[]
|
101
|
+
# Returns only persisted items of the same ActiveRecord model
|
102
|
+
class Items < Array
|
103
|
+
def initialize(items)
|
104
|
+
items = Array(items).map{ |item| Item.new item }.compact
|
105
|
+
items = [] if items.map{ |item| item.class }.uniq.count > 1
|
106
|
+
super items.sort_by{ |item| item.id }
|
106
107
|
end
|
107
108
|
end
|
108
109
|
|
109
|
-
#
|
110
|
-
|
111
|
-
|
112
|
-
item.class.ancestors.include?
|
113
|
-
|
114
|
-
|
115
|
-
|
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 }
|
121
|
-
end
|
122
|
-
|
123
|
-
# Объединяет две записи.
|
124
|
-
# Переносит ошибки в текущий объект.
|
125
|
-
def merge(first, second)
|
126
|
-
service = ActiveMerge::SimpleService.new(first, second)
|
127
|
-
begin
|
128
|
-
service.provide
|
129
|
-
rescue
|
130
|
-
service.errors.each{ |key, val| errors.add key, val } and raise
|
110
|
+
# Initializes a persisted item of an ActiveRecord model
|
111
|
+
class Item
|
112
|
+
def self.new(item)
|
113
|
+
return unless item.class.ancestors.include? ActiveRecord::Base
|
114
|
+
return unless item.persisted?
|
115
|
+
item
|
131
116
|
end
|
132
117
|
end
|
133
118
|
end
|
@@ -1,16 +1,16 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module ActiveMerge
|
3
3
|
|
4
|
-
#
|
5
|
-
#
|
4
|
+
# Service Object responds for merging two ActiveRecord instances as a whole
|
5
|
+
# transaction.
|
6
6
|
#
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# All objects linked to the second instance via "has_many" association
|
8
|
+
# are re-associated to the first one.
|
9
|
+
#
|
10
|
+
# Then the second instance removed.
|
11
|
+
# All errors collected in the #errors method.
|
9
12
|
#
|
10
|
-
|
11
|
-
# <tt>errors</tt>
|
12
|
-
#
|
13
|
-
class SimpleService
|
13
|
+
class SimpleService < ActivePatterns::BaseService
|
14
14
|
include ActiveModel::Validations
|
15
15
|
|
16
16
|
def initialize(first, second)
|
@@ -28,49 +28,46 @@ module ActiveMerge
|
|
28
28
|
validates :second, presence: true
|
29
29
|
|
30
30
|
def provide
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
destroy
|
31
|
+
transaction do
|
32
|
+
Links.new(second).each { |item, key| rebind(item, key) }
|
33
|
+
change(second) { second.destroy! }
|
35
34
|
end
|
36
35
|
end
|
37
36
|
|
38
37
|
private
|
39
38
|
|
40
|
-
#
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
39
|
+
# Initializes a hash, whose keys are instances linked to given one,
|
40
|
+
# and their values are names of methods for linking to another object.
|
41
|
+
class Links
|
42
|
+
class << self
|
43
|
+
|
44
|
+
def new(item)
|
45
|
+
@item = item
|
46
|
+
return hash
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a hash whose keys are "has_many" associations' names
|
50
|
+
# and their values are corresponding foreign keys
|
51
|
+
def refs
|
52
|
+
@item.class.reflect_on_all_associations(:has_many).
|
53
|
+
inject({}){ |hash, item| hash.merge(item.name => item.foreign_key) }
|
54
|
+
end
|
46
55
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
56
|
+
def hash
|
57
|
+
@hash = {}
|
58
|
+
refs.each do |name, foreign_key|
|
59
|
+
@item.send(name).each{ |item| @hash[item] = "#{ foreign_key }=" }
|
60
|
+
end
|
61
|
+
@hash
|
62
|
+
end
|
53
63
|
end
|
54
|
-
return @refs
|
55
64
|
end
|
56
65
|
|
57
|
-
#
|
58
|
-
# Ошибки накапливаются в массиве <tt>errors</tt>
|
66
|
+
# Re-assigns given object to the #first
|
59
67
|
def rebind(item, key)
|
60
|
-
|
68
|
+
change item do
|
61
69
|
item.send key, first.id
|
62
70
|
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
71
|
end
|
75
72
|
end
|
76
73
|
end
|
data/lib/active_merge/version.rb
CHANGED
data/lib/active_merge.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
|
1
|
+
require "active_patterns"
|
2
2
|
|
3
|
-
#
|
3
|
+
# Declares service object for merging ActiveRecord instances.
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# After extending your active record model with the module,
|
6
|
+
# new <tt>::merge_all</tt> method is available.
|
7
7
|
#
|
8
8
|
module ActiveMerge
|
9
9
|
extend ActiveSupport::Autoload
|
@@ -11,18 +11,18 @@ module ActiveMerge
|
|
11
11
|
autoload :SimpleService
|
12
12
|
autoload :Service
|
13
13
|
|
14
|
-
#
|
14
|
+
# Merges instances from the association
|
15
15
|
#
|
16
16
|
# class Lord < ActiveRecord::Base
|
17
17
|
# extend ActiveMerge
|
18
18
|
# end
|
19
19
|
#
|
20
|
-
# Lord.all.merge_all
|
21
|
-
# Lord.where(id > 100) # =>
|
20
|
+
# Lord.all.merge_all # => merges all the class instances
|
21
|
+
# Lord.where("id > :id", id: 100) # => merges instances with id > 100
|
22
22
|
#
|
23
|
-
#
|
23
|
+
# See details in <tt>ActiveMerge::Service#provide</tt> documentation.
|
24
24
|
#
|
25
25
|
def merge_all
|
26
|
-
ActiveMerge::Service.new(
|
26
|
+
ActiveMerge::Service.new(all).provide
|
27
27
|
end
|
28
28
|
end
|
@@ -0,0 +1,205 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
module ActiveMerge
|
5
|
+
describe Service do
|
6
|
+
|
7
|
+
describe "#item" do
|
8
|
+
|
9
|
+
it "объявлен" do
|
10
|
+
Service.new.should respond_to :item
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#items" do
|
15
|
+
|
16
|
+
it "объявлен" do
|
17
|
+
Service.new.should respond_to :items
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "::new" do
|
22
|
+
|
23
|
+
let!(:items) { 3.times.map{ Man.create! }}
|
24
|
+
|
25
|
+
context "если передан запрос ActiveRelations" do
|
26
|
+
|
27
|
+
let!(:service) { Service.new Man.all }
|
28
|
+
|
29
|
+
it "присваивает переменной item первый объект (с минимальным id)" do
|
30
|
+
service.item.should eq Man.first
|
31
|
+
end
|
32
|
+
|
33
|
+
it "присваивает переменной items все объекты, кроме первого (с минимальным id)" do
|
34
|
+
service.items.should eq Man.all.order("id ASC").to_a[1..-1]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "если запрос возвращает только один элемент" do
|
39
|
+
|
40
|
+
let!(:service) { Service.new Man.where(id: Man.first.id) }
|
41
|
+
|
42
|
+
it "присваивает переменной item первый объект (с минимальным id)" do
|
43
|
+
service.item.should eq Man.first
|
44
|
+
end
|
45
|
+
|
46
|
+
it "присваивает переменной items пустой массив" do
|
47
|
+
service.items.should eq []
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context "если запрос возвращает пустой массив" do
|
52
|
+
|
53
|
+
let!(:service) { Service.new Man.where(id: 0) }
|
54
|
+
|
55
|
+
it "присваивает nil переменной item" do
|
56
|
+
service.item.should be_nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "присваивает пустой массив переменной items" do
|
60
|
+
service.items.should eq []
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "если передан массив объектов ActiveRecord вместе с другими, non-Active record элементами" do
|
65
|
+
|
66
|
+
let!(:service) { Service.new (items + [Man.new, nil, 1]).shuffle }
|
67
|
+
|
68
|
+
it "присваивает переменной item первый объект (с минимальным id)" do
|
69
|
+
service.item.should eq Man.first
|
70
|
+
end
|
71
|
+
|
72
|
+
it "присваивает переменной items все сохраненные объекты, кроме первого (с минимальным id)" do
|
73
|
+
service.items.should eq Man.all.order("id ASC").to_a[1..-1]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "если переданный массив содержит только один сохраненный объект ActiveRecord" do
|
78
|
+
|
79
|
+
let!(:service) { Service.new [Man.first, 1, nil, Man.new] }
|
80
|
+
|
81
|
+
it "присваивает переменной item первый объект (с минимальным id)" do
|
82
|
+
service.item.should eq Man.first
|
83
|
+
end
|
84
|
+
|
85
|
+
it "присваивает переменной items пустой массив" do
|
86
|
+
service.items.should eq []
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "если массив не содержит сохраненных объектов ActiveRecord" do
|
91
|
+
|
92
|
+
let!(:service) { Service.new [1, nil, Man.new] }
|
93
|
+
|
94
|
+
it "присваивает nil переменной item" do
|
95
|
+
service.item.should be_nil
|
96
|
+
end
|
97
|
+
|
98
|
+
it "присваивает пустой массив переменной items" do
|
99
|
+
service.items.should eq []
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context "если массив содержит сохраненные объекты ActiveRecord разных классов" do
|
104
|
+
|
105
|
+
let!(:service) { Service.new [Man.first, Domain.create!] }
|
106
|
+
|
107
|
+
it "присваивает nil переменной item" do
|
108
|
+
service.item.should be_nil
|
109
|
+
end
|
110
|
+
|
111
|
+
it "присваивает пустой массив переменной items" do
|
112
|
+
service.items.should eq []
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context "если атрибут не передан" do
|
117
|
+
|
118
|
+
let!(:service) { Service.new }
|
119
|
+
|
120
|
+
it "присваивает nil переменной item" do
|
121
|
+
service.item.should be_nil
|
122
|
+
end
|
123
|
+
|
124
|
+
it "присваивает пустой массив переменной items" do
|
125
|
+
service.items.should eq []
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "#valid?" do
|
131
|
+
|
132
|
+
it "возвращает true если список записей для присоединения установлен" do
|
133
|
+
Service.new(2.times.map{ Lord.create! }).should be_valid
|
134
|
+
end
|
135
|
+
|
136
|
+
it "возвращает false если список записей для присоединения пуст" do
|
137
|
+
service = Service.new [Lord.create!]
|
138
|
+
service.should_not be_valid
|
139
|
+
service.errors.should_not be_blank
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "#provide" do
|
144
|
+
|
145
|
+
let!(:lords) { 2.times.map{ Lord.create! }}
|
146
|
+
let!(:domains) { lords.map{ |lord| lord.domains.create! }}
|
147
|
+
let!(:men) { lords.map{ |lord| lord.men.create! }}
|
148
|
+
let!(:service) { Service.new lords }
|
149
|
+
|
150
|
+
context "если перепривязка разрешена" do
|
151
|
+
|
152
|
+
it "не вызывает исключений" do
|
153
|
+
expect{ service.provide }.not_to raise_error
|
154
|
+
end
|
155
|
+
|
156
|
+
it "объединяет записи" do
|
157
|
+
begin; service.provide; rescue; end
|
158
|
+
Lord.count.should eq 1
|
159
|
+
Lord.first.domains.count.should eq 2
|
160
|
+
Lord.first.men.count.should eq 2
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
context "если перепривязка не может быть выполнена" do
|
165
|
+
|
166
|
+
before do
|
167
|
+
service.items.last.stub(:destroy!).and_raise
|
168
|
+
service.items.last.stub(:errors).and_return({ base: "Удаление запрещено." })
|
169
|
+
end
|
170
|
+
|
171
|
+
it "вызывает исключение" do
|
172
|
+
expect{ service.provide }.to raise_error
|
173
|
+
end
|
174
|
+
|
175
|
+
it "не объединяет записи" do
|
176
|
+
begin; service.provide; rescue; end
|
177
|
+
Lord.count.should eq 2
|
178
|
+
Lord.all.each do |lord|
|
179
|
+
lord.domains.count.should eq 1
|
180
|
+
lord.men.count.should eq 1
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
it "добавляет ошибки в массив" do
|
185
|
+
begin; service.provide; rescue; end
|
186
|
+
service.errors.should_not be_blank
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
context "если атрибут #items пуст" do
|
191
|
+
|
192
|
+
before { service.stub(:items).and_return [] }
|
193
|
+
|
194
|
+
it "вызывает исключение" do
|
195
|
+
expect{ service.provide }.to raise_error
|
196
|
+
end
|
197
|
+
|
198
|
+
it "добавляет ошибки в массив" do
|
199
|
+
begin; service.provide; rescue; end
|
200
|
+
service.errors.should_not be_blank
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|