mongo_mapper_ext 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/Rakefile +5 -5
  2. data/lib/mongo_db_ext/micelaneous.rb +12 -0
  3. data/lib/mongo_mapper_ext/gems.rb +17 -2
  4. data/lib/mongo_mapper_ext/hacks/active_model.rb +16 -0
  5. data/lib/mongo_mapper_ext/hacks/fixes.rb +37 -0
  6. data/lib/mongo_mapper_ext/{micelaneous.rb → logging.rb} +30 -8
  7. data/lib/mongo_mapper_ext/migration.rb +1 -1
  8. data/lib/mongo_mapper_ext/mongo_mapper.rb +0 -25
  9. data/lib/mongo_mapper_ext/plugins/{attributes_cache.rb → attribute_cache.rb} +2 -1
  10. data/lib/mongo_mapper_ext/plugins/attribute_convertors.rb +79 -0
  11. data/lib/mongo_mapper_ext/plugins/belongs_to_with_counter_cache.rb +45 -0
  12. data/lib/mongo_mapper_ext/plugins/carrierwave.rb +60 -0
  13. data/lib/mongo_mapper_ext/plugins/{default_scope.rb → custom_scope.rb} +3 -2
  14. data/lib/mongo_mapper_ext/plugins/db_config.rb +84 -46
  15. data/lib/mongo_mapper_ext/plugins/micelaneous.rb +24 -68
  16. data/lib/mongo_mapper_ext/rad/file_uploader.rb +28 -0
  17. data/lib/mongo_mapper_ext/rad.rb +2 -0
  18. data/lib/mongo_mapper_ext/spec.rb +103 -0
  19. data/lib/mongo_mapper_ext/{migrate.rake → tasks.rb} +3 -15
  20. data/lib/mongo_mapper_ext.rb +41 -24
  21. data/readme.md +74 -2
  22. data/spec/attribute_convertors_spec.rb +71 -0
  23. data/spec/carrierwave_spec/plane.jpg +0 -0
  24. data/spec/carrierwave_spec.rb +42 -0
  25. data/spec/{scope_spec.rb → custom_scope_spec.rb} +26 -32
  26. data/spec/micelaneous_plugin_spec.rb +34 -20
  27. data/spec/micelaneous_spec.rb +105 -24
  28. data/spec/migration_spec.rb +8 -17
  29. data/spec/{mm_spec.rb → mongo_mapper_spec.rb} +0 -0
  30. data/spec/spec_helper.rb +2 -5
  31. data/spec/uploading_spec/ship.jpg +0 -0
  32. data/spec/uploading_spec//321/204/320/260/320/270/314/206/320/273 /321/201 /320/277/321/200/320/276/320/261/320/265/320/273/320/260/320/274/320/270.txt" +1 -0
  33. data/spec/uploading_spec.rb +49 -0
  34. metadata +164 -72
  35. data/lib/mongo_mapper_ext/db_config.rb +0 -67
  36. data/lib/mongo_mapper_ext/hacks/time_measuring.rb +0 -44
  37. data/lib/mongo_mapper_ext/spec/helper.rb +0 -61
data/Rakefile CHANGED
@@ -1,10 +1,10 @@
1
1
  require 'rake_ext'
2
2
 
3
3
  project(
4
- :name => "mongo_mapper_ext",
5
- :version => "0.2.2",
6
- :summary => "Extensions for MongoMapper",
4
+ name: "mongo_mapper_ext",
5
+ version: "0.2.3",
6
+ summary: "Extensions for MongoMapper",
7
7
 
8
- :author => "Alexey Petrushin",
9
- :homepage => "http://github.com/alexeypetrushin/mongo_mapper"
8
+ author: "Alexey Petrushin",
9
+ homepage: "http://github.com/alexeypetrushin/mongo_mapper"
10
10
  )
@@ -0,0 +1,12 @@
1
+ #
2
+ # upsert
3
+ #
4
+ Mongo::Collection.class_eval do
5
+ def upsert! query, opt
6
+ opt.size.must == 1
7
+ opt.must_be.a Hash
8
+ opt.values.first.must_be.a Hash
9
+
10
+ update(query, opt, {upsert: true, safe: true})
11
+ end
12
+ end
@@ -1,2 +1,17 @@
1
- gem 'mongo_mapper', '0.8.6'
2
- gem 'bson_ext', '1.1.1'
1
+ # core gems
2
+ gem 'mongo_mapper', '0.9.0'
3
+
4
+ gem 'carrierwave', '0.5.3'
5
+
6
+ # dependencies for core gems
7
+ gem 'i18n', '0.5.0'
8
+ gem 'activesupport', '3.0.7'
9
+ gem 'activemodel', '3.0.7'
10
+ gem 'bson', '1.3.0'
11
+ gem 'bson_ext', '1.3.0'
12
+ gem 'mongo', '1.3.0'
13
+ gem 'plucky', '0.3.6'
14
+ gem 'jnunemaker-validatable', '1.8.4'
15
+
16
+ gem 'mini_magick', '3.2.1'
17
+ gem 'subexec', '0.0.4'
@@ -0,0 +1,16 @@
1
+ ActiveModel::Name.class_eval do
2
+ def initialize klass, name = nil
3
+ name ||= klass.name
4
+
5
+ super name
6
+
7
+ @klass = klass
8
+ @singular = ActiveSupport::Inflector.underscore(self).tr('/', '_').freeze
9
+ @plural = ActiveSupport::Inflector.pluralize(@singular).freeze
10
+ @element = ActiveSupport::Inflector.underscore(ActiveSupport::Inflector.demodulize(self)).freeze
11
+ @human = ActiveSupport::Inflector.humanize(@element).freeze
12
+ @collection = ActiveSupport::Inflector.tableize(self).freeze
13
+ @partial_path = "#{@collection}/#{@element}".freeze
14
+ @i18n_key = ActiveSupport::Inflector.underscore(self).tr('/', '.').to_sym
15
+ end
16
+ end
@@ -18,3 +18,40 @@ MongoMapper::Plugins::Associations::InArrayProxy.class_eval do
18
18
  reset
19
19
  end
20
20
  end
21
+
22
+ #
23
+ # Problem after destroying model the :to_param method returns :nill,
24
+ # and we can't use :to_param in view (for example in ajax to remove element with id from the screen).
25
+ #
26
+ module MongoMapper
27
+ module Plugins
28
+ module Rails
29
+ module InstanceMethods
30
+ # def to_param
31
+ # id.to_s if persisted? # old realization
32
+ # end
33
+ def to_param
34
+ id.to_s
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+
42
+ #
43
+ # Use class alias instead of class name, because it causes foreign keys like 'models_account_id' instead of 'account_id' if
44
+ # for models like Models::Account
45
+ #
46
+ module MongoMapper
47
+ module Plugins
48
+ module Associations
49
+ class ManyDocumentsProxy
50
+ def foreign_key
51
+ # options[:foreign_key] || proxy_owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
52
+ options[:foreign_key] || proxy_owner.class.alias.to_s.underscore.gsub("/", "_") + "_id"
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,13 +1,28 @@
1
- #
2
- # upsert
3
1
  #
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
2
+ # Custom Logger
3
+ #
4
+ MongoMapper.class_eval do
5
+ class << self
6
+
7
+ def logger
8
+ unless @logger
9
+ @logger = if "irb" == $0
10
+ Logger.new(STDOUT)
11
+ else
12
+ if defined?(Rails)
13
+ Rails.test? ? Logger.new(nil) : Rails.logger
14
+ else
15
+ Logger.new(STDOUT)
16
+ end
17
+ end
18
+ end
19
+ @logger
20
+ end
21
+
22
+ def logger= logger
23
+ @logger = logger
24
+ end
9
25
 
10
- update({:_id => id}, opt, {:upsert => true, :safe => true})
11
26
  end
12
27
  end
13
28
 
@@ -36,6 +51,13 @@ MongoMapper.class_eval do
36
51
  end
37
52
  end
38
53
  end
54
+
55
+ def self.use_database database_alias
56
+ database_alias = database_alias.to_s
57
+ MongoMapper.db_config.must.include database_alias
58
+ MongoMapper.connection = MongoMapper.connections['default']
59
+ MongoMapper.database = MongoMapper.db_config['default']['name']
60
+ end
39
61
  end
40
62
 
41
63
 
@@ -65,7 +65,7 @@ module MongoMapper::Migration
65
65
 
66
66
  def metadata db
67
67
  col = db.collection 'db_metadata'
68
- metadata = (col.find_one || {:version => 0}).to_openobject
68
+ metadata = (col.find_one || {version: 0}).to_openobject
69
69
  end
70
70
 
71
71
  def definitions
@@ -1,25 +0,0 @@
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
@@ -1,6 +1,7 @@
1
1
  module MongoMapper
2
2
  module Plugins
3
- module AttributesCache
3
+ module AttributeCache
4
+ extend ActiveSupport::Concern
4
5
 
5
6
  module InstanceMethods
6
7
  def cache
@@ -0,0 +1,79 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module AttributeConvertors
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ ATTRIBUTE_CONVERTORS = {
8
+ line: {
9
+ from_string: -> s {(s || "").split(',').collect{|s| s.strip}},
10
+ to_string: -> v {v.join(', ')}
11
+ },
12
+ column: {
13
+ from_string: -> s {(s || "").split("\n").collect{|s| s.strip}},
14
+ to_string: -> v {v.join("\n")}
15
+ },
16
+ yaml: {
17
+ from_string: -> s {YAML.load s rescue {}},
18
+ to_string: -> v {
19
+ # MongoMapper uses it's internal Hash that doesn't support to_yaml
20
+ hash = {}; v.each{|k, v| hash[k] = v}
21
+ hash.to_yaml.strip
22
+ }
23
+ },
24
+ json: {
25
+ from_string: -> s {JSON.parse s rescue {}},
26
+ to_string: -> v {
27
+ # MongoMapper uses it's internal Hash that doesn't support to_yaml
28
+ hash = {}; v.each{|k, v| hash[k] = v}
29
+ hash.to_json.strip
30
+ }
31
+ }
32
+ }
33
+
34
+
35
+ #
36
+ # supporf for :as_string option
37
+ #
38
+ def key(*args)
39
+ key = super
40
+ if converter_name = key.options[:as_string]
41
+ key_name = key.name.to_sym
42
+ available_as_string key_name, converter_name
43
+ attr_protected "#{key_name}_as_string".to_sym if key.options[:protected]
44
+ end
45
+ key
46
+ end
47
+
48
+ def available_as_string key_name, converter_name
49
+ converter = ATTRIBUTE_CONVERTORS[converter_name]
50
+ raise "unknown converter name :#{converter_name} for :#{key_name} key!" unless converter
51
+
52
+ from_string, to_string = converter[:from_string], converter[:to_string]
53
+ key_name_as_string = "#{key_name}_as_string".to_sym
54
+ define_method key_name_as_string do
55
+ cache[key_name_as_string] ||= to_string.call(self.send(key_name))
56
+ end
57
+ define_method "#{key_name_as_string}=" do |value|
58
+ cache.delete key_name_as_string
59
+ self.send "#{key_name}=", from_string.call(value)
60
+ end
61
+ end
62
+
63
+ def available_as_yaml key_name
64
+ raise "delimiter not specified for :#{key_name} key!" unless delimiter
65
+ method = "#{key_name}_as_string"
66
+ define_method method do
67
+ self.send(key_name).join(delimiter)
68
+ end
69
+ define_method "#{method}=" do |value|
70
+ value = (value || "").split(delimiter.strip).collect{|s| s.strip}
71
+ self.send "#{key_name}=", value
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,45 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module BelongsToWithCounterCache
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ #
8
+ # CounterCache
9
+ # belongs_to :item, counter_cashe: true
10
+ #
11
+ def belongs_to association_id, options={}, &extension
12
+ options.must_not.include :counter_cashe
13
+ if options.delete(:counter_cache) || options.delete('counter_cache')
14
+ association_id = association_id.to_s
15
+ association_key = "#{association_id}_id"
16
+ cache_attribute = "#{self.alias.pluralize.underscore}_count"
17
+ cache_class = if class_name = options[:class_name]
18
+ class_name.constantize
19
+ else
20
+ association_id.classify.constantize
21
+ end
22
+ cache_class.keys.must.include cache_attribute
23
+ increase_method_name = "increase_#{cache_class.alias.underscore}_#{self.alias.pluralize.underscore}_counter"
24
+ decrease_method_name = "decrease_#{cache_class.alias.underscore}_#{self.alias.pluralize.underscore}_counter"
25
+
26
+ define_method increase_method_name do
27
+ cache_class.upsert!({id: self.send(association_key)}, :$inc => {cache_attribute => 1})
28
+ end
29
+ protected increase_method_name
30
+
31
+ define_method decrease_method_name do
32
+ cache_class.upsert!({id: self.send(association_key)}, :$inc => {cache_attribute => -1})
33
+ end
34
+ protected decrease_method_name
35
+
36
+ after_create increase_method_name
37
+ after_destroy decrease_method_name
38
+ end
39
+ super association_id, options, &extension
40
+ end
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,60 @@
1
+ require 'carrierwave/validations/active_model'
2
+
3
+ #
4
+ # Hacks
5
+ #
6
+ CarrierWave::SanitizedFile.class_eval do
7
+ def sanitize_regexp
8
+ /[^[:word:]\.\-\+\s_]/i
9
+ end
10
+ end
11
+
12
+ CarrierWave::Uploader::Cache.class_eval do
13
+ def original_filename=(filename)
14
+ raise CarrierWave::InvalidParameter, "invalid filename" unless filename =~ /\A[[:word:]\.\-\+\s_]+\z/i
15
+ @original_filename = filename
16
+ end
17
+ end
18
+
19
+
20
+ #
21
+ # mount_uploader
22
+ #
23
+ module MongoMapper
24
+ module Plugins
25
+ module CarrierWave
26
+ extend ActiveSupport::Concern
27
+
28
+ module ClassMethods
29
+ include ::CarrierWave::Mount
30
+ ##
31
+ # See +CarrierWave::Mount#mount_uploader+ for documentation
32
+ #
33
+ def mount_uploader(column, uploader, options={}, &block)
34
+ define_key column, uploader, options
35
+
36
+ super
37
+
38
+ alias_method :read_uploader, :read_attribute
39
+ alias_method :write_uploader, :write_attribute
40
+
41
+ include ::CarrierWave::Validations::ActiveModel
42
+
43
+ validates_integrity_of column if uploader_option(column.to_sym, :validate_integrity)
44
+ validates_processing_of column if uploader_option(column.to_sym, :validate_processing)
45
+
46
+ after_save "store_#{column}!".to_sym
47
+ before_save "write_#{column}_identifier".to_sym
48
+ after_destroy "remove_#{column}!".to_sym
49
+ end
50
+
51
+ protected
52
+ def define_key column, uploader, options
53
+ options[:mount_on] ||= "#{column}_filename"
54
+ name = options[:mount_on]
55
+ key name
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,6 +1,7 @@
1
1
  module MongoMapper
2
2
  module Plugins
3
- module DefaultScope
3
+ module CustomScope
4
+ extend ActiveSupport::Concern
4
5
 
5
6
  module ClassMethods
6
7
  def query options = {}
@@ -46,7 +47,7 @@ module MongoMapper
46
47
 
47
48
  protected
48
49
  def default_scope options = nil, &block
49
- options.must_be.a [NilClass, Hash]
50
+ options.must_be.a NilClass, Hash
50
51
  self.write_inheritable_attribute(:default_scope, (options || block))
51
52
  end
52
53
 
@@ -1,47 +1,85 @@
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
1
+ module MongoMapper
2
+ #
3
+ # Connection Pool
4
+ #
5
+ class ConnectionsPool < Hash
6
+ def [](database_alias)
7
+ database_alias = database_alias.to_s
8
+ unless connection = super(database_alias)
9
+ MongoMapper.db_config.must.include database_alias
10
+ db_options = MongoMapper.db_config[database_alias]
11
+ connection = Mongo::Connection.new(db_options['host'], db_options['port'], logger: MongoMapper.logger)
12
+
13
+ if defined?(PhusionPassenger)
14
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
15
+ connection.connect_to_master if forked
16
+ end
17
+ end
18
+
19
+ self[database_alias] = connection
20
+ end
21
+ return connection
22
+ end
23
+ end
24
+
25
+
26
+ #
27
+ # Databases Pool
28
+ #
29
+ class DatabasesPool < Hash
30
+ def [](database_alias)
31
+ database_alias = database_alias.to_s
32
+ unless db = super(database_alias)
33
+ MongoMapper.db_config.must.include database_alias
34
+ db_options = MongoMapper.db_config[database_alias]
35
+ db = MongoMapper.connections[database_alias].db db_options['name'].must_be.a(String)
36
+ self[database_alias] = db
37
+ end
38
+ return db
39
+ end
40
+ end
41
+
42
+ class << self
43
+ attr_accessor :db_config
44
+
45
+ def db_config
46
+ @db_config ||= {}
47
+ end
48
+
49
+ def connections
50
+ @connections ||= ConnectionsPool.new
51
+ end
52
+
53
+ def databases
54
+ @databases ||= DatabasesPool.new
55
+ end
56
+ end
57
+ end
58
+
59
+
22
60
  #
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
61
+ # Plugin
62
+ #
63
+ module MongoMapper
64
+ module Plugins
65
+ module DbConfig
66
+ extend ActiveSupport::Concern
67
+
68
+ module ClassMethods
69
+ #
70
+ # Connect to database_alias specified in config
71
+ #
72
+ def use_database database_alias
73
+ # defer do
74
+ database_alias = database_alias.to_s
75
+ MongoMapper.db_config.must.include database_alias
76
+
77
+ self.connection MongoMapper.connections[database_alias]
78
+ set_database_name MongoMapper.db_config[database_alias]['name']
79
+ # end
80
+ end
81
+ end
82
+
83
+ end
84
+ end
85
+ end
@@ -1,95 +1,51 @@
1
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
2
  module Plugins
9
3
  module Micelaneous
4
+ extend ActiveSupport::Concern
10
5
 
11
6
  module InstanceMethods
12
- def upsert *args
13
- self.class.upsert id, *args
7
+ def upsert! *args
8
+ self.class.upsert!({id: id}, *args)
9
+ end
10
+
11
+ def exist?
12
+ self.class.find(id) != nil
14
13
  end
15
14
  end
16
15
 
17
- module ClassMethods
16
+ module ClassMethods
17
+ #
18
+ # model_name
19
+ #
20
+ def model_name *args
21
+ if args.empty?
22
+ @model_name ||= ::ActiveModel::Name.new self, self.alias
23
+ else
24
+ @model_name = ::ActiveModel::Name.new self, args.first
25
+ end
26
+ end
27
+
28
+
18
29
  #
19
30
  # Sequentiall :all for big collection
20
31
  #
21
32
  def all_sequentially &block
22
33
  page, per_page = 1, 5
23
34
  begin
24
- results = paginate(:page => page, :per_page => per_page, :order => '_id asc')
35
+ results = paginate(page: page, per_page: per_page, order: '_id asc')
25
36
  results.each{|o| block.call o}
26
37
  page += 1
27
38
  end until results.blank? or results.size < per_page
28
39
  end
29
40
 
30
41
 
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
42
  #
54
43
  # shortcut for upsert
55
44
  #
56
- def upsert *args
57
- collection.upsert *args
45
+ def upsert! query, *args
46
+ query[:_id] = query.delete :id if query.include? :id
47
+ collection.upsert! query, *args
58
48
  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
49
  end
94
50
 
95
51
  end