active_conductor 0.1.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 (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
+