djsun-mongomapper 0.3.1

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 (61) hide show
  1. data/.gitignore +7 -0
  2. data/History +51 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/bin/mmconsole +56 -0
  8. data/lib/mongomapper.rb +96 -0
  9. data/lib/mongomapper/associations.rb +61 -0
  10. data/lib/mongomapper/associations/base.rb +71 -0
  11. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +32 -0
  12. data/lib/mongomapper/associations/belongs_to_proxy.rb +22 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +85 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/many_embedded_proxy.rb +17 -0
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/many_proxy.rb +6 -0
  18. data/lib/mongomapper/associations/proxy.rb +67 -0
  19. data/lib/mongomapper/callbacks.rb +106 -0
  20. data/lib/mongomapper/document.rb +278 -0
  21. data/lib/mongomapper/embedded_document.rb +237 -0
  22. data/lib/mongomapper/finder_options.rb +96 -0
  23. data/lib/mongomapper/key.rb +80 -0
  24. data/lib/mongomapper/observing.rb +50 -0
  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/save_with_validation.rb +19 -0
  29. data/lib/mongomapper/serialization.rb +55 -0
  30. data/lib/mongomapper/serializers/json_serializer.rb +79 -0
  31. data/lib/mongomapper/validations.rb +47 -0
  32. data/mongomapper.gemspec +139 -0
  33. data/test/NOTE_ON_TESTING +1 -0
  34. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +39 -0
  35. data/test/functional/associations/test_belongs_to_proxy.rb +35 -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 +267 -0
  39. data/test/functional/associations/test_many_proxy.rb +236 -0
  40. data/test/functional/test_associations.rb +40 -0
  41. data/test/functional/test_callbacks.rb +85 -0
  42. data/test/functional/test_document.rb +691 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +31 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +108 -0
  47. data/test/test_helper.rb +67 -0
  48. data/test/unit/serializers/test_json_serializer.rb +103 -0
  49. data/test/unit/test_association_base.rb +136 -0
  50. data/test/unit/test_document.rb +125 -0
  51. data/test/unit/test_embedded_document.rb +370 -0
  52. data/test/unit/test_finder_options.rb +214 -0
  53. data/test/unit/test_key.rb +217 -0
  54. data/test/unit/test_mongo_id.rb +35 -0
  55. data/test/unit/test_mongomapper.rb +28 -0
  56. data/test/unit/test_observing.rb +101 -0
  57. data/test/unit/test_pagination.rb +113 -0
  58. data/test/unit/test_rails_compatibility.rb +34 -0
  59. data/test/unit/test_serializations.rb +52 -0
  60. data/test/unit/test_validations.rb +259 -0
  61. metadata +189 -0
@@ -0,0 +1,52 @@
1
+ module MongoMapper
2
+ module Pagination
3
+ class PaginationProxy < BasicObject
4
+ attr_accessor :subject
5
+ attr_reader :total_entries, :per_page, :current_page
6
+ alias limit per_page
7
+
8
+ def initialize(total_entries, current_page, per_page=nil)
9
+ @total_entries = total_entries.to_i
10
+ self.per_page = per_page
11
+ self.current_page = current_page
12
+ end
13
+
14
+ def total_pages
15
+ (total_entries / per_page.to_f).ceil
16
+ end
17
+
18
+ def out_of_bounds?
19
+ current_page > total_pages
20
+ end
21
+
22
+ def previous_page
23
+ current_page > 1 ? (current_page - 1) : nil
24
+ end
25
+
26
+ def next_page
27
+ current_page < total_pages ? (current_page + 1) : nil
28
+ end
29
+
30
+ def skip
31
+ (current_page - 1) * per_page
32
+ end
33
+ alias offset skip
34
+
35
+ def method_missing(name, *args, &block)
36
+ @subject.send(name, *args, &block)
37
+ end
38
+
39
+ private
40
+ def per_page=(value)
41
+ value = 25 if value.blank?
42
+ @per_page = value.to_i
43
+ end
44
+
45
+ def current_page=(value)
46
+ value = value.to_i
47
+ value = 1 if value < 1
48
+ @current_page = value
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,15 @@
1
+ module MongoMapper
2
+ module RailsCompatibility
3
+ module Document
4
+ def self.included(model)
5
+ model.class_eval do
6
+ alias_method :new_record?, :new?
7
+ end
8
+ end
9
+
10
+ def to_param
11
+ id
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,25 @@
1
+ module MongoMapper
2
+ module RailsCompatibility
3
+ module EmbeddedDocument
4
+ def self.included(model)
5
+ model.class_eval do
6
+ extend ClassMethods
7
+ end
8
+
9
+ class << model
10
+ alias has_many many
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def column_names
16
+ keys.keys
17
+ end
18
+ end
19
+
20
+ def to_param
21
+ raise "Missing to_param method in #{self.class}. You should implement it to return the unique identifier of this embedded document within a document."
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ module MongoMapper
2
+ module SaveWithValidation
3
+ def self.included(base)
4
+ base.class_eval do
5
+ alias_method_chain :save, :validation
6
+ alias_method_chain :save!, :validation
7
+ end
8
+ end
9
+
10
+ private
11
+ def save_with_validation
12
+ valid? ? save_without_validation : false
13
+ end
14
+
15
+ def save_with_validation!
16
+ valid? ? save_without_validation! : raise(DocumentNotValid.new(self))
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,55 @@
1
+ require 'active_support/json'
2
+
3
+ module MongoMapper #:nodoc:
4
+ module Serialization
5
+ class Serializer #:nodoc:
6
+ attr_reader :options
7
+
8
+ def initialize(record, options = {})
9
+ @record, @options = record, options.dup
10
+ end
11
+
12
+ def serializable_key_names
13
+ key_names = @record.class.keys.keys
14
+
15
+ if options[:only]
16
+ options.delete(:except)
17
+ key_names = key_names & Array(options[:only]).collect { |n| n.to_s }
18
+ else
19
+ options[:except] = Array(options[:except])
20
+ key_names = key_names - options[:except].collect { |n| n.to_s }
21
+ end
22
+
23
+ key_names
24
+ end
25
+
26
+ def serializable_method_names
27
+ Array(options[:methods]).inject([]) do |method_attributes, name|
28
+ method_attributes << name if @record.respond_to?(name.to_s)
29
+ method_attributes
30
+ end
31
+ end
32
+
33
+ def serializable_names
34
+ serializable_key_names + serializable_method_names
35
+ end
36
+
37
+ def serializable_record
38
+ returning(serializable_record = {}) do
39
+ serializable_names.each { |name| serializable_record[name] = @record.send(name) }
40
+ end
41
+ end
42
+
43
+ def serialize
44
+ # overwrite to implement
45
+ end
46
+
47
+ def to_s(&block)
48
+ serialize(&block)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ dir = Pathname(__FILE__).dirname.expand_path + 'serializers'
55
+ require dir + 'json_serializer'
@@ -0,0 +1,79 @@
1
+ module MongoMapper #:nodoc:
2
+ module Serialization
3
+ def self.included(base)
4
+ base.cattr_accessor :include_root_in_json, :instance_writer => false
5
+ base.extend ClassMethods
6
+ end
7
+
8
+ # Returns a JSON string representing the model. Some configuration is
9
+ # available through +options+.
10
+ #
11
+ # The option <tt>include_root_in_json</tt> controls the top-level behavior of
12
+ # to_json. When it is <tt>true</tt>, to_json will emit a single root node named
13
+ # after the object's type. For example:
14
+ #
15
+ # konata = User.find(1)
16
+ # User.include_root_in_json = true
17
+ # konata.to_json
18
+ # # => { "user": {"id": 1, "name": "Konata Izumi", "age": 16,
19
+ # "created_at": "2006/08/01", "awesome": true} }
20
+ #
21
+ # User.include_root_in_json = false
22
+ # konata.to_json
23
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
24
+ # "created_at": "2006/08/01", "awesome": true}
25
+ #
26
+ # The remainder of the examples in this section assume include_root_in_json is set to
27
+ # <tt>false</tt>.
28
+ #
29
+ # Without any +options+, the returned JSON string will include all
30
+ # the model's attributes. For example:
31
+ #
32
+ # konata = User.find(1)
33
+ # konata.to_json
34
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
35
+ # "created_at": "2006/08/01", "awesome": true}
36
+ #
37
+ # The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the attributes
38
+ # included, and work similar to the +attributes+ method. For example:
39
+ #
40
+ # konata.to_json(:only => [ :id, :name ])
41
+ # # => {"id": 1, "name": "Konata Izumi"}
42
+ #
43
+ # konata.to_json(:except => [ :id, :created_at, :age ])
44
+ # # => {"name": "Konata Izumi", "awesome": true}
45
+ #
46
+ # To include any methods on the model, use <tt>:methods</tt>.
47
+ #
48
+ # konata.to_json(:methods => :permalink)
49
+ # # => {"id": 1, "name": "Konata Izumi", "age": 16,
50
+ # "created_at": "2006/08/01", "awesome": true,
51
+ # "permalink": "1-konata-izumi"}
52
+ def to_json(options = {})
53
+ options.merge!(:methods => :id) unless options[:only]
54
+ options.reverse_merge!(:except => :_id)
55
+ if include_root_in_json
56
+ "{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
57
+ else
58
+ JsonSerializer.new(self, options).to_s
59
+ end
60
+ end
61
+
62
+ def from_json(json)
63
+ self.attributes = ActiveSupport::JSON.decode(json)
64
+ self
65
+ end
66
+
67
+ class JsonSerializer < MongoMapper::Serialization::Serializer #:nodoc:
68
+ def serialize
69
+ serializable_record.to_json
70
+ end
71
+ end
72
+
73
+ module ClassMethods
74
+ def json_class_name
75
+ @json_class_name ||= name.demodulize.underscore.inspect
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,47 @@
1
+ module MongoMapper
2
+ module Validations
3
+ class ValidatesUniquenessOf < Validatable::ValidationBase
4
+ def valid?(instance)
5
+ # TODO: scope
6
+ doc = instance.class.find(:first, :conditions => {self.attribute => instance[attribute]}, :limit => 1)
7
+ doc.nil? || instance.id == doc.id
8
+ end
9
+
10
+ def message(instance)
11
+ super || "has already been taken"
12
+ end
13
+ end
14
+
15
+ class ValidatesExclusionOf < Validatable::ValidationBase
16
+ required_option :within
17
+
18
+ def valid?(instance)
19
+ value = instance[attribute]
20
+ return true if allow_nil && value.nil?
21
+ return true if allow_blank && value.blank?
22
+
23
+ !within.include?(instance[attribute])
24
+ end
25
+
26
+ def message(instance)
27
+ super || "is reserved"
28
+ end
29
+ end
30
+
31
+ class ValidatesInclusionOf < Validatable::ValidationBase
32
+ required_option :within
33
+
34
+ def valid?(instance)
35
+ value = instance[attribute]
36
+ return true if allow_nil && value.nil?
37
+ return true if allow_blank && value.blank?
38
+
39
+ within.include?(value)
40
+ end
41
+
42
+ def message(instance)
43
+ super || "is not in the list"
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,139 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{mongomapper}
5
+ s.version = "0.3.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["John Nunemaker"]
9
+ s.date = %q{2009-08-04}
10
+ s.default_executable = %q{mmconsole}
11
+ s.email = %q{nunemaker@gmail.com}
12
+ s.executables = ["mmconsole"]
13
+ s.extra_rdoc_files = [
14
+ "LICENSE",
15
+ "README.rdoc"
16
+ ]
17
+ s.files = [
18
+ ".gitignore",
19
+ "History",
20
+ "LICENSE",
21
+ "README.rdoc",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "bin/mmconsole",
25
+ "lib/mongomapper.rb",
26
+ "lib/mongomapper/associations.rb",
27
+ "lib/mongomapper/associations/base.rb",
28
+ "lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb",
29
+ "lib/mongomapper/associations/belongs_to_proxy.rb",
30
+ "lib/mongomapper/associations/many_documents_proxy.rb",
31
+ "lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb",
32
+ "lib/mongomapper/associations/many_embedded_proxy.rb",
33
+ "lib/mongomapper/associations/many_polymorphic_proxy.rb",
34
+ "lib/mongomapper/associations/many_proxy.rb",
35
+ "lib/mongomapper/associations/proxy.rb",
36
+ "lib/mongomapper/callbacks.rb",
37
+ "lib/mongomapper/document.rb",
38
+ "lib/mongomapper/embedded_document.rb",
39
+ "lib/mongomapper/finder_options.rb",
40
+ "lib/mongomapper/key.rb",
41
+ "lib/mongomapper/observing.rb",
42
+ "lib/mongomapper/pagination.rb",
43
+ "lib/mongomapper/rails_compatibility/document.rb",
44
+ "lib/mongomapper/rails_compatibility/embedded_document.rb",
45
+ "lib/mongomapper/save_with_validation.rb",
46
+ "lib/mongomapper/serialization.rb",
47
+ "lib/mongomapper/serializers/json_serializer.rb",
48
+ "lib/mongomapper/validations.rb",
49
+ "mongomapper.gemspec",
50
+ "test/NOTE_ON_TESTING",
51
+ "test/functional/associations/test_belongs_to_polymorphic_proxy.rb",
52
+ "test/functional/associations/test_belongs_to_proxy.rb",
53
+ "test/functional/associations/test_many_embedded_polymorphic_proxy.rb",
54
+ "test/functional/associations/test_many_embedded_proxy.rb",
55
+ "test/functional/associations/test_many_polymorphic_proxy.rb",
56
+ "test/functional/associations/test_many_proxy.rb",
57
+ "test/functional/test_associations.rb",
58
+ "test/functional/test_callbacks.rb",
59
+ "test/functional/test_document.rb",
60
+ "test/functional/test_pagination.rb",
61
+ "test/functional/test_rails_compatibility.rb",
62
+ "test/functional/test_validations.rb",
63
+ "test/models.rb",
64
+ "test/test_helper.rb",
65
+ "test/unit/serializers/test_json_serializer.rb",
66
+ "test/unit/test_association_base.rb",
67
+ "test/unit/test_document.rb",
68
+ "test/unit/test_embedded_document.rb",
69
+ "test/unit/test_finder_options.rb",
70
+ "test/unit/test_key.rb",
71
+ "test/unit/test_mongo_id.rb",
72
+ "test/unit/test_mongomapper.rb",
73
+ "test/unit/test_observing.rb",
74
+ "test/unit/test_pagination.rb",
75
+ "test/unit/test_rails_compatibility.rb",
76
+ "test/unit/test_serializations.rb",
77
+ "test/unit/test_validations.rb"
78
+ ]
79
+ s.homepage = %q{http://github.com/jnunemaker/mongomapper}
80
+ s.rdoc_options = ["--charset=UTF-8"]
81
+ s.require_paths = ["lib"]
82
+ s.rubyforge_project = %q{mongomapper}
83
+ s.rubygems_version = %q{1.3.4}
84
+ s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
85
+ s.test_files = [
86
+ "test/functional/associations/test_belongs_to_polymorphic_proxy.rb",
87
+ "test/functional/associations/test_belongs_to_proxy.rb",
88
+ "test/functional/associations/test_many_embedded_polymorphic_proxy.rb",
89
+ "test/functional/associations/test_many_embedded_proxy.rb",
90
+ "test/functional/associations/test_many_polymorphic_proxy.rb",
91
+ "test/functional/associations/test_many_proxy.rb",
92
+ "test/functional/test_associations.rb",
93
+ "test/functional/test_callbacks.rb",
94
+ "test/functional/test_document.rb",
95
+ "test/functional/test_pagination.rb",
96
+ "test/functional/test_rails_compatibility.rb",
97
+ "test/functional/test_validations.rb",
98
+ "test/models.rb",
99
+ "test/test_helper.rb",
100
+ "test/unit/serializers/test_json_serializer.rb",
101
+ "test/unit/test_association_base.rb",
102
+ "test/unit/test_document.rb",
103
+ "test/unit/test_embedded_document.rb",
104
+ "test/unit/test_finder_options.rb",
105
+ "test/unit/test_key.rb",
106
+ "test/unit/test_mongo_id.rb",
107
+ "test/unit/test_mongomapper.rb",
108
+ "test/unit/test_observing.rb",
109
+ "test/unit/test_pagination.rb",
110
+ "test/unit/test_rails_compatibility.rb",
111
+ "test/unit/test_serializations.rb",
112
+ "test/unit/test_validations.rb"
113
+ ]
114
+
115
+ if s.respond_to? :specification_version then
116
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
117
+ s.specification_version = 3
118
+
119
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
120
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
121
+ s.add_runtime_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
122
+ s.add_runtime_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
123
+ s.add_development_dependency(%q<mocha>, ["= 0.9.4"])
124
+ s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
125
+ else
126
+ s.add_dependency(%q<activesupport>, [">= 0"])
127
+ s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
128
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
129
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
130
+ s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
131
+ end
132
+ else
133
+ s.add_dependency(%q<activesupport>, [">= 0"])
134
+ s.add_dependency(%q<mongodb-mongo>, ["= 0.10.1"])
135
+ s.add_dependency(%q<jnunemaker-validatable>, ["= 1.7.2"])
136
+ s.add_dependency(%q<mocha>, ["= 0.9.4"])
137
+ s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
138
+ end
139
+ end
@@ -0,0 +1 @@
1
+ I am doing my best to keep unit and functional tests separate. As I see them, functional tests hit the database and should never care about internals. Unit tests do not hit the database.
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default to nil" do
10
+ status = Status.new
11
+ status.target.should be_nil
12
+ end
13
+
14
+ should "be able to replace the association" do
15
+ status = Status.new
16
+ project = Project.new(:name => "mongomapper")
17
+ status.target = project
18
+ status.save.should be_true
19
+
20
+ from_db = Status.find(status.id)
21
+ from_db.target.should_not be_nil
22
+ from_db.target_id.should == project.id
23
+ from_db.target_type.should == "Project"
24
+ from_db.target.name.should == "mongomapper"
25
+ end
26
+
27
+ should "unset the association" do
28
+ status = Status.new
29
+ project = Project.new(:name => "mongomapper")
30
+ status.target = project
31
+ status.save.should be_true
32
+
33
+ from_db = Status.find(status.id)
34
+ from_db.target = nil
35
+ from_db.target_type.should be_nil
36
+ from_db.target_id.should be_nil
37
+ from_db.target.should be_nil
38
+ end
39
+ end