mongodoc 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.document +5 -0
  2. data/.gitignore +7 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +80 -0
  6. data/VERSION +1 -0
  7. data/data/.gitignore +2 -0
  8. data/features/mongodoc_base.feature +117 -0
  9. data/features/saving_an_object.feature +17 -0
  10. data/features/step_definitions/collection_steps.rb +14 -0
  11. data/features/step_definitions/connect_steps.rb +4 -0
  12. data/features/step_definitions/document_steps.rb +88 -0
  13. data/features/step_definitions/json_steps.rb +9 -0
  14. data/features/step_definitions/object_steps.rb +43 -0
  15. data/features/step_definitions/util_steps.rb +7 -0
  16. data/features/support/support.rb +9 -0
  17. data/lib/mongodoc.rb +17 -0
  18. data/lib/mongodoc/attributes.rb +97 -0
  19. data/lib/mongodoc/base.rb +163 -0
  20. data/lib/mongodoc/bson.rb +45 -0
  21. data/lib/mongodoc/connection.rb +20 -0
  22. data/lib/mongodoc/ext/array.rb +5 -0
  23. data/lib/mongodoc/ext/binary.rb +7 -0
  24. data/lib/mongodoc/ext/boolean_class.rb +11 -0
  25. data/lib/mongodoc/ext/date.rb +16 -0
  26. data/lib/mongodoc/ext/date_time.rb +13 -0
  27. data/lib/mongodoc/ext/dbref.rb +7 -0
  28. data/lib/mongodoc/ext/hash.rb +7 -0
  29. data/lib/mongodoc/ext/nil_class.rb +5 -0
  30. data/lib/mongodoc/ext/numeric.rb +17 -0
  31. data/lib/mongodoc/ext/object.rb +17 -0
  32. data/lib/mongodoc/ext/object_id.rb +7 -0
  33. data/lib/mongodoc/ext/regexp.rb +5 -0
  34. data/lib/mongodoc/ext/string.rb +5 -0
  35. data/lib/mongodoc/ext/symbol.rb +5 -0
  36. data/lib/mongodoc/ext/time.rb +5 -0
  37. data/lib/mongodoc/parent_proxy.rb +37 -0
  38. data/lib/mongodoc/proxy.rb +76 -0
  39. data/lib/mongodoc/query.rb +7 -0
  40. data/lib/mongodoc/value_equals.rb +8 -0
  41. data/mongod.example.yml +2 -0
  42. data/mongodoc.gemspec +117 -0
  43. data/script/console +8 -0
  44. data/spec/attributes_spec.rb +159 -0
  45. data/spec/base_ext.rb +9 -0
  46. data/spec/base_spec.rb +273 -0
  47. data/spec/bson_matchers.rb +54 -0
  48. data/spec/bson_spec.rb +316 -0
  49. data/spec/connection_spec.rb +81 -0
  50. data/spec/parent_proxy_spec.rb +42 -0
  51. data/spec/query_spec.rb +12 -0
  52. data/spec/spec.opts +2 -0
  53. data/spec/spec_helper.rb +13 -0
  54. data/spec/test_classes.rb +19 -0
  55. data/spec/test_documents.rb +35 -0
  56. metadata +159 -0
@@ -0,0 +1,17 @@
1
+ class Object
2
+ def to_bson(*args)
3
+ {MongoDoc::BSON::CLASS_KEY => self.class.name}.tap do |bson_hash|
4
+ instance_variables.each do |name|
5
+ bson_hash[name[1..-1]] = instance_variable_get(name).to_bson(args)
6
+ end
7
+ end
8
+ end
9
+
10
+ def self.bson_create(bson_hash, options = {})
11
+ new.tap do |obj|
12
+ bson_hash.each do |name, value|
13
+ obj.instance_variable_set("@#{name}", MongoDoc::BSON.decode(value, options))
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module Mongo
2
+ class ObjectID
3
+ def to_bson(*args)
4
+ self
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class Regexp
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class String
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Symbol
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Time
2
+ def to_bson(*args)
3
+ self
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ module MongoDoc
2
+ module Document
3
+ class ParentProxy
4
+ attr_reader :assoc_name, :_parent
5
+
6
+ def initialize(parent, assoc_name)
7
+ raise ArgumentError.new('ParentProxy requires a parent') if parent.nil?
8
+ raise ArgumentError.new('ParentProxy require an association name') if assoc_name.blank?
9
+ @_parent = parent
10
+ @assoc_name = assoc_name
11
+ end
12
+
13
+ def path_to_root(attrs)
14
+ assoc_attrs = attrs.inject({}) do |assoc_attrs, (key, value)|
15
+ assoc_attrs["#{assoc_name}.#{key}"] = value
16
+ assoc_attrs
17
+ end
18
+ _parent.path_to_root(assoc_attrs)
19
+ end
20
+
21
+ private
22
+
23
+ def method_missing(method, *args)
24
+ unless @_parent.respond_to?(method)
25
+ message = "undefined method `#{method.to_s}' for proxied \"#{@_parent}\":#{@_parent.class.to_s}"
26
+ raise NoMethodError, message
27
+ end
28
+
29
+ if block_given?
30
+ @_parent.send(method, *args) { |*block_args| yield(*block_args) }
31
+ else
32
+ @_parent.send(method, *args)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,76 @@
1
+ # Thanks Sandro!
2
+ # http://github.com/sandro
3
+ module MongoDoc
4
+ module Document
5
+ class Proxy
6
+ # List of array methods (that are not in +Object+) that need to be
7
+ # delegated to +collection+.
8
+ ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
9
+
10
+ # List of additional methods that must be delegated to +collection+.
11
+ MUST_DEFINE = %w[to_a to_ary inspect to_bson ==]
12
+
13
+ (ARRAY_METHODS + MUST_DEFINE).uniq.each do |method|
14
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
+ def #{method}(*args, &block) # def each(*args, &block)
16
+ collection.send(:#{method}, *args, &block) # collection.send(:each, *args, &block)
17
+ end # end
18
+ RUBY
19
+ end
20
+
21
+ attr_reader :assoc_name, :collection, :collection_class, :_parent, :_root
22
+
23
+ def _parent=(parent)
24
+ @_parent = parent
25
+ end
26
+
27
+ def _root=(root)
28
+ @_root = root
29
+ collection.each do |item|
30
+ item._root = root
31
+ end
32
+ end
33
+
34
+ def initialize(options)
35
+ @assoc_name = options[:assoc_name]
36
+ @collection = []
37
+ @collection_class = options[:collection_class]
38
+ @_root = options[:root]
39
+ @_parent = options[:parent]
40
+ end
41
+
42
+ alias_method :append, :<<
43
+ def <<(items)
44
+ items = [items] unless items.kind_of?(Array)
45
+ items.each do |item|
46
+ item = collection_class.new(item) if Hash === item
47
+ raise NotADocumentError unless collection_class === item
48
+ append item
49
+ item._parent = self
50
+ item._root = _root
51
+ end
52
+ self
53
+ end
54
+ alias_method :push, :<<
55
+ alias_method :concat, :<<
56
+
57
+ # Lie about our class. Borrowed from Rake::FileList
58
+ # Note: Does not work for case equality (<tt>===</tt>)
59
+ def is_a?(klass)
60
+ klass == Array || super(klass)
61
+ end
62
+ alias kind_of? is_a?
63
+
64
+ def path_to_root(attrs)
65
+ _parent.path_to_root(attrs)
66
+ end
67
+
68
+ protected
69
+
70
+ def _propose_update_attributes(src, attrs, safe)
71
+ src.errors.add(:base, 'update_attributes called through a has_many')
72
+ false
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,7 @@
1
+ module MongoDoc
2
+ module Query
3
+ def self.set_modifier(bson_hash)
4
+ {'$set' => bson_hash}
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module MongoDoc
2
+ module ValueEquals
3
+ def ==(other)
4
+ return false unless instance_variables.size == other.instance_variables.size
5
+ instance_variables.all? {|var| self.instance_variable_get(var) == other.instance_variable_get(var)}
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,2 @@
1
+ mongod: /usr/local/bin/mongod
2
+ dbpath: /data/db
@@ -0,0 +1,117 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{mongodoc}
8
+ s.version = "0.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Les Hill"]
12
+ s.date = %q{2009-11-22}
13
+ s.description = %q{ODM for MongoDB}
14
+ s.email = %q{leshill@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "data/.gitignore",
27
+ "features/mongodoc_base.feature",
28
+ "features/saving_an_object.feature",
29
+ "features/step_definitions/collection_steps.rb",
30
+ "features/step_definitions/connect_steps.rb",
31
+ "features/step_definitions/document_steps.rb",
32
+ "features/step_definitions/json_steps.rb",
33
+ "features/step_definitions/object_steps.rb",
34
+ "features/step_definitions/util_steps.rb",
35
+ "features/support/support.rb",
36
+ "lib/mongodoc.rb",
37
+ "lib/mongodoc/attributes.rb",
38
+ "lib/mongodoc/base.rb",
39
+ "lib/mongodoc/bson.rb",
40
+ "lib/mongodoc/connection.rb",
41
+ "lib/mongodoc/ext/array.rb",
42
+ "lib/mongodoc/ext/binary.rb",
43
+ "lib/mongodoc/ext/boolean_class.rb",
44
+ "lib/mongodoc/ext/date.rb",
45
+ "lib/mongodoc/ext/date_time.rb",
46
+ "lib/mongodoc/ext/dbref.rb",
47
+ "lib/mongodoc/ext/hash.rb",
48
+ "lib/mongodoc/ext/nil_class.rb",
49
+ "lib/mongodoc/ext/numeric.rb",
50
+ "lib/mongodoc/ext/object.rb",
51
+ "lib/mongodoc/ext/object_id.rb",
52
+ "lib/mongodoc/ext/regexp.rb",
53
+ "lib/mongodoc/ext/string.rb",
54
+ "lib/mongodoc/ext/symbol.rb",
55
+ "lib/mongodoc/ext/time.rb",
56
+ "lib/mongodoc/parent_proxy.rb",
57
+ "lib/mongodoc/proxy.rb",
58
+ "lib/mongodoc/query.rb",
59
+ "lib/mongodoc/value_equals.rb",
60
+ "mongod.example.yml",
61
+ "mongodoc.gemspec",
62
+ "script/console",
63
+ "spec/attributes_spec.rb",
64
+ "spec/base_ext.rb",
65
+ "spec/base_spec.rb",
66
+ "spec/bson_matchers.rb",
67
+ "spec/bson_spec.rb",
68
+ "spec/connection_spec.rb",
69
+ "spec/parent_proxy_spec.rb",
70
+ "spec/query_spec.rb",
71
+ "spec/spec.opts",
72
+ "spec/spec_helper.rb",
73
+ "spec/test_classes.rb",
74
+ "spec/test_documents.rb"
75
+ ]
76
+ s.homepage = %q{http://github.com/leshill/mongodoc}
77
+ s.rdoc_options = ["--charset=UTF-8"]
78
+ s.require_paths = ["lib"]
79
+ s.rubygems_version = %q{1.3.5}
80
+ s.summary = %q{ODM for MongoDB}
81
+ s.test_files = [
82
+ "spec/attributes_spec.rb",
83
+ "spec/base_ext.rb",
84
+ "spec/base_spec.rb",
85
+ "spec/bson_matchers.rb",
86
+ "spec/bson_spec.rb",
87
+ "spec/connection_spec.rb",
88
+ "spec/parent_proxy_spec.rb",
89
+ "spec/query_spec.rb",
90
+ "spec/spec_helper.rb",
91
+ "spec/test_classes.rb",
92
+ "spec/test_documents.rb"
93
+ ]
94
+
95
+ if s.respond_to? :specification_version then
96
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
97
+ s.specification_version = 3
98
+
99
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
100
+ s.add_runtime_dependency(%q<mongo>, ["= 0.16"])
101
+ s.add_runtime_dependency(%q<durran-validatable>, ["= 1.8.2"])
102
+ s.add_development_dependency(%q<rspec>, [">= 0"])
103
+ s.add_development_dependency(%q<cucumber>, [">= 0"])
104
+ else
105
+ s.add_dependency(%q<mongo>, ["= 0.16"])
106
+ s.add_dependency(%q<durran-validatable>, ["= 1.8.2"])
107
+ s.add_dependency(%q<rspec>, [">= 0"])
108
+ s.add_dependency(%q<cucumber>, [">= 0"])
109
+ end
110
+ else
111
+ s.add_dependency(%q<mongo>, ["= 0.16"])
112
+ s.add_dependency(%q<durran-validatable>, ["= 1.8.2"])
113
+ s.add_dependency(%q<rspec>, [">= 0"])
114
+ s.add_dependency(%q<cucumber>, [">= 0"])
115
+ end
116
+ end
117
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+
5
+ require 'irb'
6
+ require 'mongodoc'
7
+
8
+ IRB.start(__FILE__)
@@ -0,0 +1,159 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "MongoDoc::Document::Attributes" do
4
+ context ".key" do
5
+ class TestKeys < MongoDoc::Base
6
+ end
7
+
8
+ it "adds its arguments to _keys" do
9
+ TestKeys.key :attr1, :attr2
10
+ TestKeys._keys.should == [:attr1, :attr2]
11
+ end
12
+
13
+ describe "accessors" do
14
+ before do
15
+ TestKeys.key :attr1
16
+ end
17
+
18
+ subject do
19
+ TestKeys.new
20
+ end
21
+ it "has an attr1 reader" do
22
+ should respond_to(:attr1)
23
+ end
24
+
25
+ it "has an attr1 writer" do
26
+ should respond_to(:attr1=)
27
+ end
28
+ end
29
+
30
+ describe "used with inheritance" do
31
+ class TestParent < MongoDoc::Base
32
+ key :parent_attr
33
+ end
34
+
35
+ class TestChild < TestParent
36
+ key :child_attr
37
+ end
38
+
39
+ it "has its own keys" do
40
+ TestChild._keys.should include(:child_attr)
41
+ end
42
+
43
+ it "has the keys from the parent class" do
44
+ TestChild._keys.should include(*TestParent._keys)
45
+ end
46
+ end
47
+ end
48
+
49
+ context ".has_one" do
50
+ class TestDoc < MongoDoc::Base
51
+ has_one :subdoc
52
+ end
53
+
54
+ class SubDoc < MongoDoc::Base
55
+ key :data
56
+ end
57
+
58
+ it "sets the subdocuments parent to the parent proxy" do
59
+ subdoc = SubDoc.new
60
+ doc = TestDoc.new(:subdoc => subdoc)
61
+ MongoDoc::Document::ParentProxy.should === subdoc._parent
62
+ subdoc._parent._parent.should == doc
63
+ end
64
+
65
+ it "set the subdocuments root" do
66
+ subdoc = SubDoc.new
67
+ middoc = TestDoc.new
68
+ doc = TestDoc.new(:subdoc => middoc)
69
+ middoc.subdoc = subdoc
70
+ subdoc._root.should == doc
71
+ end
72
+
73
+ it "sets the subdocuments root no matter how when it is inserted" do
74
+ subdoc = SubDoc.new
75
+ middoc = TestDoc.new(:subdoc => subdoc)
76
+ doc = TestDoc.new(:subdoc => middoc)
77
+ subdoc._root.should == doc
78
+ end
79
+
80
+ class HasOneValidationTest < MongoDoc::Base
81
+ key :data
82
+ validates_presence_of :data
83
+ end
84
+
85
+ it "cascades validations down" do
86
+ invalid = HasOneValidationTest.new
87
+ doc = TestDoc.new(:subdoc => invalid)
88
+ doc.should have(1).error_on(:subdoc)
89
+ end
90
+ end
91
+
92
+ context "._attributes" do
93
+ class TestHasOneDoc < MongoDoc::Base
94
+ key :key
95
+ has_one :has_one
96
+ end
97
+
98
+ it "is _keys + _associations" do
99
+ TestHasOneDoc._attributes.should == TestHasOneDoc._keys + TestHasOneDoc._associations
100
+ end
101
+ end
102
+
103
+ context ".has_many" do
104
+
105
+ class SubHasManyDoc < MongoDoc::Base
106
+ key :data
107
+ end
108
+
109
+ class TestHasManyDoc < MongoDoc::Base
110
+ has_many :sub_docs, :class_name => 'SubHasManyDoc'
111
+ end
112
+
113
+ class TestImplicitHasManyDoc < MongoDoc::Base
114
+ has_many :sub_has_many_docs
115
+ end
116
+
117
+ it "uses a proxy" do
118
+ MongoDoc::Document::Proxy.should === TestHasManyDoc.new.sub_docs
119
+ end
120
+
121
+ it "sets the subdocuments parent to the proxy" do
122
+ subdoc = SubHasManyDoc.new
123
+ doc = TestHasManyDoc.new(:sub_docs => [subdoc])
124
+ subdoc._parent.should == doc.sub_docs
125
+ end
126
+
127
+ it "set the subdocuments root to the root" do
128
+ subdoc = SubHasManyDoc.new
129
+ doc = TestHasManyDoc.new(:sub_docs => [subdoc])
130
+ subdoc._root.should == doc
131
+ end
132
+
133
+ it "uses the association name to find the children's class name" do
134
+ subdoc = SubHasManyDoc.new
135
+ doc = TestImplicitHasManyDoc.new(:sub_has_many_docs => [subdoc])
136
+ end
137
+
138
+ class HasManyValidationChild < MongoDoc::Base
139
+ key :data
140
+ validates_presence_of :data
141
+ end
142
+
143
+ class HasManyValidationTest < MongoDoc::Base
144
+ has_many :subdocs, :class_name => 'HasManyValidationChild'
145
+ end
146
+
147
+ it "cascades validations and marks it in the parent" do
148
+ invalid = HasManyValidationChild.new
149
+ doc = HasManyValidationTest.new(:subdocs => [invalid])
150
+ doc.should have(1).error_on(:subdocs)
151
+ end
152
+
153
+ it "cascades validations and marks it in the child" do
154
+ invalid = HasManyValidationChild.new
155
+ doc = HasManyValidationTest.new(:subdocs => [invalid])
156
+ invalid.should have(1).error_on(:data)
157
+ end
158
+ end
159
+ end