mongo_thing 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.bundle/config ADDED
@@ -0,0 +1,3 @@
1
+ ---
2
+ BUNDLE_WITHOUT: ""
3
+ BUNDLE_PATH: development
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .DS_Store
2
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ # Use `bundle install` in order to install these gems
2
+ # Use `bundle exec rake` in order to run the specs using the bundle
3
+ source "http://rubygems.org"
4
+
5
+ gem "mongo", "~> 1.0"
6
+ gem "bson", "~> 1.0"
7
+ gem "bson_ext", "~> 1.0"
8
+ gem "activesupport", "3.0.0.beta3"
9
+
10
+ group :development do
11
+ gem "rake"
12
+ gem "ruby-debug"
13
+ gem "rspec", "1.3.0"
14
+ gem "jeweler"
15
+ end
data/MIT_LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Durran Jordan
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,36 @@
1
+ require "rubygems"
2
+ require "bundler"
3
+
4
+ begin
5
+ Bundler.require(:development)
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "mongo_thing"
8
+ gem.summary = "ODM framework for MongoDB"
9
+ gem.email = "daniel@flyingmachinestudios.com"
10
+ gem.homepage = ""
11
+ gem.authors = ["Daniel Higginbotham"]
12
+
13
+ gem.add_dependency("mongo", "~> 1.0.1")
14
+ gem.add_dependency("bson", "~> 1.0.1")
15
+ end
16
+
17
+ require "spec/rake/spectask"
18
+ Spec::Rake::SpecTask.new(:spec) do |spec|
19
+ spec.pattern = "spec/**/*_spec.rb"
20
+ spec.spec_opts = ["--options", "spec/spec.opts"]
21
+ end
22
+
23
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
24
+ spec.libs << "lib" << "spec"
25
+ spec.pattern = "spec/**/*_spec.rb"
26
+ spec.spec_opts = ["--options", "spec/spec.opts"]
27
+ spec.rcov = true
28
+ end
29
+
30
+ task :default => :spec do
31
+ end
32
+ rescue LoadError => e
33
+ puts "Error loading dependcy: #{e}."
34
+ end
35
+
36
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,82 @@
1
+ # encoding: utf-8
2
+ module MongoThing #:nodoc
3
+ class Cursor
4
+ include Enumerable
5
+ # Operations on the Mongo::Cursor object that will not get overriden by the
6
+ # MongoThing::Cursor are defined here.
7
+ OPERATIONS = [
8
+ :admin,
9
+ :close,
10
+ :closed?,
11
+ :count,
12
+ :explain,
13
+ :fields,
14
+ :full_collection_name,
15
+ :hint,
16
+ :limit,
17
+ :order,
18
+ :query_options_hash,
19
+ :query_opts,
20
+ :selector,
21
+ :skip,
22
+ :snapshot,
23
+ :sort,
24
+ :timeout
25
+ ]
26
+
27
+ attr_reader :collection
28
+
29
+ # The operations above will all delegate to the proxied Mongo::Cursor.
30
+ #
31
+ # Example:
32
+ #
33
+ # <tt>cursor.close</tt>
34
+ OPERATIONS.each do |name|
35
+ define_method(name) { |*args| @cursor.send(name, *args) }
36
+ end
37
+
38
+ # Iterate over each document in the cursor and yield to it.
39
+ #
40
+ # Example:
41
+ #
42
+ # <tt>cursor.each { |doc| p doc.title }</tt>
43
+ def each
44
+ @cursor.each do |document|
45
+ yield @klass.new(document)
46
+ end
47
+ end
48
+
49
+ # Create the new +MongoThing::Cursor+.
50
+ #
51
+ # Options:
52
+ #
53
+ # collection: The MongoThing::Collection instance.
54
+ # cursor: The Mongo::Cursor to be proxied.
55
+ #
56
+ # Example:
57
+ #
58
+ # <tt>MongoThing::Cursor.new(Person, cursor)</tt>
59
+ def initialize(klass, cursor)
60
+ @klass, @cursor = klass, cursor
61
+ end
62
+
63
+ # Return the next document in the cursor. Will instantiate a new MongoThing
64
+ # document with the attributes.
65
+ #
66
+ # Example:
67
+ #
68
+ # <tt>cursor.next_document</tt>
69
+ def next_document
70
+ @klass.new(@cursor.next_document)
71
+ end
72
+
73
+ # Returns an array of all the documents in the cursor.
74
+ #
75
+ # Example:
76
+ #
77
+ # <tt>cursor.to_a</tt>
78
+ def to_a
79
+ @cursor.to_a.collect { |attrs| @klass.new(attrs) }
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,176 @@
1
+ # encoding: utf-8
2
+ module MongoThing #:nodoc:
3
+ module Document
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class << self
8
+ attr_accessor :properties
9
+ def properties(*set)
10
+ if !set.empty?
11
+ @properties = set
12
+ else
13
+ @properties | [:_id]
14
+ end
15
+ end
16
+ end
17
+ self.properties = []
18
+
19
+ delegate :db, :collection, :to => "self.class"
20
+ end
21
+
22
+ module ClassMethods
23
+ # Return the database associated with this class.
24
+ def db
25
+ collection.db
26
+ end
27
+
28
+ def collection
29
+ MongoThing.db.collection(self.name)
30
+ end
31
+
32
+ # Finding
33
+ # Returns an array of Document objects
34
+ # Wonder if it would be desirable to expose the cursor?
35
+ def find(selector={}, opts={})
36
+ mongo_cursor = collection.find(selector, opts)
37
+ Cursor.new(self, mongo_cursor).to_a
38
+ end
39
+
40
+ def [](doc_id)
41
+ find_one(doc_id)
42
+ end
43
+
44
+ def find_one(spec_or_object_id=nil, opts={})
45
+ self.new(collection.find_one(spec_or_object_id, opts))
46
+ end
47
+
48
+ # Creating
49
+ def create(document)
50
+ self.new(document).save
51
+ end
52
+
53
+ # Deleting
54
+ def remove(selector={}, opts={})
55
+ collection.remove(selector, opts)
56
+ end
57
+ end
58
+
59
+ module InstanceMethods
60
+ # OpenStruct like behavior
61
+ def method_missing(mid, *args) # :nodoc:
62
+ mname = mid.id2name
63
+ chomped = mname.chomp('=')
64
+ len = args.length
65
+ if self.class.properties.include?(chomped.to_sym)
66
+ if mname == chomped && len > 0 || len > 1
67
+ raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
68
+ end
69
+ new_attribute(mname.chomp('='))
70
+ self.send(mid, *args)
71
+ else
72
+ raise NoMethodError, "undefined method `#{mname}' for #{self}", caller(1)
73
+ end
74
+ end
75
+
76
+ def new_attribute(name)
77
+ name = name.to_sym
78
+ unless self.respond_to?(name)
79
+ class << self; self; end.class_eval do
80
+ define_method(name) { @attributes.send(name) }
81
+ define_method("#{name}=") { |x| @attributes.send("#{name}=".to_sym, x) }
82
+ end
83
+ end
84
+ name
85
+ end
86
+
87
+ # Performs equality checking on the document ids. For more robust
88
+ # equality checking please override this method.
89
+ def ==(other)
90
+ return false unless other.is_a?(Document)
91
+ id == other.id
92
+ end
93
+
94
+ # Delegates to ==
95
+ def eql?(comparison_object)
96
+ self == (comparison_object)
97
+ end
98
+
99
+ def to_hash
100
+ @attributes.to_hash
101
+ end
102
+
103
+ # Clone the current +Document+. This will return all attributes with the
104
+ # exception of the document's id and versions.
105
+ def clone
106
+ self.class.instantiate(@attributes.except("_id").except("versions").dup, true)
107
+ end
108
+
109
+
110
+ # Instantiate a new +Document+, setting the Document's attributes if
111
+ # given. If no attributes are provided, they will be initialized with
112
+ # an empty +Hash+.
113
+ #
114
+ # If a primary key is defined, the document's id will be set to that key,
115
+ # otherwise it will be set to a fresh +BSON::ObjectID+ string.
116
+ #
117
+ # Options:
118
+ #
119
+ # attrs: The attributes +Hash+ to set up the document with.
120
+ def initialize(attrs = {})
121
+ @attributes = NestedOpenStruct.new
122
+ self.attributes = attrs
123
+ @new_record = true if id.nil?
124
+ end
125
+
126
+ def attributes=(attrs={})
127
+ attrs.each do |k,v|
128
+ self.send("#{k}=", v)
129
+ end
130
+ end
131
+
132
+ # Returns the class name plus its attributes.
133
+ def inspect
134
+ attrs = fields.map { |name, field| "#{name}: #{@attributes[name].inspect}" }
135
+ if Mongoid.allow_dynamic_fields
136
+ dynamic_keys = @attributes.keys - fields.keys - ["_id", "_type"]
137
+ attrs += dynamic_keys.map { |name| "#{name}: #{@attributes[name].inspect}" }
138
+ end
139
+ "#<#{self.class.name} _id: #{id}, #{attrs * ', '}>"
140
+ end
141
+
142
+ # Reloads the +Document+ attributes from the database.
143
+ def reload
144
+ if self.id
145
+ self.attributes = self.class[self.id].to_hash
146
+ else
147
+ raise ArgumentError, "this document has not been saved"
148
+ end
149
+ end
150
+
151
+ # Return an array with this +Document+ only in it.
152
+ def to_a
153
+ [ self ]
154
+ end
155
+
156
+ # Returns the id of the Document, used in Rails compatibility.
157
+ def to_param
158
+ id
159
+ end
160
+
161
+ def id
162
+ @attributes._id
163
+ end
164
+
165
+ def id=(new_id)
166
+ @attributes._id = new_id
167
+ end
168
+
169
+ def save
170
+ @attributes._id = BSON::ObjectID.new if @attributes._id.nil?
171
+ collection.save(self.to_hash)
172
+ self
173
+ end
174
+ end
175
+ end
176
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module NamedScope
4
+ # Creates a named_scope for the +Document+, similar to ActiveRecord's
5
+ # named_scopes. +NamedScopes+ are proxied +Criteria+ objects that can be
6
+ # chained.
7
+ #
8
+ # Example:
9
+ #
10
+ # class Person
11
+ # include Mongoid::Document
12
+ # field :active, :type => Boolean
13
+ # field :count, :type => Integer
14
+ #
15
+ # named_scope :active, :where => { :active => true }
16
+ # named_scope :count_gt_one, :where => { :count.gt => 1 }
17
+ # named_scope :at_least_count, lambda { |count| { :where => { :count.gt => count } } }
18
+ # end
19
+ def named_scope(name, options = {}, &block)
20
+ name = name.to_sym
21
+ scopes[name] = lambda do |parent, *args|
22
+ Scope.new(parent, options.scoped(*args), &block)
23
+ end
24
+ (class << self; self; end).class_eval <<-EOT
25
+ def #{name}(*args)
26
+ scopes[:#{name}].call(self, *args)
27
+ end
28
+ EOT
29
+ end
30
+ alias :scope :named_scope
31
+
32
+ # Return the scopes or default to an empty +Hash+.
33
+ def scopes
34
+ read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {})
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,49 @@
1
+ # NestedOpenStruct works like OpenStruct except that all hash values are converted
2
+ # to NestedOpenStruct
3
+
4
+ module MongoThing
5
+ class NestedOpenStruct < OpenStruct
6
+ def initialize(hash=nil)
7
+ @table = {}
8
+ @nested_open_structs = []
9
+ if hash
10
+ for k,v in hash
11
+ v = NestedOpenStruct.new(v) if v.is_a? Hash
12
+ v = v.collect{|nv| nv.is_a?(Hash) ? NestedOpenStruct.new(nv) : nv} if v.is_a?(Array)
13
+ @table[k.to_sym] = v
14
+ new_ostruct_member(k)
15
+ end
16
+ end
17
+ end
18
+
19
+ def method_missing(mid, *args) # :nodoc:
20
+ mname = mid.id2name
21
+ if mname[-1..-1] == "=" && args[0] && args[0].is_a?(Hash)
22
+ args[0] = NestedOpenStruct.new(args[0])
23
+ end
24
+ super
25
+ end
26
+
27
+ def to_hash
28
+ marshal_dump
29
+ end
30
+
31
+ def marshal_dump
32
+ @table.collect do |k,v|
33
+ n = if v.is_a?(NestedOpenStruct)
34
+ v.marshal_dump
35
+ elsif v.is_a?(Array)
36
+ v.collect{|a| a.is_a?(NestedOpenStruct) ? a.marshal_dump : a}
37
+ else
38
+ v
39
+ end
40
+ [k,n]
41
+ end.inject({}){|h,v|h[v[0]] = v[1]; h}
42
+ end
43
+
44
+ def marshal_load(x)
45
+ @table = x
46
+ @table.each_key{|key| new_ostruct_member(key)}
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,53 @@
1
+ module Rails #:nodoc:
2
+ module MongoThing #:nodoc:
3
+ class Railtie < Rails::Railtie #:nodoc:
4
+
5
+ # do we want a custom log subscriber for mongoid?
6
+ # log_subscriber :mongoid, ::Mongoid::Railties::LogSubscriber.new
7
+
8
+ rake_tasks do
9
+ load "mongo-thing/railties/database.rake"
10
+ end
11
+
12
+ # Initialize Mongoid. This will look for a mongoid.yml in the config
13
+ # directory and configure mongoid appropriately.
14
+ #
15
+ # Example mongoid.yml:
16
+ #
17
+ # defaults: &defaults
18
+ # host: localhost
19
+ # slaves:
20
+ # # - host: localhost
21
+ # # port: 27018
22
+ # # - host: localhost
23
+ # # port: 27019
24
+ # allow_dynamic_fields: false
25
+ # parameterize_keys: false
26
+ # persist_in_safe_mode: false
27
+ #
28
+ # development:
29
+ # <<: *defaults
30
+ # database: mongoid
31
+ initializer "setup database" do
32
+ config_file = Rails.root.join("config", "mongoid.yml")
33
+ if config_file.file?
34
+ settings = YAML.load(ERB.new(config_file.read).result)[Rails.env]
35
+ ::MongoThing.connection = settings if settings.present?
36
+ end
37
+ end
38
+
39
+ initializer "verify that mongoid is configured" do
40
+ config.after_initialize do
41
+ begin
42
+ ::Mongoid.master
43
+ rescue ::Mongoid::Errors::InvalidDatabase => e
44
+ unless Rails.root.join("config", "mongoid.yml").file?
45
+ puts "\nMongoid config not found. Create a config file at: config/mongoid.yml"
46
+ puts "to generate one run: script/rails generate mongoid:config\n\n"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,37 @@
1
+ namespace :db do
2
+
3
+ desc 'Drops all the collections for the database for the current Rails.env'
4
+ task :drop => :environment do
5
+ Mongoid.master.collections.each{|col| col.drop unless col.name == 'system.users' }
6
+ end
7
+
8
+ desc 'Load the seed data from db/seeds.rb'
9
+ task :seed => :environment do
10
+ seed_file = File.join(Rails.root, 'db', 'seeds.rb')
11
+ load(seed_file) if File.exist?(seed_file)
12
+ end
13
+
14
+ desc 'Create the database, and initialize with the seed data'
15
+ task :setup => [ 'db:create', 'db:seed' ]
16
+
17
+ desc 'Delete data and seed'
18
+ task :reseed => [ 'db:drop', 'db:seed' ]
19
+
20
+ task :create => :environment do
21
+ # noop
22
+ end
23
+
24
+ task :migrate => :environment do
25
+ # noop
26
+ end
27
+
28
+ namespace :schema do
29
+ task :load do
30
+ # noop
31
+ end
32
+ end
33
+
34
+ ########
35
+ # TODO: lots more useful db tasks can be added here. stuff like copyDatabase, etc
36
+ ########
37
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+ # Copyright (c) 2010 Daniel Higginbotham
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ require 'rubygems'
24
+ require 'bundler'
25
+ Bundler.setup(:default)
26
+ require 'active_support/core_ext'
27
+ require 'bson'
28
+ require 'ostruct'
29
+
30
+ $:.unshift(File.expand_path(File.dirname(__FILE__)))
31
+ require 'mongo_thing/cursor'
32
+ require 'mongo_thing/document'
33
+ require 'mongo_thing/nested_ostruct'
34
+
35
+
36
+ module MongoThing #:nodoc
37
+
38
+ class << self
39
+ attr_accessor :connection, :db
40
+ def connection=(conn)
41
+ case conn
42
+ when Hash
43
+ @connection = Mongo::Connection.new(conn.delete(:host), conn.delete(:port), conn)
44
+ when Mongo::Connection
45
+ @connection = conn
46
+ end
47
+ self.db = conn if conn[:name]
48
+ end
49
+
50
+ def db=(new_db)
51
+ case new_db
52
+ when String, Symbol
53
+ @db = connection.db(new_db.to_s)
54
+ when Hash
55
+ @db = connection.db(new_db[:name], new_db)
56
+ when Mongo::DB
57
+ @db = new_db
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+
64
+ end
@@ -0,0 +1,64 @@
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{mongo_thing}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Daniel Higginbotham"]
12
+ s.date = %q{2010-05-09}
13
+ s.email = %q{daniel@flyingmachinestudios.com}
14
+ s.files = [
15
+ ".bundle/config",
16
+ ".gitignore",
17
+ "Gemfile",
18
+ "MIT_LICENSE",
19
+ "Rakefile",
20
+ "VERSION",
21
+ "lib/mongo_thing.rb",
22
+ "lib/mongo_thing/cursor.rb",
23
+ "lib/mongo_thing/document.rb",
24
+ "lib/mongo_thing/named_scope.rb",
25
+ "lib/mongo_thing/nested_ostruct.rb",
26
+ "lib/mongo_thing/railtie.rb",
27
+ "lib/mongo_thing/railties/database.rake",
28
+ "mongo_thing.gemspec",
29
+ "spec/config/mongoid.yml",
30
+ "spec/integration/mongo_thing/document_spec.rb",
31
+ "spec/integration/mongo_thing/nested_ostruct_spec.rb",
32
+ "spec/integration/mongo_thing_spec.rb",
33
+ "spec/spec.opts",
34
+ "spec/spec_helper.rb"
35
+ ]
36
+ s.homepage = %q{}
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.require_paths = ["lib"]
39
+ s.rubygems_version = %q{1.3.6}
40
+ s.summary = %q{ODM framework for MongoDB}
41
+ s.test_files = [
42
+ "spec/integration/mongo_thing/document_spec.rb",
43
+ "spec/integration/mongo_thing/nested_ostruct_spec.rb",
44
+ "spec/integration/mongo_thing_spec.rb",
45
+ "spec/spec_helper.rb"
46
+ ]
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 3
51
+
52
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
+ s.add_runtime_dependency(%q<mongo>, ["~> 1.0.1"])
54
+ s.add_runtime_dependency(%q<bson>, ["~> 1.0.1"])
55
+ else
56
+ s.add_dependency(%q<mongo>, ["~> 1.0.1"])
57
+ s.add_dependency(%q<bson>, ["~> 1.0.1"])
58
+ end
59
+ else
60
+ s.add_dependency(%q<mongo>, ["~> 1.0.1"])
61
+ s.add_dependency(%q<bson>, ["~> 1.0.1"])
62
+ end
63
+ end
64
+
@@ -0,0 +1,19 @@
1
+ :defaults: &defaults
2
+ :host: localhost
3
+ :slaves:
4
+ # - host: localhost
5
+ # port: 27018
6
+ # - host: localhost
7
+ # port: 27019
8
+ :allow_dynamic_fields: false
9
+ :parameterize_keys: false
10
+ :persist_in_safe_mode: false
11
+ :raise_not_found_error: false
12
+ :reconnect_time: 5
13
+ :use_object_ids: true
14
+ :persist_types: false
15
+ :option_no_exist: false
16
+
17
+ :test:
18
+ <<: *defaults
19
+ :name: mongo_thing_test
@@ -0,0 +1,143 @@
1
+ require 'spec_helper'
2
+
3
+ class Person
4
+ include MongoThing::Document
5
+ self.properties = [:name, :address, :friends]
6
+ end
7
+
8
+
9
+ describe MongoThing::Document do
10
+ describe "attributes" do
11
+ it "should only allow properties to be treated as attributes" do
12
+ p = Person.new
13
+ lambda{p.blarg = "Tom"}.should raise_error(NoMethodError)
14
+ end
15
+
16
+ it "should allow properties to be treated as attributes" do
17
+ p = Person.new
18
+ lambda{p.name = "Tom"}.should_not raise_error(NoMethodError)
19
+ end
20
+
21
+ it "should assign attributes in the initializer" do
22
+ p = Person.new({
23
+ :name => "Tom"
24
+ })
25
+ p.name.should == "Tom"
26
+ end
27
+
28
+ it "should raise an error when trying to assign a non-attribute in the initializer" do
29
+ lambda {
30
+ p = Person.new({
31
+ :name => "Tom",
32
+ :foo => "bar"
33
+ })
34
+ }.should raise_error(NoMethodError)
35
+ end
36
+
37
+ it "should return a hash of attributes" do
38
+ person_hash = {
39
+ :name => "Tom",
40
+ :address => {:street => "Tomahawk", :city => "Placeville"},
41
+ :friends => [
42
+ {:name => "John", :address => {:street => "Pleasant", :city => "Cityville"}},
43
+ {:name => "Bill", :address => {:street => "Prospect", :city => "Townville"}}
44
+ ]
45
+ }
46
+
47
+ p = Person.new(person_hash)
48
+ p.to_hash.should == person_hash
49
+ end
50
+
51
+ it "should set properties using properties method" do
52
+ class SetProperties
53
+ include MongoThing::Document
54
+ properties :one, :two, :three
55
+ end
56
+
57
+ lambda{SetProperties.new(:one => 1, :two => 2, :three => 3)}.should_not raise_error
58
+ end
59
+ end
60
+
61
+ describe "class modifications" do
62
+ it "should add the 'properties' attribute to class" do
63
+ Person.respond_to?(:properties).should be_true
64
+ end
65
+
66
+ it "should default 'properties' to [:_id]" do
67
+ class Bear
68
+ include MongoThing::Document
69
+ end
70
+
71
+ Bear.properties.should == [:_id]
72
+ end
73
+ end
74
+
75
+ describe "actual db interaction" do
76
+ before(:all) do
77
+ connect_to_test_database
78
+ end
79
+ describe "saving" do
80
+ it "should save a basic document" do
81
+ p = Person.new
82
+ p.name = "Tom"
83
+ p.save
84
+ end
85
+
86
+ it "should not have an ID before being saved" do
87
+ p = Person.new
88
+ p.id.should be_nil
89
+ end
90
+
91
+ it "should have an ID after being saved" do
92
+ p = Person.new
93
+ p.name = "Tom"
94
+ p.save
95
+ p.id.should_not be_nil
96
+ end
97
+
98
+ it "should save a document with 'create'" do
99
+ Person.create(:name => "Tom").id.should_not be_nil
100
+ end
101
+ end
102
+
103
+ describe "finding" do
104
+ it "should find a person given an ID" do
105
+ p = Person.new
106
+ p.name = "Tom"
107
+ p.save
108
+
109
+ h = Person[p.id]
110
+ h.name.should == "Tom"
111
+ h.id.should == p.id
112
+
113
+ i = Person.find_one(p.id)
114
+ i.name.should == "Tom"
115
+ i.id.should == p.id
116
+ end
117
+
118
+ it "should return all matching documents" do
119
+ Person.create(:name => "Tom")
120
+ Person.create(:name => "Voldemort")
121
+
122
+ r = Person.find.to_a
123
+ end
124
+
125
+ it "should initialize documents from find" do
126
+ Person.create(:name => "Tom")
127
+ Person.create(:name => "Voldemort")
128
+
129
+ r = Person.find.to_a
130
+ r[0].name.should == "Tom"
131
+ r[1].name.should == "Voldemort"
132
+ end
133
+
134
+ it "should reload a document" do
135
+ p = Person.create(:name => "Tom")
136
+
137
+ p.name = "Voldemort"
138
+ p.reload
139
+ p.name.should == "Tom"
140
+ end
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe MongoThing::NestedOpenStruct do
4
+ before(:each) do
5
+ @person_hash = {
6
+ :name => "Tom",
7
+ :address => {:street => "Tomahawk", :city => "Placeville"},
8
+ :friends => [
9
+ {:name => "John", :address => {:street => "Pleasant", :city => "Cityville"}},
10
+ {:name => "Bill", :address => {:street => "Prospect", :city => "Townville"}}
11
+ ]
12
+ }
13
+ end
14
+
15
+ it "should not modify original hash" do
16
+ MongoThing::NestedOpenStruct.new(@person_hash)
17
+
18
+ @person_hash.should == {
19
+ :name => "Tom",
20
+ :address => {:street => "Tomahawk", :city => "Placeville"},
21
+ :friends => [
22
+ {:name => "John", :address => {:street => "Pleasant", :city => "Cityville"}},
23
+ {:name => "Bill", :address => {:street => "Prospect", :city => "Townville"}}
24
+ ]
25
+ }
26
+ end
27
+
28
+ it "should convert a hash value to a nested open struct" do
29
+ p = MongoThing::NestedOpenStruct.new(@person_hash)
30
+
31
+ p.name.should == "Tom"
32
+ p.address.street.should == "Tomahawk"
33
+ p.address.city.should == "Placeville"
34
+ p.friends.size.should == 2
35
+ p.friends[0].name.should == "John"
36
+ p.friends[0].address.street.should == "Pleasant"
37
+ p.friends[0].address.city.should == "Cityville"
38
+ end
39
+
40
+ it "should convert NestedOpenStruct values to hashes when dumping" do
41
+ p = MongoThing::NestedOpenStruct.new(@person_hash)
42
+ p.marshal_dump.should == @person_hash
43
+ end
44
+
45
+ it "should respond identically to marshal_dump and to_hash" do
46
+ p = MongoThing::NestedOpenStruct.new(@person_hash)
47
+ p.marshal_dump.should == p.to_hash
48
+ end
49
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ # Connection is established in spec_helper
4
+ describe MongoThing do
5
+ describe "connection" do
6
+ it "should set the connection given a hash" do
7
+ MongoThing.connection.host.should == "localhost"
8
+ MongoThing.connection.size.should == 1
9
+ end
10
+
11
+ it "should set the database when a name is given in connection settings" do
12
+ MongoThing.db.should be_a Mongo::DB
13
+ end
14
+ end
15
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,3 @@
1
+ --colour
2
+ --format progress
3
+ --backtrace
@@ -0,0 +1,34 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.require(:default, :development)
4
+ require "mongo_thing"
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
8
+
9
+ MODELS = File.join(File.dirname(__FILE__), "models")
10
+ $LOAD_PATH.unshift(MODELS)
11
+
12
+
13
+ Dir[ File.join(MODELS, "*.rb") ].sort.each { |file| require File.basename(file) }
14
+
15
+ Spec::Runner.configure do |config|
16
+ config.before :suite do
17
+ connect_to_test_database
18
+ end
19
+
20
+ config.after(:each) do
21
+ MongoThing.db.collections.each(&:remove)
22
+ end
23
+
24
+ config.after :suite do
25
+ MongoThing.db.collections.each(&:drop)
26
+ end
27
+ end
28
+
29
+ # This is probably a very naive way to do thsi
30
+ def connect_to_test_database
31
+ config = File.read(File.join(File.dirname(__FILE__), 'config', 'mongoid.yml'))
32
+ settings = YAML.load(ERB.new(config).result)
33
+ MongoThing.connection = settings[:test] unless MongoThing.connection
34
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongo_thing
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Daniel Higginbotham
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-05-09 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ name: mongo
23
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 1
29
+ - 0
30
+ - 1
31
+ version: 1.0.1
32
+ requirement: *id001
33
+ prerelease: false
34
+ - !ruby/object:Gem::Dependency
35
+ type: :runtime
36
+ name: bson
37
+ version_requirements: &id002 !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ~>
40
+ - !ruby/object:Gem::Version
41
+ segments:
42
+ - 1
43
+ - 0
44
+ - 1
45
+ version: 1.0.1
46
+ requirement: *id002
47
+ prerelease: false
48
+ description:
49
+ email: daniel@flyingmachinestudios.com
50
+ executables: []
51
+
52
+ extensions: []
53
+
54
+ extra_rdoc_files: []
55
+
56
+ files:
57
+ - .bundle/config
58
+ - .gitignore
59
+ - Gemfile
60
+ - MIT_LICENSE
61
+ - Rakefile
62
+ - VERSION
63
+ - lib/mongo_thing.rb
64
+ - lib/mongo_thing/cursor.rb
65
+ - lib/mongo_thing/document.rb
66
+ - lib/mongo_thing/named_scope.rb
67
+ - lib/mongo_thing/nested_ostruct.rb
68
+ - lib/mongo_thing/railtie.rb
69
+ - lib/mongo_thing/railties/database.rake
70
+ - mongo_thing.gemspec
71
+ - spec/config/mongoid.yml
72
+ - spec/integration/mongo_thing/document_spec.rb
73
+ - spec/integration/mongo_thing/nested_ostruct_spec.rb
74
+ - spec/integration/mongo_thing_spec.rb
75
+ - spec/spec.opts
76
+ - spec/spec_helper.rb
77
+ has_rdoc: true
78
+ homepage: ""
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options:
83
+ - --charset=UTF-8
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ requirements: []
101
+
102
+ rubyforge_project:
103
+ rubygems_version: 1.3.6
104
+ signing_key:
105
+ specification_version: 3
106
+ summary: ODM framework for MongoDB
107
+ test_files:
108
+ - spec/integration/mongo_thing/document_spec.rb
109
+ - spec/integration/mongo_thing/nested_ostruct_spec.rb
110
+ - spec/integration/mongo_thing_spec.rb
111
+ - spec/spec_helper.rb