dm-is-remixable 0.9.7 → 0.9.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.txt CHANGED
@@ -125,3 +125,46 @@ class Video
125
125
 
126
126
  #... methods, properties, etc ...#
127
127
  end
128
+
129
+
130
+ Further, remixables can namespace methods that should exist in the generated and remixing classes, if these
131
+ modules are present the are attached appropriately to the other classes.
132
+
133
+ module ExampleRemixable
134
+ include DataMapper::Resource
135
+ is :remixable
136
+
137
+ #... your properies ...
138
+
139
+ # Class methods that will be attached to class doing the remixing...
140
+ #
141
+ # These methods would be attached to the User class given:
142
+ # User.remixes n, :images
143
+ #
144
+ module RemixerClassMethods
145
+ end
146
+
147
+ # Instances methods that will be attached to objects of the class doing the remixing...
148
+ #
149
+ # These methods would be attached to User objects given:
150
+ # User.remixes n, :images
151
+ #
152
+ module RemixerInstanceMethods
153
+ end
154
+
155
+ # Class methods that will be attached to genereated remixed class
156
+ #
157
+ # These methods would be attached to the UserImage class given:
158
+ # User.remixes n, :images
159
+ #
160
+ module RemixeeClassMethods
161
+ end
162
+
163
+ # Instances methods that will be attached to objects of the genereated remixed class
164
+ #
165
+ # These methods would be attached to UserImage objects given:
166
+ # User.remixes n, :images
167
+ #
168
+ module RemixeeInstanceMethods
169
+ end
170
+ end
data/Rakefile CHANGED
@@ -10,12 +10,12 @@ AUTHOR = "Cory O'Daniel"
10
10
  EMAIL = "dm-is-remixable [a] coryodaniel [d] com"
11
11
  GEM_NAME = "dm-is-remixable"
12
12
  GEM_VERSION = DataMapper::Is::Remixable::VERSION
13
- GEM_DEPENDENCIES = [["dm-core", GEM_VERSION]]
13
+ GEM_DEPENDENCIES = [['dm-core', "~>#{GEM_VERSION}"]]
14
14
  GEM_CLEAN = ["log", "pkg"]
15
15
  GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.txt LICENSE TODO ] }
16
16
 
17
17
  PROJECT_NAME = "datamapper"
18
- PROJECT_URL = "http://github.com/sam/dm-more/tree/master/dm-remixes"
18
+ PROJECT_URL = "http://github.com/sam/dm-more/tree/master/dm-is-remixable"
19
19
  PROJECT_DESCRIPTION = PROJECT_SUMMARY = "dm-is-remixable allow you to create reusable data functionality"
20
20
 
21
21
  require ROOT.parent + 'tasks/hoe'
data/TODO CHANGED
@@ -14,17 +14,5 @@ TODO
14
14
  - Test nested remixing User remixes Photogenic; Photogenic Remixes comments
15
15
  - Test double+ remixing. User remixes Commentable; enhance Commentable remix Commentable
16
16
 
17
- - Harvest Class methods (including it into Remixed Model gets the instance methods, but not class methods...)
18
-
19
- - Squash protection;
20
- IF ClassA => remix ModuleB, :table_name => "squashme"
21
- AND ClassC => remix ModuleB, :table_name => "squashme" #SQUASHED THAT TABLE
22
-
23
17
  - Remixable.related(*remixed_models)
24
- Taggable.related(Article, JobPostings)
25
-
26
-
27
- CONSIDERATIONS
28
- ==============
29
- - Customizing Assocations (http://datamapper.org/docs/associations.html)
30
- - Adding Conditions to Associations (http://datamapper.org/docs/associations.html)
18
+ Taggable.related(Article, JobPostings)
@@ -55,6 +55,7 @@ module DataMapper
55
55
  extend DataMapper::Is::Remixable::RemixeeClassMethods
56
56
  include DataMapper::Is::Remixable::RemixeeInstanceMethods
57
57
  @is_remixable = true
58
+
58
59
  # support clean suffixes for nested modules
59
60
  default_suffix = Extlib::Inflection.demodulize(self.name).singular.snake_case
60
61
  suffix(options.delete(:suffix) || default_suffix)
@@ -93,7 +94,8 @@ module DataMapper
93
94
  # This is the class that will be created from the Remixable Module
94
95
  # The storage_name can be changed via 'enhance' in the class that is remixing
95
96
  # Default: self.name.downcase + "_" + remixable.suffix.pluralize
96
- # :as <String> Alias to access associated data
97
+ # :as <String> Alters the name that the remixable items will be available through, this WILL NOT
98
+ # create the standard accessor
97
99
  # Default: tableize(:class_name)
98
100
  # :for|:on <String> Class name to join to through Remixable
99
101
  # This will create a M:M relationship THROUGH the remixable, rather than
@@ -114,7 +116,7 @@ module DataMapper
114
116
  #
115
117
  # Tables: users, user_addresses
116
118
  # Classes: User, UserAddress
117
- # User.user_addresses << UserAddress.new
119
+ # User.user_addresses << UserAddress.new => Raise No Method Exception since it was alias with :as
118
120
  # User.addresses << UserAddress.new
119
121
  # --------------------------------------------
120
122
  # --------------------------------------------
@@ -175,6 +177,15 @@ module DataMapper
175
177
  remixable_key = Extlib::Inflection.demodulize(remixable_module.name).snake_case.to_sym
176
178
  populate_remixables_mapping(model, options.merge(:remixable_key => remixable_key))
177
179
 
180
+ # attach RemixerClassMethods and RemixerInstanceMethods to remixer if defined by remixee
181
+ if Object.full_const_defined? "#{remixable_module}::RemixerClassMethods"
182
+ extend Object.full_const_get("#{remixable_module}::RemixerClassMethods")
183
+ end
184
+
185
+ if Object.full_const_defined? "#{remixable_module}::RemixerInstanceMethods"
186
+ include Object.full_const_get("#{remixable_module}::RemixerInstanceMethods")
187
+ end
188
+
178
189
  #Create relationships between Remixer and remixed class
179
190
  if options[:other_model]
180
191
  # M:M Class-To-Class w/ Remixable Module as intermediate table
@@ -185,9 +196,6 @@ module DataMapper
185
196
  # has n and belongs_to (or One-To-Many)
186
197
  remix_one_to_many cardinality, model, options
187
198
  end
188
-
189
- #Add accessor alias
190
- attach_accessor(options) unless options[:as].nil?
191
199
  else
192
200
  DataMapper.logger.warn "#{__FILE__}:#{__LINE__} warning: already remixed constant #{options[:class_name]}"
193
201
  end
@@ -232,7 +240,6 @@ module DataMapper
232
240
  # belongs_to :bot
233
241
  # belongs_to :tag
234
242
  # end
235
-
236
243
  def enhance(remixable,remixable_model=nil, &block)
237
244
  # always use innermost singular snake_cased constant name
238
245
  remixable_name = remixable.to_s.singular.snake_case.to_sym
@@ -253,18 +260,6 @@ module DataMapper
253
260
 
254
261
  private
255
262
 
256
- # - attach_accessor
257
- # ==== Description
258
- # Creates additional alias for r/w accessor
259
- # ==== Parameters
260
- # options <Hash> options hash
261
- def attach_accessor(options)
262
- self.class_eval(<<-EOS, __FILE__, __LINE__ + 1)
263
- alias #{options[:as].to_sym} #{options[:table_name].to_sym}
264
- alias #{options[:as].to_sym}= #{options[:table_name].to_sym}=
265
- EOS
266
- end
267
-
268
263
  # - populate_remixables_mapping
269
264
  # ==== Description
270
265
  # Populates the Hash of remixables with information about the remixable
@@ -290,7 +285,7 @@ module DataMapper
290
285
  # model <Class> remixed model that 'self' is relating to
291
286
  # options <Hash> options hash
292
287
  def remix_one_to_many(cardinality, model, options)
293
- self.has cardinality, options[:table_name].intern
288
+ self.has cardinality, (options[:as] || options[:table_name]).to_sym, :class_name => model.name
294
289
  model.property Extlib::Inflection.foreign_key(self.name).intern, Integer, :nullable => false
295
290
  model.belongs_to Extlib::Inflection.tableize(self.name).intern
296
291
  end
@@ -311,7 +306,7 @@ module DataMapper
311
306
 
312
307
  # Is M:M between two different classes or the same class
313
308
  unless self.name == options[:other_model].name
314
- self.has cardinality, options[:table_name].intern
309
+ self.has cardinality, (options[:as] || options[:table_name]).to_sym, :class_name => model.name
315
310
  options[:other_model].has cardinality, options[:table_name].intern
316
311
 
317
312
  model.belongs_to Extlib::Inflection.tableize(self.name).intern
@@ -319,7 +314,7 @@ module DataMapper
319
314
  else
320
315
  raise Exception, "options[:via] must be specified when Remixing a module between two of the same class" unless options[:via]
321
316
 
322
- self.has cardinality, options[:table_name].intern
317
+ self.has cardinality, (options[:as] || options[:table_name]).to_sym, :class_name => model.name
323
318
  model.belongs_to Extlib::Inflection.tableize(self.name).intern
324
319
  model.belongs_to options[:via].intern, :class_name => options[:other_model].name, :child_key => ["#{options[:via]}_id".intern]
325
320
  end
@@ -350,6 +345,15 @@ module DataMapper
350
345
  model.property(prop.name, prop.type, prop.options)
351
346
  end
352
347
 
348
+ # attach remixed model access to RemixeeClassMethods and RemixeeInstanceMethods if defined
349
+ if Object.full_const_defined? "#{remixable}::RemixeeClassMethods"
350
+ model.send :extend, Object.full_const_get("#{remixable}::RemixeeClassMethods")
351
+ end
352
+
353
+ if Object.full_const_defined? "#{remixable}::RemixeeInstanceMethods"
354
+ model.send :include, Object.full_const_get("#{remixable}::RemixeeInstanceMethods")
355
+ end
356
+
353
357
  model
354
358
  end
355
359
 
@@ -358,7 +362,7 @@ module DataMapper
358
362
  # - RemixeeClassMethods
359
363
  # ==== Description
360
364
  # Methods available to any model that is :remixable
361
- module RemixeeClassMethods
365
+ module RemixeeClassMethods
362
366
  # - suffix
363
367
  # ==== Description
364
368
  # modifies the storage name suffix, which is by default based on the Remixable Module name
@@ -1,7 +1,7 @@
1
1
  module DataMapper
2
2
  module Is
3
3
  module Remixable
4
- VERSION = "0.9.7"
4
+ VERSION = "0.9.8"
5
5
  end
6
6
  end
7
7
  end
@@ -7,4 +7,5 @@ module Commentable
7
7
  property :id, Integer, :key => true, :serial => true
8
8
  property :comment, String
9
9
  property :created_at, DateTime
10
+
10
11
  end
@@ -6,4 +6,40 @@ module Image
6
6
  property :id, Integer, :key => true, :serial => true
7
7
  property :description, String
8
8
  property :path, String
9
+
10
+ # These methods will be available to the class remixing this module
11
+ # If 'User' remixes 'Images', these methods will be available to a User class
12
+ #
13
+ module RemixerClassMethods
14
+ def test_remixer_class_method
15
+ 'CLASS METHOD FOR REMIXER'
16
+ end
17
+ end
18
+
19
+ # These methods will be available to instantiated objects of the remixing this module
20
+ # If 'User' remixes 'Images', these methods will be available to a User object
21
+ #
22
+ module RemixerInstanceMethods
23
+ def test_remixer_instance_method
24
+ 'INSTANCE METHOD FOR REMIXER'
25
+ end
26
+ end
27
+
28
+ # These methods will be available to the Generated Remixed Class
29
+ # If 'User' remixes 'Images', these methods will be available to UserImage class
30
+ #
31
+ module RemixeeClassMethods
32
+ def test_remixee_class_method
33
+ 'CLASS METHOD FOR REMIXEE'
34
+ end
35
+ end
36
+
37
+ # These methods will be available to an instantiated Generated Remixed Class
38
+ # If 'User' remixes 'Images', these methods will be available to a UserImage object
39
+ #
40
+ module RemixeeInstanceMethods
41
+ def test_remixee_instance_method
42
+ 'INSTANCE METHOD FOR REMIXEE'
43
+ end
44
+ end
9
45
  end
@@ -33,7 +33,7 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
33
33
 
34
34
  it "should not allow enhancements of modules that aren't remixed" do
35
35
  lambda {
36
- User.enhance Image
36
+ User.enhance :images
37
37
  }.should raise_error
38
38
  end
39
39
 
@@ -135,7 +135,6 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
135
135
  it "should allow creating an accessor alias" do
136
136
  article = Article.new
137
137
  article.should respond_to("pics")
138
- article.should respond_to("article_images")
139
138
  end
140
139
 
141
140
  it "should copy properties from the Remixable Module to the Remixed Model" do
@@ -196,8 +195,10 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
196
195
  article.pics.path.should == image2.path
197
196
  end
198
197
 
198
+ # Example:
199
+ # Users are Commentable by many Users
200
+ #
199
201
  it "should allow M:M unary relationships through the Remixable Module" do
200
- #User => Commentable => User
201
202
  user = User.new
202
203
  user.first_name = "Tester"
203
204
  user2 = User.new
@@ -206,16 +207,20 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
206
207
  comment = UserComment.new
207
208
  comment.comment = "YOU SUCK!"
208
209
  comment.commentor = user2
209
- user.user_comments << comment
210
210
 
211
- user2.user_comments.length.should be(0)
211
+ user.comments << comment
212
+
213
+ user2.comments.length.should be(0)
212
214
 
213
215
  comment.commentor.first_name.should == "Testy"
214
- user.user_comments.length.should be(1)
216
+
217
+ user.comments.length.should be(1)
215
218
  end
216
219
 
220
+ # Example:
221
+ # Articles are Commentable by many Users
222
+ #
217
223
  it "should allow M:M relationships through the Remixable Module" do
218
- #Article => Commentable => User
219
224
  user = User.new
220
225
  article = Article.new
221
226
 
@@ -235,5 +240,89 @@ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
235
240
  article.comments.first.should be(ac)
236
241
  user.article_comments.first.should be(ac)
237
242
  end
243
+
244
+ # Example:
245
+ # Remixable Image add functionality to any class that remixes it
246
+ # Image::RemixerClassMethods defines a method called 'total_images' that counts the total number of images for the class
247
+ # Image::RemixerInstanceMethods defines a method called 'most_viewed_image' that find the most viewed image for an object
248
+ #
249
+ # User.remixes n, :images
250
+ # User.total_images => count of all images owned by all users
251
+ # User.first.most_viewed_image => would return the most viewed image
252
+ #
253
+ it "should add a remixables' 'RemixerClassMethods' modules to the remixing class" do
254
+ Article.respond_to?(:test_remixer_class_method).should be(true)
255
+ Article.test_remixer_class_method.should == 'CLASS METHOD FOR REMIXER'
256
+ end
257
+
258
+ it "should add a remixables' 'RemixerInstanceMethods' modules to the remixing class" do
259
+ Article.new.respond_to?(:test_remixer_instance_method).should be(true)
260
+ Article.new.test_remixer_instance_method.should == 'INSTANCE METHOD FOR REMIXER'
261
+ end
262
+
263
+ # Example:
264
+ # Remixable Image add functionality to any class that remixes it
265
+ # Image::RemixeeClassMethods defines a method called 'damaged_files' would return a list of all images with invalid checksums (or whatev)
266
+ # Image::RemixeeInstanceMethods defines a method called 'mime_type' that find the mime type of the particular image
267
+ #
268
+ # Article.remixes n, :images
269
+ # # => yields and ArticleImage Class
270
+ # ArticleImage.damaged_files => list of all images with invalid checksums
271
+ # ArticleImage.first.mime_type => would return the mime type of that image
272
+ #
273
+ it "should add a remixables' 'RemixeeClassMethods' modules to the generated remixed class" do
274
+ ArticleImage.respond_to?(:test_remixee_class_method).should be(true)
275
+ ArticleImage.test_remixee_class_method.should == 'CLASS METHOD FOR REMIXEE'
276
+ end
277
+
278
+ it "should add a remixables' 'RemixeeInstanceMethods' modules to the generated remixed class" do
279
+ ArticleImage.new.respond_to?(:test_remixee_instance_method).should be(true)
280
+ ArticleImage.new.test_remixee_instance_method.should == 'INSTANCE METHOD FOR REMIXEE'
281
+ end
282
+
283
+ # Example:
284
+ # User.remixes n, :images, :as => "pics"
285
+ # User.first.pics would be the acessor for images
286
+ # User.first.user_images should raise method not found
287
+ #
288
+ it 'should remove the original attribute accessor when attaching an optional one' do
289
+ Article.new.respond_to?(:pics).should be(true)
290
+ User.new.respond_to?(:user_addresses).should be(true)
291
+ end
292
+
293
+ # Currently:
294
+ # Submission.remixes n, :comments
295
+ # SubmissionComment.new.user = User.first => throws exception, accessor name is 'users' instead
296
+ #
297
+ # Example:
298
+ # User.remix 1, :images
299
+ # # => User.image & UserImage.user
300
+ #
301
+ # User.remix n, :images
302
+ # # => User.images & UserImage.user
303
+ #
304
+ # User.remix n, :comments, :for => 'User', :via => 'commentor'
305
+ # # => User.comments & UserComment.user & UserComment.commentor
306
+ #
307
+ it 'should pluralize accessor names with respect to cardinality' do
308
+ pending
309
+ end
310
+
311
+ # Note:
312
+ # Currently the :via flag allows one to specify another name for the field, but it always appends _id
313
+ #
314
+ # Example:
315
+ # User w/ PK being 'login_name'
316
+ # User.remixes n, :comments, :for => 'User', :via => 'commentor'
317
+ #
318
+ # Comment Table:
319
+ # * id
320
+ # * text
321
+ # * user_login_name
322
+ # * commentor_id #=> should be able to specify it to be commentor_login_name
323
+ #
324
+ it 'should allow the primary and child field names to be specified while remixing' do
325
+ pending
326
+ end
238
327
  end
239
328
  end
@@ -3,7 +3,7 @@ gem 'rspec', '>=1.1.3'
3
3
  require 'spec'
4
4
  require 'pathname'
5
5
  require Pathname(__FILE__).dirname.expand_path.parent + 'lib/dm-is-remixable'
6
- require "ruby-debug"
6
+
7
7
  def load_driver(name, default_uri)
8
8
  return false if ENV['ADAPTER'] != name.to_s
9
9
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dm-is-remixable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cory O'Daniel
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-18 00:00:00 -08:00
12
+ date: 2008-12-09 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -18,19 +18,9 @@ dependencies:
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - "="
21
+ - - ~>
22
22
  - !ruby/object:Gem::Version
23
- version: 0.9.7
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: hoe
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.8.2
23
+ version: 0.9.8
34
24
  version:
35
25
  description: dm-is-remixable allow you to create reusable data functionality
36
26
  email:
@@ -69,7 +59,7 @@ files:
69
59
  - spec/spec.opts
70
60
  - spec/spec_helper.rb
71
61
  has_rdoc: true
72
- homepage: http://github.com/sam/dm-more/tree/master/dm-remixes
62
+ homepage: http://github.com/sam/dm-more/tree/master/dm-is-remixable
73
63
  post_install_message:
74
64
  rdoc_options:
75
65
  - --main