mongoo 0.4.10 → 0.5.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/CHANGELOG CHANGED
@@ -1,5 +1,23 @@
1
1
  == Changelog
2
2
 
3
+ === 0.5.0
4
+
5
+ * Introduced an API/DSL for defining attributes and other features.
6
+ The old API will no longer work.
7
+
8
+ class Book < Mongoo::Base
9
+ describe do |d|
10
+ d.attribute "title", :type => :string
11
+ d.embeds_one "sample_chapter", :class => "Book::Chapter"
12
+ d.embeds_many "chapters", :class => 'Book::Chapter'
13
+ d.index "title"
14
+ end
15
+ end
16
+
17
+ * Notice too, there is now better support for embedded docs. See test_embedded.rb.
18
+
19
+ * General, misc cleanup and restructuring of code.
20
+
3
21
  === 0.4.2
4
22
 
5
23
  * Added find_and_modify
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.10
1
+ 0.5.0
data/lib/mongoo.rb CHANGED
@@ -7,10 +7,6 @@ end
7
7
  # Mongoo.conn => #<Mongo::Connection:0x00000100db8ac0>
8
8
 
9
9
  module Mongoo
10
- INDEX_META = {}
11
- ATTRIBUTE_META = {}
12
- EMBEDS_META = {}
13
-
14
10
  class << self
15
11
  attr_accessor :verbose_debug
16
12
 
@@ -46,6 +42,8 @@ require "forwardable"
46
42
  require "active_support/core_ext"
47
43
  require "active_model"
48
44
 
45
+ require "mongoo/describe_dsl"
46
+
49
47
  require "mongoo/hash_ext"
50
48
  require "mongoo/cursor"
51
49
  require "mongoo/attribute_sanitizer"
@@ -53,9 +51,22 @@ require "mongoo/attribute_proxy"
53
51
  require "mongoo/changelog"
54
52
  require "mongoo/persistence"
55
53
  require "mongoo/modifiers"
54
+
55
+ require "mongoo/embedded/describe_dsl"
56
+ require "mongoo/embedded/core_mixin"
57
+
58
+ require "mongoo/attributes/describe_dsl"
59
+ require "mongoo/attributes"
60
+
56
61
  require "mongoo/core"
57
62
  require "mongoo/base"
63
+
58
64
  require "mongoo/embedded/base"
59
65
  require "mongoo/embedded/hash_proxy"
66
+
60
67
  require "mongoo/mongohash"
61
68
  require "mongoo/identity_map"
69
+
70
+ require "mongoo/grid_fs/describe_dsl"
71
+ require "mongoo/grid_fs/file"
72
+ require "mongoo/grid_fs/files"
@@ -0,0 +1,116 @@
1
+ class Mongoo::UnknownAttributeError < Exception; end
2
+
3
+ module Mongoo::Attributes
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def attributes
8
+ if @attributes
9
+ @attributes
10
+ else
11
+ @attributes = {}
12
+ end
13
+ end
14
+
15
+ def attributes_tree
16
+ tree = {}
17
+ self.attributes.each do |name, opts|
18
+ parts = name.split(".")
19
+ curr_branch = tree
20
+ while part = parts.shift
21
+ if !parts.empty?
22
+ curr_branch[part.to_s] ||= {}
23
+ curr_branch = curr_branch[part.to_s]
24
+ else
25
+ curr_branch[part.to_s] = opts[:type]
26
+ end
27
+ end
28
+ end
29
+ tree
30
+ end
31
+
32
+ def known_attribute?(k)
33
+ k == "_id" || self.attributes[k.to_s]
34
+ end
35
+ end # ClassMethods
36
+
37
+ module InstanceMethods
38
+ def known_attribute?(k)
39
+ self.class.known_attribute?(k)
40
+ end
41
+
42
+ def read_attribute_for_validation(key)
43
+ get_attribute(key)
44
+ end
45
+
46
+ def get_attribute(k)
47
+ unless known_attribute?(k)
48
+ raise Mongoo::UnknownAttributeError, k
49
+ end
50
+ mongohash.dot_get(k.to_s)
51
+ end
52
+ alias :get :get_attribute
53
+ alias :g :get_attribute
54
+
55
+ def set_attribute(k,v)
56
+ unless known_attribute?(k)
57
+ if self.respond_to?("#{k}=")
58
+ self.send("#{k}=", v)
59
+ return v
60
+ else
61
+ raise Mongoo::UnknownAttributeError, k
62
+ end
63
+ end
64
+ unless k.to_s == "_id" || v.nil?
65
+ field_type = self.class.attributes[k.to_s][:type]
66
+ v = Mongoo::AttributeSanitizer.sanitize(field_type, v)
67
+ end
68
+ mongohash.dot_set(k.to_s,v); v
69
+ end
70
+ alias :set :set_attribute
71
+ alias :s :set_attribute
72
+
73
+ def get_or_set_attribute(k, v)
74
+ get_attribute(k) || set_attribute(k, v)
75
+ end
76
+ alias :get_or_set :get_or_set_attribute
77
+ alias :gs :get_or_set_attribute
78
+
79
+ def unset_attribute(k)
80
+ mongohash.dot_delete(k); true
81
+ end
82
+ alias :unset :unset_attribute
83
+ alias :u :unset_attribute
84
+
85
+ def set_attributes(k_v_pairs)
86
+ k_v_pairs.each do |k,v|
87
+ set_attribute(k,v)
88
+ end
89
+ end
90
+ alias :sets :set_attributes
91
+
92
+ def get_attributes(keys)
93
+ found = {}
94
+ keys.each { |k| found[k.to_s] = get_attribute(k) }
95
+ found
96
+ end
97
+ alias :gets :get_attributes
98
+
99
+ def unset_attributes(keys)
100
+ keys.each { |k| unset_attribute(k) }; true
101
+ end
102
+ alias :unsets :unset_attributes
103
+
104
+ def attributes
105
+ mongohash.to_key_value
106
+ end
107
+
108
+ def id
109
+ get "_id"
110
+ end
111
+
112
+ def id=(val)
113
+ set "_id", val
114
+ end
115
+ end # InstanceMethods
116
+ end
@@ -0,0 +1,32 @@
1
+ module Mongoo
2
+ module Attributes
3
+ module DescribeDsl
4
+ def attribute(name, opts={})
5
+ raise ArgumentError.new("missing :type") unless opts[:type]
6
+ @klass.attributes[name.to_s] = opts
7
+ true
8
+ end
9
+
10
+ def define_attribute_methods
11
+ @klass.attributes_tree.each do |name, val|
12
+ if val.is_a?(Hash)
13
+ blk = Proc.new { Mongoo::AttributeProxy.new(val, [name], self) }
14
+ @klass.send(:define_method, name, &blk)
15
+ else
16
+ blk = Proc.new { get(name) }
17
+ @klass.send(:define_method, name, &blk)
18
+ blk = Proc.new { |val| set(name, val) }
19
+ @klass.send(:define_method, "#{name}=", &blk)
20
+ end
21
+ end
22
+ end # define_attribute_methods
23
+ protected :define_attribute_methods
24
+ end # DescribeDsl
25
+ end # Attributes
26
+ end # Mongoo
27
+
28
+ class Mongoo::DescribeDsl
29
+ include Mongoo::Attributes::DescribeDsl
30
+ end
31
+
32
+ Mongoo::DescribeDsl.after_describe << :define_attribute_methods
data/lib/mongoo/core.rb CHANGED
@@ -1,154 +1,13 @@
1
1
  module Mongoo
2
- class UnknownAttributeError < Exception; end
3
-
4
2
  class Core
5
3
  include ActiveModel::Validations
6
4
  extend ActiveModel::Naming
7
5
 
8
- def self.embeds_meta
9
- Mongoo::EMBEDS_META[self.to_s] ||= {}
10
- end
11
-
12
- def self.embeds_many(attrib_key, opts)
13
- raise(ArgumentError, "missing opt :as") unless opts[:as]
14
- raise(ArgumentError, "missing opt :class") unless opts[:class]
15
-
16
- self.embeds_meta["embeds_many"] ||= {}
17
- self.embeds_meta["embeds_many"][attrib_key] = opts
18
-
19
- define_embeds_many_methods
20
- end
21
-
22
- def self.define_embeds_many_methods
23
- (self.embeds_meta["embeds_many"] || {}).each do |attrib_key, opts|
24
- define_method(opts[:as]) do
25
- if val = instance_variable_get("@#{opts[:as]}")
26
- val
27
- else
28
- instance_variable_set("@#{opts[:as]}",
29
- embedded_hash_proxy(get_or_set(attrib_key,{}), eval(opts[:class])))
30
- end
31
- end # define_method
32
- unless opts[:validate] == false
33
- define_method("validate_#{opts[:as]}") do
34
- send(opts[:as]).each do |k,v|
35
- unless v.valid?
36
- v.errors.each do |field, messages|
37
- errors.add "#{attrib_key}.#{k}.#{field}", messages
38
- end
39
- end
40
- end
41
- end # define_method
42
- validate "validate_#{opts[:as]}"
43
- end
44
- end
45
- end
46
-
47
- def self.embeds_one(attrib_key, opts)
48
- raise(ArgumentError, "missing opt :as") unless opts[:as]
49
- raise(ArgumentError, "missing opt :class") unless opts[:class]
50
-
51
- self.embeds_meta["embeds_one"] ||= {}
52
- self.embeds_meta["embeds_one"][attrib_key] = opts
6
+ include Mongoo::Embedded::CoreMixin
7
+ include Mongoo::Attributes
53
8
 
54
- define_embeds_one_methods
55
- end
56
-
57
- def self.define_embeds_one_methods
58
- (self.embeds_meta["embeds_one"] || {}).each do |attrib_key, opts|
59
- define_method(opts[:as]) do
60
- if val = instance_variable_get("@#{opts[:as]}")
61
- val
62
- else
63
- if hash = get(attrib_key)
64
- instance_variable_set("@#{opts[:as]}",
65
- embedded_doc(hash, eval(opts[:class])))
66
- end
67
- end
68
- end
69
-
70
- define_method("#{opts[:as]}=") do |obj|
71
- set(attrib_key, (obj.nil? ? nil : obj.to_hash))
72
- send("#{opts[:as]}")
73
- end
74
-
75
- unless opts[:validate] == false
76
- define_method("validate_#{opts[:as]}") do
77
- if v = send(opts[:as])
78
- unless v.valid?
79
- v.errors.each do |field, messages|
80
- errors.add "#{attrib_key}.#{field}", messages
81
- end
82
- end
83
- end
84
- end # define_method
85
- validate "validate_#{opts[:as]}"
86
- end
87
- end
88
- end
89
-
90
- def embedded_hash_proxy(attrib, klass)
91
- Mongoo::Embedded::HashProxy.new(self, attrib, klass)
92
- end
93
-
94
- def embedded_doc(attrib, klass)
95
- klass.new(self, attrib)
96
- end
97
-
98
- def self.attribute(name, opts={})
99
- raise ArgumentError.new("missing :type") unless opts[:type]
100
- self.attributes[name.to_s] = opts
101
- define_attribute_methods
102
- true
103
- end
104
-
105
- def self.attributes
106
- Mongoo::ATTRIBUTE_META[self.to_s] ||= {}
107
- end
108
-
109
- def self.attributes_tree
110
- tree = {}
111
- self.attributes.each do |name, opts|
112
- parts = name.split(".")
113
- curr_branch = tree
114
- while part = parts.shift
115
- if !parts.empty?
116
- curr_branch[part.to_s] ||= {}
117
- curr_branch = curr_branch[part.to_s]
118
- else
119
- curr_branch[part.to_s] = opts[:type]
120
- end
121
- end
122
- end
123
- tree
124
- end
125
-
126
- def self.define_attribute_methods
127
- define_method("id") do
128
- get("_id")
129
- end
130
- define_method("id=") do |val|
131
- set("_id", val)
132
- end
133
-
134
- self.attributes_tree.each do |name, val|
135
- if val.is_a?(Hash)
136
- define_method(name) do
137
- AttributeProxy.new(val, [name], self)
138
- end
139
- else
140
- define_method(name) do
141
- get(name)
142
- end
143
- define_method("#{name}=") do |val|
144
- set(name, val)
145
- end
146
- end
147
- end
148
- end
149
-
150
- def self.known_attribute?(k)
151
- k == "_id" || self.attributes[k.to_s]
9
+ def self.describe(&block)
10
+ Mongoo::DescribeDsl.new(self).describe(&block)
152
11
  end
153
12
 
154
13
  def initialize(hash={}, persisted=false)
@@ -167,76 +26,6 @@ module Mongoo
167
26
  end
168
27
  end
169
28
 
170
- def known_attribute?(k)
171
- self.class.known_attribute?(k)
172
- end
173
-
174
- def read_attribute_for_validation(key)
175
- get_attribute(key)
176
- end
177
-
178
- def get_attribute(k)
179
- unless known_attribute?(k)
180
- raise UnknownAttributeError, k
181
- end
182
- mongohash.dot_get(k.to_s)
183
- end
184
- alias :get :get_attribute
185
- alias :g :get_attribute
186
-
187
- def set_attribute(k,v)
188
- unless known_attribute?(k)
189
- if self.respond_to?("#{k}=")
190
- self.send("#{k}=", v)
191
- return v
192
- else
193
- raise UnknownAttributeError, k
194
- end
195
- end
196
- unless k.to_s == "_id" || v.nil?
197
- field_type = self.class.attributes[k.to_s][:type]
198
- v = Mongoo::AttributeSanitizer.sanitize(field_type, v)
199
- end
200
- mongohash.dot_set(k.to_s,v); v
201
- end
202
- alias :set :set_attribute
203
- alias :s :set_attribute
204
-
205
- def get_or_set_attribute(k, v)
206
- get_attribute(k) || set_attribute(k, v)
207
- end
208
- alias :get_or_set :get_or_set_attribute
209
- alias :gs :get_or_set_attribute
210
-
211
- def unset_attribute(k)
212
- mongohash.dot_delete(k); true
213
- end
214
- alias :unset :unset_attribute
215
- alias :u :unset_attribute
216
-
217
- def set_attributes(k_v_pairs)
218
- k_v_pairs.each do |k,v|
219
- set_attribute(k,v)
220
- end
221
- end
222
- alias :sets :set_attributes
223
-
224
- def get_attributes(keys)
225
- found = {}
226
- keys.each { |k| found[k.to_s] = get_attribute(k) }
227
- found
228
- end
229
- alias :gets :get_attributes
230
-
231
- def unset_attributes(keys)
232
- keys.each { |k| unset_attribute(k) }; true
233
- end
234
- alias :unsets :unset_attributes
235
-
236
- def attributes
237
- mongohash.to_key_value
238
- end
239
-
240
29
  def merge!(hash)
241
30
  if hash.is_a?(Mongoo::Mongohash)
242
31
  hash = hash.raw_hash
@@ -0,0 +1,36 @@
1
+ module Mongoo
2
+ class DescribeDsl
3
+ def self.after_describe
4
+ @after_describe ||= []
5
+ end
6
+
7
+ def self.before_describe
8
+ @before_describe ||= []
9
+ end
10
+
11
+ def initialize(klass)
12
+ @klass = klass
13
+ end
14
+
15
+ def describe(&block)
16
+ Mutex.new.synchronize do
17
+ self.class.before_describe.uniq!
18
+ self.class.after_describe.uniq!
19
+
20
+ self.class.before_describe.each do |m|
21
+ send(m)
22
+ end
23
+
24
+ block.call(self)
25
+
26
+ self.class.after_describe.each do |m|
27
+ send(m)
28
+ end
29
+ end
30
+ end
31
+
32
+ def index(*args)
33
+ @klass.send(:index, *args)
34
+ end
35
+ end # DescribeDsl
36
+ end # Mongoo
@@ -12,6 +12,18 @@ module Mongoo
12
12
  @parent.persisted?
13
13
  end
14
14
 
15
+ def db
16
+ @parent.db
17
+ end
18
+
19
+ def conn
20
+ @parent.conn
21
+ end
22
+
23
+ def collection_name
24
+ @parent.collection_name
25
+ end
26
+
15
27
  def ==(other)
16
28
  to_hash == other.to_hash
17
29
  end
@@ -0,0 +1,20 @@
1
+ module Mongoo
2
+ module Embedded
3
+ module CoreMixin
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ end # ClassMethods
8
+
9
+ module InstanceMethods
10
+ def embedded_hash_proxy(attrib, klass)
11
+ Mongoo::Embedded::HashProxy.new(self, attrib, klass)
12
+ end
13
+
14
+ def embedded_doc(attrib, klass)
15
+ klass.new(self, attrib)
16
+ end
17
+ end # InstanceMethods
18
+ end # CoreMixin
19
+ end # Embedded
20
+ end # Mongoo
@@ -0,0 +1,91 @@
1
+ module Mongoo
2
+ module Embedded
3
+ module DescribeDsl
4
+ def embeds_one(attrib_key, opts)
5
+ raise(ArgumentError, "missing opt :class") unless opts[:class]
6
+ define_embeds_one_method(attrib_key, opts)
7
+ end
8
+
9
+ def embeds_many(attrib_key, opts)
10
+ raise(ArgumentError, "missing opt :class") unless opts[:class]
11
+ define_embeds_many_method(attrib_key, opts)
12
+ end
13
+
14
+ def define_embeds_many_method(attrib_key, opts)
15
+ as = attrib_key
16
+ attrib_key = "embedded_#{attrib_key}"
17
+
18
+ attribute(attrib_key, :type => :hash)
19
+
20
+ blk = Proc.new {
21
+ if val = instance_variable_get("@#{as}")
22
+ val
23
+ else
24
+ instance_variable_set("@#{as}",
25
+ embedded_hash_proxy(get_or_set(attrib_key,{}), eval(opts[:class])))
26
+ end
27
+ }
28
+ @klass.send(:define_method, as, &blk)
29
+
30
+ unless opts[:validate] == false
31
+ blk = Proc.new {
32
+ send(as).each do |k,v|
33
+ unless v.valid?
34
+ v.errors.each do |field, messages|
35
+ errors.add "#{attrib_key}.#{k}.#{field}", messages
36
+ end
37
+ end
38
+ end
39
+ }
40
+ @klass.send(:define_method, "validate_#{as}", &blk)
41
+ @klass.validate "validate_#{as}"
42
+ end
43
+ end # define_embeds_many_method
44
+ protected :define_embeds_many_method
45
+
46
+ def define_embeds_one_method(attrib_key, opts)
47
+ as = attrib_key
48
+ attrib_key = "embedded_#{attrib_key}"
49
+
50
+ attribute(attrib_key, :type => :hash)
51
+
52
+ blk = Proc.new {
53
+ if val = instance_variable_get("@#{as}")
54
+ val
55
+ else
56
+ if hash = get(attrib_key)
57
+ instance_variable_set("@#{as}",
58
+ embedded_doc(hash, eval(opts[:class])))
59
+ end
60
+ end
61
+ }
62
+ @klass.send(:define_method, as, &blk)
63
+
64
+ blk = Proc.new { |obj|
65
+ set(attrib_key, (obj.nil? ? nil : obj.to_hash))
66
+ send("#{as}")
67
+ }
68
+ @klass.send(:define_method, "#{as}=", &blk)
69
+
70
+ unless opts[:validate] == false
71
+ blk = Proc.new {
72
+ if v = send(as)
73
+ unless v.valid?
74
+ v.errors.each do |field, messages|
75
+ errors.add "#{attrib_key}.#{field}", messages
76
+ end
77
+ end
78
+ end
79
+ }
80
+ @klass.send(:define_method, "validate_#{as}", &blk)
81
+ @klass.validate "validate_#{as}"
82
+ end
83
+ end # define_embeds_one_method
84
+ protected :define_embeds_one_method
85
+ end # DescribeDsl
86
+ end # Embedded
87
+ end
88
+
89
+ class Mongoo::DescribeDsl
90
+ include Mongoo::Embedded::DescribeDsl
91
+ end
@@ -0,0 +1,51 @@
1
+ module Mongoo
2
+ module GridFs
3
+ module DescribeDsl
4
+ def grid_fs_file(name, opts={})
5
+ define_grid_fs_file_method(name, opts)
6
+ end
7
+
8
+ def grid_fs_files(name, opts={})
9
+ define_grid_fs_files_method(name, opts)
10
+ end
11
+
12
+ def define_grid_fs_file_method(name, opts)
13
+ attrib_name = "gridfs_#{name}"
14
+ attribute(attrib_name, :type => :hash)
15
+
16
+ blk = Proc.new {
17
+ if file = instance_variable_get("@#{name}")
18
+ file
19
+ else
20
+ db_lambda = opts[:db] || lambda { self.db }
21
+ container = get_or_set(attrib_name, {})
22
+ file = Mongoo::GridFs::File.new(container, db_lambda)
23
+ instance_variable_set("@#{name}", file)
24
+ end
25
+ }
26
+ @klass.send(:define_method, name, &blk)
27
+ end # define_grid_fs_file_methods
28
+
29
+ def define_grid_fs_files_method(name, opts)
30
+ attrib_name = "gridfs_#{name}"
31
+ attribute(attrib_name, :type => :hash)
32
+
33
+ blk = Proc.new {
34
+ if files = instance_variable_get("@#{name}")
35
+ files
36
+ else
37
+ db_lambda = opts[:db] || lambda { self.db }
38
+ container = get_or_set(attrib_name, {})
39
+ files = Mongoo::GridFs::Files.new(container, db_lambda)
40
+ instance_variable_set("@#{name}", files)
41
+ end
42
+ }
43
+ @klass.send(:define_method, name, &blk)
44
+ end
45
+ end # DescribeDsl
46
+ end # GridFs
47
+ end # Mongoo
48
+
49
+ class Mongoo::DescribeDsl
50
+ include Mongoo::GridFs::DescribeDsl
51
+ end
@@ -0,0 +1,40 @@
1
+ module Mongoo
2
+ module GridFs
3
+
4
+ class File
5
+ def initialize(container_hash, db_lambda)
6
+ @db_lambda = db_lambda
7
+ @container_hash = container_hash
8
+ end
9
+
10
+ def grid
11
+ @grid ||= Mongo::Grid.new(@db_lambda.call)
12
+ end
13
+
14
+ def put(*args)
15
+ @container_hash["_id"] = grid.put(*args)
16
+ end
17
+
18
+ def delete(*args)
19
+ if file_id = @container_hash["_id"]
20
+ args ||= []
21
+ args.unshift file_id
22
+ res = grid.delete(*args)
23
+ @container_hash.clear
24
+ res
25
+ end
26
+ end
27
+
28
+ def get(*args)
29
+ if file_id = @container_hash["_id"]
30
+ args ||= []
31
+ args.unshift file_id
32
+ if io = grid.get(*args)
33
+ io.read
34
+ end
35
+ end
36
+ end
37
+ end # File
38
+
39
+ end
40
+ end
@@ -0,0 +1,34 @@
1
+ module Mongoo
2
+ module GridFs
3
+
4
+ class Files
5
+ def initialize(container_hash, db_lambda)
6
+ @db_lambda = db_lambda
7
+ @container_hash = container_hash
8
+ end
9
+
10
+ def get(*args)
11
+ key = args.shift
12
+ if @container_hash[key]
13
+ Mongoo::GridFs::File.new(@container_hash[key], @db_lambda).get(*args)
14
+ end
15
+ end
16
+
17
+ def put(*args)
18
+ key = args.shift
19
+ unless @container_hash[key]
20
+ @container_hash[key] = {}
21
+ end
22
+ Mongoo::GridFs::File.new(@container_hash[key], @db_lambda).put(*args)
23
+ end
24
+
25
+ def delete(*args)
26
+ key = args.shift
27
+ if @container_hash[key]
28
+ Mongoo::GridFs::File.new(@container_hash[key], @db_lambda).delete(*args)
29
+ end
30
+ end
31
+ end # Files
32
+
33
+ end
34
+ end
@@ -123,7 +123,8 @@ module Mongoo
123
123
  end
124
124
 
125
125
  def index_meta
126
- Mongoo::INDEX_META[self.collection_name] ||= {}
126
+ return @index_meta if @index_meta
127
+ @index_meta = {}
127
128
  end
128
129
 
129
130
  def index(spec, opts={})
@@ -138,6 +139,18 @@ module Mongoo
138
139
  end
139
140
  end # ClassMethods
140
141
 
142
+ def db
143
+ self.class.db
144
+ end
145
+
146
+ def conn
147
+ self.class.conn
148
+ end
149
+
150
+ def collection_name
151
+ self.class.collection_name
152
+ end
153
+
141
154
  def to_param
142
155
  persisted? ? get("_id").to_s : nil
143
156
  end
data/mongoo.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongoo}
8
- s.version = "0.4.10"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Ben Myles"]
12
- s.date = %q{2011-06-08}
12
+ s.date = %q{2011-06-10}
13
13
  s.description = %q{Simple object mapper for MongoDB}
14
14
  s.email = %q{ben.myles@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -28,12 +28,20 @@ Gem::Specification.new do |s|
28
28
  "lib/mongoo.rb",
29
29
  "lib/mongoo/attribute_proxy.rb",
30
30
  "lib/mongoo/attribute_sanitizer.rb",
31
+ "lib/mongoo/attributes.rb",
32
+ "lib/mongoo/attributes/describe_dsl.rb",
31
33
  "lib/mongoo/base.rb",
32
34
  "lib/mongoo/changelog.rb",
33
35
  "lib/mongoo/core.rb",
34
36
  "lib/mongoo/cursor.rb",
37
+ "lib/mongoo/describe_dsl.rb",
35
38
  "lib/mongoo/embedded/base.rb",
39
+ "lib/mongoo/embedded/core_mixin.rb",
40
+ "lib/mongoo/embedded/describe_dsl.rb",
36
41
  "lib/mongoo/embedded/hash_proxy.rb",
42
+ "lib/mongoo/grid_fs/describe_dsl.rb",
43
+ "lib/mongoo/grid_fs/file.rb",
44
+ "lib/mongoo/grid_fs/files.rb",
37
45
  "lib/mongoo/hash_ext.rb",
38
46
  "lib/mongoo/identity_map.rb",
39
47
  "lib/mongoo/modifiers.rb",
@@ -43,6 +51,7 @@ Gem::Specification.new do |s|
43
51
  "test/helper.rb",
44
52
  "test/test_activemodel.rb",
45
53
  "test/test_embedded.rb",
54
+ "test/test_grid_fs.rb",
46
55
  "test/test_identity_map.rb",
47
56
  "test/test_mongohash.rb",
48
57
  "test/test_mongoo.rb",
@@ -57,6 +66,7 @@ Gem::Specification.new do |s|
57
66
  "test/helper.rb",
58
67
  "test/test_activemodel.rb",
59
68
  "test/test_embedded.rb",
69
+ "test/test_grid_fs.rb",
60
70
  "test/test_identity_map.rb",
61
71
  "test/test_mongohash.rb",
62
72
  "test/test_mongoo.rb",
data/test/helper.rb CHANGED
@@ -20,25 +20,28 @@ Mongoo.conn = lambda { Mongo::Connection.new("localhost", 27017, :pool_size => 5
20
20
  Mongoo.db = "mongoo-test"
21
21
 
22
22
  class SearchIndex < Mongoo::Base
23
- attribute "terms", :type => :array
24
- index "terms"
23
+ describe do |d|
24
+ d.attribute "terms", :type => :array
25
+ d.index "terms"
26
+ end
25
27
  end
26
28
 
27
29
  class Person < Mongoo::Base
28
- attribute "name", :type => :string
29
- attribute "visits", :type => :integer
30
- attribute "interests", :type => :array
31
- attribute "jobs.total", :type => :integer
32
- attribute "jobs.professional", :type => :array
33
- attribute "jobs.volunteer", :type => :array
34
- attribute "jobs.internships.high_school", :type => :array
35
- attribute "location.city", :type => :string
36
- attribute "location.demographics.crime_rate", :type => :symbol
37
- attribute "location.demographics.education_quality", :type => :symbol
38
- attribute "misc", :type => :hash
39
-
40
- index "name"
41
- index "location.city"
30
+ describe do |d|
31
+ d.attribute "name", :type => :string
32
+ d.attribute "visits", :type => :integer
33
+ d.attribute "interests", :type => :array
34
+ d.attribute "jobs.total", :type => :integer
35
+ d.attribute "jobs.professional", :type => :array
36
+ d.attribute "jobs.volunteer", :type => :array
37
+ d.attribute "jobs.internships.high_school", :type => :array
38
+ d.attribute "location.city", :type => :string
39
+ d.attribute "location.demographics.crime_rate", :type => :symbol
40
+ d.attribute "location.demographics.education_quality", :type => :symbol
41
+ d.attribute "misc", :type => :hash
42
+ d.index "name"
43
+ d.index "location.city"
44
+ end
42
45
  end
43
46
 
44
47
  class SpacePerson < Mongoo::Base
@@ -46,13 +49,15 @@ class SpacePerson < Mongoo::Base
46
49
  end
47
50
 
48
51
  class TvShow < Mongoo::Base
49
- attribute "name", :type => :string
50
- attribute "cast.director", :type => :string
51
- attribute "cast.lead", :type => :string
52
- attribute "rating", :type => :float
53
- attribute "comments", :type => :array
54
-
55
- index "name"
52
+ describe do |d|
53
+ d.attribute "name", :type => :string
54
+ d.attribute "cast.director", :type => :string
55
+ d.attribute "cast.lead", :type => :string
56
+ d.attribute "rating", :type => :float
57
+ d.attribute "comments", :type => :array
58
+ d.index "name"
59
+ d.index "cast.director"
60
+ end
56
61
 
57
62
  validates_presence_of "name"
58
63
  validates_presence_of "cast.director"
@@ -1,40 +1,43 @@
1
1
  require 'helper'
2
2
 
3
3
  class Book < Mongoo::Base
4
- attribute "title", :type => :string
5
-
6
- attribute "chapters", :type => :hash
7
- attribute "authors", :type => :hash
8
- attribute "sample_chapter", :type => :hash
9
- attribute "purchases", :type => :hash
10
-
11
- embeds_one "sample_chapter", :as => "sample_chapter", :class => "Book::Chapter"
12
- embeds_many "chapters", :as => "chapters", :class => 'Book::Chapter'
13
- embeds_many "authors", :as => "authors", :class => 'Book::Author'
14
- embeds_many "purchases", :as => "purchases", :class => 'Book::Purchase'
4
+ describe do |d|
5
+ d.attribute "title", :type => :string
6
+ d.embeds_one "sample_chapter", :class => "Book::Chapter"
7
+ d.embeds_many "chapters", :class => 'Book::Chapter'
8
+ d.embeds_many "authors", :class => 'Book::Author'
9
+ d.embeds_many "purchases", :class => 'Book::Purchase'
10
+ end
15
11
  end
16
12
 
17
13
  class Book::Chapter < Mongoo::Embedded::Base
18
- attribute "title", :type => :string
14
+ describe do |d|
15
+ d.attribute "title", :type => :string
16
+ end
19
17
  end
20
18
 
21
19
  class Book::Author < Mongoo::Embedded::Base
22
- attribute "first_name", :type => :string
23
- attribute "last_name", :type => :string
20
+ describe do |d|
21
+ d.attribute "first_name", :type => :string
22
+ d.attribute "last_name", :type => :string
23
+ end
24
24
  end
25
25
 
26
26
  class Book::Purchase < Mongoo::Embedded::Base
27
- attribute "payment_type", :type => :string
28
-
29
- attribute "customer", :type => :hash
30
- embeds_one "customer", :as => "customer", :class => 'Book::Purchase::Customer'
27
+ describe do |d|
28
+ d.attribute "payment_type", :type => :string
29
+ d.embeds_one "customer", :class => 'Book::Purchase::Customer'
30
+ end
31
31
 
32
32
  validates_presence_of :payment_type
33
33
  end
34
34
 
35
35
  class Book::Purchase::Customer < Mongoo::Embedded::Base
36
- attribute "name", :type => :string
37
- attribute "phone", :type => :string
36
+ describe do |d|
37
+ d.attribute "name", :type => :string
38
+ d.attribute "phone", :type => :string
39
+ end
40
+
38
41
  validates_presence_of :name
39
42
  validates_presence_of :phone
40
43
  end
@@ -68,11 +71,11 @@ class TestEmbedded < Test::Unit::TestCase
68
71
  b = Book.new(title: "BASE Jumping Basics")
69
72
  b.sample_chapter = Book::Chapter.new(b, {})
70
73
  b.sample_chapter.title = "Understanding the Risks"
71
- assert_equal "Understanding the Risks", b.g('sample_chapter')['title']
74
+ assert_equal "Understanding the Risks", b.g('embedded_sample_chapter')['title']
72
75
  b.insert!
73
76
  b = Book.find_one(b.id)
74
77
  assert_equal "Understanding the Risks", b.sample_chapter.title
75
- assert_equal "Understanding the Risks", b.g('sample_chapter')['title']
78
+ assert_equal "Understanding the Risks", b.g('embedded_sample_chapter')['title']
76
79
  end
77
80
 
78
81
  should "validate embedded docs and can have nested embeds" do
@@ -82,7 +85,7 @@ class TestEmbedded < Test::Unit::TestCase
82
85
  purchase_id = BSON::ObjectId.new.to_s
83
86
  b.purchases[purchase_id] = b.purchases.build({})
84
87
  assert !b.valid?
85
- assert_equal({:"purchases.#{purchase_id}.payment_type"=>["can't be blank"]}, b.errors)
88
+ assert_equal({:"embedded_purchases.#{purchase_id}.payment_type"=>["can't be blank"]}, b.errors)
86
89
  b.purchases[purchase_id].payment_type = "Cash"
87
90
  assert b.valid?
88
91
  b.update!
@@ -93,14 +96,14 @@ class TestEmbedded < Test::Unit::TestCase
93
96
  b.purchases[purchase_id].customer = Book::Purchase::Customer.new(b.purchases[purchase_id], name: "Jiminy")
94
97
  assert_equal "Jiminy", b.purchases[purchase_id].customer.name
95
98
  assert !b.valid?
96
- assert_equal({:"purchases.#{purchase_id}.customer.phone"=>["can't be blank"]}, b.errors)
99
+ assert_equal({:"embedded_purchases.#{purchase_id}.embedded_customer.phone"=>["can't be blank"]}, b.errors)
97
100
  b.purchases[purchase_id].customer.phone = "123"
98
101
  assert b.valid?
99
102
  b.update!
100
103
  b = Book.find_one(b.id)
101
104
  assert_equal "Jiminy", b.purchases[purchase_id].customer.name
102
105
  b.purchases[purchase_id].customer = nil
103
- assert_equal [[:unset, "purchases.#{purchase_id}.customer", 1]], b.changelog
106
+ assert_equal [[:unset, "embedded_purchases.#{purchase_id}.embedded_customer", 1]], b.changelog
104
107
  b.update!
105
108
  b = Book.find_one(b.id)
106
109
  assert_nil b.purchases[purchase_id].customer
@@ -0,0 +1,91 @@
1
+ require 'helper'
2
+
3
+ class Email < Mongoo::Base
4
+ include Mongoo::GridFs
5
+
6
+ describe do |d|
7
+ d.attribute "subject", :type => :string
8
+ d.embeds_one "attachment", :class => "Email::Attachment"
9
+ d.grid_fs_file "raw_message"
10
+ d.grid_fs_files "notes"
11
+ end
12
+ end
13
+
14
+ class Email::Attachment < Mongoo::Embedded::Base
15
+ include Mongoo::GridFs
16
+
17
+ describe do |d|
18
+ d.attribute "filename", :type => :string
19
+ d.grid_fs_file "data"
20
+ end
21
+ end
22
+
23
+ class Image < Mongoo::Base
24
+ include Mongoo::GridFs
25
+ end
26
+
27
+ class TestGridFs < Test::Unit::TestCase
28
+
29
+ def setup
30
+ [Email].each do |obj|
31
+ obj.drop
32
+ obj.create_indexes
33
+ end
34
+ end
35
+
36
+ should "be able to use a file in a normal doc" do
37
+ e = Email.new(subject: "Hello, World!")
38
+ assert_equal Mongoo::GridFs::File, e.raw_message.class
39
+ assert_nil e.raw_message.get
40
+ assert_nil e.raw_message.delete
41
+ file_id = e.raw_message.put "Welcome to GridFS!"
42
+ assert file_id.is_a?(BSON::ObjectId)
43
+ assert_equal "Welcome to GridFS!", e.raw_message.get
44
+ e.insert!
45
+ assert_equal "Welcome to GridFS!", e.raw_message.get
46
+
47
+ e = Email.find_one(e.id)
48
+ assert_equal "Welcome to GridFS!", e.raw_message.get
49
+ e.raw_message.delete
50
+ assert_nil e.raw_message.get
51
+ e.update!
52
+
53
+ e = Email.find_one(e.id)
54
+ assert_nil e.raw_message.get
55
+ end
56
+
57
+ should "be able to use a file in an embedded doc" do
58
+ e = Email.new(subject: "Hello, World!")
59
+ e.attachment = Email::Attachment.new(e, {filename: "secret.txt"})
60
+ assert_nil e.attachment.data.get
61
+ e.attachment.data.put "super secret message"
62
+ assert_equal "super secret message", e.attachment.data.get
63
+ e.attachment.save!
64
+
65
+ e = Email.find_one(e.id)
66
+ assert_equal "super secret message", e.attachment.data.get
67
+ e.attachment.data.delete
68
+ assert_nil e.attachment.data.get
69
+ e.save!
70
+
71
+ e = Email.find_one(e.id)
72
+ assert_nil e.attachment.data.get
73
+ end
74
+
75
+ should "be able to have multiple files keyed under a hash" do
76
+ e = Email.new(subject: "Hello, World!")
77
+ assert_equal Mongoo::GridFs::Files, e.notes.class
78
+ assert_nil e.notes.get("monday")
79
+ e.notes.put("tuesday", "Tuesday is a good day.")
80
+ assert_equal "Tuesday is a good day.", e.notes.get("tuesday")
81
+ e.insert!
82
+ e = Email.find_one(e.id)
83
+ assert_equal "Tuesday is a good day.", e.notes.get("tuesday")
84
+ e.notes.delete("tuesday")
85
+ assert_nil e.notes.get("tuesday")
86
+ e.update!
87
+ e = Email.find_one(e.id)
88
+ assert_nil e.notes.get("tuesday")
89
+ end
90
+
91
+ end
data/test/test_mongoo.rb CHANGED
@@ -9,6 +9,22 @@ class TestMongoo < Test::Unit::TestCase
9
9
  end
10
10
  end
11
11
 
12
+ should "respond to the correct attributes" do
13
+ assert Person.new.respond_to?("jobs")
14
+ assert !Person.new.respond_to?("cast")
15
+
16
+ assert !TvShow.new.respond_to?("jobs")
17
+ assert TvShow.new.respond_to?("cast")
18
+ end
19
+
20
+ should "have the right index meta" do
21
+ assert Person.index_meta["location.city"]
22
+ assert !Person.index_meta["cast.director"]
23
+
24
+ assert !TvShow.index_meta["location.city"]
25
+ assert TvShow.index_meta["cast.director"]
26
+ end
27
+
12
28
  should "be able to use a different db for each model" do
13
29
  assert_equal "mongoo-test", Mongoo.db.name
14
30
  assert_equal "mongoo-test", Person.db.name
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.10
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-06-08 00:00:00.000000000 -07:00
12
+ date: 2011-06-10 00:00:00.000000000 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: i18n
17
- requirement: &2161066080 !ruby/object:Gem::Requirement
17
+ requirement: &2151904720 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 0.4.1
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2161066080
25
+ version_requirements: *2151904720
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: activesupport
28
- requirement: &2161063520 !ruby/object:Gem::Requirement
28
+ requirement: &2151902760 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ! '>='
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 3.0.3
34
34
  type: :runtime
35
35
  prerelease: false
36
- version_requirements: *2161063520
36
+ version_requirements: *2151902760
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: activemodel
39
- requirement: &2161062040 !ruby/object:Gem::Requirement
39
+ requirement: &2151899180 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 3.0.3
45
45
  type: :runtime
46
46
  prerelease: false
47
- version_requirements: *2161062040
47
+ version_requirements: *2151899180
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: mongo
50
- requirement: &2161060660 !ruby/object:Gem::Requirement
50
+ requirement: &2151897040 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ~>
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 1.3.1
56
56
  type: :runtime
57
57
  prerelease: false
58
- version_requirements: *2161060660
58
+ version_requirements: *2151897040
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: ruby-debug19
61
- requirement: &2161059080 !ruby/object:Gem::Requirement
61
+ requirement: &2151896120 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: '0'
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *2161059080
69
+ version_requirements: *2151896120
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: shoulda
72
- requirement: &2161047120 !ruby/object:Gem::Requirement
72
+ requirement: &2151893780 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ! '>='
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: '0'
78
78
  type: :development
79
79
  prerelease: false
80
- version_requirements: *2161047120
80
+ version_requirements: *2151893780
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: bundler
83
- requirement: &2161045260 !ruby/object:Gem::Requirement
83
+ requirement: &2151891820 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ~>
@@ -88,10 +88,10 @@ dependencies:
88
88
  version: 1.0.0
89
89
  type: :development
90
90
  prerelease: false
91
- version_requirements: *2161045260
91
+ version_requirements: *2151891820
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: jeweler
94
- requirement: &2161041560 !ruby/object:Gem::Requirement
94
+ requirement: &2151888440 !ruby/object:Gem::Requirement
95
95
  none: false
96
96
  requirements:
97
97
  - - ~>
@@ -99,10 +99,10 @@ dependencies:
99
99
  version: 1.5.1
100
100
  type: :development
101
101
  prerelease: false
102
- version_requirements: *2161041560
102
+ version_requirements: *2151888440
103
103
  - !ruby/object:Gem::Dependency
104
104
  name: rcov
105
- requirement: &2161034660 !ruby/object:Gem::Requirement
105
+ requirement: &2151886720 !ruby/object:Gem::Requirement
106
106
  none: false
107
107
  requirements:
108
108
  - - ! '>='
@@ -110,10 +110,10 @@ dependencies:
110
110
  version: '0'
111
111
  type: :development
112
112
  prerelease: false
113
- version_requirements: *2161034660
113
+ version_requirements: *2151886720
114
114
  - !ruby/object:Gem::Dependency
115
115
  name: perftools.rb
116
- requirement: &2161031960 !ruby/object:Gem::Requirement
116
+ requirement: &2151884780 !ruby/object:Gem::Requirement
117
117
  none: false
118
118
  requirements:
119
119
  - - ! '>='
@@ -121,10 +121,10 @@ dependencies:
121
121
  version: '0'
122
122
  type: :development
123
123
  prerelease: false
124
- version_requirements: *2161031960
124
+ version_requirements: *2151884780
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: bson_ext
127
- requirement: &2161029140 !ruby/object:Gem::Requirement
127
+ requirement: &2151882520 !ruby/object:Gem::Requirement
128
128
  none: false
129
129
  requirements:
130
130
  - - ~>
@@ -132,7 +132,7 @@ dependencies:
132
132
  version: 1.3.1
133
133
  type: :development
134
134
  prerelease: false
135
- version_requirements: *2161029140
135
+ version_requirements: *2151882520
136
136
  description: Simple object mapper for MongoDB
137
137
  email: ben.myles@gmail.com
138
138
  executables: []
@@ -152,12 +152,20 @@ files:
152
152
  - lib/mongoo.rb
153
153
  - lib/mongoo/attribute_proxy.rb
154
154
  - lib/mongoo/attribute_sanitizer.rb
155
+ - lib/mongoo/attributes.rb
156
+ - lib/mongoo/attributes/describe_dsl.rb
155
157
  - lib/mongoo/base.rb
156
158
  - lib/mongoo/changelog.rb
157
159
  - lib/mongoo/core.rb
158
160
  - lib/mongoo/cursor.rb
161
+ - lib/mongoo/describe_dsl.rb
159
162
  - lib/mongoo/embedded/base.rb
163
+ - lib/mongoo/embedded/core_mixin.rb
164
+ - lib/mongoo/embedded/describe_dsl.rb
160
165
  - lib/mongoo/embedded/hash_proxy.rb
166
+ - lib/mongoo/grid_fs/describe_dsl.rb
167
+ - lib/mongoo/grid_fs/file.rb
168
+ - lib/mongoo/grid_fs/files.rb
161
169
  - lib/mongoo/hash_ext.rb
162
170
  - lib/mongoo/identity_map.rb
163
171
  - lib/mongoo/modifiers.rb
@@ -167,6 +175,7 @@ files:
167
175
  - test/helper.rb
168
176
  - test/test_activemodel.rb
169
177
  - test/test_embedded.rb
178
+ - test/test_grid_fs.rb
170
179
  - test/test_identity_map.rb
171
180
  - test/test_mongohash.rb
172
181
  - test/test_mongoo.rb
@@ -187,7 +196,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
187
196
  version: '0'
188
197
  segments:
189
198
  - 0
190
- hash: -2477631038074627607
199
+ hash: -2521719238518645958
191
200
  required_rubygems_version: !ruby/object:Gem::Requirement
192
201
  none: false
193
202
  requirements:
@@ -204,6 +213,7 @@ test_files:
204
213
  - test/helper.rb
205
214
  - test/test_activemodel.rb
206
215
  - test/test_embedded.rb
216
+ - test/test_grid_fs.rb
207
217
  - test/test_identity_map.rb
208
218
  - test/test_mongohash.rb
209
219
  - test/test_mongoo.rb