mongo_mapper_ext 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,68 @@
1
+ require 'rake'
2
+ require 'spec/rake/spectask'
3
+
4
+ Dir.chdir File.dirname(__FILE__)
5
+
6
+ # Specs
7
+ task :default => :spec
8
+
9
+ Spec::Rake::SpecTask.new('spec') do |t|
10
+ t.spec_files = FileList["spec/**/*_spec.rb"].select{|f| f !~ /\/_/}
11
+ t.libs = ['lib'].collect{|f| "#{File.dirname __FILE__}/#{f}"}
12
+ end
13
+
14
+ # Gem
15
+ require 'rake/clean'
16
+ require 'rake/gempackagetask'
17
+ require 'fileutils'
18
+
19
+ spec = Gem::Specification.new do |s|
20
+ s.name = "mongo_mapper_ext"
21
+ s.version = "0.0.1"
22
+ s.summary = "Extensions for MongoMapper"
23
+ s.description = "Extensions for MongoMapper"
24
+ s.author = "Alexey Petrushin"
25
+ # s.email = ""
26
+ s.homepage = "http://github.com/alexeypetrushin/mongo_mapper_ext"
27
+
28
+ s.platform = Gem::Platform::RUBY
29
+ s.has_rdoc = true
30
+ # s.extra_rdoc_files = ["README.rdoc"]
31
+
32
+ # s.files = (%w{rakefile readme.md .gitignore} + Dir.glob("{app,lib,spec,.git}/**/*"))
33
+ s.files = (['Rakefile', 'readme.md'] + Dir.glob("{lib,spec}/**/*"))
34
+
35
+ s.require_paths = ["lib"]
36
+
37
+ warn 'uncomment ruby_ext'
38
+ [
39
+ # 'ruby_ext',
40
+ 'mongo_mapper',
41
+ ].each{|name| s.add_dependency(name)}
42
+
43
+ end
44
+
45
+ PACKAGE_DIR = "#{File.expand_path File.dirname(__FILE__)}/build"
46
+
47
+ Rake::GemPackageTask.new(spec) do |p|
48
+ package_dir = PACKAGE_DIR
49
+ # FileUtils.mkdir package_dir unless File.exist? package_dir
50
+ p.need_tar = true if RUBY_PLATFORM !~ /mswin/
51
+ p.need_zip = true
52
+ p.package_dir = package_dir
53
+ end
54
+
55
+ # CLEAN.include [ 'pkg', '*.gem']
56
+
57
+ task :push do
58
+ dir = Dir.chdir PACKAGE_DIR do
59
+ gem_file = Dir.glob("mongo_mapper_ext*.gem").first
60
+ system "gem push #{gem_file}"
61
+ end
62
+ end
63
+
64
+ task :clean do
65
+ system "rm -r #{PACKAGE_DIR}"
66
+ end
67
+
68
+ task :release => [:gem, :push, :clean]
@@ -0,0 +1,67 @@
1
+ module MongoMapper
2
+ class ConnectionsPool < Hash
3
+ def [](database_alias)
4
+ database_alias = database_alias.to_s
5
+ unless connection = super(database_alias)
6
+ MongoMapper.db_config.must.include database_alias
7
+ db_options = MongoMapper.db_config[database_alias]
8
+ connection = Mongo::Connection.new(db_options['host'], db_options['port'], :logger => MongoMapper.logger)
9
+
10
+ if defined?(PhusionPassenger)
11
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
12
+ connection.connect_to_master if forked
13
+ end
14
+ end
15
+
16
+ self[database_alias] = connection
17
+ end
18
+ return connection
19
+ end
20
+ end
21
+
22
+ class DatabasesPool < Hash
23
+ def [](database_alias)
24
+ database_alias = database_alias.to_s
25
+ unless db = super(database_alias)
26
+ MongoMapper.db_config.must.include database_alias
27
+ db_options = MongoMapper.db_config[database_alias]
28
+ db = MongoMapper.connections[database_alias].db db_options['name'].must_be.a(String)
29
+ self[database_alias] = db
30
+ end
31
+ return db
32
+ end
33
+ end
34
+
35
+ class << self
36
+ attr_accessor :db_config
37
+
38
+ def db_config
39
+ # unless @db_config
40
+ #
41
+ # if defined?(::Rails) and defined?(DATABASE)
42
+ # @db_config = {}
43
+ # DATABASE["#{::Rails.env}!"].to_h.each do |db_alias, options|
44
+ # @db_config[db_alias.to_s] = {
45
+ # 'name' => options.name!,
46
+ # 'host' => options.host(nil),
47
+ # 'port' => options.port(nil)
48
+ # }
49
+ # end
50
+ # else
51
+ # @db_config = {}
52
+ # # raise "If you don't using Rails you must override this method and provide your own config!"
53
+ # end
54
+ # end
55
+ @db_config ||= {}
56
+ end
57
+
58
+ def connections
59
+ @connections ||= ConnectionsPool.new
60
+ end
61
+
62
+ def databases
63
+ @databases ||= DatabasesPool.new
64
+ end
65
+ end
66
+
67
+ end
@@ -0,0 +1,20 @@
1
+ #
2
+ # ObjectID
3
+ #
4
+ # Mongo::ObjectID.class_eval do
5
+ # def == other
6
+ # self.to_s == other.to_s
7
+ # end
8
+ #
9
+ # def to_yaml *args
10
+ # to_s.to_yaml *args
11
+ # end
12
+ # end
13
+
14
+ MongoMapper::Plugins::Associations::InArrayProxy.class_eval do
15
+ def delete(doc)
16
+ ids.delete(doc.id)
17
+ klass.delete(doc.id)
18
+ reset
19
+ end
20
+ end
@@ -0,0 +1,44 @@
1
+ # Measures MongoDB requests time and adds it to log
2
+
3
+ if defined?(Rails) and RAILS_ENV == 'development'
4
+ Mongo::Connection.class_eval do
5
+ def send_message_with_time operation, message, log_message=nil
6
+ begin
7
+ logger = @logger
8
+ @logger = nil
9
+ t = Time.now
10
+ send_message_without_time operation, message, log_message
11
+ ensure
12
+ logger.debug(" MONGODB (#{Time.now - t}) #{log_message || message}") if logger
13
+ @logger = logger
14
+ end
15
+ end
16
+ alias_method_chain :send_message, :time
17
+
18
+ def send_message_with_safe_check_with_time operation, message, db_name, log_message=nil
19
+ begin
20
+ logger = @logger
21
+ @logger = nil
22
+ t = Time.now
23
+ send_message_with_safe_check_without_time operation, message, db_name, log_message
24
+ ensure
25
+ logger.debug(" MONGODB (#{Time.now - t}) #{log_message || message}") if logger
26
+ @logger = logger
27
+ end
28
+ end
29
+ alias_method_chain :send_message_with_safe_check, :time
30
+
31
+ def receive_message_with_time operation, message, log_message=nil, socket=nil
32
+ begin
33
+ logger = @logger
34
+ @logger = nil
35
+ t = Time.now
36
+ receive_message_without_time operation, message, log_message, socket
37
+ ensure
38
+ logger.debug(" MONGODB (#{Time.now - t}) #{log_message || message}") if logger
39
+ @logger = logger
40
+ end
41
+ end
42
+ alias_method_chain :receive_message, :time
43
+ end
44
+ end
@@ -0,0 +1,53 @@
1
+ #
2
+ # upsert
3
+ #
4
+ Mongo::Collection.class_eval do
5
+ def upsert id, opt
6
+ opt.size.must == 1
7
+ opt.must_be.a Hash
8
+ opt.values.first.must_be.a Hash
9
+
10
+ update({:_id => id}, opt, {:upsert => true, :safe => true})
11
+ end
12
+ end
13
+
14
+
15
+ #
16
+ # silence logging
17
+ #
18
+ Mongo::Connection.class_eval do
19
+ attr_writer :logger
20
+ end
21
+
22
+ MongoMapper.class_eval do
23
+ def self.temporary_silince_logger &block
24
+ logger, nil_logger = self.logger, Logger.new(nil)
25
+
26
+ begin
27
+ MongoMapper.logger = nil_logger
28
+ connections.each do |name, connection|
29
+ connection.logger = nil_logger
30
+ end
31
+ block.call
32
+ ensure
33
+ MongoMapper.logger = logger
34
+ connections.each do |name, connection|
35
+ connection.logger = logger
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+ #
43
+ # Silence index creation
44
+ #
45
+ MongoMapper::Plugins::Indexes::ClassMethods.class_eval do
46
+ def ensure_index_with_silent_logger *args
47
+ MongoMapper.temporary_silince_logger do
48
+ ensure_index_without_silent_logger *args
49
+ end
50
+ end
51
+
52
+ alias_method_chain :ensure_index, :silent_logger
53
+ end
@@ -0,0 +1,33 @@
1
+ Rake::TaskManager.class_eval do
2
+ def remove_task(task_name)
3
+ @tasks.delete(task_name.to_s)
4
+ end
5
+ end
6
+
7
+ def remove_task(task_name)
8
+ Rake.application.remove_task(task_name)
9
+ end
10
+
11
+ namespace :db do
12
+
13
+ remove_task 'db:migrate'
14
+ desc "Migrate Database"
15
+ task :migrate => :environment do
16
+ ::Migration = MongoMapper::Migration
17
+ Dir["#{Rails.root}/lib/db/**/*.rb"].each{|f| require f.sub(/\.rb$/, '')}
18
+
19
+ database_alias = ENV['d'] || ENV['database']
20
+ database_alias = 'accounts' if database_alias.blank?
21
+
22
+ version = ENV['v'] || ENV['version']
23
+ if version.blank?
24
+ size = MongoMapper::Migration.definitions[database_alias].size
25
+ highest_defined_version = size == 0 ? 0 : size - 1
26
+ version = highest_defined_version
27
+ else
28
+ version = version.to_i
29
+ end
30
+
31
+ MongoMapper::Migration.update database_alias, version
32
+ end
33
+ end
@@ -0,0 +1,108 @@
1
+ module MongoMapper::Migration
2
+ class MigrationDefinition
3
+ def upgrade &block
4
+ if block
5
+ @upgrade = block
6
+ else
7
+ @upgrade
8
+ end
9
+ end
10
+ alias_method :up, :upgrade
11
+
12
+ def downgrade &block
13
+ if block
14
+ @downgrade = block
15
+ else
16
+ @downgrade
17
+ end
18
+ end
19
+ alias_method :down, :downgrade
20
+ end
21
+
22
+ class Logger
23
+ attr_accessor :enabled
24
+
25
+ def initialize enabled = true
26
+ self.enabled = enabled
27
+ end
28
+
29
+ def info message
30
+ puts message if enabled
31
+ end
32
+ end
33
+
34
+ class << self
35
+ def logger= logger
36
+ @logger = logger ? logger : Logger.new(false)
37
+ end
38
+
39
+ def logger; @logger ||= Logger.new end
40
+
41
+ def define database_alias, version, &block
42
+ database_alias = database_alias.to_s
43
+
44
+ version.must_be.a Integer
45
+ definition = MigrationDefinition.new
46
+ block.call definition
47
+ definitions[database_alias][version] = definition
48
+ end
49
+
50
+ def update database_alias, version
51
+ database_alias = database_alias.to_s
52
+ db = MongoMapper.databases[database_alias]
53
+
54
+ if metadata(db).version == version
55
+ logger.info "Database '#{database_alias}' already is of #{version} version, no migration needed."
56
+ return false
57
+ else
58
+ logger.info "Migration for '#{database_alias}' Database:"
59
+ end
60
+
61
+ increase_db_version database_alias, db while metadata(db).version < version
62
+ decrease_db_version database_alias, db while metadata(db).version > version
63
+ true
64
+ end
65
+
66
+ def metadata db
67
+ col = db.collection 'db_metadata'
68
+ metadata = (col.find_one || {:version => 0}).to_openobject
69
+ end
70
+
71
+ def definitions
72
+ @definitions ||= Hash.new{|h, k| h[k] = []}
73
+ end
74
+
75
+ protected
76
+ def increase_db_version database_alias, db
77
+ m = metadata(db)
78
+ migration = definitions[database_alias][m.version + 1]
79
+ raise "No upgrade for version #{m.version + 1} of '#{database_alias}' Database!" unless migration and migration.up
80
+
81
+ migration.up.call db
82
+
83
+ m.version += 1
84
+ update_metadata db, m
85
+
86
+ logger.info "Database '#{database_alias}' upgraded to version #{m.version}."
87
+ end
88
+
89
+ def decrease_db_version database_alias, db
90
+ m = metadata(db)
91
+ migration = definitions[database_alias][m.version]
92
+ raise "No downgrade for version #{m.version} of '#{database_alias}' Database!" unless migration and migration.down
93
+
94
+ migration.down.call db
95
+
96
+ m.version -= 1
97
+ update_metadata db, m
98
+
99
+ logger.info "Database '#{database_alias}' downgraded to version #{m.version}."
100
+ end
101
+
102
+
103
+ def update_metadata db, metadata
104
+ col = db.collection 'db_metadata'
105
+ col.save metadata.to_hash
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,25 @@
1
+ MongoMapper.class_eval do
2
+ class << self
3
+
4
+ def logger
5
+ # return @logger ||= Logger.new(nil) if defined?(Spec)
6
+ unless @logger
7
+ @logger = if "irb" == $0
8
+ Logger.new(STDOUT)
9
+ else
10
+ if defined?(Rails)
11
+ Rails.test? ? Logger.new(nil) : Rails.logger
12
+ else
13
+ Logger.new(STDOUT)
14
+ end
15
+ end
16
+ end
17
+ @logger
18
+ end
19
+
20
+ def logger= logger
21
+ @logger = logger
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module AttributesCache
4
+
5
+ module InstanceMethods
6
+ def cache
7
+ @cache ||= {}
8
+ end
9
+
10
+ def clear_cache
11
+ @cache = {}
12
+ end
13
+
14
+ def reload
15
+ @cache.clear if @cache
16
+ super
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ # #
2
+ # # Connect to database_alias specified in config
3
+ # #
4
+ # module MongoMapper
5
+ # module Plugins
6
+ # module DbConfig
7
+ #
8
+ # module ClassMethods
9
+ # inheritable_accessor :database_alias, nil
10
+ # def use_database database_alias
11
+ # self.database_alias = database_alias.to_s
12
+ # end
13
+ #
14
+ # def connection(mongo_connection=nil)
15
+ # assert_supported
16
+ # if mongo_connection.nil?
17
+ # @connection || connection_from_alias || MongoMapper.connection
18
+ # else
19
+ # @connection = mongo_connection
20
+ # end
21
+ # end
22
+ #
23
+ # def database_name
24
+ # assert_supported
25
+ # @database_name || database_name_from_alias
26
+ # end
27
+ #
28
+ # private
29
+ # def database_name_from_alias
30
+ # return unless database_alias
31
+ #
32
+ # MongoMapper.db_config.must.include database_alias
33
+ # MongoMapper.db_config[database_alias]['name']
34
+ # end
35
+ #
36
+ # def connection_from_alias
37
+ # return unless database_alias
38
+ #
39
+ # MongoMapper.db_config.must.include database_alias
40
+ # MongoMapper.connections[database_alias]
41
+ # end
42
+ #
43
+ # end
44
+ #
45
+ # end
46
+ # end
47
+ # end
@@ -0,0 +1,80 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module DefaultScope
4
+
5
+ module ClassMethods
6
+ def query options = {}
7
+ super default_scope_options.merge(options)
8
+ end
9
+
10
+ def find_one options = {}
11
+ super default_scope_options.merge(options)
12
+ end
13
+
14
+ def find_many options = {}
15
+ super default_scope_options.merge(options)
16
+ end
17
+
18
+ def count options={}
19
+ super default_scope_options.merge(options)
20
+ end
21
+
22
+ def with_exclusive_scope options = {}, &block
23
+ Thread.current['mm_with_exclusive_scope'].must_be.nil
24
+
25
+ before = Thread.current['mm_with_exclusive_scope']
26
+ begin
27
+ Thread.current['mm_with_exclusive_scope'] = options
28
+ block.call if block
29
+ ensure
30
+ Thread.current['mm_with_exclusive_scope'] = before
31
+ end
32
+ end
33
+
34
+ def with_scope options = {}, &block
35
+ Thread.current['mm_with_exclusive_scope'].must_be.nil
36
+
37
+ before = Thread.current['mm_with_scope']
38
+ begin
39
+ options = before.merge options if before
40
+ Thread.current['mm_with_scope'] = options
41
+ block.call if block
42
+ ensure
43
+ Thread.current['mm_with_scope'] = before
44
+ end
45
+ end
46
+
47
+ protected
48
+ def default_scope options = nil, &block
49
+ options.must_be.a [NilClass, Hash]
50
+ self.write_inheritable_attribute(:default_scope, (options || block))
51
+ end
52
+
53
+ private
54
+ def default_scope_options
55
+ default_scope = self.read_inheritable_attribute(:default_scope)
56
+
57
+ exclusive_options = Thread.current['mm_with_exclusive_scope']
58
+ return exclusive_options if exclusive_options
59
+
60
+ options = if default_scope
61
+ if default_scope.respond_to? :call
62
+ default_scope.call self
63
+ else
64
+ default_scope
65
+ end
66
+ else
67
+ {}
68
+ end
69
+
70
+ if scope_options = Thread.current['mm_with_scope']
71
+ options = options.merge scope_options
72
+ end
73
+
74
+ options
75
+ end
76
+ end
77
+
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,97 @@
1
+ module MongoMapper
2
+ # def self.deferred; @deferred ||= [] end
3
+ # def self.call_deferred
4
+ # deferred.every.call
5
+ # deferred.clear
6
+ # end
7
+
8
+ module Plugins
9
+ module Micelaneous
10
+
11
+ module InstanceMethods
12
+ def upsert *args
13
+ self.class.upsert id, *args
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ #
19
+ # Sequentiall :all for big collection
20
+ #
21
+ def all_sequentially &block
22
+ page, per_page = 1, 5
23
+ begin
24
+ results = paginate(:page => page, :per_page => per_page, :order => '_id asc')
25
+ results.each{|o| block.call o}
26
+ page += 1
27
+ end until results.blank? or results.size < per_page
28
+ end
29
+
30
+
31
+ #
32
+ # Deferred execution
33
+ #
34
+ # def defer &block
35
+ # MongoMapper.deferred << block
36
+ # end
37
+
38
+
39
+ #
40
+ # Connect to database_alias specified in config
41
+ #
42
+ def use_database database_alias
43
+ # defer do
44
+ database_alias = database_alias.to_s
45
+ MongoMapper.db_config.must.include database_alias
46
+
47
+ self.connection MongoMapper.connections[database_alias]
48
+ set_database_name MongoMapper.db_config[database_alias]['name']
49
+ # end
50
+ end
51
+
52
+
53
+ #
54
+ # shortcut for upsert
55
+ #
56
+ def upsert *args
57
+ collection.upsert *args
58
+ end
59
+
60
+
61
+ #
62
+ # CounterCache
63
+ # belongs_to :item, :counter_cashe => true
64
+ #
65
+ def belongs_to association_id, options={}, &extension
66
+ options.must_not.include :counter_cashe
67
+ if options.delete(:counter_cache) || options.delete('counter_cache')
68
+ association_id = association_id.to_s
69
+ association_key = "#{association_id}_id"
70
+ cache_attribute = "#{name.pluralize.underscore}_count"
71
+ cache_class = association_id.classify.constantize
72
+ cache_class.keys.must.include cache_attribute
73
+ increase_method_name = "increase_#{cache_class.name.underscore}_#{name.pluralize.underscore}_counter"
74
+ decrease_method_name = "decrease_#{cache_class.name.underscore}_#{name.pluralize.underscore}_counter"
75
+
76
+ define_method increase_method_name do
77
+ cache_class.upsert self.send(association_key), :$inc => {cache_attribute => 1}
78
+ end
79
+ protected increase_method_name
80
+
81
+ define_method decrease_method_name do
82
+ cache_class.upsert self.send(association_key), :$inc => {cache_attribute => -1}
83
+ end
84
+ protected decrease_method_name
85
+
86
+ after_create increase_method_name
87
+ after_destroy decrease_method_name
88
+ end
89
+
90
+ super association_id, options, &extension
91
+ end
92
+
93
+ end
94
+
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,61 @@
1
+ #
2
+ # Disabling indexes in test environment
3
+ #
4
+ # if Object.const_defined?(:RAILS_ENV) and Object.const_get(:RAILS_ENV) != 'production'
5
+ # MongoMapper::Plugins::Indexes::ClassMethods.class_eval do
6
+ # def ensure_index(name_or_array, options={})
7
+ # end
8
+ # end
9
+ # end
10
+
11
+ if Object.const_defined?(:Crystal) and Crystal.respond_to?(:run)
12
+ MongoMapper::Plugins::Indexes::ClassMethods.class_eval do
13
+ alias_method :original_ensure_index, :ensure_index
14
+ def ensure_index_stub *args; end
15
+ end
16
+
17
+ crystal.after :config do |config|
18
+ if config.production?
19
+ MongoMapper::Plugins::Indexes::ClassMethods.send :alias_method, :ensure_index, :original_ensure_index
20
+ else
21
+ MongoMapper::Plugins::Indexes::ClassMethods.send :alias_method, :ensure_index, :ensure_index_stub
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+ #
28
+ # Clear db before each test
29
+ #
30
+ Spec::Example::ExampleGroup.class_eval do
31
+ class << self
32
+ def with_mongo_mapper
33
+ before :each do
34
+ MongoMapper.db_config.each do |db_alias, opt|
35
+ db = MongoMapper.databases[db_alias]
36
+ db.collection_names.each do |name|
37
+ next if name =~ /^system\./
38
+ db.collection(name).drop
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ # Spec::Runner.configure do |config|
46
+ # config.before(:each) do
47
+ # end
48
+ # end
49
+
50
+
51
+ #
52
+ # Silence logger
53
+ #
54
+ MongoMapper.logger = Logger.new(nil)
55
+ if defined? Paperclip
56
+ Paperclip.class_eval do
57
+ def self.logger
58
+ @logger ||= Logger.new(nil)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,10 @@
1
+ #
2
+ # HTML helpers
3
+ #
4
+ [MongoMapper::EmbeddedDocument, MongoMapper::Document].each do |aclass|
5
+ aclass.class_eval do
6
+ def dom_id
7
+ new_record? ? "new_#{self.class.name.underscore}" : to_param
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,32 @@
1
+ gem 'mongo_mapper', '>=0.8'
2
+ require 'mongo_mapper'
3
+
4
+
5
+ [
6
+ 'hacks/fixes',
7
+ 'hacks/time_measuring',
8
+ 'migration',
9
+ 'mongo_mapper',
10
+ 'view_helpers',
11
+ 'db_config',
12
+ 'micelaneous',
13
+
14
+ 'plugins/default_scope',
15
+ # 'plugins/db_config',
16
+ 'plugins/attributes_cache',
17
+ 'plugins/micelaneous',
18
+ ].each do |file|
19
+ require "mongo_mapper_ext/#{file}"
20
+ end
21
+
22
+ module CommonPluginsAddition
23
+ def self.included(model)
24
+ model.plugin MongoMapper::Plugins::DefaultScope
25
+ # model.plugin MongoMapper::Plugins::DbConfig
26
+ model.plugin MongoMapper::Plugins::AttributesCache
27
+ model.plugin MongoMapper::Plugins::Micelaneous
28
+
29
+ model.attr_protected :id, :_id, :_type, :created_at, :updated_at
30
+ end
31
+ end
32
+ MongoMapper::Document.append_inclusions(CommonPluginsAddition)
data/readme.md ADDED
@@ -0,0 +1,3 @@
1
+ # Extensions for MongoMapper.
2
+
3
+ [add readme, for now go to specs]
data/spec/helper.rb ADDED
@@ -0,0 +1,8 @@
1
+ dir = File.expand_path(File.dirname(__FILE__))
2
+ lib_dir = File.expand_path("#{dir}/../../../lib")
3
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include? lib_dir
4
+
5
+ require 'spec_ext'
6
+ gem 'mongo_mapper', '>=0.8'
7
+ require "mongo_mapper"
8
+ require 'ruby_ext'
@@ -0,0 +1,56 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper"
2
+
3
+ require "mongo_mapper_ext/micelaneous"
4
+ require "mongo_mapper_ext/plugins/micelaneous"
5
+
6
+ describe "MongoMapper Default Scope" do
7
+
8
+ before :all do
9
+ class ::Post
10
+ include MongoMapper::Document
11
+ plugin MongoMapper::Plugins::Micelaneous
12
+
13
+ key :comments_count, Integer, :default => 0
14
+ has_many :comments
15
+ end
16
+
17
+ class ::Comment
18
+ include MongoMapper::Document
19
+ plugin MongoMapper::Plugins::Micelaneous
20
+
21
+ key :post_id
22
+ belongs_to :post, :counter_cache => true
23
+ end
24
+
25
+ MongoMapper.database = 'test'
26
+ end
27
+
28
+ after :all do
29
+ %w{Post Comment}.each do |obj_name|
30
+ Object.send :remove_const, obj_name if Object.const_defined? obj_name
31
+ end
32
+ end
33
+
34
+ before :each do
35
+ [Post, Comment].every.delete_all
36
+ end
37
+
38
+ it "should increase count of comments" do
39
+ post = Post.create!
40
+ comment = post.comments.create!
41
+
42
+ post.reload
43
+ post.comments_count.should == 1
44
+ end
45
+
46
+ it "should decrease count of comments" do
47
+ post = Post.create!
48
+ comment = post.comments.create!
49
+ post.reload
50
+ post.comments_count.should == 1
51
+
52
+ comment.destroy
53
+ post.reload
54
+ post.comments_count.should == 0
55
+ end
56
+ end
@@ -0,0 +1,53 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper"
2
+
3
+ require "mongo_mapper_ext/micelaneous"
4
+ require "mongo_mapper_ext/plugins/micelaneous"
5
+
6
+ describe "MongoMapper micelaneous" do
7
+ before :all do
8
+ @db = Mongo::Connection.new.db('test')
9
+ MongoMapper.database = 'test'
10
+ end
11
+
12
+ before :each do
13
+ @db.collection('test').drop
14
+ @coll = @db.collection('test')
15
+ end
16
+
17
+ it "upsert should update" do
18
+ id = @coll.save :count => 2
19
+ @coll.upsert id, :$inc => {:count => 1}
20
+ @coll.find(:_id => id).first['count'].should == 3
21
+ end
22
+
23
+ it "upsert should set" do
24
+ id = @coll.save({})
25
+ @coll.upsert id, :$inc => {:count => 1}
26
+ @coll.find(:_id => id).first['count'].should == 1
27
+ end
28
+
29
+ describe "handy upsert" do
30
+ class ::UpsertSample
31
+ include MongoMapper::Document
32
+ plugin MongoMapper::Plugins::Micelaneous
33
+
34
+ key :counter, Integer, :default => 1
35
+ end
36
+
37
+ before :each do
38
+ @model = UpsertSample.create!
39
+ end
40
+
41
+ it "class upsert" do
42
+ UpsertSample.upsert @model.id, :$inc => {:counter => 1}
43
+ @model.reload
44
+ @model.counter.should == 2
45
+ end
46
+
47
+ it "model upsert" do
48
+ @model.upsert :$inc => {:counter => 1}
49
+ @model.reload
50
+ @model.counter.should == 2
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,79 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper"
2
+
3
+ require "mongo_mapper_ext"
4
+ require "mongo_mapper_ext/spec/helper"
5
+
6
+ describe "MongoMapper Migration" do
7
+ with_mongo_mapper
8
+
9
+ Migration = MongoMapper::Migration
10
+
11
+ before :all do
12
+ MongoMapper.logger = Logger.new(nil)
13
+ MongoMapper.db_config = {
14
+ 'global' => {'name' => 'global_test'},
15
+ 'accounts' => {'name' => "accounts_test"}
16
+ }
17
+
18
+ class ::Sample
19
+ include MongoMapper::Document
20
+ use_database :global
21
+
22
+ key :name, String
23
+ end
24
+
25
+ # MongoMapper.call_deferred
26
+ Migration.logger = nil
27
+ end
28
+
29
+ after :all do
30
+ Object.send :remove_const, :Sample if Object.const_defined? :Sample
31
+ end
32
+
33
+ before :each do
34
+ Migration.definitions.clear
35
+ end
36
+
37
+ it "Shouldn't update if versions are the same" do
38
+ Migration.update(:global, 0).should be_false
39
+ end
40
+
41
+ it "migration should provide access to current database" do
42
+ Sample.count.should == 0
43
+ Migration.define :global, 1 do |m|
44
+ m.up do |db|
45
+ Sample.create :name => 'name'
46
+ coll = db.collection 'samples'
47
+ coll.find.count.should == 1
48
+ end
49
+ end
50
+
51
+ Migration.update(:global, 1).should be_true
52
+ Sample.count.should == 1
53
+ end
54
+
55
+ it "increase_db_version" do
56
+ Sample.count.should == 0
57
+ Migration.define :global, 1 do |m|
58
+ m.up{Sample.create :name => 'name'}
59
+ end
60
+
61
+ Migration.update(:global, 1).should be_true
62
+ Sample.count.should == 1
63
+ Migration.metadata(MongoMapper.databases[:global]).version.should == 1
64
+ end
65
+
66
+ it "decrease_db_version" do
67
+ Migration.define :global, 1 do |m|
68
+ m.up{Sample.create :name => 'name'}
69
+ m.down{Sample.destroy_all}
70
+ end
71
+ Migration.update(:global, 1).should be_true
72
+ Sample.count.should == 1
73
+
74
+ Migration.update(:global, 0).should be_true
75
+ Sample.count.should == 0
76
+ Migration.metadata(MongoMapper.databases[:global]).version.should == 0
77
+ end
78
+
79
+ end
data/spec/mm_spec.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'mongo_mapper'
2
+
3
+ describe "Special test to check some errors in the MongoMapper itself" do
4
+ before :all do
5
+ MongoMapper.database = 'test'
6
+
7
+ class ::AnObject
8
+ include MongoMapper::Document
9
+
10
+ key :owner_name, String
11
+ key :viewers, Array
12
+
13
+ def owner_name= owner_name
14
+ viewers.delete self.owner_name
15
+ viewers << owner_name
16
+ # write_attribute :owner_name, owner_name
17
+ super owner_name
18
+ owner_name
19
+ end
20
+ end
21
+ end
22
+
23
+ after :all do
24
+ Object.send :remove_const, :AnObject if Object.const_defined? :AnObject
25
+ end
26
+
27
+ it do
28
+ o = AnObject.new
29
+ o.owner_name = 'user'
30
+ o.save!
31
+
32
+ # o = AnObject.first # don't use reload, it willn't catch this error
33
+ o.viewers.should == %w{user}
34
+ end
35
+ end
@@ -0,0 +1,124 @@
1
+ require "#{File.expand_path(File.dirname(__FILE__))}/helper"
2
+
3
+ require "mongo_mapper_ext/plugins/default_scope"
4
+
5
+ describe "MongoMapper Default Scope" do
6
+ before :all do
7
+ MongoMapper.database = 'test'
8
+ end
9
+
10
+ before :each do
11
+ class ::ScopeSample
12
+ include MongoMapper::Document
13
+ plugin MongoMapper::Plugins::DefaultScope
14
+
15
+ key :name, String
16
+ key :_type, String
17
+ end
18
+
19
+ ScopeSample.delete_all
20
+ ScopeSample.create! :name => 'a'
21
+ ScopeSample.create! :name => 'b'
22
+ end
23
+
24
+ after :each do
25
+ Object.send :remove_const, :ScopeSample if Object.const_defined? :ScopeSample
26
+ end
27
+
28
+ it "should not affect objects without default_scope" do
29
+ ScopeSample.count.should == 2
30
+ ScopeSample.all.count.should == 2
31
+ end
32
+
33
+ it "default_scope" do
34
+ ScopeSample.send :default_scope, :name => 'a'
35
+ ScopeSample.count.should == 1
36
+ ScopeSample.all.count.should == 1
37
+ ScopeSample.first.name.should == 'a'
38
+ end
39
+
40
+ it "default_scope as block" do
41
+ ScopeSample.send :default_scope do
42
+ {:name => 'a'}
43
+ end
44
+ ScopeSample.count.should == 1
45
+ ScopeSample.all.count.should == 1
46
+ ScopeSample.first.name.should == 'a'
47
+ end
48
+
49
+ it "default_scope should be inherited" do
50
+ ScopeSample.send :default_scope, :name => 'a'
51
+ class ScopeSampleAncestor < ScopeSample
52
+ end
53
+
54
+ ScopeSampleAncestor.create! :name => 'a'
55
+ ScopeSampleAncestor.create! :name => 'b'
56
+
57
+ ScopeSampleAncestor.count.should == 1
58
+ ScopeSampleAncestor.all.count.should == 1
59
+ ScopeSampleAncestor.first.name.should == 'a'
60
+ end
61
+
62
+ it "ancestors should be able to override default_scope" do
63
+ ScopeSample.send :default_scope, :name => 'a'
64
+ class ScopeSampleAncestor2 < ScopeSample
65
+ default_scope :name => 'b'
66
+ end
67
+
68
+ ScopeSampleAncestor2.create! :name => 'a'
69
+ ScopeSampleAncestor2.create! :name => 'b'
70
+
71
+ ScopeSampleAncestor2.count.should == 1
72
+ ScopeSampleAncestor2.all.count.should == 1
73
+ ScopeSampleAncestor2.first.name.should == 'b'
74
+ end
75
+
76
+ it "shouldn't allow to nest with_exclusive_scope" do
77
+ lambda{
78
+ ScopeSample.with_exclusive_scope do
79
+ ScopeSample.with_exclusive_scope{}
80
+ end
81
+ }.should raise_error(AssertionError)
82
+
83
+ lambda{
84
+ ScopeSample.with_exclusive_scope do
85
+ ScopeSample.with_scope{}
86
+ end
87
+ }.should raise_error(AssertionError)
88
+ end
89
+
90
+ it "with_exclusive_scope should clear other scopes" do
91
+ ScopeSample.send :default_scope, :name => 'a'
92
+
93
+ ScopeSample.with_scope :name => 'a' do
94
+ ScopeSample.with_exclusive_scope :name => 'b' do
95
+ ScopeSample.count.should == 1
96
+ ScopeSample.first.name.should == 'b'
97
+ end
98
+ end
99
+ end
100
+
101
+ it "with_scope" do
102
+ ScopeSample.with_scope :name => 'a' do
103
+ ScopeSample.count.should == 1
104
+ ScopeSample.first.name.should == 'a'
105
+ end
106
+ end
107
+
108
+ it "with scope should merge scope" do
109
+ ScopeSample.class_eval do
110
+ key :name2, String
111
+ key :name3, String
112
+ default_scope :name => 'a'
113
+ end
114
+ ScopeSample.create! :name => 'a', :name2 => 'a2', :name3 => 'a3'
115
+ ScopeSample.create! :name => 'b', :name2 => 'b2', :name3 => 'b3'
116
+
117
+ ScopeSample.with_scope :name2 => 'a2' do
118
+ ScopeSample.with_scope :name3 => 'a3' do
119
+ ScopeSample.count.should == 1
120
+ ScopeSample.first.name2.should == 'a2'
121
+ end
122
+ end
123
+ end
124
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongo_mapper_ext
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Alexey Petrushin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-11 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: mongo_mapper
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Extensions for MongoMapper
36
+ email:
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - Rakefile
45
+ - readme.md
46
+ - lib/mongo_mapper_ext/db_config.rb
47
+ - lib/mongo_mapper_ext/hacks/fixes.rb
48
+ - lib/mongo_mapper_ext/hacks/time_measuring.rb
49
+ - lib/mongo_mapper_ext/micelaneous.rb
50
+ - lib/mongo_mapper_ext/migrate.rake
51
+ - lib/mongo_mapper_ext/migration.rb
52
+ - lib/mongo_mapper_ext/mongo_mapper.rb
53
+ - lib/mongo_mapper_ext/plugins/attributes_cache.rb
54
+ - lib/mongo_mapper_ext/plugins/db_config.rb
55
+ - lib/mongo_mapper_ext/plugins/default_scope.rb
56
+ - lib/mongo_mapper_ext/plugins/micelaneous.rb
57
+ - lib/mongo_mapper_ext/spec/helper.rb
58
+ - lib/mongo_mapper_ext/view_helpers.rb
59
+ - lib/mongo_mapper_ext.rb
60
+ - spec/helper.rb
61
+ - spec/micelaneous_plugin_spec.rb
62
+ - spec/micelaneous_spec.rb
63
+ - spec/migration_spec.rb
64
+ - spec/mm_spec.rb
65
+ - spec/scope_spec.rb
66
+ - spec/spec.opts
67
+ has_rdoc: true
68
+ homepage: http://github.com/alexeypetrushin/mongo_mapper_ext
69
+ licenses: []
70
+
71
+ post_install_message:
72
+ rdoc_options: []
73
+
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ hash: 3
82
+ segments:
83
+ - 0
84
+ version: "0"
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ requirements: []
95
+
96
+ rubyforge_project:
97
+ rubygems_version: 1.3.7
98
+ signing_key:
99
+ specification_version: 3
100
+ summary: Extensions for MongoMapper
101
+ test_files: []
102
+