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.
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