mongodoc 0.0.0
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.
- data/.document +5 -0
- data/.gitignore +7 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +80 -0
- data/VERSION +1 -0
- data/data/.gitignore +2 -0
- data/features/mongodoc_base.feature +117 -0
- data/features/saving_an_object.feature +17 -0
- data/features/step_definitions/collection_steps.rb +14 -0
- data/features/step_definitions/connect_steps.rb +4 -0
- data/features/step_definitions/document_steps.rb +88 -0
- data/features/step_definitions/json_steps.rb +9 -0
- data/features/step_definitions/object_steps.rb +43 -0
- data/features/step_definitions/util_steps.rb +7 -0
- data/features/support/support.rb +9 -0
- data/lib/mongodoc.rb +17 -0
- data/lib/mongodoc/attributes.rb +97 -0
- data/lib/mongodoc/base.rb +163 -0
- data/lib/mongodoc/bson.rb +45 -0
- data/lib/mongodoc/connection.rb +20 -0
- data/lib/mongodoc/ext/array.rb +5 -0
- data/lib/mongodoc/ext/binary.rb +7 -0
- data/lib/mongodoc/ext/boolean_class.rb +11 -0
- data/lib/mongodoc/ext/date.rb +16 -0
- data/lib/mongodoc/ext/date_time.rb +13 -0
- data/lib/mongodoc/ext/dbref.rb +7 -0
- data/lib/mongodoc/ext/hash.rb +7 -0
- data/lib/mongodoc/ext/nil_class.rb +5 -0
- data/lib/mongodoc/ext/numeric.rb +17 -0
- data/lib/mongodoc/ext/object.rb +17 -0
- data/lib/mongodoc/ext/object_id.rb +7 -0
- data/lib/mongodoc/ext/regexp.rb +5 -0
- data/lib/mongodoc/ext/string.rb +5 -0
- data/lib/mongodoc/ext/symbol.rb +5 -0
- data/lib/mongodoc/ext/time.rb +5 -0
- data/lib/mongodoc/parent_proxy.rb +37 -0
- data/lib/mongodoc/proxy.rb +76 -0
- data/lib/mongodoc/query.rb +7 -0
- data/lib/mongodoc/value_equals.rb +8 -0
- data/mongod.example.yml +2 -0
- data/mongodoc.gemspec +117 -0
- data/script/console +8 -0
- data/spec/attributes_spec.rb +159 -0
- data/spec/base_ext.rb +9 -0
- data/spec/base_spec.rb +273 -0
- data/spec/bson_matchers.rb +54 -0
- data/spec/bson_spec.rb +316 -0
- data/spec/connection_spec.rb +81 -0
- data/spec/parent_proxy_spec.rb +42 -0
- data/spec/query_spec.rb +12 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/test_classes.rb +19 -0
- data/spec/test_documents.rb +35 -0
- 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,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
|
data/mongod.example.yml
ADDED
data/mongodoc.gemspec
ADDED
@@ -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
|
+
|
data/script/console
ADDED
@@ -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
|