datamappify 0.30.0 → 0.40.0

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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/ERD.png +0 -0
  4. data/README.md +78 -16
  5. data/datamappify.gemspec +4 -3
  6. data/lib/datamappify/data/criteria/active_record/destroy.rb +1 -1
  7. data/lib/datamappify/data/criteria/active_record/exists.rb +2 -2
  8. data/lib/datamappify/data/criteria/active_record/transaction.rb +1 -1
  9. data/lib/datamappify/data/criteria/common.rb +21 -1
  10. data/lib/datamappify/data/criteria/relational/count.rb +1 -1
  11. data/lib/datamappify/data/criteria/relational/find.rb +1 -1
  12. data/lib/datamappify/data/criteria/relational/save.rb +1 -1
  13. data/lib/datamappify/data/criteria/sequel/destroy.rb +1 -1
  14. data/lib/datamappify/data/criteria/sequel/exists.rb +1 -1
  15. data/lib/datamappify/data/criteria/sequel/transaction.rb +1 -1
  16. data/lib/datamappify/data/mapper/attribute.rb +9 -0
  17. data/lib/datamappify/data/mapper.rb +7 -2
  18. data/lib/datamappify/data/provider/common_provider.rb +1 -1
  19. data/lib/datamappify/entity/lazy_checking.rb +12 -0
  20. data/lib/datamappify/entity.rb +4 -0
  21. data/lib/datamappify/lazy/attributes_handler.rb +123 -0
  22. data/lib/datamappify/lazy/source_attributes_walker.rb +49 -0
  23. data/lib/datamappify/lazy.rb +24 -0
  24. data/lib/datamappify/logger.rb +13 -0
  25. data/lib/datamappify/repository/lazy_checking.rb +19 -0
  26. data/lib/datamappify/repository/mapping_dsl.rb +7 -1
  27. data/lib/datamappify/repository/query_method/callbacks.rb +83 -0
  28. data/lib/datamappify/repository/query_method/count.rb +6 -1
  29. data/lib/datamappify/repository/query_method/create.rb +10 -0
  30. data/lib/datamappify/repository/query_method/destroy.rb +6 -14
  31. data/lib/datamappify/repository/query_method/exists.rb +17 -0
  32. data/lib/datamappify/repository/query_method/find.rb +12 -19
  33. data/lib/datamappify/repository/query_method/method/source_attributes_walker.rb +81 -0
  34. data/lib/datamappify/repository/query_method/method.rb +74 -25
  35. data/lib/datamappify/repository/query_method/save.rb +15 -14
  36. data/lib/datamappify/repository/query_method/update.rb +10 -0
  37. data/lib/datamappify/repository/query_methods.rb +123 -0
  38. data/lib/datamappify/repository/unit_of_work/persistent_states/object.rb +122 -0
  39. data/lib/datamappify/repository/unit_of_work/persistent_states.rb +54 -0
  40. data/lib/datamappify/repository/unit_of_work/transaction.rb +18 -0
  41. data/lib/datamappify/repository/unit_of_work.rb +1 -0
  42. data/lib/datamappify/repository.rb +16 -51
  43. data/lib/datamappify/version.rb +1 -1
  44. data/lib/datamappify.rb +3 -1
  45. data/spec/lazy_spec.rb +73 -0
  46. data/spec/repository/callbacks_spec.rb +140 -0
  47. data/spec/repository/dirty_persistence_spec.rb +44 -0
  48. data/spec/repository/dirty_tracking_spec.rb +82 -0
  49. data/spec/repository/persistence_spec.rb +41 -119
  50. data/spec/repository/transactions_spec.rb +25 -0
  51. data/spec/repository/validation_spec.rb +42 -0
  52. data/spec/repository_spec.rb +8 -6
  53. data/spec/spec_helper.rb +2 -2
  54. data/spec/support/entities/hero_user.rb +5 -0
  55. data/spec/support/repositories/callbacks_chaining_repository.rb +92 -0
  56. data/spec/support/repositories/hero_user_repository.rb +30 -0
  57. data/spec/support/shared/contexts.rb +10 -0
  58. data/spec/support/tables/sequel.rb +1 -0
  59. data/spec/unit/repository/query_method_spec.rb +55 -0
  60. metadata +57 -10
  61. data/lib/datamappify/repository/query_method/transaction.rb +0 -18
  62. data/lib/datamappify/repository/query_method.rb +0 -3
@@ -1,158 +1,80 @@
1
- require_relative '../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  shared_examples_for "repository persistence" do |data_provider|
4
- let!(:user_repository) { "UserRepository#{data_provider}".constantize }
5
- let(:existing_user) { user_repository.save(User.new(:first_name => 'Fred', :driver_license => 'FREDWU42')) }
6
- let(:new_valid_user) { User.new(:first_name => 'Batman', :driver_license => 'ARKHAMCITY') }
7
- let(:new_valid_user2) { User.new(:first_name => 'Ironman', :driver_license => 'NEWYORKCITY') }
8
- let(:new_invalid_user) { User.new(:first_name => 'a') }
9
- let(:new_invalid_user2) { User.new(:first_name => 'b') }
10
- let(:data_passports) { "Datamappify::Data::Record::#{data_provider}::UserPassport".constantize }
11
- let(:data_driver_licenses) { "Datamappify::Data::Record::#{data_provider}::UserDriverLicense".constantize }
12
-
13
- describe "#find" do
14
- describe "resource" do
4
+ include_context "user repository", data_provider
5
+
6
+ context "#{data_provider}" do
7
+ describe "#find" do
15
8
  it "found" do
16
9
  user_repository.find(existing_user.id).should == existing_user
17
- user_repository.find([existing_user.id]).should == [existing_user]
18
10
  end
19
11
 
20
12
  it "not found" do
21
- user_repository.find(42).should == nil
13
+ user_repository.find(233).should == nil
22
14
  end
23
15
  end
24
16
 
25
- describe "collection" do
26
- it "found" do
27
- user_repository.find([existing_user.id]).should == [existing_user]
28
- end
17
+ [:create, :create!, :update, :update!, :save, :save!].each do |query_method|
18
+ let(:query_method) { query_method }
29
19
 
30
- it "partial found" do
31
- user_repository.find([existing_user.id, 42]).should == [existing_user]
32
- end
20
+ describe "##{query_method}" do
21
+ it "success" do
22
+ new_user = nil
33
23
 
34
- it "not found" do
35
- user_repository.find([42, 255]).should == []
36
- end
37
- end
38
- end
39
-
40
- describe "#save" do
41
- it "success" do
42
- new_user = nil
24
+ expect { new_user = user_repository.send(query_method, new_valid_user) }.to change { user_repository.count }.by(1)
43
25
 
44
- expect { new_user = user_repository.save(new_valid_user) }.to change { user_repository.count }.by(1)
45
-
46
- new_user.should be_kind_of(User)
47
- new_user.first_name.should == 'Batman'
48
- new_user.driver_license.should == 'ARKHAMCITY'
49
- end
50
-
51
- it "failure" do
52
- -> { user_repository.save!(new_invalid_user) }.should raise_error(Datamappify::Data::EntityNotSaved)
53
- end
54
-
55
- it "transaction" do
56
- new_valid_user.passport = 'DEVOPS'
57
-
58
- save_action = Proc.new { -> { user_repository.save(new_valid_user) }.should raise_error }
59
-
60
- expect { save_action.call }.to change { user_repository.count }.by(0)
61
- expect { save_action.call }.to change { data_passports.count }.by(0)
62
- expect { save_action.call }.to change { data_driver_licenses.count }.by(0)
63
- end
64
-
65
- describe "update multiple entities" do
66
- describe "#save" do
67
- it "all successes" do
68
- expect { user_repository.save([new_valid_user, new_valid_user2]) }.to change { user_repository.count }.by(2)
26
+ new_user.should be_kind_of(User)
27
+ new_user.first_name.should == 'Batman'
28
+ new_user.driver_license.should == 'ARKHAMCITY'
69
29
  end
70
30
 
71
- it "successes + failures" do
72
- expect { user_repository.save([new_valid_user, new_invalid_user]) }.to change { user_repository.count }.by(1)
31
+ it "failure" do
32
+ -> { user_repository.save!(new_invalid_user) }.should raise_error(Datamappify::Data::EntityNotSaved)
73
33
  end
74
34
 
75
- it "all failures" do
76
- expect { user_repository.save([new_invalid_user, new_invalid_user2]) }.to change { user_repository.count }.by(0)
77
- end
78
- end
35
+ it "updates existing records" do
36
+ existing_user.first_name = 'Vivian'
37
+ existing_user.driver_license = 'LOCOMOTE'
79
38
 
80
- describe "#save!" do
81
- it "all successes" do
82
- expect { user_repository.save!([new_valid_user, new_valid_user2]) }.to change { user_repository.count }.by(2)
83
- end
39
+ updated_user = nil
84
40
 
85
- it "successes + failures" do
86
- expect { -> { user_repository.save!([new_valid_user, new_invalid_user]) }.should raise_error(Datamappify::Data::EntityNotSaved) }.to change { user_repository.count }.by(1)
87
- end
88
-
89
- it "all failures" do
90
- expect { -> { user_repository.save!([new_invalid_user, new_invalid_user2]) }.should raise_error(Datamappify::Data::EntityNotSaved) }.to change { user_repository.count }.by(0)
91
- end
92
- end
93
- end
41
+ expect { updated_user = user_repository.send(query_method, existing_user) }.to change { user_repository.count }.by(0)
94
42
 
95
- describe "update an existing entity" do
96
- it "updates existing records" do
97
- existing_user.first_name = 'Vivian'
98
- existing_user.driver_license = 'LOCOMOTE'
43
+ updated_user.first_name.should == 'Vivian'
44
+ updated_user.driver_license.should == 'LOCOMOTE'
99
45
 
100
- updated_user = nil
46
+ persisted_user = user_repository.find(updated_user.id)
101
47
 
102
- expect { updated_user = user_repository.save(existing_user) }.to change { user_repository.count }.by(0)
103
-
104
- updated_user.first_name.should == 'Vivian'
105
- updated_user.driver_license.should == 'LOCOMOTE'
106
-
107
- persisted_user = user_repository.find(updated_user.id)
108
-
109
- persisted_user.first_name.should == 'Vivian'
110
- persisted_user.driver_license.should == 'LOCOMOTE'
111
- end
48
+ persisted_user.first_name.should == 'Vivian'
49
+ persisted_user.driver_license.should == 'LOCOMOTE'
50
+ end
112
51
 
113
- it "updates existing and new records" do
114
- existing_user.first_name = 'Vivian'
115
- existing_user.health_care = 'BATMANCAVE'
52
+ it "updates existing and new records" do
53
+ existing_user.first_name = 'Vivian'
54
+ existing_user.health_care = 'BATMANCAVE'
116
55
 
117
- updated_user = nil
56
+ updated_user = nil
118
57
 
119
- expect { updated_user = user_repository.save(existing_user) }.to change { user_repository.count }.by(0)
58
+ expect { updated_user = user_repository.send(query_method, existing_user) }.to change { user_repository.count }.by(0)
120
59
 
121
- updated_user.first_name.should == 'Vivian'
122
- updated_user.health_care.should == 'BATMANCAVE'
60
+ updated_user.first_name.should == 'Vivian'
61
+ updated_user.health_care.should == 'BATMANCAVE'
123
62
 
124
- persisted_user = user_repository.find(updated_user.id)
63
+ persisted_user = user_repository.find(updated_user.id)
125
64
 
126
- persisted_user.first_name.should == 'Vivian'
127
- persisted_user.health_care.should == 'BATMANCAVE'
65
+ persisted_user.first_name.should == 'Vivian'
66
+ persisted_user.health_care.should == 'BATMANCAVE'
67
+ end
128
68
  end
129
69
  end
130
- end
131
70
 
132
- describe "#destroy" do
133
- describe "resource" do
71
+ describe "#destroy" do
134
72
  let!(:user) { user_repository.save(new_valid_user) }
135
73
 
136
- it "via id" do
137
- expect { user_repository.destroy!(user.id) }.to change { user_repository.count }.by(-1)
138
- end
139
-
140
- it "via entity" do
74
+ it "destroys an entity" do
141
75
  expect { user_repository.destroy!(user) }.to change { user_repository.count }.by(-1)
142
76
  end
143
77
  end
144
-
145
- describe "collection" do
146
- let!(:users) { user_repository.save([new_valid_user, new_valid_user2]) }
147
-
148
- it "via id" do
149
- expect { user_repository.destroy!(users.map(&:id)) }.to change { user_repository.count }.by(-2)
150
- end
151
-
152
- it "via entity" do
153
- expect { user_repository.destroy!(users) }.to change { user_repository.count }.by(-2)
154
- end
155
- end
156
78
  end
157
79
  end
158
80
 
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "transactions" do |data_provider|
4
+ include_context "user repository", data_provider
5
+
6
+ context "#{data_provider}" do
7
+ describe "#save" do
8
+ it "raises error upon transaction failure" do
9
+ new_valid_user.passport = 'DEVOPS'
10
+
11
+ save_action = Proc.new { -> { user_repository.save(new_valid_user) }.should raise_error }
12
+
13
+ expect { save_action.call }.to change { user_repository.count }.by(0)
14
+ expect { save_action.call }.to change { data_passports.count }.by(0)
15
+ expect { save_action.call }.to change { data_driver_licenses.count }.by(0)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ describe Datamappify::Repository do
22
+ DATA_PROVIDERS.each do |data_provider|
23
+ it_behaves_like "transactions", data_provider
24
+ end
25
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ shared_examples_for "repository (in)validation" do |data_provider|
4
+ include_context "user repository", data_provider
5
+
6
+ context "#{data_provider}" do
7
+ describe "invalid" do
8
+ let(:invalid_user) { User.new(:first_name => 'F') }
9
+
10
+ after do
11
+ invalid_user.id.should be_nil
12
+ end
13
+
14
+ it "makes sure the entity is invalid" do
15
+ invalid_user.valid?.should == false
16
+ end
17
+
18
+ it "doesn't persist the entity" do
19
+ user_repository.save(invalid_user).should == false
20
+ end
21
+ end
22
+
23
+ describe "valid" do
24
+ let(:valid_user) { User.new(:first_name => 'Fred', :driver_license => 'MOSDEVOPS') }
25
+
26
+ it "makes sure the entity is invalid" do
27
+ valid_user.valid?.should == true
28
+ end
29
+
30
+ it "does persist the entity" do
31
+ user_repository.save(valid_user).should be_kind_of(User)
32
+ valid_user.id.should be_kind_of(Integer)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ describe Datamappify::Repository do
39
+ DATA_PROVIDERS.each do |data_provider|
40
+ it_behaves_like "repository (in)validation", data_provider
41
+ end
42
+ end
@@ -4,13 +4,15 @@ shared_examples_for "a repository" do |data_provider|
4
4
  let(:namespace) { "Datamappify::Data::Record::#{data_provider}".constantize }
5
5
  let(:user_repository) { "UserRepository#{data_provider}".constantize.instance }
6
6
 
7
- it "defines the data class" do
8
- user_repository.data_mapper.default_source_class
9
- namespace.const_defined?(:User, false).should == true
10
- end
7
+ context "#{data_provider}" do
8
+ it "defines the data class" do
9
+ user_repository.data_mapper.default_source_class
10
+ namespace.const_defined?(:User, false).should == true
11
+ end
11
12
 
12
- it "delegates methods to the instance singleton" do
13
- expect { "UserRepository#{data_provider}".constantize.find(1) }.to_not raise_error
13
+ it "delegates methods to the instance singleton" do
14
+ expect { "UserRepository#{data_provider}".constantize.find(1) }.to_not raise_error
15
+ end
14
16
  end
15
17
  end
16
18
 
data/spec/spec_helper.rb CHANGED
@@ -15,11 +15,11 @@ end
15
15
 
16
16
  require File.expand_path('../../lib/datamappify', __FILE__)
17
17
 
18
- %w{tables entities repositories}.each do |sub_dir|
18
+ %w{tables entities repositories shared}.each do |sub_dir|
19
19
  Dir[File.expand_path("../support/#{sub_dir}/**/*.rb", __FILE__)].each { |f| require f }
20
20
  end
21
21
 
22
- DATA_PROVIDERS = %w{ActiveRecord Sequel}
22
+ DATA_PROVIDERS = ENV['DATA_PROVIDER'] ? [ENV['DATA_PROVIDER']] : %w{ActiveRecord Sequel}
23
23
 
24
24
  RSpec.configure do |config|
25
25
  DatabaseCleaner.strategy = :truncation
@@ -1,9 +1,14 @@
1
1
  class HeroUser
2
2
  include Datamappify::Entity
3
+ include Datamappify::Lazy
3
4
 
4
5
  attribute :first_name, String
5
6
  attribute :last_name, String
6
7
  attribute :nickname, String
8
+ attribute :gender, String
9
+
10
+ validates :first_name, :presence => true,
11
+ :length => { :minimum => 2 }
7
12
 
8
13
  def full_name
9
14
  "#{first_name} #{last_name}"
@@ -0,0 +1,92 @@
1
+ class CallbacksChainingRepository
2
+ include Datamappify::Repository
3
+
4
+ for_entity HeroUser
5
+ default_provider :ActiveRecord
6
+
7
+ map_attribute :first_name, 'ActiveRecord::HeroUser#first_name'
8
+ map_attribute :last_name, 'Sequel::HeroUserLastName#last_name'
9
+ map_attribute :gender, 'Sequel::HeroUserLastName#gender'
10
+
11
+ before_save :before_save_1
12
+ before_save :before_save_2
13
+ before_save :before_save_3
14
+ after_save :after_save_1
15
+ after_save :after_save_2
16
+ after_save :after_save_3
17
+
18
+ private
19
+
20
+ def before_save_1(entity); performed(:before_save_1, entity); true; end
21
+ def before_save_2(entity); performed(:before_save_2, entity); true; end
22
+ def before_save_3(entity); performed(:before_save_3, entity); true; end
23
+ def after_save_1 (entity); performed(:after_save_1, entity); true; end
24
+ def after_save_2 (entity); performed(:after_save_2, entity); true; end
25
+ def after_save_3 (entity); performed(:after_save_3 , entity); true; end
26
+
27
+ def performed(*args)
28
+ true
29
+ end
30
+ end
31
+
32
+ class CallbacksChainingPauseBeforeRepository
33
+ include Datamappify::Repository
34
+
35
+ for_entity HeroUser
36
+ default_provider :ActiveRecord
37
+
38
+ map_attribute :first_name, 'ActiveRecord::HeroUser#first_name'
39
+ map_attribute :last_name, 'Sequel::HeroUserLastName#last_name'
40
+ map_attribute :gender, 'Sequel::HeroUserLastName#gender'
41
+
42
+ before_save :before_save_1
43
+ before_save :before_save_2
44
+ before_save :before_save_3
45
+ after_save :after_save_1
46
+ after_save :after_save_2
47
+ after_save :after_save_3
48
+
49
+ private
50
+
51
+ def before_save_1(entity); performed(:before_save_1, entity); true; end
52
+ def before_save_2(entity); performed(:before_save_2, entity); false; end
53
+ def before_save_3(entity); performed(:before_save_3, entity); true; end
54
+ def after_save_1 (entity); performed(:after_save_1, entity); true; end
55
+ def after_save_2 (entity); performed(:after_save_2, entity); true; end
56
+ def after_save_3 (entity); performed(:after_save_3 , entity); true; end
57
+
58
+ def performed(*args)
59
+ true
60
+ end
61
+ end
62
+
63
+ class CallbacksChainingPauseAfterRepository
64
+ include Datamappify::Repository
65
+
66
+ for_entity HeroUser
67
+ default_provider :ActiveRecord
68
+
69
+ map_attribute :first_name, 'ActiveRecord::HeroUser#first_name'
70
+ map_attribute :last_name, 'Sequel::HeroUserLastName#last_name'
71
+ map_attribute :gender, 'Sequel::HeroUserLastName#gender'
72
+
73
+ before_save :before_save_1
74
+ before_save :before_save_2
75
+ before_save :before_save_3
76
+ after_save :after_save_1
77
+ after_save :after_save_2
78
+ after_save :after_save_3
79
+
80
+ private
81
+
82
+ def before_save_1(entity); performed(:before_save_1, entity); true; end
83
+ def before_save_2(entity); performed(:before_save_2, entity); true; end
84
+ def before_save_3(entity); performed(:before_save_3, entity); true; end
85
+ def after_save_1 (entity); performed(:after_save_1, entity); true; end
86
+ def after_save_2 (entity); performed(:after_save_2, entity); false; end
87
+ def after_save_3 (entity); performed(:after_save_3 , entity); true; end
88
+
89
+ def performed(*args)
90
+ true
91
+ end
92
+ end
@@ -6,4 +6,34 @@ class HeroUserRepository
6
6
 
7
7
  map_attribute :first_name, 'ActiveRecord::HeroUser#first_name'
8
8
  map_attribute :last_name, 'Sequel::HeroUserLastName#last_name'
9
+ map_attribute :gender, 'Sequel::HeroUserLastName#gender'
10
+
11
+ before_create :action_before_create
12
+ before_create :action_before_create_2
13
+ before_create { |entity| performed(:before_create_block, entity); true }
14
+ before_update :action_before_update
15
+ before_save :action_before_save
16
+ before_destroy :action_before_destroy
17
+
18
+ after_create :action_after_create
19
+ after_update :action_after_update
20
+ after_save :action_after_save
21
+ after_destroy :action_after_destroy
22
+
23
+ private
24
+
25
+ def action_before_create (entity); performed(:before_create, entity); true; end
26
+ def action_before_create_2(entity); performed(:before_create_2, entity); true; end
27
+ def action_before_update (entity); performed(:before_update, entity); true; end
28
+ def action_before_save (entity); performed(:before_save, entity); true; end
29
+ def action_before_destroy (entity); performed(:before_destroy, entity); true; end
30
+
31
+ def action_after_create (entity); performed(:after_create, entity); true; end
32
+ def action_after_update (entity); performed(:after_update, entity); true; end
33
+ def action_after_save (entity); performed(:after_save, entity); true; end
34
+ def action_after_destroy (entity); performed(:after_destroy, entity); true; end
35
+
36
+ def performed(*args)
37
+ true
38
+ end
9
39
  end
@@ -0,0 +1,10 @@
1
+ shared_context "user repository" do |data_provider|
2
+ let!(:user_repository) { "UserRepository#{data_provider}".constantize }
3
+ let!(:existing_user) { user_repository.save(User.new(:first_name => 'Fred', :driver_license => 'FREDWU42')) }
4
+ let(:new_valid_user) { User.new(:first_name => 'Batman', :driver_license => 'ARKHAMCITY') }
5
+ let(:new_valid_user2) { User.new(:first_name => 'Ironman', :driver_license => 'NEWYORKCITY') }
6
+ let(:new_invalid_user) { User.new(:first_name => 'a') }
7
+ let(:new_invalid_user2) { User.new(:first_name => 'b') }
8
+ let(:data_passports) { "Datamappify::Data::Record::#{data_provider}::UserPassport".constantize }
9
+ let(:data_driver_licenses) { "Datamappify::Data::Record::#{data_provider}::UserDriverLicense".constantize }
10
+ end
@@ -5,6 +5,7 @@ DB = Sequel.sqlite
5
5
  DB.create_table :hero_user_last_names do
6
6
  primary_key :id
7
7
  String :last_name, :null => false
8
+ String :gender
8
9
  Integer :hero_user_id
9
10
  DateTime :created_at
10
11
  DateTime :updated_at
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ module Datamappify::Repository::QueryMethod
4
+ describe Datamappify::Repository::QueryMethod do
5
+ describe Method do
6
+ subject { Method }
7
+
8
+ it { should_not be_a_reader }
9
+ it { should_not be_a_writer }
10
+ end
11
+
12
+ describe Exists do
13
+ subject { Exists }
14
+
15
+ it { should be_a_reader }
16
+ it { should_not be_a_writer }
17
+ end
18
+
19
+ describe Count do
20
+ subject { Count }
21
+
22
+ it { should be_a_reader }
23
+ it { should_not be_a_writer }
24
+ end
25
+
26
+ describe Destroy do
27
+ subject { Destroy }
28
+
29
+ it { should_not be_a_reader }
30
+ it { should be_a_writer }
31
+ end
32
+
33
+ describe Find do
34
+ subject { Find }
35
+
36
+ it { should be_a_reader }
37
+ it { should_not be_a_writer }
38
+ end
39
+
40
+ describe Save do
41
+ subject { Save }
42
+
43
+ it { should_not be_a_reader }
44
+ it { should be_a_writer }
45
+ end
46
+
47
+ RSpec::Matchers.define :be_a_reader do
48
+ match { |method| method.new({}, {}).reader? == true }
49
+ end
50
+
51
+ RSpec::Matchers.define :be_a_writer do
52
+ match { |method| method.new({}, {}).writer? == true }
53
+ end
54
+ end
55
+ end