djsun-mongomapper 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
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