crnixon-mongomapper 0.2.0 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.gitignore +1 -0
  2. data/History +48 -0
  3. data/README.rdoc +5 -3
  4. data/Rakefile +6 -4
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +29 -18
  8. data/lib/mongomapper/associations.rb +53 -38
  9. data/lib/mongomapper/associations/base.rb +53 -20
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_documents_as_proxy.rb +27 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +103 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +6 -8
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/{array_proxy.rb → many_proxy.rb} +1 -1
  18. data/lib/mongomapper/associations/proxy.rb +24 -21
  19. data/lib/mongomapper/callbacks.rb +1 -1
  20. data/lib/mongomapper/document.rb +160 -74
  21. data/lib/mongomapper/dynamic_finder.rb +38 -0
  22. data/lib/mongomapper/embedded_document.rb +154 -105
  23. data/lib/mongomapper/finder_options.rb +11 -7
  24. data/lib/mongomapper/key.rb +15 -21
  25. data/lib/mongomapper/pagination.rb +52 -0
  26. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  27. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  28. data/lib/mongomapper/serialization.rb +1 -1
  29. data/lib/mongomapper/serializers/json_serializer.rb +15 -0
  30. data/lib/mongomapper/support.rb +30 -0
  31. data/mongomapper.gemspec +87 -46
  32. data/test/NOTE_ON_TESTING +1 -0
  33. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -0
  34. data/test/functional/associations/test_belongs_to_proxy.rb +45 -0
  35. data/test/functional/associations/test_many_documents_as_proxy.rb +253 -0
  36. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
  37. data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
  38. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -0
  39. data/test/functional/associations/test_many_proxy.rb +295 -0
  40. data/test/functional/test_associations.rb +47 -0
  41. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  42. data/test/functional/test_document.rb +952 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +30 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +169 -0
  47. data/test/test_helper.rb +7 -2
  48. data/test/unit/serializers/test_json_serializer.rb +189 -0
  49. data/test/unit/test_association_base.rb +144 -0
  50. data/test/unit/test_document.rb +123 -0
  51. data/test/unit/test_embedded_document.rb +526 -0
  52. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +36 -1
  53. data/test/{test_key.rb → unit/test_key.rb} +59 -12
  54. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  55. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  56. data/test/unit/test_pagination.rb +113 -0
  57. data/test/unit/test_rails_compatibility.rb +34 -0
  58. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  59. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  60. metadata +81 -43
  61. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  62. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  63. data/lib/mongomapper/rails_compatibility.rb +0 -23
  64. data/test/serializers/test_json_serializer.rb +0 -104
  65. data/test/test_associations.rb +0 -174
  66. data/test/test_document.rb +0 -944
  67. data/test/test_embedded_document.rb +0 -253
  68. data/test/test_rails_compatibility.rb +0 -29
data/.gitignore CHANGED
@@ -4,3 +4,4 @@ coverage
4
4
  rdoc
5
5
  pkg
6
6
  *~
7
+ *.gem
data/History CHANGED
@@ -1,3 +1,51 @@
1
+ 0.3.4 8/28/2009
2
+ * BACKWORDS COMPATIBILITY BREAK: Timestamps are now optional. To use them add timestamps! to your model.
3
+ * BACKWORDS COMPATIBILITY BREAK: Associations keys are no longer created automatically when you use belongs_to and many. Too much was hidden from the developer. You now have to declare them like key :creator_id, String and such.
4
+ * to_json now includes dynamic keys and embedded stuff by default
5
+ * added polymorphic many with :as option (dcu)
6
+
7
+ 0.3.3 8/16/2009
8
+ * BACKWORDS COMPATIBILITY BREAK: _id is now once again a string rather than an object id and will stay that way.
9
+ * Custom id's can now be used because of the change to string id's
10
+ * Added dynamic finders to document. (dcu)
11
+ * Added destroy_all, delete_all and nullify for many document association
12
+ * Added :dependent option for many documents assocation (dcu)
13
+ * update_attributes now returns true or false instead of the document. (Durran Jordan and me)
14
+ * Keys no longer require a type
15
+ * Keys can now be added on the fly using []=
16
+
17
+ 0.3.2 8/6/2009
18
+ * Added many polymorphic documents association
19
+ * Implemented build and create for many and many polymorphic documents
20
+ * <<, push and concat now work correctly for many and many polymorphic documents
21
+ * find(:first) now accepts order option
22
+ * id is now included by default with to_json
23
+ * _id is now always excluded from to_json
24
+ * Times are now always returned as UTC
25
+ * Default values are now a bit more intelligent for Array and Hash keys (djsun)
26
+ * Embedded documents now have _id as well so they can be identified more easily
27
+
28
+ 0.3.1 7/28/2009
29
+ * 1 minor tweak
30
+ * Removed deep_merge gem as dependency as ActiveSupport has deep_merge that works good enough
31
+
32
+ 0.3.0 7/28/2009
33
+ * 5 major additions, 3 minor additions, 3 bug fix, and other miscellany
34
+ * BACKWORDS COMPATIBILITY BREAK: _id is now stored in binary form (recommended by mongodb team) instead of string, api is the same everywhere as before but data stored with string id's previous to change will need to be updated
35
+ * Added Document#paginate which works just like find but adds pagination (dcu did basics and I pimped)
36
+ * Added a basic console for playing around with MongoMapper (dcu)
37
+ * Embedded associations can now be deeply nested (Keith Hanson)
38
+ * Added support for many polymorphic documents (Felipe Coury and Me)
39
+ * Fixed bug where conditions that disallowed using $in, $all and $any with an array
40
+ * Bumped version of validatable so :if validation option supports symbol/string to proc.
41
+ * Document#create with no attributes now creates a document as long as it is valid
42
+ * Now defining accessor methods when key is declared rather than using method missing and all that jazz
43
+ * Attributes now have boolean methods that return true or false based on whether they have value present
44
+ * Added scoped finds and pagination on many document association.
45
+ * find first and last now use natural order which is more reliable.
46
+ * Updated to latest ruby driver (0.10.1)
47
+
48
+
1
49
  0.2.0 7/7/2009
2
50
  * 2 major additions (observers, associations), several minor additions, and a few bug fixes
3
51
  * Added observers
data/README.rdoc CHANGED
@@ -2,16 +2,18 @@
2
2
 
3
3
  Awesome gem for modeling your domain and storing it in mongo.
4
4
 
5
- == Note on Releases
5
+ Releases are tagged on github and also released as gems on github and rubyforge. Master is pushed to whenever I add a patch or a new feature. To build from master, you can clone the code, generate the updated gemspec, build the gem and install.
6
6
 
7
- Releases are tagged on github and also released as gems on github and rubyforge. Master is pushed to whenever I add a patch or a new feature. To build from master, you can clone the code and run 'rake install' to install the gem.
7
+ * rake gemspec
8
+ * gem build mongomapper.gemspec
9
+ * gem install the gem that was built
8
10
 
9
11
  == Note on Patches/Pull Requests
10
12
 
11
13
  * Fork the project.
12
14
  * Make your feature addition or bug fix.
13
15
  * Add tests for it. This is important so I don't break it in a future version unintentionally.
14
- * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
16
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
15
17
  * Send me a pull request. Bonus points for topic branches.
16
18
 
17
19
  == Dependencies
data/Rakefile CHANGED
@@ -12,14 +12,16 @@ begin
12
12
  gem.rubyforge_project = "mongomapper"
13
13
 
14
14
  gem.add_dependency('activesupport')
15
- gem.add_dependency('mongodb-mongo', '0.9')
16
- gem.add_dependency('jnunemaker-validatable', '1.7.1')
15
+ gem.add_dependency('mongodb-mongo', '0.11.1')
16
+ gem.add_dependency('jnunemaker-validatable', '1.7.2')
17
17
 
18
18
  gem.add_development_dependency('mocha', '0.9.4')
19
19
  gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
20
20
  end
21
-
22
- Jeweler::RubyforgeTasks.new
21
+
22
+ Jeweler::RubyforgeTasks.new do |rubyforge|
23
+ rubyforge.doc_task = "rdoc"
24
+ end
23
25
  rescue LoadError
24
26
  puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
25
27
  end
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.4
data/bin/mmconsole ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift File.dirname(__FILE__)+"/../lib"
3
+
4
+ require 'mongomapper'
5
+ require 'irb'
6
+
7
+ IRB.setup(nil)
8
+ irb = IRB::Irb.new
9
+
10
+ IRB.conf[:MAIN_CONTEXT] = irb.context
11
+
12
+ irb.context.evaluate("require 'irb/completion'", 0)
13
+ irb.context.evaluate(%@
14
+ include XGen::Mongo::Driver
15
+ include MongoMapper
16
+
17
+ MongoMapper.database = "mmtest"
18
+ $db = MongoMapper.database
19
+
20
+ @, 0)
21
+
22
+ puts %@
23
+ Welcome to the MongoMapper Console!
24
+
25
+ Example 1:
26
+ things = $db.collection("things")
27
+ things.insert("name" => "Raw Thing")
28
+ things.insert("name" => "Another Thing", "date" => Time.now)
29
+
30
+ cursor = things.find("name" => "Raw Thing")
31
+ puts cursor.next_object.inspect
32
+
33
+ Example 2:
34
+ class Thing
35
+ include MongoMapper::Document
36
+ key :name, String, :required => true
37
+ key :date, Time
38
+ end
39
+
40
+ thing = Thing.new
41
+ thing.name = "My thing"
42
+ thing.date = Time.now
43
+ thing.save
44
+
45
+ all_things = Thing.all
46
+ puts all_things.map { |object| object.name }.inspect
47
+
48
+ @
49
+
50
+ trap("SIGINT") do
51
+ irb.signal_handle
52
+ end
53
+ catch(:IRB_EXIT) do
54
+ irb.eval_input
55
+ end
56
+
data/lib/mongomapper.rb CHANGED
@@ -2,8 +2,8 @@ require 'pathname'
2
2
  require 'rubygems'
3
3
 
4
4
  gem 'activesupport'
5
- gem 'mongodb-mongo', '0.9'
6
- gem 'jnunemaker-validatable', '1.7.1'
5
+ gem 'mongodb-mongo', '0.11.1'
6
+ gem 'jnunemaker-validatable', '1.7.2'
7
7
 
8
8
  require 'activesupport'
9
9
  require 'mongo'
@@ -11,37 +11,48 @@ require 'validatable'
11
11
 
12
12
  dir = Pathname(__FILE__).dirname.expand_path + 'mongomapper'
13
13
 
14
- require dir + 'key'
14
+ require dir + 'support'
15
+
16
+ require dir + 'associations'
17
+ require dir + 'associations/base'
18
+
19
+ require dir + 'associations/proxy'
20
+ require dir + 'associations/many_documents_proxy'
21
+
22
+ require dir + 'associations/belongs_to_proxy'
23
+ require dir + 'associations/belongs_to_polymorphic_proxy'
24
+ require dir + 'associations/many_proxy'
25
+ require dir + 'associations/many_polymorphic_proxy'
26
+ require dir + 'associations/many_embedded_proxy'
27
+ require dir + 'associations/many_embedded_polymorphic_proxy'
28
+ require dir + 'associations/many_documents_as_proxy'
29
+
30
+ require dir + 'callbacks'
15
31
  require dir + 'finder_options'
16
- require dir + 'rails_compatibility'
32
+ require dir + 'dynamic_finder'
33
+ require dir + 'key'
34
+ require dir + 'observing'
35
+ require dir + 'pagination'
17
36
  require dir + 'save_with_validation'
18
37
  require dir + 'serialization'
19
- require dir + 'callbacks'
20
- require dir + 'observing'
21
38
  require dir + 'validations'
22
39
 
23
- require dir + 'associations/proxy'
24
- require dir + 'associations/array_proxy'
25
- require dir + 'associations/base'
26
-
27
- require dir + 'associations/has_many_proxy'
28
- require dir + 'associations/has_many_embedded_proxy'
29
- require dir + 'associations/belongs_to_proxy'
30
- require dir + 'associations/polymorphic_belongs_to_proxy'
31
- require dir + 'associations'
40
+ require dir + 'rails_compatibility/document'
41
+ require dir + 'rails_compatibility/embedded_document'
32
42
 
33
43
  require dir + 'embedded_document'
34
44
  require dir + 'document'
35
45
 
36
46
  module MongoMapper
37
- class DocumentNotFound < StandardError; end
38
- class DocumentNotValid < StandardError
47
+ DocumentNotFound = Class.new(StandardError)
48
+
49
+ DocumentNotValid = Class.new(StandardError) do
39
50
  def initialize(document)
40
51
  @document = document
41
52
  super("Validation failed: #{@document.errors.full_messages.join(", ")}")
42
53
  end
43
54
  end
44
-
55
+
45
56
  def self.connection
46
57
  @@connection ||= XGen::Mongo::Driver::Mongo.new
47
58
  end
@@ -2,33 +2,12 @@ module MongoMapper
2
2
  module Associations
3
3
  module ClassMethods
4
4
  def belongs_to(association_id, options = {})
5
- association = create_association(:belongs_to, association_id, options)
6
-
7
- ref_id = "#{association_id}_id"
8
- key ref_id, String
9
-
10
- define_method("#{ref_id}=") do |value|
11
- write_attribute(ref_id, value)
12
- end
13
-
14
- if options[:polymorphic]
15
- ref_type = "#{association_id}_type"
16
- key ref_type, String
17
-
18
- define_method("#{ref_type}=") do |value|
19
- write_attribute(ref_type, value)
20
- end
21
- end
22
-
23
- define_association_methods(association)
24
-
5
+ create_association(:belongs_to, association_id, options)
25
6
  self
26
7
  end
27
8
 
28
9
  def many(association_id, options = {})
29
- association = create_association(:many, association_id, options)
30
- define_association_methods(association)
31
-
10
+ create_association(:many, association_id, options)
32
11
  self
33
12
  end
34
13
 
@@ -37,31 +16,67 @@ module MongoMapper
37
16
  end
38
17
 
39
18
  private
40
- def create_association(type, name, options)
41
- association = Associations::Base.new(type, name, options)
42
- associations[association.name] = association
43
- association
44
- end
19
+ def create_association(type, name, options)
20
+ association = Associations::Base.new(type, name, options)
21
+ associations[association.name] = association
22
+ define_association_methods(association)
23
+ define_dependent_callback(association)
24
+ association
25
+ end
45
26
 
46
- def define_association_methods(association)
47
- define_method(association.name) do
48
- get_proxy(association)
27
+ def define_association_methods(association)
28
+ define_method(association.name) do
29
+ get_proxy(association)
30
+ end
31
+
32
+ define_method("#{association.name}=") do |value|
33
+ get_proxy(association).replace(value)
34
+ value
35
+ end
49
36
  end
50
37
 
51
- define_method("#{association.name}=") do |value|
52
- get_proxy(association).replace(value)
53
- value
38
+ def define_dependent_callback(association)
39
+ if association.options[:dependent]
40
+ if association.many?
41
+ define_dependent_callback_for_many(association)
42
+ elsif association.belongs_to?
43
+ define_dependent_callback_for_belongs_to(association)
44
+ end
45
+ end
46
+ end
47
+
48
+ def define_dependent_callback_for_many(association)
49
+ return if association.embeddable?
50
+
51
+ after_destroy do |doc|
52
+ case association.options[:dependent]
53
+ when :destroy
54
+ doc.get_proxy(association).destroy_all
55
+ when :delete_all
56
+ doc.get_proxy(association).delete_all
57
+ when :nullify
58
+ doc.get_proxy(association).nullify
59
+ end
60
+ end
61
+ end
62
+
63
+ def define_dependent_callback_for_belongs_to(association)
64
+ after_destroy do |doc|
65
+ case association.options[:dependent]
66
+ when :destroy
67
+ doc.get_proxy(association).destroy
68
+ end
69
+ end
54
70
  end
55
- end
56
71
  end
57
72
 
58
73
  module InstanceMethods
59
74
  def get_proxy(association)
60
- proxy = self.instance_variable_get(association.ivar)
61
- if proxy.nil?
75
+ unless proxy = self.instance_variable_get(association.ivar)
62
76
  proxy = association.proxy_class.new(self, association)
63
- self.instance_variable_set(association.ivar, proxy)
77
+ self.instance_variable_set(association.ivar, proxy) if !frozen?
64
78
  end
79
+
65
80
  proxy
66
81
  end
67
82
  end
@@ -4,20 +4,14 @@ module MongoMapper
4
4
  attr_reader :type, :name, :options
5
5
 
6
6
  def initialize(type, name, options = {})
7
- @options = options
8
- @type = type
9
- @name = name
10
- end
11
-
12
- def klass
13
- class_name.constantize
7
+ @type, @name, @options = type, name, options
14
8
  end
15
9
 
16
10
  def class_name
17
11
  @class_name ||= begin
18
12
  if cn = options[:class_name]
19
13
  cn
20
- elsif @type == :many
14
+ elsif many?
21
15
  name.to_s.singularize.camelize
22
16
  else
23
17
  name.to_s.camelize
@@ -25,26 +19,65 @@ module MongoMapper
25
19
  end
26
20
  end
27
21
 
22
+ def klass
23
+ @klass ||= class_name.constantize
24
+ end
25
+
26
+ def many?
27
+ @many_type ||= @type == :many
28
+ end
29
+
30
+ def belongs_to?
31
+ @belongs_to_type ||= @type == :belongs_to
32
+ end
33
+
34
+ def polymorphic?
35
+ !!@options[:polymorphic]
36
+ end
37
+
38
+ def as?
39
+ !!@options[:as]
40
+ end
41
+
42
+ def type_key_name
43
+ @type_key_name ||= many? ? '_type' : "#{as}_type"
44
+ end
45
+
46
+ def as
47
+ @options[:as] || self.name
48
+ end
49
+
50
+ def foreign_key
51
+ @options[:foreign_key] || "#{name}_id"
52
+ end
53
+
28
54
  def ivar
29
55
  @ivar ||= "@_#{name}"
30
56
  end
31
57
 
58
+ def embeddable?
59
+ many? && klass.embeddable?
60
+ end
61
+
32
62
  def proxy_class
33
- case @type
34
- when :belongs_to
35
- if @options[:polymorphic]
36
- PolymorphicBelongsToProxy
37
- else
38
- BelongsToProxy
39
- end
40
- when :many
63
+ @proxy_class ||= begin
64
+ if many?
41
65
  if self.klass.embeddable?
42
- HasManyEmbeddedProxy
66
+ polymorphic? ? ManyEmbeddedPolymorphicProxy : ManyEmbeddedProxy
43
67
  else
44
- HasManyProxy
68
+ if polymorphic?
69
+ ManyPolymorphicProxy
70
+ elsif as?
71
+ ManyDocumentsAsProxy
72
+ else
73
+ ManyProxy
74
+ end
45
75
  end
46
- end
47
- end
76
+ else
77
+ polymorphic? ? BelongsToPolymorphicProxy : BelongsToProxy
78
+ end
79
+ end # end begin
80
+ end # end proxy_class
48
81
  end
49
82
  end
50
83
  end