has_media 0.0.4
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.
- data/.document +6 -0
- data/.gitignore +21 -0
- data/LICENSE +22 -0
- data/README.rdoc +33 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/generators/has_media/has_media_generator.rb +8 -0
- data/generators/has_media/templates/create_media.rb +24 -0
- data/generators/has_media/templates/create_media_links.rb +17 -0
- data/generators/has_media_generator.rb +8 -0
- data/lib/has_media/models/audio.rb +9 -0
- data/lib/has_media/models/image.rb +9 -0
- data/lib/has_media/models/media_link.rb +4 -0
- data/lib/has_media/models/medium.rb +166 -0
- data/lib/has_media/models/pdf.rb +9 -0
- data/lib/has_media/uploaders/audio_uploader.rb +7 -0
- data/lib/has_media/uploaders/image_uploader.rb +7 -0
- data/lib/has_media/uploaders/medium_uploader.rb +15 -0
- data/lib/has_media/uploaders/pdf_uploader.rb +10 -0
- data/lib/has_media.rb +195 -0
- data/spec/fixtures/media/Conversational_Capital _Explained.pdf +0 -0
- data/spec/fixtures/media/audio.wav +0 -0
- data/spec/fixtures/media/image.jpg +0 -0
- data/spec/fixtures/media/image_bis.jpg +0 -0
- data/spec/fixtures/media/lc_pdf_overview_format.pdf +0 -0
- data/spec/has_media_spec.rb +166 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +53 -0
- metadata +124 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
(The MIT License)
|
2
|
+
|
3
|
+
Copyright (c) 2009 AF83
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
= has_media
|
2
|
+
|
3
|
+
Media Managment Library for ActiveRecord and Carrierwave
|
4
|
+
|
5
|
+
Easy way to link media (ie image, audio, pdf for now) on other activerecords models
|
6
|
+
|
7
|
+
=== Create migrations
|
8
|
+
|
9
|
+
./script/generate has_media
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
has_one_medium :image, :only => :image
|
14
|
+
has_many_media :images, :only => :image
|
15
|
+
|
16
|
+
has_one_medium :audio, :only => :audio
|
17
|
+
has_many_media :audios, :only => :audio
|
18
|
+
|
19
|
+
has_one_medium :image_no_encode, :only => :image, :encode => false
|
20
|
+
|
21
|
+
has_one_medium :pdf, :encode => false
|
22
|
+
|
23
|
+
== TODO
|
24
|
+
|
25
|
+
* Add a video class
|
26
|
+
|
27
|
+
== Contributors
|
28
|
+
|
29
|
+
klacointe, spk, shingara, nono
|
30
|
+
|
31
|
+
== Copyright
|
32
|
+
|
33
|
+
Copyright (c) 2009 AF83. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rubygems'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "has_media"
|
8
|
+
gem.summary = %Q{Media Managment Library for ActiveRecord and Carrierwave}
|
9
|
+
gem.description = %Q{Media Managment Library for ActiveRecord and Carrierwave}
|
10
|
+
gem.email = "kevinlacointe@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/AF83/has_media"
|
12
|
+
gem.authors = ["klacointe", "spk"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_dependency('carrierwave', '>=0.4.2')
|
15
|
+
gem.add_dependency('activerecord', '>=2.3.4')
|
16
|
+
gem.add_dependency('activesupport', '>=2.3.4')
|
17
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
+
end
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'spec/rake/spectask'
|
24
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
25
|
+
spec.libs << 'lib' << 'spec'
|
26
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
end
|
28
|
+
|
29
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
32
|
+
spec.rcov = true
|
33
|
+
end
|
34
|
+
|
35
|
+
task :spec => :check_dependencies
|
36
|
+
|
37
|
+
task :default => :spec
|
38
|
+
|
39
|
+
require 'rake/rdoctask'
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "has_media #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.4
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class HasMediaGenerator < Rails::Generator::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.migration_template('create_media.rb', 'db/migrate', :migration_file_name => 'create_media')
|
5
|
+
m.migration_template('create_media_links.rb', 'db/migrate', :migration_file_name => 'create_media_links')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class CreateMedia < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :media do |t|
|
4
|
+
t.integer :width
|
5
|
+
t.integer :height
|
6
|
+
t.integer :size
|
7
|
+
t.string :content_type # required
|
8
|
+
t.string :url
|
9
|
+
t.string :filename # required
|
10
|
+
t.string :thumbnail
|
11
|
+
t.integer :encode_status # required
|
12
|
+
t.string :type # required
|
13
|
+
t.string :status
|
14
|
+
t.string :context # required
|
15
|
+
t.timestamps
|
16
|
+
end
|
17
|
+
add_index :media, :encode_status
|
18
|
+
add_index :media, [:type, :context]
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.down
|
22
|
+
drop_table :media
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreateMediaLinks < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :media_links do |t|
|
4
|
+
t.integer :medium_id # required
|
5
|
+
t.integer :mediated_id # required
|
6
|
+
t.string :mediated_type # required
|
7
|
+
|
8
|
+
t.timestamps
|
9
|
+
end
|
10
|
+
add_index :media_links, :medium_id
|
11
|
+
add_index :media_links, [:mediated_id, :mediated_type]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
drop_table :media_links
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
class HasMediaGenerator < Rails::Generator::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.migration_template('create_media.rb', 'db/migrate', :migration_file_name => 'create_media')
|
5
|
+
m.migration_template('create_media_links.rb', 'db/migrate', :migration_file_name => 'create_media_links')
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
class Medium < ActiveRecord::Base
|
2
|
+
set_table_name 'media'
|
3
|
+
|
4
|
+
has_many :media_links, :foreign_key => :medium_id, :dependent => :destroy
|
5
|
+
has_many :mediated, :through => :media_links
|
6
|
+
|
7
|
+
mount_uploader :file, MediumUploader
|
8
|
+
|
9
|
+
validates_presence_of :context
|
10
|
+
|
11
|
+
attr_accessible :label, :description
|
12
|
+
|
13
|
+
ENCODE_WAIT = 0
|
14
|
+
ENCODE_ENCODING = 1
|
15
|
+
ENCODE_SUCCESS = 2
|
16
|
+
ENCODE_FAILURE = 3
|
17
|
+
ENCODE_NOT_READY = 4
|
18
|
+
NO_ENCODING = 5
|
19
|
+
|
20
|
+
EXTENSIONS = {
|
21
|
+
:image => 'png',
|
22
|
+
:audio => 'mp3',
|
23
|
+
:pdf => 'pdf',
|
24
|
+
}
|
25
|
+
|
26
|
+
# Allowed MIME types for upload
|
27
|
+
# need custom configuration
|
28
|
+
# TODO: add errors if not type of file
|
29
|
+
@@mime_types = {
|
30
|
+
:video => ['video/mpeg', 'video/mp4', 'video/quicktime', 'video/x-ms-wmv', 'video/x-flv', 'video/x-msvideo'],
|
31
|
+
:image => HasMedia.images_content_types,
|
32
|
+
:audio => ['audio/mpeg', 'audio/x-ms-wma', 'audio/x-wav'],
|
33
|
+
:flash => ['application/x-shockwave-flash'],
|
34
|
+
:pdf => ['application/pdf'],
|
35
|
+
}
|
36
|
+
|
37
|
+
# TODO : check that carrierwave destroy files on after detroy hook
|
38
|
+
after_destroy :remove_file_from_fs
|
39
|
+
after_initialize :set_default_encoding_status
|
40
|
+
|
41
|
+
|
42
|
+
named_scope :with_context, lambda {|context|
|
43
|
+
{ :conditions => { :context => context.to_s} }
|
44
|
+
}
|
45
|
+
|
46
|
+
def self.sanitize(name)
|
47
|
+
name = name.gsub("\\", "/") # work-around for IE
|
48
|
+
name = File.basename(name)
|
49
|
+
name = name.gsub(/[^a-zA-Z0-9\.\-\+_]/,"_")
|
50
|
+
name = "_#{name}" if name =~ /\A\.+\z/
|
51
|
+
name = "unnamed" if name.size == 0
|
52
|
+
return name.downcase
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.new_from_value(object, value, context, encode, only)
|
56
|
+
only ||= ""
|
57
|
+
medium_types = [Image, Audio, Pdf]
|
58
|
+
if only != "" and klass = Kernel.const_get(only.capitalize)
|
59
|
+
medium_types = [klass]
|
60
|
+
end
|
61
|
+
klass = medium_types.find do |k|
|
62
|
+
if k.respond_to?(:handle_content_type?)
|
63
|
+
k.handle_content_type?(value.content_type)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if klass.nil?
|
67
|
+
object.media_errors = [HasMedia.errors_messages[:type_error]]
|
68
|
+
return
|
69
|
+
end
|
70
|
+
medium = klass.new
|
71
|
+
medium.filename = self.sanitize(value.original_filename)
|
72
|
+
medium.file = value
|
73
|
+
medium.content_type = value.content_type
|
74
|
+
medium.context = context
|
75
|
+
medium.encode_status = (encode == "false" ? NO_ENCODING : ENCODE_WAIT)
|
76
|
+
medium.save
|
77
|
+
medium
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Is this medium encoding?
|
82
|
+
#
|
83
|
+
def encoding?
|
84
|
+
encode_status == ENCODE_ENCODING
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# Is this medium ready?
|
89
|
+
#
|
90
|
+
def ready?
|
91
|
+
encode_status == ENCODE_SUCCESS
|
92
|
+
end
|
93
|
+
|
94
|
+
##
|
95
|
+
# Has the encoding failed for this medium
|
96
|
+
#
|
97
|
+
def failed?
|
98
|
+
encode_status == ENCODE_FAILURE
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# Delete media file(s) from disk
|
103
|
+
#
|
104
|
+
def unlink_files
|
105
|
+
file = self.full_filename
|
106
|
+
File.unlink(file) if File.exists? file
|
107
|
+
end
|
108
|
+
|
109
|
+
# Public path to the file originally uploaded.
|
110
|
+
def original_file_path
|
111
|
+
File.join(directory_path, self.filename)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Http uri to the originally file
|
115
|
+
def original_file_uri
|
116
|
+
File.join(directory_uri, self.filename)
|
117
|
+
end
|
118
|
+
|
119
|
+
# System directory to store files
|
120
|
+
def directory_path
|
121
|
+
self.file.store_dir
|
122
|
+
end
|
123
|
+
# system path for a medium
|
124
|
+
def file_path(thumbnail = nil)
|
125
|
+
final_name = filename.gsub /\.[^.]+$/, '.' + file_extension
|
126
|
+
final_name[-4,0] = "_#{thumbnail}" if thumbnail
|
127
|
+
File.join(directory_path, final_name)
|
128
|
+
end
|
129
|
+
|
130
|
+
# http uri for a medium
|
131
|
+
def file_uri(thumbnail = nil)
|
132
|
+
final_name = filename.gsub /\.[^.]+$/, '.' + file_extension
|
133
|
+
final_name[-4,0] = "_#{thumbnail}" if thumbnail
|
134
|
+
File.join(directory_uri, final_name)
|
135
|
+
end
|
136
|
+
# http uri of directory which stores media
|
137
|
+
def directory_uri
|
138
|
+
File.join(HasMedia.directory_uri,
|
139
|
+
ActiveSupport::Inflector.underscore(self.type),
|
140
|
+
self.id.to_s)
|
141
|
+
end
|
142
|
+
|
143
|
+
def file_exists?(thumbnail = nil)
|
144
|
+
File.exist?(File.join(Rails.root, 'public', file_uri(thumbnail)))
|
145
|
+
end
|
146
|
+
|
147
|
+
def file_extension
|
148
|
+
EXTENSIONS[type.downcase.to_sym]
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
##
|
154
|
+
# Set encode_status value to notify the encoder of a new file
|
155
|
+
def set_default_encoding_status
|
156
|
+
self.encode_status = ENCODE_NOT_READY if filename_changed?
|
157
|
+
end
|
158
|
+
|
159
|
+
##
|
160
|
+
# Unlink the folder containing the files
|
161
|
+
# TODO : remove all files, not only the original one
|
162
|
+
def remove_file_from_fs
|
163
|
+
require 'fileutils'
|
164
|
+
FileUtils.rm_rf(self.original_file_path)
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class MediumUploader < CarrierWave::Uploader::Base
|
4
|
+
|
5
|
+
# Choose what kind of storage to use for this uploader
|
6
|
+
storage :file
|
7
|
+
# storage :s3
|
8
|
+
|
9
|
+
# Override the directory where uploaded files will be stored
|
10
|
+
# This is a sensible default for uploaders that are meant to be mounted:
|
11
|
+
def store_dir
|
12
|
+
type = ActiveSupport::Inflector.underscore(model.class.to_s)
|
13
|
+
"#{HasMedia.directory_path}/#{type}/#{model.id}"
|
14
|
+
end
|
15
|
+
end
|
data/lib/has_media.rb
ADDED
@@ -0,0 +1,195 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'active_support'
|
4
|
+
require 'carrierwave'
|
5
|
+
|
6
|
+
module HasMedia
|
7
|
+
|
8
|
+
VERSION = "0.0.1"
|
9
|
+
|
10
|
+
@@store_dir = '/tmp'
|
11
|
+
@@directory_uri = ''
|
12
|
+
@@errors_messages = {:type_error => 'Wrong type'}
|
13
|
+
@@images_content_types = [
|
14
|
+
'image/jpeg',
|
15
|
+
'image/pjpeg',
|
16
|
+
'image/jpg',
|
17
|
+
'image/gif',
|
18
|
+
'image/png',
|
19
|
+
'image/x-png',
|
20
|
+
'image/jpg',
|
21
|
+
'image/x-ms-bmp',
|
22
|
+
'image/bmp',
|
23
|
+
'image/x-bmp',
|
24
|
+
'image/x-bitmap',
|
25
|
+
'image/x-xbitmap',
|
26
|
+
'image/x-win-bitmap',
|
27
|
+
'image/x-windows-bmp',
|
28
|
+
'image/ms-bmp',
|
29
|
+
'application/bmp',
|
30
|
+
'application/x-bmp',
|
31
|
+
'application/x-win-bitmap',
|
32
|
+
'application/preview',
|
33
|
+
'image/jp_',
|
34
|
+
'application/jpg',
|
35
|
+
'application/x-jpg',
|
36
|
+
'image/pipeg',
|
37
|
+
'image/vnd.swiftview-jpeg',
|
38
|
+
'image/x-xbitmap',
|
39
|
+
'application/png',
|
40
|
+
'application/x-png',
|
41
|
+
'image/gi_',
|
42
|
+
'image/x-citrix-pjpeg'
|
43
|
+
]
|
44
|
+
|
45
|
+
def self.directory_path=(value)
|
46
|
+
@@store_dir = value
|
47
|
+
end
|
48
|
+
def self.directory_path
|
49
|
+
@@store_dir
|
50
|
+
end
|
51
|
+
def self.directory_uri=(value)
|
52
|
+
@@directory_uri = value
|
53
|
+
end
|
54
|
+
def self.directory_uri
|
55
|
+
@@directory_uri
|
56
|
+
end
|
57
|
+
# taken from http://github.com/technoweenie/attachment_fu/blob/master/lib/technoweenie/attachment_fu.rb
|
58
|
+
def self.images_content_types
|
59
|
+
@@images_content_types
|
60
|
+
end
|
61
|
+
def self.errors_messages
|
62
|
+
@@errors_messages
|
63
|
+
end
|
64
|
+
def self.errors_messages=(h)
|
65
|
+
@@errors_messages.merge!(h)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.included(mod)
|
69
|
+
mod.extend ClassMethods
|
70
|
+
end
|
71
|
+
|
72
|
+
module ClassMethods
|
73
|
+
|
74
|
+
def has_one_medium(context, options = {})
|
75
|
+
set_relations(context, :has_one)
|
76
|
+
set_general_methods
|
77
|
+
create_one_accessors(context, options)
|
78
|
+
end
|
79
|
+
|
80
|
+
def has_many_media(context, options = {})
|
81
|
+
set_relations(context, :has_many)
|
82
|
+
set_general_methods
|
83
|
+
create_many_accessors(context, options)
|
84
|
+
end
|
85
|
+
|
86
|
+
def set_general_methods
|
87
|
+
@methods_present ||= false
|
88
|
+
unless @methods_present
|
89
|
+
set_media_links_relation
|
90
|
+
set_attributes
|
91
|
+
set_validate_methods
|
92
|
+
set_callbacks
|
93
|
+
end
|
94
|
+
@methods_present = true
|
95
|
+
end
|
96
|
+
|
97
|
+
def set_relations(context, relation)
|
98
|
+
@contexts ||= {}
|
99
|
+
@contexts[relation] ||= []
|
100
|
+
@media_relation_set ||= []
|
101
|
+
if @contexts[relation].include?(context)
|
102
|
+
raise Exception.new("You should NOT use same context identifier for several has_one or has_many relation to media")
|
103
|
+
end
|
104
|
+
@contexts[relation] << context
|
105
|
+
return if @media_relation_set.include? self
|
106
|
+
has_many :media, :through => :media_links, :dependent => :destroy
|
107
|
+
|
108
|
+
@media_relation_set << self
|
109
|
+
end
|
110
|
+
|
111
|
+
def set_callbacks
|
112
|
+
validate :merge_media_errors
|
113
|
+
before_save :remove_old_media
|
114
|
+
end
|
115
|
+
def set_attributes
|
116
|
+
attr_accessor :media_errors
|
117
|
+
end
|
118
|
+
def set_validate_methods
|
119
|
+
module_eval <<-"end;", __FILE__, __LINE__
|
120
|
+
def merge_media_errors
|
121
|
+
self.media_errors ||= []
|
122
|
+
self.media_errors.each do |error|
|
123
|
+
self.errors.add_to_base(error)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end;
|
127
|
+
end
|
128
|
+
|
129
|
+
def set_media_links_relation
|
130
|
+
has_many :media_links, :as => :mediated, :dependent => :destroy
|
131
|
+
end
|
132
|
+
|
133
|
+
def create_one_accessors(context, options)
|
134
|
+
#check_conditions = ''
|
135
|
+
#check_conditions << "return unless medium.is_a? #{options[:only].to_s.capitalize}" if options.has_key? :only
|
136
|
+
|
137
|
+
define_method(context) do
|
138
|
+
media.with_context(context.to_sym).first
|
139
|
+
end
|
140
|
+
|
141
|
+
module_eval <<-"end;", __FILE__, __LINE__
|
142
|
+
def #{context}=(value)
|
143
|
+
return if value.blank?
|
144
|
+
medium = Medium.new_from_value(self, value, "#{context}", "#{options[:encode]}", "#{options[:only]}")
|
145
|
+
if medium
|
146
|
+
@old_media ||= []
|
147
|
+
@old_media += media.with_context("#{context}")
|
148
|
+
media << medium
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end;
|
152
|
+
end
|
153
|
+
|
154
|
+
def create_many_accessors(context, options)
|
155
|
+
#check_conditions = ''
|
156
|
+
#check_conditions << "return unless medium.is_a? #{options[:only].to_s.capitalize}" if options.has_key? :only
|
157
|
+
|
158
|
+
define_method(context.to_s.pluralize) do
|
159
|
+
media.with_context(context.to_sym).uniq
|
160
|
+
end
|
161
|
+
|
162
|
+
module_eval <<-"end;", __FILE__, __LINE__
|
163
|
+
def #{context}=(values)
|
164
|
+
return if values.blank?
|
165
|
+
Array(values).each do |value|
|
166
|
+
next if value.nil?
|
167
|
+
medium = Medium.new_from_value(self, value, "#{context}", "#{options[:encode]}", "#{options[:only]}")
|
168
|
+
media << medium if medium
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end;
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def remove_old_media
|
176
|
+
(@old_media || []).each do |medium|
|
177
|
+
medium.destroy if medium
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
class ActiveRecord::Base
|
184
|
+
include HasMedia
|
185
|
+
end
|
186
|
+
|
187
|
+
require File.dirname(__FILE__) + '/has_media/uploaders/medium_uploader'
|
188
|
+
Dir.glob(File.dirname(__FILE__) + '/has_media/uploaders/*.rb').each do |uploader|
|
189
|
+
require uploader
|
190
|
+
end
|
191
|
+
|
192
|
+
require File.dirname(__FILE__) + '/has_media/models/medium'
|
193
|
+
Dir.glob(File.dirname(__FILE__) + '/has_media/models/*.rb').each do |model|
|
194
|
+
require model
|
195
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "HasMedia" do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
class MediumRelatedTest < ActiveRecord::Base
|
7
|
+
include HasMedia
|
8
|
+
has_one_medium :image, :only => :image
|
9
|
+
has_many_media :images, :only => :image
|
10
|
+
has_one_medium :audio, :only => :audio
|
11
|
+
has_many_media :audios, :only => :audio
|
12
|
+
has_one_medium :image_no_encode, :only => :image, :encode => false
|
13
|
+
has_one_medium :pdf, :encode => false
|
14
|
+
end
|
15
|
+
HasMedia.directory_path = 'tmp'
|
16
|
+
HasMedia.directory_uri = '/media'
|
17
|
+
end
|
18
|
+
|
19
|
+
before :each do
|
20
|
+
@medium = MediumRelatedTest.new
|
21
|
+
@image = ActionController::TestUploadedFile.new('spec/fixtures/media/image.jpg', 'image/jpeg')
|
22
|
+
@audio = ActionController::TestUploadedFile.new('spec/fixtures/media/audio.wav', 'audio/wav')
|
23
|
+
@image_bis = ActionController::TestUploadedFile.new('spec/fixtures/media/image_bis.jpg', 'image/jpeg')
|
24
|
+
@pdf = ActionController::TestUploadedFile.new('spec/fixtures/media/Conversational_Capital _Explained.pdf', 'application/pdf')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should not have 2 has_one_medium with same context' do
|
28
|
+
lambda {
|
29
|
+
class Prout < ActiveRecord::Base
|
30
|
+
include HasMedia
|
31
|
+
has_one_medium :prout, :only => :image
|
32
|
+
has_one_medium :prout, :only => :audio
|
33
|
+
end
|
34
|
+
}.should raise_error(Exception)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should define accessors" do
|
38
|
+
@medium.methods.should include("image")
|
39
|
+
@medium.methods.should include("images")
|
40
|
+
@medium.methods.should include("audio")
|
41
|
+
@medium.methods.should include("audios")
|
42
|
+
@medium.methods.should include("pdf")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should define setters" do
|
46
|
+
@medium.methods.should include("image=")
|
47
|
+
@medium.methods.should include("images=")
|
48
|
+
@medium.methods.should include("audio=")
|
49
|
+
@medium.methods.should include("audios=")
|
50
|
+
@medium.methods.should include("pdf=")
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should associate image to mediated object" do
|
54
|
+
@medium.image = @image
|
55
|
+
@medium.save!
|
56
|
+
@medium.image.should_not be_nil
|
57
|
+
@medium.image.class.should == Image
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should associate audio to mediated object" do
|
61
|
+
@medium.audio = @audio
|
62
|
+
@medium.save!
|
63
|
+
@medium.audio.should_not be_nil
|
64
|
+
@medium.audio.class.should == Audio
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should associate pdf to mediated object" do
|
68
|
+
@medium.pdf = @pdf
|
69
|
+
@medium.save!
|
70
|
+
@medium.pdf.should_not be_nil
|
71
|
+
@medium.pdf.class.should == Pdf
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should add both audio and image " do
|
75
|
+
@medium.image = @image
|
76
|
+
@medium.audio = @audio
|
77
|
+
@medium.save!
|
78
|
+
@medium.audio.should_not be_nil
|
79
|
+
@medium.audio.class.should == Audio
|
80
|
+
@medium.audio.filename.should == @audio.original_filename
|
81
|
+
@medium.audio.content_type.should == "audio/wav"
|
82
|
+
@medium.audio
|
83
|
+
@medium.image.should_not be_nil
|
84
|
+
@medium.image.class.should == Image
|
85
|
+
@medium.image.filename.should == @image.original_filename
|
86
|
+
@medium.image.content_type.should == "image/jpeg"
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should replace media when in has_one_medium relations" do
|
90
|
+
@medium.image = @image_bis
|
91
|
+
@medium.save
|
92
|
+
@medium.image.filename.should == @image_bis.original_filename
|
93
|
+
@medium.image = @image
|
94
|
+
@medium.save
|
95
|
+
@medium.image.filename.should == @image.original_filename
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should destroy files from fs when Related Model is destroyed" do
|
99
|
+
@medium.image = @image
|
100
|
+
@medium.save!
|
101
|
+
path = @medium.image.original_file_path
|
102
|
+
File.exist?(path).should be_true
|
103
|
+
@medium.destroy
|
104
|
+
File.exist?(path).should be_false
|
105
|
+
end
|
106
|
+
|
107
|
+
[:encoding?, :ready?, :failed?].each do |method|
|
108
|
+
[:image, :audio, :images, :audios].each do |context|
|
109
|
+
class_eval %{
|
110
|
+
it "should responds to #{context}.#{method}" do
|
111
|
+
@medium.send("#{context}=", @#{context})
|
112
|
+
@medium.save!
|
113
|
+
media = @medium.send("#{context}")
|
114
|
+
if media.is_a? Array
|
115
|
+
media.each do |medium|
|
116
|
+
[true, false].include?(medium.send("#{method}"))
|
117
|
+
end
|
118
|
+
else
|
119
|
+
[true, false].include?(media.send("#{method}"))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
}
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should add several has_many_media for the same context" do
|
127
|
+
@medium.images = [@image, @image_bis]
|
128
|
+
@medium.save!
|
129
|
+
@medium.media.size.should == 2
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should have the right encode status" do
|
133
|
+
@medium.image_no_encode = @image
|
134
|
+
@medium.save!
|
135
|
+
@medium.image_no_encode.encode_status.should == Medium::NO_ENCODING
|
136
|
+
@medium.image = @image_bis
|
137
|
+
@medium.save!
|
138
|
+
@medium.image.encode_status.should == Medium::ENCODE_WAIT
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should have an original uri" do
|
142
|
+
@medium.image = @image
|
143
|
+
@medium.save!
|
144
|
+
@medium.image.original_file_uri.should == File.join(HasMedia.directory_uri,
|
145
|
+
ActiveSupport::Inflector.underscore(@medium.image.type),
|
146
|
+
@medium.image.id.to_s,
|
147
|
+
@medium.image.filename)
|
148
|
+
end
|
149
|
+
|
150
|
+
it "pdf should exist" do
|
151
|
+
@medium.pdf = @pdf
|
152
|
+
@medium.save!
|
153
|
+
path = @medium.pdf.file_path
|
154
|
+
File.exist?(path).should be_true
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should add errors on parent model if type is not allowed" do
|
158
|
+
@image = ActionController::TestUploadedFile.new('spec/fixtures/media/image.jpg', 'image/jpeg')
|
159
|
+
@medium.audio = @image
|
160
|
+
@medium.valid?
|
161
|
+
@medium.should_not be_valid
|
162
|
+
@medium.save.should be_false
|
163
|
+
@medium.errors.full_messages.include?(HasMedia.errors_messages[:type_error])
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'spec'
|
4
|
+
require 'spec/autorun'
|
5
|
+
require 'rubygems'
|
6
|
+
require 'action_controller'
|
7
|
+
require 'action_controller/test_process'
|
8
|
+
require 'has_media'
|
9
|
+
|
10
|
+
dbconfig = {
|
11
|
+
:adapter => 'sqlite3',
|
12
|
+
:database => ':memory:',
|
13
|
+
# :database => 'has_media.sqlite'
|
14
|
+
}
|
15
|
+
|
16
|
+
ActiveRecord::Base.establish_connection(dbconfig)
|
17
|
+
ActiveRecord::Migration.verbose = false
|
18
|
+
#ActiveRecord::Base.logger = Logger.new(STDOUT)
|
19
|
+
class TestMigration < ActiveRecord::Migration
|
20
|
+
def self.up
|
21
|
+
create_table :medium_related_tests, :force => true do |t|
|
22
|
+
t.string :name
|
23
|
+
end
|
24
|
+
create_table :prouts, :force => true do |t|
|
25
|
+
t.string :name
|
26
|
+
end
|
27
|
+
create_table :media, :force => true do |t|
|
28
|
+
t.string :context
|
29
|
+
t.string :content_type
|
30
|
+
t.string :filename
|
31
|
+
t.integer :encode_status
|
32
|
+
t.string :type
|
33
|
+
t.timestamps
|
34
|
+
end
|
35
|
+
create_table :media_links, :force => true do |t|
|
36
|
+
t.integer :medium_id
|
37
|
+
t.integer :mediated_id
|
38
|
+
t.string :mediated_type
|
39
|
+
t.timestamps
|
40
|
+
end
|
41
|
+
end
|
42
|
+
def self.down
|
43
|
+
drop_table :medium_related_tests
|
44
|
+
drop_table :media
|
45
|
+
drop_table :media_links
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Spec::Runner.configure do |config|
|
50
|
+
config.before(:all) { TestMigration.up }
|
51
|
+
config.after(:all) { TestMigration.down }
|
52
|
+
config.after(:each) { Medium.destroy_all; MediaLink.destroy_all; MediumRelatedTest.destroy_all; }
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_media
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- klacointe
|
8
|
+
- spk
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-01-08 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: rspec
|
18
|
+
type: :development
|
19
|
+
version_requirement:
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 1.2.9
|
25
|
+
version:
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: carrierwave
|
28
|
+
type: :runtime
|
29
|
+
version_requirement:
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: 0.4.2
|
35
|
+
version:
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: activerecord
|
38
|
+
type: :runtime
|
39
|
+
version_requirement:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 2.3.4
|
45
|
+
version:
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: activesupport
|
48
|
+
type: :runtime
|
49
|
+
version_requirement:
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.3.4
|
55
|
+
version:
|
56
|
+
description: Media Managment Library for ActiveRecord and Carrierwave
|
57
|
+
email: kevinlacointe@gmail.com
|
58
|
+
executables: []
|
59
|
+
|
60
|
+
extensions: []
|
61
|
+
|
62
|
+
extra_rdoc_files:
|
63
|
+
- LICENSE
|
64
|
+
- README.rdoc
|
65
|
+
files:
|
66
|
+
- .document
|
67
|
+
- .gitignore
|
68
|
+
- LICENSE
|
69
|
+
- README.rdoc
|
70
|
+
- Rakefile
|
71
|
+
- VERSION
|
72
|
+
- generators/has_media/has_media_generator.rb
|
73
|
+
- generators/has_media/templates/create_media.rb
|
74
|
+
- generators/has_media/templates/create_media_links.rb
|
75
|
+
- generators/has_media_generator.rb
|
76
|
+
- lib/has_media.rb
|
77
|
+
- lib/has_media/models/audio.rb
|
78
|
+
- lib/has_media/models/image.rb
|
79
|
+
- lib/has_media/models/media_link.rb
|
80
|
+
- lib/has_media/models/medium.rb
|
81
|
+
- lib/has_media/models/pdf.rb
|
82
|
+
- lib/has_media/uploaders/audio_uploader.rb
|
83
|
+
- lib/has_media/uploaders/image_uploader.rb
|
84
|
+
- lib/has_media/uploaders/medium_uploader.rb
|
85
|
+
- lib/has_media/uploaders/pdf_uploader.rb
|
86
|
+
- spec/fixtures/media/Conversational_Capital _Explained.pdf
|
87
|
+
- spec/fixtures/media/audio.wav
|
88
|
+
- spec/fixtures/media/image.jpg
|
89
|
+
- spec/fixtures/media/image_bis.jpg
|
90
|
+
- spec/fixtures/media/lc_pdf_overview_format.pdf
|
91
|
+
- spec/has_media_spec.rb
|
92
|
+
- spec/spec.opts
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
has_rdoc: true
|
95
|
+
homepage: http://github.com/AF83/has_media
|
96
|
+
licenses: []
|
97
|
+
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options:
|
100
|
+
- --charset=UTF-8
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
version: "0"
|
108
|
+
version:
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: "0"
|
114
|
+
version:
|
115
|
+
requirements: []
|
116
|
+
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 1.3.5
|
119
|
+
signing_key:
|
120
|
+
specification_version: 3
|
121
|
+
summary: Media Managment Library for ActiveRecord and Carrierwave
|
122
|
+
test_files:
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
- spec/has_media_spec.rb
|