mongoo 0.4.10 → 0.5.0

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