mongo_mapper_ext 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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