carrierwave_backgrounder_revived 1.0.0

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. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +15 -0
  5. data/CHANGELOG.md +99 -0
  6. data/Gemfile +4 -0
  7. data/README.md +229 -0
  8. data/Rakefile +12 -0
  9. data/carrierwave_backgrounder.gemspec +25 -0
  10. data/lib/backgrounder/delay.rb +26 -0
  11. data/lib/backgrounder/orm/activemodel.rb +36 -0
  12. data/lib/backgrounder/orm/base.rb +120 -0
  13. data/lib/backgrounder/orm/data_mapper.rb +63 -0
  14. data/lib/backgrounder/railtie.rb +25 -0
  15. data/lib/backgrounder/support/backends.rb +94 -0
  16. data/lib/backgrounder/version.rb +5 -0
  17. data/lib/backgrounder/workers.rb +6 -0
  18. data/lib/backgrounder/workers/base.rb +42 -0
  19. data/lib/backgrounder/workers/class_methods.rb +14 -0
  20. data/lib/backgrounder/workers/process_asset.rb +10 -0
  21. data/lib/backgrounder/workers/process_asset_mixin.rb +28 -0
  22. data/lib/backgrounder/workers/store_asset.rb +10 -0
  23. data/lib/backgrounder/workers/store_asset_mixin.rb +43 -0
  24. data/lib/carrierwave_backgrounder.rb +35 -0
  25. data/lib/generators/carrierwave_backgrounder/USAGE +8 -0
  26. data/lib/generators/carrierwave_backgrounder/install_generator.rb +20 -0
  27. data/lib/generators/carrierwave_backgrounder/templates/config/initializers/carrierwave_backgrounder.rb +10 -0
  28. data/spec/backgrounder/orm/activemodel_spec.rb +97 -0
  29. data/spec/backgrounder/orm/base_spec.rb +74 -0
  30. data/spec/backgrounder/support/backends_spec.rb +234 -0
  31. data/spec/backgrounder/workers/fixtures/images/test.jpg +0 -0
  32. data/spec/backgrounder/workers/process_asset_spec.rb +70 -0
  33. data/spec/backgrounder/workers/store_asset_spec.rb +137 -0
  34. data/spec/spec_helper.rb +20 -0
  35. data/spec/support/backend_constants.rb +58 -0
  36. data/spec/support/mock_worker.rb +22 -0
  37. metadata +151 -0
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+ require 'backgrounder/workers'
3
+
4
+ module CarrierWave
5
+ module Backgrounder
6
+ module ORM
7
+
8
+ ##
9
+ # Base class for all things orm
10
+ module Base
11
+
12
+ ##
13
+ # User#process_in_background will process and create versions in a background process.
14
+ #
15
+ # class User < ActiveRecord::Base
16
+ # mount_uploader :avatar, AvatarUploader
17
+ # process_in_background :avatar
18
+ # end
19
+ #
20
+ # The above adds a User#process_upload method which can be used at times when you want to bypass
21
+ # background storage and processing.
22
+ #
23
+ # @user.process_avatar = true
24
+ # @user.save
25
+ #
26
+ # You can also pass in your own workers using the second argument in case you need other things done
27
+ # during processing.
28
+ #
29
+ # class User < ActiveRecord::Base
30
+ # mount_uploader :avatar, AvatarUploader
31
+ # process_in_background :avatar, CustomWorker
32
+ # end
33
+ #
34
+ # In addition you can also add a column to the database appended by _processing with a type of boolean
35
+ # which can be used to check if processing is complete.
36
+ #
37
+ # def self.up
38
+ # add_column :users, :avatar_processing, :boolean
39
+ # end
40
+ #
41
+ def process_in_background(column, worker=::CarrierWave::Workers::ProcessAsset)
42
+ attr_accessor :"process_#{column}_upload"
43
+
44
+ mod = Module.new
45
+ include mod
46
+
47
+ _define_shared_backgrounder_methods(mod, column, worker)
48
+ end
49
+
50
+ ##
51
+ # #store_in_background will process, version and store uploads in a background process.
52
+ #
53
+ # class User < ActiveRecord::Base
54
+ # mount_uploader :avatar, AvatarUploader
55
+ # store_in_background :avatar
56
+ # end
57
+ #
58
+ # The above adds a User#process_<column>_upload method which can be used at times when you want to bypass
59
+ # background storage and processing.
60
+ #
61
+ # @user.process_avatar_upload = true
62
+ # @user.save
63
+ #
64
+ # You can also pass in your own workers using the second argument in case you need other things done
65
+ # during processing.
66
+ #
67
+ # class User < ActiveRecord::Base
68
+ # mount_uploader :avatar, AvatarUploader
69
+ # store_in_background :avatar, CustomWorker
70
+ # end
71
+ #
72
+ def store_in_background(column, worker=::CarrierWave::Workers::StoreAsset)
73
+ attr_accessor :"process_#{column}_upload"
74
+
75
+ mod = Module.new
76
+ include mod
77
+ mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
78
+ def remove_#{column}=(value)
79
+ super
80
+ self.process_#{column}_upload = true
81
+ end
82
+
83
+ def write_#{column}_identifier
84
+ super and return if process_#{column}_upload
85
+ self.#{column}_tmp = _mounter(:#{column}).cache_name if _mounter(:#{column}).cache_name
86
+ end
87
+
88
+ def store_#{column}!
89
+ super if process_#{column}_upload
90
+ end
91
+
92
+ RUBY
93
+
94
+ _define_shared_backgrounder_methods(mod, column, worker)
95
+ end
96
+
97
+ private
98
+
99
+ def _define_shared_backgrounder_methods(mod, column, worker)
100
+ mod.class_eval <<-RUBY, __FILE__, __LINE__ + 1
101
+ def #{column}_updated?; true; end
102
+
103
+ def set_#{column}_processing
104
+ self.#{column}_processing = true if respond_to?(:#{column}_processing)
105
+ end
106
+
107
+ def enqueue_#{column}_background_job?
108
+ !remove_#{column}? && !process_#{column}_upload && #{column}_updated?
109
+ end
110
+
111
+ def enqueue_#{column}_background_job
112
+ CarrierWave::Backgrounder.enqueue_for_backend(#{worker}, self.class.name, id.to_s, #{column}.mounted_as)
113
+ end
114
+ RUBY
115
+ end
116
+ end # Base
117
+
118
+ end #ORM
119
+ end #Backgrounder
120
+ end #CarrierWave
@@ -0,0 +1,63 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ module ORM
4
+
5
+ module DataMapper
6
+ include CarrierWave::Backgrounder::ORM::Base
7
+
8
+ def process_in_background(column, worker=::CarrierWave::Workers::ProcessAsset)
9
+ super
10
+
11
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
12
+ def set_#{column}_processing
13
+ @#{column}_changed = attribute_dirty?(:#{column})
14
+ self.#{column}_processing = true if respond_to?(:#{column}_processing)
15
+ end
16
+ RUBY
17
+ end
18
+
19
+ def store_in_background(column, worker=::CarrierWave::Workers::StoreAsset)
20
+ super
21
+
22
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
23
+ def set_#{column}_changed
24
+ @#{column}_changed = attribute_dirty?(:#{column})
25
+ end
26
+
27
+ def write_#{column}_identifier
28
+ super and return if process_#{column}_upload
29
+ self.#{column}_tmp = _mounter(:#{column}).cache_name
30
+ end
31
+ RUBY
32
+ end
33
+
34
+ private
35
+
36
+ def _define_shared_backgrounder_methods(mod, column, worker)
37
+ before :save, :"set_#{column}_changed"
38
+ after :save, :"enqueue_#{column}_background_job"
39
+
40
+ super
41
+
42
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
43
+ attr_reader :#{column}_changed
44
+
45
+ def enqueue_#{column}_background_job
46
+ if enqueue_#{column}_background_job?
47
+ CarrierWave::Backgrounder.enqueue_for_backend(#{worker}, self.class.name, id, #{column}.mounted_as)
48
+ @#{column}_changed = false
49
+ end
50
+ end
51
+
52
+ def #{column}_updated?
53
+ #{column}_changed
54
+ end
55
+ RUBY
56
+ end
57
+ end # DataMapper
58
+
59
+ end #ORM
60
+ end #Backgrounder
61
+ end #CarrierWave
62
+
63
+ DataMapper::Model.append_extensions ::CarrierWave::Backgrounder::ORM::DataMapper
@@ -0,0 +1,25 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ class Railtie < Rails::Railtie
4
+
5
+ initializer "carrierwave_backgrounder.active_record" do
6
+ ActiveSupport.on_load :active_record do
7
+ require 'backgrounder/orm/activemodel'
8
+ ::ActiveRecord::Base.extend CarrierWave::Backgrounder::ORM::ActiveModel
9
+ end
10
+ end
11
+
12
+ initializer "carrierwave_backgrounder.data_mapper", :before =>"data_mapper.add_to_prepare" do
13
+ require 'backgrounder/orm/data_mapper' if defined?(DataMapper)
14
+ end
15
+
16
+ initializer "carrierwave_backgrounder.mongoid" do
17
+ if defined?(Mongoid)
18
+ require 'backgrounder/orm/activemodel'
19
+ ::Mongoid::Document::ClassMethods.send(:include, ::CarrierWave::Backgrounder::ORM::ActiveModel)
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,94 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ module Support
4
+ module Backends
5
+
6
+ def self.included(base)
7
+ base.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ attr_reader :queue_options
12
+
13
+ def backend(queue_name=nil, args={})
14
+ return @backend if @backend
15
+ @queue_options = args
16
+ @backend = queue_name
17
+ end
18
+
19
+ def enqueue_for_backend(worker, class_name, subject_id, mounted_as)
20
+ self.send :"enqueue_#{backend}", worker, class_name, subject_id, mounted_as
21
+ end
22
+
23
+ private
24
+
25
+ def enqueue_active_job(worker, *args)
26
+ worker.perform(*args.map(&:to_s))
27
+ end
28
+
29
+ def enqueue_delayed_job(worker, *args)
30
+ worker_args = {}
31
+ if ::Delayed::Job.new.respond_to?(:queue)
32
+ worker_args[:queue] = queue_options[:queue] if queue_options[:queue]
33
+ worker_args[:priority] = queue_options[:priority] if queue_options[:priority]
34
+ ::Delayed::Job.enqueue worker.new(*args), worker_args
35
+ else
36
+ worker_args[:priority] = queue_options[:priority] if queue_options[:priority]
37
+ ::Delayed::Job.enqueue worker.new(*args), worker_args
38
+ if queue_options[:queue]
39
+ ::Rails.logger.warn("Queue name given but no queue column exists for Delayed::Job")
40
+ end
41
+ end
42
+ end
43
+
44
+ def enqueue_resque(worker, *args)
45
+ worker.instance_variable_set('@queue', queue_options[:queue] || :carrierwave)
46
+ ::Resque.enqueue worker, *args
47
+ end
48
+
49
+ def enqueue_sidekiq(worker, *args)
50
+ override_queue_name = worker.sidekiq_options['queue'] == 'default' || worker.sidekiq_options['queue'].nil?
51
+ args = sidekiq_queue_options(override_queue_name, 'class' => worker, 'args' => args)
52
+ worker.client_push(args)
53
+ end
54
+
55
+ def enqueue_girl_friday(worker, *args)
56
+ @girl_friday_queue ||= GirlFriday::WorkQueue.new(queue_options.delete(:queue) || :carrierwave, queue_options) do |msg|
57
+ worker = msg[:worker]
58
+ worker.perform
59
+ end
60
+ @girl_friday_queue << { :worker => worker.new(*args) }
61
+ end
62
+
63
+ def enqueue_sucker_punch(worker, *args)
64
+ worker.new.async.perform(*args)
65
+ end
66
+
67
+ def enqueue_qu(worker, *args)
68
+ worker.instance_variable_set('@queue', queue_options[:queue] || :carrierwave)
69
+ ::Qu.enqueue worker, *args
70
+ end
71
+
72
+ def enqueue_qc(worker, *args)
73
+ class_name, subject_id, mounted_as = args
74
+ ::QC.enqueue "#{worker.name}.perform", class_name, subject_id, mounted_as.to_s
75
+ end
76
+
77
+ def enqueue_immediate(worker, *args)
78
+ worker.new(*args).perform
79
+ end
80
+
81
+ def sidekiq_queue_options(override_queue_name, args)
82
+ if override_queue_name && queue_options[:queue]
83
+ args['queue'] = queue_options[:queue]
84
+ end
85
+ args['retry'] = queue_options[:retry] unless queue_options[:retry].nil?
86
+ args['timeout'] = queue_options[:timeout] if queue_options[:timeout]
87
+ args['backtrace'] = queue_options[:backtrace] if queue_options[:backtrace]
88
+ args
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,5 @@
1
+ module CarrierWave
2
+ module Backgrounder
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'backgrounder/workers/base'
2
+ require 'backgrounder/workers/class_methods'
3
+ require 'backgrounder/workers/process_asset_mixin'
4
+ require 'backgrounder/workers/store_asset_mixin'
5
+ require 'backgrounder/workers/process_asset'
6
+ require 'backgrounder/workers/store_asset'
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module Base
6
+ attr_accessor :klass, :id, :column, :record
7
+
8
+ def initialize(*args)
9
+ super(*args) unless self.class.superclass == Object
10
+ set_args(*args) if args.present?
11
+ end
12
+
13
+ def perform(*args)
14
+ set_args(*args) if args.present?
15
+ self.record = constantized_resource.find id
16
+ rescue *not_found_errors
17
+ end
18
+
19
+ private
20
+
21
+ def not_found_errors
22
+ [].tap do |errors|
23
+ errors << ::ActiveRecord::RecordNotFound if defined?(::ActiveRecord)
24
+ errors << ::Mongoid::Errors::DocumentNotFound if defined?(::Mongoid)
25
+ end
26
+ end
27
+
28
+ def set_args(klass, id, column)
29
+ self.klass, self.id, self.column = klass, id, column
30
+ end
31
+
32
+ def constantized_resource
33
+ klass.is_a?(String) ? klass.constantize : klass
34
+ end
35
+
36
+ def when_not_ready
37
+ end
38
+
39
+ end # Base
40
+
41
+ end # Workers
42
+ end # CarrierWave
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module ClassMethods
6
+
7
+ def perform(*args)
8
+ new(*args).perform
9
+ end
10
+
11
+ end # ClassMethods
12
+
13
+ end # Workers
14
+ end # Backgrounder
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ class ProcessAsset
6
+ include CarrierWave::Workers::ProcessAssetMixin
7
+ end # ProcessAsset
8
+
9
+ end # Workers
10
+ end # Backgrounder
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module ProcessAssetMixin
6
+ include CarrierWave::Workers::Base
7
+
8
+ def self.included(base)
9
+ base.extend CarrierWave::Workers::ClassMethods
10
+ end
11
+
12
+ def perform(*args)
13
+ record = super(*args)
14
+
15
+ if record && record.send(:"#{column}").present?
16
+ record.send(:"process_#{column}_upload=", true)
17
+ if record.send(:"#{column}").recreate_versions! && record.respond_to?(:"#{column}_processing")
18
+ record.update_attribute :"#{column}_processing", false
19
+ end
20
+ else
21
+ when_not_ready
22
+ end
23
+ end
24
+
25
+ end # ProcessAssetMixin
26
+
27
+ end # Workers
28
+ end # Backgrounder
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ class StoreAsset
6
+ include CarrierWave::Workers::StoreAssetMixin
7
+ end # StoreAsset
8
+
9
+ end # Workers
10
+ end # Backgrounder
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ module CarrierWave
3
+ module Workers
4
+
5
+ module StoreAssetMixin
6
+ include CarrierWave::Workers::Base
7
+
8
+ def self.included(base)
9
+ base.extend CarrierWave::Workers::ClassMethods
10
+ end
11
+
12
+ attr_reader :cache_path, :tmp_directory
13
+
14
+ def perform(*args)
15
+ record = super(*args)
16
+
17
+ if record && record.send(:"#{column}_tmp")
18
+ store_directories(record)
19
+ record.send :"process_#{column}_upload=", true
20
+ record.send :"#{column}_tmp=", nil
21
+ record.send :"#{column}_processing=", false if record.respond_to?(:"#{column}_processing")
22
+ File.open(cache_path) { |f| record.send :"#{column}=", f }
23
+ if record.save!
24
+ FileUtils.rm_r(tmp_directory, :force => true)
25
+ end
26
+ else
27
+ when_not_ready
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def store_directories(record)
34
+ asset, asset_tmp = record.send(:"#{column}"), record.send(:"#{column}_tmp")
35
+ cache_directory = File.expand_path(asset.cache_dir, asset.root)
36
+ @cache_path = File.join(cache_directory, asset_tmp)
37
+ @tmp_directory = File.join(cache_directory, asset_tmp.split("/").first)
38
+ end
39
+
40
+ end # StoreAssetMixin
41
+
42
+ end # Workers
43
+ end # Backgrounder