has_media 0.2.5 → 0.2.6

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -90,6 +90,9 @@ Configuration take place in config/initializers/has_media.rb
90
90
  require uploader
91
91
  end
92
92
 
93
+ # Change CarrierWave root path
94
+ CarrierWave.root = HasMedia.directory_path
95
+
93
96
  == Routes
94
97
 
95
98
  Add routes for media in your config/routes.rb
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.5
1
+ 0.2.6
@@ -1,5 +1,15 @@
1
1
  module HasMediaHelper
2
2
 
3
+ ##
4
+ # Generate a unique uid used in forms
5
+ #
6
+ # @param [Hash] available keys :
7
+ # - context: the context to link medium
8
+ # - object : the medium related object
9
+ # - medium : the medium object
10
+ #
11
+ # @return [String]
12
+ #
3
13
  def generate_uid(*opts)
4
14
  opts = opts.first
5
15
  object = opts[:object]||nil
@@ -16,21 +26,61 @@ module HasMediaHelper
16
26
  end
17
27
  end
18
28
 
29
+ ##
30
+ # Create a link to add medium file field with ajax
31
+ #
32
+ # @params [Hash] available keys :
33
+ # - object : the meduim related object (mandatory)
34
+ # - context: the context to link medium (mandatory)
35
+ # - text: link test label (optional)
36
+ #
37
+ # @return [String]
38
+ #
19
39
  def add_medium_link(opts)
40
+ unless opts.keys.include?(:object) ||
41
+ opts.keys.include?(:context)
42
+ raise "Must give object and context"
43
+ end
44
+ klass = opts[:object].class.to_s.underscore
45
+ opts[:text]||= I18n.t('add_link',
46
+ :medium_label => I18n.t(opts[:context], :scope => [:activerecord, :attributes, klass]),
47
+ :scope => [:has_media, :form])
20
48
  link_to_function opts[:text] do |page|
21
- page.insert_html :bottom, generate_uid(:object => opts[:object], :context => opts[:context]),
22
- :partial => 'has_media/medium_field',
23
- :locals => {
24
- :object => opts[:object],
25
- :context => opts[:context]
26
- }
49
+ page.insert_html :bottom, generate_uid(
50
+ :object => opts[:object],
51
+ :context => opts[:context]
52
+ ),
53
+ :partial => 'has_media/medium_field',
54
+ :locals => {
55
+ :object => opts[:object],
56
+ :context => opts[:context]
57
+ }
27
58
  end
28
59
  end
29
60
 
61
+ ##
62
+ # Create a remove medium link using Ajax
63
+ # Compatible with jQuery and Prototype
64
+ #
65
+ # @param [Hash] available keys :
66
+ # - medium : the medium to destroy
67
+ # - text : link text label (optional)
68
+ #
69
+ # @return [String]
70
+ #
30
71
  def remove_medium_link(opts)
72
+ opts[:text] ||= I18n.t('remove_link', :scope => [:has_media, :form])
31
73
  link_to opts[:text], medium_url(opts[:medium]), :remote => true, :method => :delete
32
74
  end
33
75
 
76
+ ##
77
+ # Create a file field for a medium
78
+ #
79
+ # @param [Medium] model, A medium object
80
+ # @param [String] context, the context to link medium
81
+ #
82
+ # @return [String]
83
+ #
34
84
  def has_media_field(model, context)
35
85
  render :partial => "has_media/media_fields", :locals => {
36
86
  :object => model,
@@ -8,8 +8,7 @@
8
8
  <%= link_to medium.original_file_uri, medium.original_file_uri %>
9
9
 
10
10
  <%- if object.send(context).is_a?(Array) and !readonly %>
11
- <%= remove_medium_link :text => "Remove",
12
- :object => object,
11
+ <%= remove_medium_link :object => object,
13
12
  :context => context,
14
13
  :medium => medium %>
15
14
  <%- end %>
@@ -14,9 +14,7 @@
14
14
  </div>
15
15
  <%- if object.send(context).is_a?(Array) %>
16
16
  <p>
17
- <%= add_medium_link :text => "Add #{context}",
18
- :object => object,
19
- :context => context %>
17
+ <%= add_medium_link :object => object, :context => context %>
20
18
  </p>
21
19
  <%- end %>
22
20
 
@@ -1,12 +1,14 @@
1
1
  <%- klass = object.class.to_s.underscore %>
2
2
  <%- if object.send(context).is_a?(Array) %>
3
3
  <p>
4
- <%= label_tag "#{klass}[#{context}][]" %>
4
+ <%= label_tag "#{klass}[#{context}][]",
5
+ t(context, :scope => [:activerecord, :attributes, klass]) %>
5
6
  <%= file_field_tag "#{klass}[#{context}][]" %>
6
7
  </p>
7
8
  <%- else %>
8
9
  <p>
9
- <%= label_tag "#{klass}[#{context}]" %>
10
+ <%= label_tag "#{klass}[#{context}]",
11
+ t(context, :scope => [:activerecord, :attributes, klass]) %>
10
12
  <%= file_field_tag "#{klass}[#{context}]" %>
11
13
  </p>
12
14
  <%- end %>
@@ -1 +1,5 @@
1
- $("#<%= generate_uid(:medium => @medium ) %>").remove();
1
+ if (typeof jQuery == 'undefined') {
2
+ $("<%= generate_uid(:medium => @medium ) %>").remove();
3
+ } else {
4
+ $("#<%= generate_uid(:medium => @medium ) %>").remove();
5
+ }
@@ -2,3 +2,6 @@ en:
2
2
  has_media:
3
3
  errors:
4
4
  type_error: "File type error"
5
+ form:
6
+ add_link: "Add %{medium_label}"
7
+ remove_link: "Remove"
data/has_media.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{has_media}
8
- s.version = "0.2.5"
8
+ s.version = "0.2.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["klacointe", "spk"]
12
- s.date = %q{2010-11-23}
12
+ s.date = %q{2010-12-03}
13
13
  s.description = %q{Media Managment Library for ActiveRecord and Carrierwave}
14
14
  s.email = %q{kevinlacointe@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -24,3 +24,6 @@ HasMedia.directory_uri = "/media"
24
24
  Dir.glob(File.dirname(__FILE__) + '/../app/uploaders/*.rb').each do |uploader|
25
25
  require uploader
26
26
  end
27
+
28
+ # Change CarrierWave root path
29
+ CarrierWave.root = HasMedia.directory_path
data/lib/has_media.rb CHANGED
@@ -24,30 +24,86 @@ module HasMedia
24
24
  :video => 'flv'
25
25
  }
26
26
 
27
+ ##
28
+ # medium_types
29
+ #
30
+ # Used to configure available medium types
31
+ #
32
+ # Each medium type id representing with its class name and contain an Array
33
+ # of possible mime types. An empty Array means no limitation on mime type
34
+ #
35
+ # Example :
36
+ # HasMedia.medium_types = {
37
+ # "Image" => ["image/jpeg", "image/png"],
38
+ # "Video" => ["video/mp4"],
39
+ # "Audio" => ["audio/mp3"],
40
+ # "Document" => []
41
+ # }
42
+ #
27
43
  def self.medium_types=(value)
28
44
  @@medium_types = value
29
45
  end
30
46
  def self.medium_types
31
47
  @@medium_types
32
48
  end
49
+
50
+ ##
51
+ # encoded_extensions
52
+ #
53
+ # Used to configure output format if you use a custom encoder
54
+ #
55
+ # Example :
56
+ # HasMedia.encoded_extensions = {
57
+ # :image => 'png',
58
+ # :audio => 'ogg',
59
+ # :video => 'flv'
60
+ # }
61
+ #
33
62
  def self.encoded_extensions=(value)
34
63
  @@encoded_extensions = value
35
64
  end
36
65
  def self.encoded_extensions
37
66
  @@encoded_extensions
38
67
  end
68
+
69
+ ##
70
+ # directory_path
71
+ #
72
+ # Used to configure directory_path to store media on filesystem
73
+ #
74
+ # Example :
75
+ # HasMedia.directory_path = Rails.root + "media"
76
+ #
39
77
  def self.directory_path=(value)
40
78
  @@store_dir = value
41
79
  end
42
80
  def self.directory_path
43
81
  @@store_dir
44
82
  end
83
+
84
+ ##
85
+ # directory_uri
86
+ #
87
+ # Used to store www access to your media
88
+ #
89
+ # Example :
90
+ # HasMedia.directory_path = Rails.root + "media"
91
+ #
45
92
  def self.directory_uri=(value)
46
93
  @@directory_uri = value
47
94
  end
48
95
  def self.directory_uri
49
96
  @@directory_uri
50
97
  end
98
+
99
+ ##
100
+ # errors_messages
101
+ #
102
+ # Used to store custom error messages
103
+ #
104
+ # Example :
105
+ # HasMedia.errors_messages = {:type_error => "Le format du logo n'est pas correct"}
106
+ #
51
107
  def self.errors_messages
52
108
  @@errors_messages
53
109
  end
@@ -59,20 +115,54 @@ module HasMedia
59
115
  mod.extend ClassMethods
60
116
  end
61
117
 
118
+ ##
119
+ # Sanitize file name
120
+ # @param [String] name
121
+ # @return [String]
122
+ #
123
+ def self.sanitize_file_name(name)
124
+ name = name.gsub("\\", "/") # work-around for IE
125
+ name = File.basename(name)
126
+ name = name.gsub(/[^a-zA-Z0-9\.\-\+_]/,"_")
127
+ name = "_#{name}" if name =~ /\A\.+\z/
128
+ name = "unnamed" if name.size == 0
129
+ return name.downcase
130
+ end
131
+
132
+
62
133
  module ClassMethods
63
134
 
135
+ ##
136
+ # has_one_medium
137
+ # Define a class method to link to a medium
138
+ #
139
+ # @param [String] context, the context (or accessor) to link medium
140
+ # @param [Hash] options, can be one of : encode, only
141
+ #
64
142
  def has_one_medium(context, options = {})
65
143
  set_relations(context, :has_one)
66
144
  set_general_methods
67
145
  create_one_accessors(context, options)
68
146
  end
69
147
 
148
+ ##
149
+ # has_many_media
150
+ # Define a class method to link to several media
151
+ #
152
+ # @param [String] context, the context (or accessor) to link media
153
+ # @param [Hash] options, can be one of : encode, only
154
+ #
70
155
  def has_many_media(context, options = {})
71
156
  set_relations(context, :has_many)
72
157
  set_general_methods
73
158
  create_many_accessors(context, options)
74
159
  end
75
160
 
161
+ ##
162
+ # set_general_methods
163
+ # Add generic methods for has_one_medium and has_many_media
164
+ # Including media_links relation, accessors, callbacks, validation ...
165
+ #
76
166
  def set_general_methods
77
167
  @methods_present ||= false
78
168
  unless @methods_present
@@ -84,6 +174,14 @@ module HasMedia
84
174
  @methods_present = true
85
175
  end
86
176
 
177
+ ##
178
+ # set_relations
179
+ # add relation on medium if not exists
180
+ # Also check if a class has a duplicate context
181
+ #
182
+ # @param [String] context
183
+ # @param [String] relation type, one of :has_many, :has_one
184
+ #
87
185
  def set_relations(context, relation)
88
186
  @contexts ||= {}
89
187
  @contexts[relation] ||= []
@@ -98,13 +196,30 @@ module HasMedia
98
196
  @media_relation_set << self
99
197
  end
100
198
 
199
+ ##
200
+ # set_callbacks
201
+ # Add callbacks to :
202
+ # - merge medium errors to class related errors
203
+ # - destroy medium
204
+ #
101
205
  def set_callbacks
102
206
  validate :merge_media_errors
103
207
  before_save :remove_old_media
104
208
  end
209
+
210
+ ##
211
+ # set_attributes
212
+ # Add media_errors attributes to store medium errors
213
+ #
105
214
  def set_attributes
106
215
  attr_accessor :media_errors
107
216
  end
217
+
218
+ ##
219
+ # set_validate_methods
220
+ # Define merge_media_errors to merge medium errors with errors given
221
+ # on master object.
222
+ #
108
223
  def set_validate_methods
109
224
  module_eval <<-"end;", __FILE__, __LINE__
110
225
  def merge_media_errors
@@ -115,15 +230,22 @@ module HasMedia
115
230
  end
116
231
  end;
117
232
  end
118
-
233
+
234
+ ##
235
+ # set_media_links_relation
236
+ # Declare media_links relation
119
237
  def set_media_links_relation
120
238
  has_many :media_links, :as => :mediated, :dependent => :destroy
121
239
  end
122
240
 
241
+ ##
242
+ # create_one_accessors
243
+ # Create needed accessors on master object for unique relation
244
+ #
245
+ # @param [String] context
246
+ # @param [Hash] options
247
+ #
123
248
  def create_one_accessors(context, options)
124
- #check_conditions = ''
125
- #check_conditions << "return unless medium.is_a? #{options[:only].to_s.capitalize}" if options.has_key? :only
126
-
127
249
  define_method(context) do
128
250
  media.with_context(context.to_sym).first
129
251
  end
@@ -141,10 +263,14 @@ module HasMedia
141
263
  end;
142
264
  end
143
265
 
266
+ ##
267
+ # create_many_accessors
268
+ # Create needed accessors on master object for multiple relation
269
+ #
270
+ # @param [String] context
271
+ # @param [Hash] options
272
+ #
144
273
  def create_many_accessors(context, options)
145
- #check_conditions = ''
146
- #check_conditions << "return unless medium.is_a? #{options[:only].to_s.capitalize}" if options.has_key? :only
147
-
148
274
  define_method(context.to_s.pluralize) do
149
275
  media.with_context(context.to_sym).uniq
150
276
  end
@@ -162,6 +288,9 @@ module HasMedia
162
288
  end
163
289
  end
164
290
 
291
+ ##
292
+ # Remove old media before saving
293
+ #
165
294
  def remove_old_media
166
295
  (@old_media || []).each do |medium|
167
296
  medium.destroy if medium
@@ -170,18 +299,22 @@ module HasMedia
170
299
 
171
300
  end
172
301
 
302
+ # Include HasMedia in all ActiveRecord::Base Object
173
303
  class ActiveRecord::Base
174
304
  include HasMedia
175
305
  end
306
+ # Include HasMediaHelper in all ActiveRecord::Base Object
176
307
  class ActionController::Base
177
308
  helper HasMediaHelper
178
309
  end
179
310
 
311
+ # Require generic medium uploader
180
312
  require File.dirname(__FILE__) + '/has_media/uploaders/medium_uploader'
181
313
  Dir.glob(File.dirname(__FILE__) + '/has_media/uploaders/*.rb').each do |uploader|
182
314
  require uploader
183
315
  end
184
316
 
317
+ # Require generic medium model
185
318
  require File.dirname(__FILE__) + '/has_media/models/medium'
186
319
  Dir.glob(File.dirname(__FILE__) + '/has_media/models/*.rb').each do |model|
187
320
  require model
@@ -22,15 +22,6 @@ class Medium < ActiveRecord::Base
22
22
  { :conditions => { :context => context.to_s} }
23
23
  }
24
24
 
25
- def self.sanitize(name)
26
- name = name.gsub("\\", "/") # work-around for IE
27
- name = File.basename(name)
28
- name = name.gsub(/[^a-zA-Z0-9\.\-\+_]/,"_")
29
- name = "_#{name}" if name =~ /\A\.+\z/
30
- name = "unnamed" if name.size == 0
31
- return name.downcase
32
- end
33
-
34
25
  def self.new_from_value(object, value, context, encode, only)
35
26
  if value.respond_to?(:content_type)
36
27
  mime_type = value.content_type
@@ -51,9 +42,9 @@ class Medium < ActiveRecord::Base
51
42
  end
52
43
  medium = klass.new
53
44
  if value.respond_to?(:original_filename)
54
- medium.filename = self.sanitize(value.original_filename)
45
+ medium.filename = HasMedia.sanitize_file_name(value.original_filename)
55
46
  else
56
- medium.filename = self.sanitize(File.basename(value.path))
47
+ medium.filename = HasMedia.sanitize_file_name(File.basename(value.path))
57
48
  end
58
49
  medium.file = value
59
50
  medium.content_type = mime_type
@@ -116,6 +107,13 @@ class Medium < ActiveRecord::Base
116
107
  File.join(directory_uri, encoded_file_name(version))
117
108
  end
118
109
 
110
+ ##
111
+ # encoded_file_name
112
+ # Return the encoded file name for a medium
113
+ # This use the HasMedia.encoded_extensions configuration
114
+ #
115
+ # @param [String] version, the string identifier for a specific encoded version
116
+ # FIXME duplicate with HasMedia::sanitize_file_name
119
117
  def encoded_file_name(version = nil)
120
118
  # remove original extension and add the encoded extension
121
119
  final_name = filename.gsub(/\.[^.]{1,4}$/, "") + '.' + file_extension
@@ -130,10 +128,25 @@ class Medium < ActiveRecord::Base
130
128
  self.id.to_s)
131
129
  end
132
130
 
131
+ ##
132
+ # file_exists?
133
+ # Is the medium for the current format exists
134
+ #
135
+ # @param [String] version to test
136
+ #
137
+ # @return [Boolean]
138
+ #
133
139
  def file_exists?(thumbnail = nil)
134
140
  File.exist?(File.join(Rails.root, 'public', file_uri(thumbnail)))
135
141
  end
136
142
 
143
+ ##
144
+ # file_extension
145
+ # Return the file extension for the current medium type
146
+ # This use the HasMedia.encoded_extensions configuration
147
+ #
148
+ # @return [String]
149
+ #
137
150
  def file_extension
138
151
  sym = type.underscore.to_sym
139
152
  unless HasMedia.encoded_extensions.keys.include?(sym)
@@ -145,14 +158,15 @@ class Medium < ActiveRecord::Base
145
158
  private
146
159
 
147
160
  ##
161
+ # set_default_encoding_status
148
162
  # Set encode_status value to notify the encoder of a new file
149
163
  def set_default_encoding_status
150
164
  self.encode_status = ENCODE_NOT_READY if filename_changed?
151
165
  end
152
166
 
153
167
  ##
168
+ # remove_file_from_fs
154
169
  # Unlink the folder containing the files
155
- # TODO : remove all files, not only the original one
156
170
  def remove_file_from_fs
157
171
  require 'fileutils'
158
172
  FileUtils.rm_rf(self.directory_path)
@@ -34,7 +34,7 @@ describe "HasMedia" do
34
34
  }
35
35
  end
36
36
 
37
- describe "fonctionalities" do
37
+ describe "basic fonctionalities" do
38
38
 
39
39
  before :each do
40
40
  @medium = MediumRelatedTest.new
@@ -202,9 +202,73 @@ describe "HasMedia" do
202
202
  @medium.save.should be_false
203
203
  @medium.errors.full_messages.include?(HasMedia.errors_messages[:type_error])
204
204
  end
205
+
206
+ it "should sanitize filename" do
207
+ @pdf = stub_temp_file('Conversational_Capital _Explained.pdf', 'application/pdf')
208
+ @medium = MediumRelatedTest.new
209
+ @medium.pdf = @pdf
210
+ @medium.save
211
+ @medium.pdf.filename.should == "conversational_capital__explained.pdf"
212
+ @medium.pdf.original_file_uri.should == "/media/pdf/#{@medium.pdf.id}/conversational_capital__explained.pdf"
213
+ end
205
214
  end
206
215
 
207
216
  describe "Configuration" do
217
+
218
+ it "should configure medium_types" do
219
+ old_conf = HasMedia.medium_types
220
+ HasMedia.medium_types = {
221
+ "Image" => ["image/jpeg"]
222
+ }
223
+ HasMedia.medium_types.should == {
224
+ "Image" => ["image/jpeg"]
225
+ }
226
+ HasMedia.medium_types = old_conf
227
+ end
228
+
229
+ it "should configure encoded_extensions" do
230
+ old_conf = HasMedia.encoded_extensions
231
+ HasMedia.encoded_extensions = {
232
+ :image => "png"
233
+ }
234
+ HasMedia.encoded_extensions.should == {
235
+ :image => "png"
236
+ }
237
+ HasMedia.encoded_extensions = old_conf
238
+ end
239
+
240
+ it "should configure directory_path" do
241
+ old_conf = HasMedia.directory_path
242
+ HasMedia.directory_path = "/tmp"
243
+ HasMedia.directory_path.should == "/tmp"
244
+ HasMedia.directory_path = old_conf
245
+ end
246
+
247
+ it "should configure directory_uri" do
248
+ old_uri = HasMedia.directory_uri
249
+ HasMedia.directory_uri = "/tmp"
250
+ HasMedia.directory_uri.should == "/tmp"
251
+ HasMedia.directory_uri = old_uri
252
+ end
253
+
254
+ it "should configure/merge errors_messages" do
255
+ old_conf = HasMedia.errors_messages
256
+ HasMedia.errors_messages = {
257
+ :type_error => "wtf?"
258
+ }
259
+ HasMedia.errors_messages.should == {
260
+ :type_error => "wtf?"
261
+ }
262
+ HasMedia.errors_messages = {
263
+ :another_error => "warning!"
264
+ }
265
+ HasMedia.errors_messages.should == {
266
+ :type_error => "wtf?",
267
+ :another_error => "warning!"
268
+ }
269
+ HasMedia.errors_messages = old_conf
270
+ end
271
+
208
272
  it "should check allowed medium types if no :only option given" do
209
273
  HasMedia.medium_types = {
210
274
  "Image" => ["image/jpeg"],
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has_media
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 2
9
- - 5
10
- version: 0.2.5
9
+ - 6
10
+ version: 0.2.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - klacointe
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2010-11-23 00:00:00 +01:00
19
+ date: 2010-12-03 00:00:00 +01:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency