active_conductor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/LICENSE.txt +20 -0
  2. data/README.md +91 -0
  3. data/lib/active_conductor.rb +161 -0
  4. metadata +203 -0
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Scott Taylor
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # ActiveConductor
2
+
3
+ This plugin uses the conductor pattern to wrap multiple models as one object.
4
+ It's basically like the Presenter pattern, but for saving and creating multiple models.
5
+ For more information, please read the blog post
6
+ [Presenters & Conductors on Rails](http://blog.new-bamboo.co.uk/2007/8/31/presenters-conductors-on-rails).
7
+
8
+ ## Installation
9
+
10
+ This plugin is built on top of Rails 3 ActiveModel. For a Rails 2 compatible version, see the
11
+ [Conductor](https://github.com/smtlaissezfaire/conductor) plugin.
12
+
13
+ ### Gem
14
+
15
+ Install the gem:
16
+
17
+ gem install active_conductor
18
+
19
+ Add it to your Gemfile:
20
+
21
+ gem "active_conductor"
22
+
23
+ ### Plugin
24
+
25
+ Install as a Rails plugin:
26
+
27
+ rails plugin install git://github.com/netzpirat/active_conductor.git
28
+
29
+ ## Documentation
30
+
31
+ You can browse the API documentation directly on [rdoc.info](http://rdoc.info/github/netzpirat/active_conductor/master/frames).
32
+
33
+ ## Example
34
+
35
+ class SignupConductor < ActiveConductor
36
+ def models
37
+ [user, profile]
38
+ end
39
+
40
+ def user
41
+ @user ||= User.new
42
+ end
43
+
44
+ def profile
45
+ @profile ||= Profile.new
46
+ end
47
+
48
+ conduct :user, :first_name, :last_name
49
+ conduct :profile, :image
50
+ end
51
+
52
+ conductor = SignupConductor.new
53
+ conductor.first_name = "Scott"
54
+ conductor.last_name = "Taylor"
55
+
56
+ conductor.first_name #=> "Scott"
57
+ conductor.user.first_name #=> "Scott"
58
+
59
+ conductor.save
60
+ conductor.valid? #=> false
61
+
62
+ conductor.errors #=> [["photo", "is not valid"]]
63
+
64
+ ## Contributors
65
+
66
+ * Michael Kessler ([netzpirat](https://github.com/netzpirat))
67
+
68
+ ## License
69
+
70
+ (The MIT License)
71
+
72
+ Copyright (c) 2011 Scott Taylor
73
+
74
+ Permission is hereby granted, free of charge, to any person obtaining
75
+ a copy of this software and associated documentation files (the
76
+ 'Software'), to deal in the Software without restriction, including
77
+ without limitation the rights to use, copy, modify, merge, publish,
78
+ distribute, sublicense, and/or sell copies of the Software, and to
79
+ permit persons to whom the Software is furnished to do so, subject to
80
+ the following conditions:
81
+
82
+ The above copyright notice and this permission notice shall be
83
+ included in all copies or substantial portions of the Software.
84
+
85
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
89
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
90
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
91
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,161 @@
1
+ require "active_model"
2
+ require "forwardable"
3
+
4
+ # The ActiveConductor is an implementation of the conductor pattern.
5
+ #
6
+ # The conductor pattern unifies some models into a single object and
7
+ # cleans up controller code massively.
8
+ #
9
+ # @example
10
+ # class SignupConductor < ActiveConductor
11
+ # def models
12
+ # [user, profile]
13
+ # end
14
+ #
15
+ # def user
16
+ # @user ||= User.new
17
+ # end
18
+ #
19
+ # def profile
20
+ # @profile ||= Profile.new
21
+ # end
22
+ #
23
+ # conduct :user, :first_name, :last_name
24
+ # conduct :profile, :image
25
+ # end
26
+ #
27
+ # @author Scott Taylor
28
+ # @author Michael Kessler
29
+ #
30
+ class ActiveConductor
31
+ include ActiveModel::Conversion
32
+ include ActiveModel::Validations
33
+
34
+ extend ActiveModel::Naming
35
+ extend ActiveModel::Translation
36
+ extend Forwardable
37
+
38
+ # Conduct an attribute from the conductor to the associated
39
+ # model.
40
+ #
41
+ # @example Conduct an the email and password attribute to the user model
42
+ # conduct :user, :email, :password
43
+ #
44
+ # @param model [Symbol] the name of the model
45
+ # @param *attributes [Symbol] one or more model attribute name
46
+ #
47
+ def self.conduct(model, *attributes)
48
+ attributes.each do |attr|
49
+ def_delegator model, attr
50
+ def_delegator model, "#{attr}="
51
+ end
52
+ end
53
+
54
+ # Initialize the conductor with optional attributes.
55
+ #
56
+ # @param attributes [Hash] the attributes hash
57
+ # @return [ActiveConductor] the created conductor
58
+ #
59
+ def initialize(attributes={})
60
+ self.attributes = attributes
61
+ end
62
+
63
+ # Set the attributes on the associated models.
64
+ #
65
+ # @param attributes [Hash] the attributes hash
66
+ #
67
+ def attributes=(attributes)
68
+ attributes.each do |key, value|
69
+ self.send("#{key}=", value)
70
+ end if attributes
71
+ end
72
+
73
+ # Tests if all of the records have been persisted.
74
+ #
75
+ # @return [true, false] the persistence status
76
+ #
77
+ def new_record?
78
+ models.all? { |m| m.new_record? }
79
+ end
80
+
81
+ # Tests if the associated models have errors. The errors
82
+ # can be accessed afterwards through {#errors}.
83
+ #
84
+ # @return [true, false] the error status
85
+ #
86
+ def valid?
87
+ models.inject(true) do |result, model|
88
+ valid = model.valid?
89
+
90
+ model.errors.each do |field, value|
91
+ errors.add(field, value)
92
+ end
93
+
94
+ result && valid
95
+ end
96
+ end
97
+
98
+ # Returns the errors of the conductor. The errors
99
+ # are populated after a call to {#save}, {#valid?} or {.create}.
100
+ #
101
+ # @return [Hash] the error hash
102
+ #
103
+ def errors
104
+ @errors ||= ActiveModel::Errors.new(self)
105
+ end
106
+
107
+ # The models that the conductor holds.
108
+ #
109
+ # @return [Array] the array with the conducted models
110
+ #
111
+ def models
112
+ []
113
+ end
114
+
115
+ # Saves the associated models.
116
+ #
117
+ # @return [true, false] the saved status
118
+ #
119
+ def save
120
+ models.each { |model| return false unless model.save } if valid?
121
+ end
122
+
123
+ # Create and persist a new conductor in one step.
124
+ #
125
+ # @example Create and yield a conductor
126
+ # registration = Registration.create(params[:registration]) do |conductor\
127
+ # conductor.user.is_admin = true
128
+ # end
129
+ #
130
+ # @param attributes [Hash] the attributes hash to initialize the conductor
131
+ # @param block [Proc] An optional proc that yields to the created conductor
132
+ # @return [ActiveConductor] the created conductor
133
+ #
134
+ def self.create(attributes, &block)
135
+ object = new(attributes)
136
+ yield(object) if block_given?
137
+ object.save
138
+ object
139
+ end
140
+
141
+ # ActiveModel compatibility method that always
142
+ # return false since a conductor cannot be
143
+ # destroyed (See {#persisted?}).
144
+ #
145
+ # @return [false] always false
146
+ #
147
+ def destroyed?
148
+ false
149
+ end
150
+
151
+ # ActiveModel compatibility method that always
152
+ # return false since a conductor will never be
153
+ # persisted.
154
+ #
155
+ # @return [false] always false
156
+ #
157
+ def persisted?
158
+ false
159
+ end
160
+
161
+ end
metadata ADDED
@@ -0,0 +1,203 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_conductor
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Scott Taylor
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-03-07 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: activemodel
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 3
30
+ - 0
31
+ - 0
32
+ version: 3.0.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bundler
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 1
45
+ - 0
46
+ - 10
47
+ version: 1.0.10
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: guard
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ~>
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 0
60
+ - 3
61
+ - 0
62
+ version: 0.3.0
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: guard-rspec
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 0
75
+ - 2
76
+ - 0
77
+ version: 0.2.0
78
+ type: :development
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: rspec
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 2
90
+ - 5
91
+ - 0
92
+ version: 2.5.0
93
+ type: :development
94
+ version_requirements: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ name: activerecord
97
+ prerelease: false
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ segments:
104
+ - 3
105
+ - 0
106
+ - 0
107
+ version: 3.0.0
108
+ type: :development
109
+ version_requirements: *id006
110
+ - !ruby/object:Gem::Dependency
111
+ name: sqlite3-ruby
112
+ prerelease: false
113
+ requirement: &id007 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ~>
117
+ - !ruby/object:Gem::Version
118
+ segments:
119
+ - 1
120
+ - 3
121
+ - 3
122
+ version: 1.3.3
123
+ type: :development
124
+ version_requirements: *id007
125
+ - !ruby/object:Gem::Dependency
126
+ name: yard
127
+ prerelease: false
128
+ requirement: &id008 !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ segments:
134
+ - 0
135
+ - 6
136
+ - 4
137
+ version: 0.6.4
138
+ type: :development
139
+ version_requirements: *id008
140
+ - !ruby/object:Gem::Dependency
141
+ name: bluecloth
142
+ prerelease: false
143
+ requirement: &id009 !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ~>
147
+ - !ruby/object:Gem::Version
148
+ segments:
149
+ - 2
150
+ - 0
151
+ - 11
152
+ version: 2.0.11
153
+ type: :development
154
+ version_requirements: *id009
155
+ description: This plugin uses the conductor pattern to wrap multiple models as one object
156
+ email:
157
+ - scott@railsnewbie.com
158
+ executables: []
159
+
160
+ extensions: []
161
+
162
+ extra_rdoc_files: []
163
+
164
+ files:
165
+ - lib/active_conductor.rb
166
+ - LICENSE.txt
167
+ - README.md
168
+ has_rdoc: true
169
+ homepage: https://github.com/smtlaissezfaire/active_conductor
170
+ licenses: []
171
+
172
+ post_install_message:
173
+ rdoc_options: []
174
+
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ none: false
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ segments:
183
+ - 0
184
+ version: "0"
185
+ required_rubygems_version: !ruby/object:Gem::Requirement
186
+ none: false
187
+ requirements:
188
+ - - ">="
189
+ - !ruby/object:Gem::Version
190
+ segments:
191
+ - 1
192
+ - 3
193
+ - 6
194
+ version: 1.3.6
195
+ requirements: []
196
+
197
+ rubyforge_project: active_conductor
198
+ rubygems_version: 1.3.7
199
+ signing_key:
200
+ specification_version: 3
201
+ summary: Conductor plugin for Rails 3
202
+ test_files: []
203
+