active_presenter 0.0.3 → 0.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.
data/README CHANGED
@@ -25,9 +25,9 @@ Or get the source from github:
25
25
  Creating a presenter is as simple as subclassing ActivePresenter::Base. Use the presents method to indicate which models the presenter should present.
26
26
 
27
27
  class SignupPresenter < ActivePresenter::Base
28
- presents User, Account
28
+ presents :user, :account
29
29
  end
30
-
30
+
31
31
  === Instantiation
32
32
 
33
33
  Then, you can instantiate the presenter using either, or both of two forms.
@@ -66,6 +66,12 @@ Both of these methods are compatible with error_messages_for. It just depends wh
66
66
 
67
67
  You can save your presenter the same way you'd save an ActiveRecord object. Both #save, and #save! behave the same way they do on a normal AR model.
68
68
 
69
+ === Callbacks
70
+
71
+ Callbacks work exactly like ActiveRecord callbacks. before_save, and after_save are available.
72
+
73
+ Note that if any of your after_save callbacks return false, the rest of them will not be run. This is consistent with AR behavior.
74
+
69
75
  == Credits
70
76
 
71
77
  ActivePresenter was created, and is maintained by {Daniel Haran}[http://danielharan.com] and {James Golick}[http://jamesgolick.com] on the train ride to {RubyFringe}[http://rubyfringe.com] from Montreal.
@@ -2,6 +2,9 @@ module ActivePresenter
2
2
  # Base class for presenters. See README for usage.
3
3
  #
4
4
  class Base
5
+ include ActiveSupport::Callbacks
6
+ define_callbacks :before_save, :after_save
7
+
5
8
  class_inheritable_accessor :presented
6
9
  self.presented = {}
7
10
 
@@ -9,7 +12,7 @@ module ActivePresenter
9
12
  # i.e.
10
13
  #
11
14
  # class SignupPresenter < ActivePresenter::Base
12
- # presents User, Account
15
+ # presents :user, :account
13
16
  # end
14
17
  #
15
18
  #
@@ -21,7 +24,7 @@ module ActivePresenter
21
24
  send(t).errors
22
25
  end
23
26
 
24
- presented[t] = t.to_s.classify.constantize
27
+ presented[t] = t.to_s.tableize.classify.constantize
25
28
  end
26
29
  end
27
30
 
@@ -101,12 +104,14 @@ module ActivePresenter
101
104
  saved = false
102
105
 
103
106
  ActiveRecord::Base.transaction do
104
- if valid?
107
+ if valid? && run_callbacks_with_halt(:before_save)
105
108
  saved = presented_instances.map { |i| i.save(false) }.all?
106
109
  raise ActiveRecord::Rollback unless saved # TODO: Does this happen implicitly?
107
110
  end
108
111
  end
109
112
 
113
+ run_callbacks_with_halt(:after_save) if saved
114
+
110
115
  saved
111
116
  end
112
117
 
@@ -115,10 +120,14 @@ module ActivePresenter
115
120
  # Returns true on success, will raise otherwise.
116
121
  #
117
122
  def save!
123
+ raise ActiveRecord::RecordNotSaved unless run_callbacks_with_halt(:before_save)
124
+
118
125
  ActiveRecord::Base.transaction do
119
126
  valid? # collect errors before potential exception raise
120
127
  presented_instances.each { |i| i.save! }
121
128
  end
129
+
130
+ run_callbacks_with_halt(:after_save)
122
131
  end
123
132
 
124
133
  # Update attributes, and save the presentables
@@ -141,7 +150,7 @@ module ActivePresenter
141
150
  end
142
151
 
143
152
  def presentable_for(method_name)
144
- presented.keys.detect do |type|
153
+ presented.keys.sort_by { |k| k.to_s.size }.reverse.detect do |type|
145
154
  method_name.to_s.starts_with?(attribute_prefix(type))
146
155
  end
147
156
  end
@@ -167,8 +176,13 @@ module ActivePresenter
167
176
 
168
177
  def attribute_protected?(name)
169
178
  presentable = presentable_for(name)
179
+ return false unless presentable
170
180
  flat_attribute = {flatten_attribute_name(name, presentable) => ''} #remove_att... normally takes a hash, so we use a ''
171
- presentable.to_s.classify.constantize.new.send(:remove_attributes_protected_from_mass_assignment, flat_attribute).empty?
181
+ presentable.to_s.tableize.classify.constantize.new.send(:remove_attributes_protected_from_mass_assignment, flat_attribute).empty?
182
+ end
183
+
184
+ def run_callbacks_with_halt(callback)
185
+ run_callbacks(callback) { |result, object| result == false }
172
186
  end
173
187
  end
174
188
  end
@@ -2,7 +2,7 @@ module ActivePresenter
2
2
  module VERSION
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 3
5
+ TINY = 5
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/test/base_test.rb CHANGED
@@ -4,76 +4,76 @@ Expectations do
4
4
  expect :user => User, :account => Account do
5
5
  SignupPresenter.presented
6
6
  end
7
-
7
+
8
8
  expect User.create!(hash_for_user) do |u|
9
9
  SignupPresenter.new(:user => u.expected).user
10
10
  end
11
-
11
+
12
12
  expect User do
13
13
  SignupPresenter.new.user
14
14
  end
15
-
15
+
16
16
  expect User.any_instance.to.receive(:login=).with('james') do
17
17
  SignupPresenter.new(:user_login => 'james')
18
18
  end
19
-
19
+
20
20
  # admin= should be protected from mass assignment
21
21
  expect SignupPresenter.new.to.be.attribute_protected?(:user_admin)
22
22
  expect SignupPresenter.new(:user_admin => true).user.not.to.be.admin?
23
-
23
+
24
24
  expect 'mymockvalue' do
25
25
  User.any_instance.stubs(:login).returns('mymockvalue')
26
26
  SignupPresenter.new.user_login
27
27
  end
28
-
28
+
29
29
  expect User.any_instance.to.receive(:login=).with('mymockvalue') do
30
30
  SignupPresenter.new.user_login = 'mymockvalue'
31
31
  end
32
-
32
+
33
33
  expect SignupPresenter.new.not.to.be.valid?
34
34
  expect SignupPresenter.new(:user => User.new(hash_for_user)).to.be.valid?
35
-
35
+
36
36
  expect ActiveRecord::Errors do
37
37
  s = SignupPresenter.new
38
38
  s.valid?
39
39
  s.errors
40
40
  end
41
-
41
+
42
42
  expect ActiveRecord::Errors do
43
43
  s = SignupPresenter.new
44
44
  s.valid?
45
45
  s.user_errors
46
46
  end
47
-
47
+
48
48
  expect ActiveRecord::Errors do
49
49
  s = SignupPresenter.new
50
50
  s.valid?
51
51
  s.account_errors
52
52
  end
53
-
53
+
54
54
  expect String do
55
55
  s = SignupPresenter.new
56
56
  s.valid?
57
57
  s.errors.on(:user_login)
58
58
  end
59
-
59
+
60
60
  expect ActiveRecord::Base.to.receive(:transaction) do
61
61
  s = SignupPresenter.new
62
62
  s.save
63
63
  end
64
-
64
+
65
65
  expect User.any_instance.to.receive(:save) do
66
66
  s = SignupPresenter.new :user => User.new(hash_for_user)
67
67
  s.save
68
68
  end
69
-
69
+
70
70
  expect Account.any_instance.to.receive(:save) do
71
71
  s = SignupPresenter.new :user => User.new(hash_for_user)
72
72
  s.save
73
73
  end
74
-
74
+
75
75
  expect SignupPresenter.new.not.to.be.save
76
-
76
+
77
77
  expect ActiveRecord::Rollback do
78
78
  ActiveRecord::Base.stubs(:transaction).yields
79
79
  User.any_instance.stubs(:save).returns(false)
@@ -81,72 +81,100 @@ Expectations do
81
81
  s = SignupPresenter.new :user => User.new(hash_for_user)
82
82
  s.save
83
83
  end
84
-
84
+
85
85
  expect ActiveRecord::Base.to.receive(:transaction) do
86
86
  s = SignupPresenter.new
87
87
  s.save!
88
88
  end
89
-
89
+
90
90
  expect User.any_instance.to.receive(:save!) do
91
91
  s = SignupPresenter.new
92
92
  s.save!
93
93
  end
94
-
94
+
95
95
  expect Account.any_instance.to.receive(:save!) do
96
96
  User.any_instance.stubs(:save!)
97
97
  s = SignupPresenter.new
98
98
  s.save!
99
99
  end
100
-
100
+
101
101
  expect ActiveRecord::RecordInvalid do
102
102
  SignupPresenter.new.save!
103
103
  end
104
-
104
+
105
105
  expect SignupPresenter.new(:user => User.new(hash_for_user)).to.be.save!
106
-
106
+
107
107
  expect SignupPresenter.new.to.be.respond_to?(:user_login)
108
108
  expect SignupPresenter.new.to.be.respond_to?(:user_password_confirmation)
109
109
  expect SignupPresenter.new.to.be.respond_to?(:valid?) # just making sure i didn't break everything :)
110
-
110
+
111
111
  expect User.create!(hash_for_user).not.to.be.login_changed? do |user|
112
112
  s = SignupPresenter.new(:user => user)
113
113
  s.update_attributes :user_login => 'Something Totally Different'
114
114
  end
115
-
115
+
116
116
  expect SignupPresenter.new(:user => User.create!(hash_for_user)).to.receive(:save) do |s|
117
117
  s.update_attributes :user_login => 'Something'
118
118
  end
119
-
119
+
120
120
  expect 'Something Different' do
121
121
  s = SignupPresenter.new
122
122
  s.update_attributes :user_login => 'Something Different'
123
123
  s.user_login
124
124
  end
125
-
125
+
126
126
  # this is a regression test to make sure that _title is working. we had a weird conflict with using String#delete
127
127
  expect 'something' do
128
128
  s = SignupPresenter.new :account_title => 'something'
129
129
  s.account_title
130
130
  end
131
-
131
+
132
132
  expect String do
133
133
  s = SignupPresenter.new
134
134
  s.save
135
135
  s.errors.on(:user_login)
136
136
  end
137
-
137
+
138
138
  expect String do
139
139
  s = SignupPresenter.new
140
140
  s.save! rescue
141
141
  s.errors.on(:user_login)
142
142
  end
143
-
143
+
144
144
  expect 'Login' do
145
145
  SignupPresenter.human_attribute_name(:user_login)
146
146
  end
147
-
147
+
148
148
  # it was raising with nil
149
149
  expect SignupPresenter do
150
150
  SignupPresenter.new(nil)
151
151
  end
152
+
153
+ expect EndingWithSPresenter.new.address.not.to.be.nil?
154
+
155
+ # this should act as ActiveRecord models do
156
+ expect NoMethodError do
157
+ SignupPresenter.new({:i_dont_exist=>"blah"})
158
+ end
159
+
160
+ expect CantSavePresenter.new.not.to.be.save # it won't save because the filter chain will halt
161
+
162
+ expect ActiveRecord::RecordNotSaved do
163
+ CantSavePresenter.new.save!
164
+ end
165
+
166
+ expect 'Some Street' do
167
+ p = AfterSavePresenter.new
168
+ p.save
169
+ p.address.street
170
+ end
171
+
172
+ expect 'Some Street' do
173
+ p = AfterSavePresenter.new
174
+ p.save!
175
+ p.address.street
176
+ end
177
+
178
+ expect SamePrefixPresenter.new.to.be.respond_to?(:account_title)
179
+ expect SamePrefixPresenter.new.to.be.respond_to?(:account_info_info)
152
180
  end
data/test/test_helper.rb CHANGED
@@ -19,6 +19,14 @@ ActiveRecord::Schema.define(:version => 0) do
19
19
  t.string :subdomain, :default => ''
20
20
  t.string :title, :default => ''
21
21
  end
22
+
23
+ create_table :addresses do |t|
24
+ t.string :street
25
+ end
26
+
27
+ create_table :account_infos do |t|
28
+ t.string :info
29
+ end
22
30
  end
23
31
 
24
32
  class User < ActiveRecord::Base
@@ -27,11 +35,39 @@ class User < ActiveRecord::Base
27
35
  attr_accessor :password_confirmation
28
36
  end
29
37
  class Account < ActiveRecord::Base; end
38
+ class Address < ActiveRecord::Base; end
39
+ class AccountInfo < ActiveRecord::Base; end
30
40
 
31
41
  class SignupPresenter < ActivePresenter::Base
32
42
  presents :account, :user
33
43
  end
34
44
 
45
+ class EndingWithSPresenter < ActivePresenter::Base
46
+ presents :address
47
+ end
48
+
49
+ class CantSavePresenter < ActivePresenter::Base
50
+ presents :address
51
+
52
+ before_save :halt
53
+
54
+ def halt; false; end
55
+ end
56
+
57
+ class AfterSavePresenter < ActivePresenter::Base
58
+ presents :address
59
+
60
+ after_save :set_street
61
+
62
+ def set_street
63
+ address.street = 'Some Street'
64
+ end
65
+ end
66
+
67
+ class SamePrefixPresenter < ActivePresenter::Base
68
+ presents :account, :account_info
69
+ end
70
+
35
71
  def hash_for_user(opts = {})
36
72
  {:login => 'jane', :password => 'seekrit' }.merge(opts)
37
73
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_presenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Golick & Daniel Haran
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-06 00:00:00 -04:00
12
+ date: 2008-11-21 00:00:00 -05:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -56,7 +56,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
56
56
  requirements: []
57
57
 
58
58
  rubyforge_project: active_presenter
59
- rubygems_version: 1.2.0
59
+ rubygems_version: 1.3.1
60
60
  signing_key:
61
61
  specification_version: 2
62
62
  summary: ActivePresenter is the presenter library you already know! (...if you know ActiveRecord)