balloon 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.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/README.md +185 -0
- data/README_EN.md +4 -0
- data/Rakefile +1 -0
- data/balloon.gemspec +35 -0
- data/lib/balloon.rb +42 -0
- data/lib/balloon/base.rb +43 -0
- data/lib/balloon/cache.rb +44 -0
- data/lib/balloon/configuration.rb +85 -0
- data/lib/balloon/download.rb +50 -0
- data/lib/balloon/error.rb +5 -0
- data/lib/balloon/file_extension.rb +187 -0
- data/lib/balloon/http/client.rb +91 -0
- data/lib/balloon/http/response.rb +71 -0
- data/lib/balloon/load.rb +33 -0
- data/lib/balloon/locale/en.yml +7 -0
- data/lib/balloon/processing.rb +98 -0
- data/lib/balloon/storage/file.rb +62 -0
- data/lib/balloon/storage/store.rb +84 -0
- data/lib/balloon/storage/upyun.rb +91 -0
- data/lib/balloon/up.rb +100 -0
- data/lib/balloon/uploader.rb +90 -0
- data/lib/balloon/validate.rb +41 -0
- data/lib/balloon/version.rb +3 -0
- data/lib/rails/generators/balloon/config/config_generator.rb +15 -0
- data/lib/rails/generators/balloon/config/templates/balloon.yml +11 -0
- data/spec/fixtures/UPCASE.JPG +0 -0
- data/spec/fixtures/egg +0 -0
- data/spec/fixtures/invalid.jpg +1 -0
- data/spec/fixtures/kid.gif +0 -0
- data/spec/fixtures/kids.gif +0 -0
- data/spec/fixtures/word.txt +1 -0
- metadata +237 -0
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'mini_magick'
|
2
|
+
|
3
|
+
module Balloon
|
4
|
+
module Processing
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
def resize_with_string(file)
|
8
|
+
width, height = "", ""
|
9
|
+
oranginl_img = MiniMagick::Image.open(file.path)
|
10
|
+
auto_orient!(oranginl_img, file.path)
|
11
|
+
if self.respond_to?(:uploader_size) && !(store_storage.to_s == "upyun" && upyun_is_image)
|
12
|
+
uploader_size.each do |s, o|
|
13
|
+
img = MiniMagick::Image.open(file.path)
|
14
|
+
raise ProcessError, "process error" unless img
|
15
|
+
width = img[:width]
|
16
|
+
height = img[:height]
|
17
|
+
new_img = resize(img, o)
|
18
|
+
new_img.write File.join(cache_path, "#{file.basename}_#{s}.#{file.extension}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return {width: oranginl_img[:width], height: oranginl_img[:height]}
|
22
|
+
end
|
23
|
+
|
24
|
+
def resize(image, size)
|
25
|
+
width, height, symbol = size[:width], size[:height], size[:symbol]
|
26
|
+
if !symbol.empty? || width.match(/\%/) || height.match(/\%/)
|
27
|
+
if width == height
|
28
|
+
image = shave(image)
|
29
|
+
image.resize "#{width}"
|
30
|
+
else
|
31
|
+
image.resize "#{width}x#{height}#{symbol}"
|
32
|
+
end
|
33
|
+
else
|
34
|
+
if width == height
|
35
|
+
image = shave(image)
|
36
|
+
value = (width.to_f / image[:width].to_f) * 100
|
37
|
+
image.resize "#{value}%"
|
38
|
+
else
|
39
|
+
if width.empty?
|
40
|
+
value = (height.to_f / image[:height].to_f) * 100
|
41
|
+
image.resize "#{value}%"
|
42
|
+
elsif height.empty?
|
43
|
+
value = (width.to_f / image[:width].to_f) * 100
|
44
|
+
image.resize "#{value}%"
|
45
|
+
else
|
46
|
+
image.resize "#{width}x#{height}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return image
|
51
|
+
end
|
52
|
+
|
53
|
+
def shave(image)
|
54
|
+
w, h = image[:width], image[:height]
|
55
|
+
if w > h
|
56
|
+
shave_off = ((w - h) / 2).round
|
57
|
+
image.shave "#{shave_off}x0"
|
58
|
+
else
|
59
|
+
shave_off = ((h - w) / 2).round
|
60
|
+
image.shave "0x#{shave_off}"
|
61
|
+
end
|
62
|
+
return image
|
63
|
+
end
|
64
|
+
|
65
|
+
def auto_orient!(img, file)
|
66
|
+
if img["exif:orientation"] == "6"
|
67
|
+
img.auto_orient
|
68
|
+
img.write file
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# parseing the size string
|
73
|
+
#
|
74
|
+
# @return [Hash] the options for string
|
75
|
+
module ClassMethods
|
76
|
+
def parsing_size_string(size)
|
77
|
+
symbol = ""
|
78
|
+
symbol_regex = /[^\d|\!|\>|\<|\%|x|X]/
|
79
|
+
if size.include?('x')
|
80
|
+
if has_symbol = size.match(/[\!|\>|\<]/)
|
81
|
+
symbol = has_symbol[0]
|
82
|
+
size_option = size[0, 7].split("x")
|
83
|
+
else
|
84
|
+
size_option = size.split("x")
|
85
|
+
end
|
86
|
+
width, height = size_option
|
87
|
+
else
|
88
|
+
width, height = size, size
|
89
|
+
end
|
90
|
+
width = width || ""
|
91
|
+
width = width.match(symbol_regex) ? "" : width
|
92
|
+
height = height || ""
|
93
|
+
height = height.match(symbol_regex) ? "" : height
|
94
|
+
return { width: width, height: height, symbol: symbol }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Balloon
|
2
|
+
module Storage
|
3
|
+
class File < Balloon::Storage::Store
|
4
|
+
def store!
|
5
|
+
_store_path = store_path
|
6
|
+
|
7
|
+
if !::File.exists? _store_path
|
8
|
+
FileUtils.mkdir_p _store_path
|
9
|
+
FileUtils.chmod_R @uploader.dir_permissions.to_i, _store_path
|
10
|
+
end
|
11
|
+
|
12
|
+
original_file = set_upload_name
|
13
|
+
store_original_file = ::File.join _store_path, original_file
|
14
|
+
cache_original_file = ::File.join @uploader.cache_path, @uploader.info[:filename]
|
15
|
+
FileUtils.mv cache_original_file, store_original_file
|
16
|
+
|
17
|
+
if @uploader.respond_to?(:uploader_size)
|
18
|
+
@uploader.uploader_size.each do |s, o|
|
19
|
+
store_file = ::File.join _store_path, set_upload_name(s)
|
20
|
+
cache_file = ::File.join @uploader.cache_path, @uploader.info[:basename]+ "_#{s}"+"."+ @uploader.info[:extension]
|
21
|
+
FileUtils.mv cache_file, store_file
|
22
|
+
end
|
23
|
+
end
|
24
|
+
return { filename: original_file, basename: store_name}
|
25
|
+
end
|
26
|
+
|
27
|
+
def retrieve!(size_name = nil)
|
28
|
+
return "" if !upload_file
|
29
|
+
path = ::File.join upload_dir, store_filename(size_name)
|
30
|
+
return "/" + path if @uploader.asset_host.nil?
|
31
|
+
@uploader.asset_host + "/" + path
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete!
|
35
|
+
return false if !upload_file
|
36
|
+
path = ::File.join store_path, store_filename
|
37
|
+
FileUtils.rm(path) if ::File.exists?(path)
|
38
|
+
if @uploader.respond_to?(:uploader_size)
|
39
|
+
@uploader.uploader_size.each do |s, o|
|
40
|
+
path = ::File.join store_path, store_filename(s)
|
41
|
+
FileUtils.rm(path) if ::File.exists?(path)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def store_filename(size_name = nil)
|
49
|
+
extension = upload_file[:extension].blank? ? "" : "." + upload_file[:extension]
|
50
|
+
if size_name.nil?
|
51
|
+
upload_file[:basename] + extension
|
52
|
+
else
|
53
|
+
upload_file[:basename] + "_" + size_name.to_s + extension
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def store_path
|
58
|
+
::File.expand_path ::File.join(@uploader.root, @uploader.store_dir, upload_dir)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Balloon
|
2
|
+
module Storage
|
3
|
+
class Store
|
4
|
+
def initialize(uploader)
|
5
|
+
@uploader = uploader
|
6
|
+
end
|
7
|
+
|
8
|
+
def store!; end
|
9
|
+
|
10
|
+
def retrieve!(size_name = nil); end
|
11
|
+
|
12
|
+
def upload_file
|
13
|
+
file_info = @uploader.info
|
14
|
+
return {} if file_info.nil?
|
15
|
+
basename = file_info[:basename] || ""
|
16
|
+
extension = file_info[:extension] || ""
|
17
|
+
{ basename: basename, extension: extension }
|
18
|
+
end
|
19
|
+
|
20
|
+
def upload_dir
|
21
|
+
@uploader.respond_to?(:uploader_dir) ? @uploader.uploader_dir : @uploader.uploader_name
|
22
|
+
end
|
23
|
+
|
24
|
+
def store_name
|
25
|
+
return upload_file[:basename] if !@uploader.respond_to?(:uploader_name_format)
|
26
|
+
name_format = @uploader.uploader_name_format
|
27
|
+
name = name_format[:name]
|
28
|
+
if name_format[:format].to_s == "downcase"
|
29
|
+
name = name.downcase
|
30
|
+
elsif name_format[:format].to_s == "upcase"
|
31
|
+
name = name.upcase
|
32
|
+
else
|
33
|
+
name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def set_upload_name(size_name = nil )
|
38
|
+
if size_name
|
39
|
+
store_name + "_#{size_name.to_s}" + "." + upload_file[:extension]
|
40
|
+
else
|
41
|
+
store_name + "." + upload_file[:extension]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def connection
|
46
|
+
options = self.class.get_option(self)
|
47
|
+
basic = self.class.get_basic_auth(self)
|
48
|
+
token = self.class.token_auth
|
49
|
+
conn = Http::Client.new(options[:url]) do |builder|
|
50
|
+
builder.headers = options[:headers]
|
51
|
+
builder.basic_auth(basic[:user], basic[:password]) if !basic.nil?
|
52
|
+
builder.token_auth(self, token) if !token.nil?
|
53
|
+
end
|
54
|
+
return conn
|
55
|
+
end
|
56
|
+
|
57
|
+
class << self
|
58
|
+
def conn_option(&block)
|
59
|
+
return @option_proc unless block_given?
|
60
|
+
@option_proc = block
|
61
|
+
end
|
62
|
+
|
63
|
+
def get_option(klass)
|
64
|
+
klass.instance_eval(&conn_option)
|
65
|
+
end
|
66
|
+
|
67
|
+
def basic_auth(&block)
|
68
|
+
return @basic_proc unless block_given?
|
69
|
+
@basic_proc = block
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_basic_auth(klass)
|
73
|
+
return nil if basic_auth.nil?
|
74
|
+
klass.instance_eval(&basic_auth)
|
75
|
+
end
|
76
|
+
|
77
|
+
def token_auth(&block)
|
78
|
+
return @token_proc unless block_given?
|
79
|
+
@token_proc = block
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Balloon
|
2
|
+
module Storage
|
3
|
+
class Upyun < Balloon::Storage::Store
|
4
|
+
|
5
|
+
conn_option do
|
6
|
+
{
|
7
|
+
url: conn_url,
|
8
|
+
headers: conn_headers,
|
9
|
+
timeout: @uploader.upyun_timeout
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
token_auth do |method, path, size, date|
|
14
|
+
"encode_canonical('#{method}', '#{path}', #{size}, '#{date}')"
|
15
|
+
end
|
16
|
+
|
17
|
+
def store!
|
18
|
+
_store_path = store_path
|
19
|
+
original_file = set_upload_name
|
20
|
+
store_original_file = ::File.join _store_path, original_file
|
21
|
+
cache_original_file = ::File.join @uploader.cache_path, @uploader.info[:filename]
|
22
|
+
file = ::File.new cache_original_file
|
23
|
+
response = connection.put(store_original_file, file.read, file.size)
|
24
|
+
raise "Connection errors" if response.nil?
|
25
|
+
|
26
|
+
if !@uploader.upyun_is_image && @uploader.respond_to?(:uploader_size)
|
27
|
+
@uploader.uploader_size.each do |s, o|
|
28
|
+
store_file = ::File.join _store_path, set_upload_name(s)
|
29
|
+
cache_file = ::File.join @uploader.cache_path, @uploader.info[:basename]+ "_#{s}"+"."+ @uploader.info[:extension]
|
30
|
+
file = ::File.new cache_file
|
31
|
+
connection.put(store_file, file.read, file.size)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
return { filename: original_file, basename: store_name }
|
36
|
+
end
|
37
|
+
|
38
|
+
def retrieve!(size_name = nil)
|
39
|
+
if !@uploader.upyun_is_image || size_name.nil?
|
40
|
+
path = ::File.join upload_dir, store_filename(size_name)
|
41
|
+
@uploader.upyun_domain + "/" + path
|
42
|
+
else
|
43
|
+
filename = store_filename + @uploader.upyun_thumb_symbol + size_name.to_s
|
44
|
+
path = ::File.join upload_dir, filename
|
45
|
+
@uploader.upyun_domain + "/" + path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete!
|
50
|
+
_store_path = store_path
|
51
|
+
store_original_file = ::File.join _store_path, store_filename
|
52
|
+
response = connection.delete(store_original_file)
|
53
|
+
if !@uploader.upyun_is_image && @uploader.respond_to?(:uploader_size)
|
54
|
+
@uploader.uploader_size.each do |s, o|
|
55
|
+
store_file = ::File.join _store_path, store_filename(s)
|
56
|
+
connection.delete(store_file)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def encode_canonical(method, path, size, date)
|
64
|
+
options = []
|
65
|
+
options << method
|
66
|
+
options << path
|
67
|
+
options << date
|
68
|
+
options << size
|
69
|
+
options << "#{Digest::MD5.hexdigest(@uploader.upyun_password)}"
|
70
|
+
"UpYun #{@uploader.upyun_username}:#{Digest::MD5.hexdigest(options.join("&"))}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def store_filename(size_name = nil)
|
74
|
+
return upload_file[:basename] + "." + upload_file[:extension] if size_name == nil
|
75
|
+
upload_file[:basename] + "_" + size_name.to_s + "." + upload_file[:extension]
|
76
|
+
end
|
77
|
+
|
78
|
+
def conn_url
|
79
|
+
@uploader.upyun_api_host || "http://v0.api.upyun.com"
|
80
|
+
end
|
81
|
+
|
82
|
+
def conn_headers
|
83
|
+
@uploader.upyun_headers.merge({ 'Mkdir' => 'true', 'Expect' => '', 'Date' => Time.now.httpdate })
|
84
|
+
end
|
85
|
+
|
86
|
+
def store_path
|
87
|
+
::File.join("/", @uploader.upyun_bucket, upload_dir)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/balloon/up.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module Balloon
|
2
|
+
module Up
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include Balloon::Uploader
|
7
|
+
include Balloon::Validate
|
8
|
+
end
|
9
|
+
|
10
|
+
module ClassMethods
|
11
|
+
def uploader(name, db = nil)
|
12
|
+
|
13
|
+
before_create :uploader_save
|
14
|
+
|
15
|
+
class_eval <<-RUBY
|
16
|
+
def #{name}=(file)
|
17
|
+
save_to_cache(file)
|
18
|
+
rescue DownloadError => e
|
19
|
+
@download_error = e
|
20
|
+
rescue ProcessError => e
|
21
|
+
@process_error = e
|
22
|
+
end
|
23
|
+
|
24
|
+
def #{name}
|
25
|
+
@info
|
26
|
+
end
|
27
|
+
|
28
|
+
def uploader_save
|
29
|
+
return if info.nil?
|
30
|
+
set_storage_engine
|
31
|
+
store_info = storage_engine.store!
|
32
|
+
@info[:filename] = store_info[:filename]
|
33
|
+
@info[:basename] = store_info[:basename]
|
34
|
+
end
|
35
|
+
|
36
|
+
def uploader_name
|
37
|
+
"#{name}".pluralize
|
38
|
+
end
|
39
|
+
RUBY
|
40
|
+
|
41
|
+
set_keyword if db
|
42
|
+
|
43
|
+
validates_download_of name
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_keyword
|
47
|
+
if defined?(MongoMapper)
|
48
|
+
key :file_name, String
|
49
|
+
key :width, Integer
|
50
|
+
key :height, Integer
|
51
|
+
key :content_type, String
|
52
|
+
key :file_size, Integer
|
53
|
+
key :storage, String
|
54
|
+
key :created_at
|
55
|
+
elsif defined?(Mongoid)
|
56
|
+
field :file_name, type: String
|
57
|
+
field :width, type: Integer
|
58
|
+
field :height, type: Integer
|
59
|
+
field :content_type, type: String
|
60
|
+
field :file_size, type: String
|
61
|
+
field :storage, type: String
|
62
|
+
field :created_at
|
63
|
+
end
|
64
|
+
|
65
|
+
before_create :save_db
|
66
|
+
after_destroy :uploader_delete
|
67
|
+
|
68
|
+
class_eval <<-RUBY
|
69
|
+
def save_db
|
70
|
+
return if info.nil?
|
71
|
+
self.file_name = info[:filename]
|
72
|
+
self.content_type = info[:mime_type]
|
73
|
+
self.file_size = info[:size]
|
74
|
+
self.storage = store_storage.to_s
|
75
|
+
self.width = info[:width]
|
76
|
+
self.height = info[:height]
|
77
|
+
end
|
78
|
+
|
79
|
+
def url(size_name = nil)
|
80
|
+
return "" if !respond_to?(:file_name) || file_name.nil?
|
81
|
+
extension = self.file_name.to_s.match(%r"(?!\\.{1})\\w{2,}$")
|
82
|
+
basename = self.file_name.to_s.gsub(%r"\\.{1}\\w{2,}$",'')
|
83
|
+
@info = { basename: basename, extension: extension.to_s }
|
84
|
+
set_storage_engine
|
85
|
+
storage_engine.retrieve!(size_name)
|
86
|
+
end
|
87
|
+
|
88
|
+
def uploader_delete
|
89
|
+
return if !respond_to?(:file_name) || file_name.nil?
|
90
|
+
extension = self.file_name.to_s.match(%r"(?!\\.{1})\\w{2,}$")
|
91
|
+
basename = self.file_name.to_s.gsub(%r"\\.{1}\\w{2,}$",'')
|
92
|
+
@info = { basename: basename, extension: extension.to_s }
|
93
|
+
set_storage_engine
|
94
|
+
storage_engine.delete!
|
95
|
+
end
|
96
|
+
RUBY
|
97
|
+
end
|
98
|
+
end #ClassMethods
|
99
|
+
end #Up
|
100
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Balloon
|
2
|
+
module Uploader
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
include Balloon::Configuration
|
7
|
+
include Balloon::Processing
|
8
|
+
include Balloon::Cache
|
9
|
+
include Balloon::Download
|
10
|
+
attr_accessor :file
|
11
|
+
attr_reader :storage_engine
|
12
|
+
attr_reader :info
|
13
|
+
attr_accessor :download_error, :process_error
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_storage_engine
|
17
|
+
@storage_engine = eval(Balloon::Base::STORAGE_EGINE[store_storage.to_sym]).new(self) if !respond_to?(:@storage_engine)
|
18
|
+
end
|
19
|
+
|
20
|
+
def save_to_cache(up_file)
|
21
|
+
uploader_file = up_file.is_a?(String) && up_file.include?("://") ? down_url(up_file) : up_file
|
22
|
+
|
23
|
+
uploader_file_ext = Balloon::FileExtension.new(uploader_file)
|
24
|
+
file_mime_type = uploader_file_ext.mime_type
|
25
|
+
|
26
|
+
if self.respond_to?(:uploader_mimetype_white)
|
27
|
+
if !uploader_mimetype_white.include?(file_mime_type)
|
28
|
+
raise Balloon::DownloadError, I18n.translate(:"errors.messages.down_mime_error")
|
29
|
+
end
|
30
|
+
elsif self.respond_to?(:uploader_mimetype_black)
|
31
|
+
if !uploader_mimetype_black.include?(file_mime_type)
|
32
|
+
raise Balloon::DownloadError, I18n.translate(:"errors.messages.down_mime_error")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
generate_cache_directory
|
37
|
+
up_file = uploader_file_ext.save_to cache_path, permissions
|
38
|
+
uploader_file = up_file
|
39
|
+
img = resize_with_string up_file
|
40
|
+
@info = {
|
41
|
+
width: img[:width],
|
42
|
+
height: img[:height],
|
43
|
+
size: up_file.size,
|
44
|
+
mime_type: up_file.mime_type,
|
45
|
+
filename: up_file.filename,
|
46
|
+
basename: up_file.basename,
|
47
|
+
extension: up_file.extension
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
def url(size_name = nil); end
|
52
|
+
|
53
|
+
module ClassMethods
|
54
|
+
def uploader_dir(name)
|
55
|
+
define_method "uploader_dir" do; name; end
|
56
|
+
end
|
57
|
+
|
58
|
+
def uploader_size(options)
|
59
|
+
list = {}
|
60
|
+
|
61
|
+
if options.is_a?(Hash)
|
62
|
+
options.each do |key, value|
|
63
|
+
list[key] = parsing_size_string(value)
|
64
|
+
end
|
65
|
+
else
|
66
|
+
list[:orignal] = parsing_size_string options
|
67
|
+
end
|
68
|
+
|
69
|
+
define_method "uploader_size" do; list; end
|
70
|
+
end
|
71
|
+
|
72
|
+
def uploader_name_format(info)
|
73
|
+
define_method "uploader_name_format" do
|
74
|
+
name = info[:name].nil? ? info[:name] : info[:name].call(self)
|
75
|
+
{ name: name, format: info[:format] }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def uploader_mimetype_white(list)
|
80
|
+
raise "just choise one method" if respond_to?(:uploader_mime_type_black)
|
81
|
+
define_method "uploader_mimetype_white" do; list; end
|
82
|
+
end
|
83
|
+
|
84
|
+
def uploader_mimetype_black(list)
|
85
|
+
raise "just choise one method" if respond_to?(:uploader_mime_type_black)
|
86
|
+
define_method "uploader_mimetype_black" do; list; end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end #Uploader
|
90
|
+
end
|