Skip to content
This repository
Browse code

Removed paperclip/paperclip and paperclip/storage

git-svn-id: https://svn.thoughtbot.com/plugins/paperclip/trunk@232 7bbfaf0e-4d1d-0410-9690-a8bb5f8ef2aa
  • Loading branch information...
commit bb51ba0dcc6a2351d15b0f8f02faf41985393003 1 parent 94925b2
jyurek authored

Showing 2 changed files with 0 additions and 474 deletions. Show diff stats Hide diff stats

  1. +0 374 lib/paperclip/paperclip.rb
  2. +0 100 lib/paperclip/storage.rb
374 lib/paperclip/paperclip.rb
... ... @@ -1,374 +0,0 @@
1   -module Thoughtbot #:nodoc:
2   - # Paperclip defines an attachment as any file, though it makes special considerations
3   - # for image files. You can declare that a model has an attached file with the
4   - # +has_attached_file+ method:
5   - #
6   - # class User < ActiveRecord::Base
7   - # has_attached_file :avatar, :thumbnails => { :thumb => "100x100" }
8   - # end
9   - #
10   - # See the +has_attached_file+ documentation for more details.
11   - module Paperclip
12   -
13   - PAPERCLIP_OPTIONS = {
14   - :whiny_deletes => false,
15   - :whiny_thumbnails => true,
16   - :image_magick_path => nil
17   - }
18   -
19   - def self.options
20   - PAPERCLIP_OPTIONS
21   - end
22   -
23   - DEFAULT_ATTACHMENT_OPTIONS = {
24   - :path_prefix => ":rails_root/public",
25   - :url_prefix => "",
26   - :path => ":attachment/:id/:style_:name",
27   - :attachment_type => :image,
28   - :thumbnails => {},
29   - :delete_on_destroy => true,
30   - :default_style => :original,
31   - :missing_url => "",
32   - :missing_path => ""
33   - }
34   -
35   - class PaperclipError < StandardError #:nodoc:
36   - attr_accessor :attachment
37   - def initialize attachment
38   - @attachment = attachment
39   - end
40   - end
41   -
42   - module ClassMethods
43   - # == Methods
44   - # +has_attached_file+ attaches a file (or files) with a given name to a model. It creates seven instance
45   - # methods using the attachment name (where "attachment" in the following is the name
46   - # passed in to +has_attached_file+):
47   - # * attachment: Returns the name of the file that was attached, with no path information.
48   - # * attachment?: Alias for _attachment_ for clarity in determining if the attachment exists.
49   - # * attachment=(file): Sets the attachment to the file and creates the thumbnails (if necessary).
50   - # +file+ can be anything normally accepted as an upload (+StringIO+ or +Tempfile+) or a +File+
51   - # if it has had the +Upfile+ module included. +file+ can also be a URL object pointing to a valid
52   - # resource. This resource will be downloaded using +open-uri+[http://www.ruby-doc.org/stdlib/libdoc/open-uri/rdoc/]
53   - # and processed as a regular file object would. Finally, you can set this property to +nil+ to clear
54   - # the attachment, which is the same thing as calling +destroy_attachment+.
55   - # Note this does not save the attachments.
56   - # user.avatar = File.new("~/pictures/me.png")
57   - # user.avatar = params[:user][:avatar] # When :avatar is a file_field
58   - # user.avatar = URI.parse("http://www.avatars-r-us.com/spiffy.png")
59   - # * attachment_file_name(style): The name of the file, including path information. Pass in the
60   - # name of a thumbnail to get the path to that thumbnail.
61   - # user.avatar_file_name(:thumb) # => "public/users/44/thumb/me.png"
62   - # user.avatar_file_name # => "public/users/44/original/me.png"
63   - # * attachment_url(style): The public URL of the attachment, suitable for passing to +image_tag+
64   - # or +link_to+. Pass in the name of a thumbnail to get the url to that thumbnail.
65   - # user.avatar_url(:thumb) # => "http://assethost.com/users/44/thumb/me.png"
66   - # user.avatar_url # => "http://assethost.com/users/44/original/me.png"
67   - # * attachment_valid?: If unsaved, returns true if all thumbnails have data (that is,
68   - # they were successfully made). If saved, returns true if all expected files exist and are
69   - # of nonzero size.
70   - # * destroy_attachment(complain = false): Flags the attachment and all thumbnails for deletion. Sets
71   - # the +attachment_file_name+ column and +attachment_content_type+ column to +nil+. Set +complain+
72   - # to true to override the +whiny_deletes+ option. NOTE: this does not actually delete the attachment.
73   - # You must still call +save+ on the model to actually delete the file and commit the change to the
74   - # database.
75   - #
76   - # == Options
77   - # There are a number of options you can set to change the behavior of Paperclip.
78   - # * +path_prefix+: The location of the repository of attachments on disk. See Interpolation below
79   - # for more control over where the files are located.
80   - # :path_prefix => ":rails_root/public"
81   - # :path_prefix => "/var/app/repository"
82   - # * +url_prefix+: The root URL of where the attachment is publically accessible. See Interpolation below
83   - # for more control over where the files are located.
84   - # :url_prefix => "/"
85   - # :url_prefix => "/user_files"
86   - # :url_prefix => "http://some.other.host/stuff"
87   - # * +path+: Where the files are stored underneath the +path_prefix+ directory and underneath the +url_prefix+ URL.
88   - # See Interpolation below for more control over where the files are located.
89   - # :path => ":class/:style/:id/:name" # => "users/original/13/picture.gif"
90   - # * +attachment_type+: If this is set to :image (which it is, by default), Paperclip will attempt to make thumbnails.
91   - # * +thumbnails+: A hash of thumbnail styles and their geometries. You can find more about geometry strings
92   - # at the ImageMagick website (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip
93   - # also adds the "#" option, which will resize the image to fit maximally inside the dimensions and then crop
94   - # the rest off (weighted at the center).
95   - # * +delete_on_destroy+: When records are deleted, the attachment that goes with it is also deleted. Set
96   - # this to +false+ to prevent the file from being deleted.
97   - # * +default_style+: The thumbnail style that will be used by default for +attachment_file_name+ and +attachment_url+
98   - # Defaults to +original+.
99   - # has_attached_file :avatar, :thumbnails => { :normal => "100x100#" },
100   - # :default_style => :normal
101   - # user.avatar_url # => "/avatars/23/normal_me.png"
102   - # * +missing_url+: The URL that will be returned if there is no attachment assigned. It should be an absolute
103   - # URL, not relative to the +url_prefix+. This field is interpolated.
104   - # has_attached_file :avatar, :missing_url => "/images/default_:style_avatar.png"
105   - # User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
106   - # * +storage+: Paperclip has two ways of storing your files. The first is on the filesystem, as specified by
107   - # the +path_prefix+ and +path+ parameters. The second is using Amazon's S3 service, via the AWS::S3 gem.
108   - # When +storage+ is set to :s3, Paperclip will at :s3_credentials_file in its options for a path to a YAML
109   - # file that will specify the access_key_id and secret_access_key for S3. If none is specified, it will look
110   - # for a the same file at the default location of RAILS_ROOT/config/s3.yml. When using S3, the +url_prefix+
111   - # is the name of the bucket in which the files will be stored. Note that while the +url_prefix+ is still
112   - # interpolated, S3 does not allow anything but alphanumerics and underscores, so it's a good practice to keep
113   - # your interpolations to the +path+ parameter. Files are stored with default permissions of :public_read. You
114   - # can read more about AWS::S3 here[http://amazon.rubyforge.org/].
115   - # Please note that S3 support is still experimental in Paperclip and does not have full test coverage. Use
116   - # at your own risk.
117   - # has_attached_file :avatar, :storage => :s3
118   - # :url_prefix => "bucket",
119   - # :path => ":attachment/:style/:id/:name"
120   - # user.avatar_url # => "http://s3.amazonaws.com/bucket/avatars/original/13/me.png"
121   - #
122   - # == Interpolation
123   - # The +path_prefix+, +url_prefix+, and +path+ options can have dynamic interpolation done so that the
124   - # locations of the files can vary depending on a variety of factors. Each variable looks like a Ruby symbol
125   - # and is searched for with +gsub+, so a variety of effects can be achieved. The list of possible variables
126   - # follows:
127   - # * +rails_root+: The value of the +RAILS_ROOT+ constant for your app. Typically used when putting your
128   - # attachments into the public directory. Probably not useful in the +path+ definition.
129   - # * +class+: The underscored, pluralized version of the class in which the attachment is defined.
130   - # * +attachment+: The pluralized name of the attachment as given to +has_attached_file+
131   - # * +style+: The name of the thumbnail style for the current thumbnail. If no style is given, "original" is used.
132   - # * +id+: The record's id.
133   - # * +name+: The file's name, as stored in the attachment_file_name column.
134   - # * +base+: The base of the file's name, e.g. "myself" from "myself.jpg", or "my.picture" from "my.picture.png".
135   - # It is defined as everything except the final period and what follows it. If there is no extension, :base works
136   - # the same as :name.
137   - # * +ext+: The extension of the file, e.g. "jpg" from "myself.jpg". It is defined as everything following the final
138   - # period
139   - #
140   - # When interpolating, you are not confined to making any one of these into its own directory. This is
141   - # perfectly valid:
142   - # :path => ":attachment/:style/:id-:name" # => "avatars/thumb/44-me.png"
143   - #
144   - # == Model Requirements
145   - # For any given attachment _foo_, the model the attachment is in needs to have both a +foo_file_name+
146   - # and +foo_content_type+ column, as a type of +string+. The +foo_file_name+ column contains only the name
147   - # of the file and none of the path information. However, the +foo_file_name+ column accessor is overwritten
148   - # by the one (defined above) which returns the full path to whichever style thumbnail is passed in.
149   - # In a pinch, you can either use +read_attribute+ or the plain +foo+ accessor, which returns the database's
150   - # +foo_file_name+ column.
151   - #
152   - # Note that if these columns are not found in the model (according to +ActiveRecord::Base#column_names+) then
153   - # Paperclip will throw a +PaperclipError+ informing you of the fact.
154   - #
155   - # == Event Triggers
156   - # When an attachment is set by using he setter (+model.attachment=+), the thumbnails are created and held in
157   - # memory. They are not saved until the +after_save+ trigger fires, at which point the attachment and all
158   - # thumbnails are written to disk.
159   - #
160   - # Attached files are destroyed when the associated record is destroyed in a +before_destroy+ trigger. Set
161   - # the +delete_on_destroy+ option to +false+ to prevent this behavior. Also note that using the ActiveRecord's
162   - # +delete+ method instead of the +destroy+ method will prevent the +before_destroy+ trigger from firing.
163   - #
164   - # == Validation
165   - # If there is a problem in the thumbnail-making process, Paperclip will add errors to your model on save. These
166   - # errors appear if there is an error with +convert+ (e.g. +convert+ doesn't exist, the file wasn't an image, etc).
167   - def has_attached_file *attachment_names
168   - options = attachment_names.last.is_a?(Hash) ? attachment_names.pop : {}
169   - options = DEFAULT_ATTACHMENT_OPTIONS.merge(options)
170   -
171   - include InstanceMethods
172   - attachments = (@attachments ||= {})
173   -
174   - define_method :after_initialize do
175   - attachments.each do |name, options|
176   - options[:instance] = self
177   - end
178   - end
179   -
180   - attachment_names.each do |attr|
181   - attachments[attr] = (attachments[attr] || {:name => attr}).merge(options)
182   - whine_about_columns_for attachments[attr]
183   -
184   - if attachments[attr][:storage]
185   - attachments[attr][:storage] = Thoughtbot::Paperclip::Storage.const_get(attachments[attr][:storage].to_s.camelize).new
186   - else
187   - attachments[attr][:storage] = Thoughtbot::Paperclip::Storage::Filesystem.new
188   - end
189   -
190   - define_method "#{attr}=" do |uploaded_file|
191   - uploaded_file = fetch_uri(uploaded_file) if uploaded_file.is_a? URI
192   - return send("destroy_#{attr}") if uploaded_file.nil?
193   - return unless is_a_file? uploaded_file
194   -
195   - attachments[attr].merge!({
196   - :dirty => true,
197   - :files => {:original => uploaded_file},
198   - :content_type => uploaded_file.content_type,
199   - :file_name => sanitize_filename(uploaded_file.original_filename),
200   - :errors => [],
201   - :delete_on_save => false
202   - })
203   - write_attribute(:"#{attr}_file_name", attachments[attr][:file_name])
204   - write_attribute(:"#{attr}_content_type", attachments[attr][:content_type])
205   -
206   - if attachments[attr][:attachment_type] == :image
207   - send("process_#{attr}_thumbnails")
208   - end
209   -
210   - uploaded_file
211   - end
212   -
213   - define_method attr do
214   - read_attribute("#{attr}_file_name")
215   - end
216   - alias_method "#{attr}?", attr
217   -
218   - define_method "#{attr}_attachment" do
219   - attachments[attr]
220   - end
221   - private :"#{attr}_attachment"
222   -
223   - define_method "#{attr}_file_name" do |*args|
224   - style = args.shift || attachments[attr][:default_style] # This prevents arity warnings
225   - attachments[attr][:storage].path_for(attachments[attr], style) ||
226   - attachments[attr][:storage].interpolate(attachments[attr], attachments[attr][:missing_path], style)
227   - end
228   -
229   - define_method "#{attr}_url" do |*args|
230   - style = args.shift || attachments[attr][:default_style] # This prevents arity warnings
231   - attachments[attr][:storage].url_for(attachments[attr], style) ||
232   - attachments[attr][:storage].interpolate(attachments[attr], attachments[attr][:missing_url], style)
233   - end
234   -
235   - define_method "#{attr}_valid?" do
236   - attachments[attr][:storage].attachment_valid? attachments[attr]
237   - end
238   -
239   - define_method "process_#{attr}_thumbnails" do
240   - attachments[attr][:storage].make_thumbnails attachments[attr]
241   - end
242   -
243   - define_method "destroy_#{attr}" do |*args|
244   - complain = args.first || false
245   - if attachments[attr].keys.any?
246   - attachments[attr][:files] = nil
247   - attachments[attr][:delete_on_save] = true
248   - attachments[attr][:complain_on_delete] = complain
249   - write_attribute("#{attr}_file_name", nil)
250   - write_attribute("#{attr}_content_type", nil)
251   - end
252   - true
253   - end
254   -
255   - validates_each attr do |r, a, v|
256   - attachments[attr][:errors].each{|e| r.errors.add(attr, e) } if attachments[attr][:errors]
257   - end
258   -
259   - define_method "#{attr}_before_save" do
260   - if attachments[attr].keys.any?
261   - if attachments[attr][:files]
262   - attachments[attr][:storage].write_attachment attachments[attr]
263   - end
264   - if attachments[attr][:delete_on_save]
265   - attachments[attr][:storage].delete_attachment attachments[attr], attachments[attr][:complain_on_delete]
266   - end
267   - attachments[attr][:delete_on_save] = false
268   - attachments[attr][:dirty] = false
269   - attachments[attr][:files] = nil
270   - end
271   - end
272   - private :"#{attr}_before_save"
273   - after_save :"#{attr}_before_save"
274   -
275   - define_method "#{attr}_before_destroy" do
276   - if attachments[attr].keys.any?
277   - attachments[attr][:storage].delete_attachment attachments[attr] if attachments[attr][:delete_on_destroy]
278   - end
279   - end
280   - private :"#{attr}_before_destroy"
281   - before_destroy :"#{attr}_before_destroy"
282   - end
283   -
284   - [attachments, options]
285   - end
286   -
287   - def attachment_names
288   - @attachments.keys
289   - end
290   -
291   - def attachment name
292   - @attachments[name]
293   - end
294   -
295   - # Adds errors if the attachments you specify are either missing or had errors on them.
296   - # Essentially, acts like validates_presence_of for attachments.
297   - def validates_attached_file *attachment_names
298   - validates_each *attachment_names do |r, a, v|
299   - r.errors.add(a, "requires a valid attachment.") unless r.send("#{a}_valid?")
300   - end
301   - end
302   -
303   - def whine_about_columns_for attachment #:nodoc:
304   - name = attachment[:name]
305   - unless column_names.include?("#{name}_file_name") && column_names.include?("#{name}_content_type")
306   - error = "Class #{self.name} does not have the necessary columns to have an attachment named #{name}. " +
307   - "(#{name}_file_name and #{name}_content_type)"
308   - raise PaperclipError.new(attachment), error
309   - end
310   - end
311   - end
312   -
313   - module InstanceMethods #:nodoc:
314   - def is_a_file? data
315   - [:content_type, :original_filename, :read].map do |meth|
316   - data.respond_to? meth
317   - end.all?
318   - end
319   -
320   - def sanitize_filename filename
321   - File.basename(filename).gsub(/[^\w\.\_]/,'_')
322   - end
323   -
324   - def fetch_uri uri
325   - image = if uri.scheme == 'file'
326   - path = url.gsub(%r{^file://}, '/')
327   - open(path)
328   - else
329   - require 'open-uri'
330   - uri
331   - end
332   - begin
333   - data = StringIO.new(image.read)
334   - uri.extend(Upfile)
335   - class << data
336   - attr_accessor :original_filename, :content_type
337   - end
338   - data.original_filename = uri.original_filename
339   - data.content_type = uri.content_type
340   - data
341   - rescue OpenURI::HTTPError => e
342   - self.errors.add_to_base("The file at #{uri.to_s} could not be found.")
343   - $stderr.puts "#{e.message}: #{uri.to_s}"
344   - return nil
345   - end
346   - end
347   - end
348   -
349   - # The Upfile module is a convenience module for adding uploaded-file-type methods
350   - # to the +File+ class. Useful for testing.
351   - # user.avatar = File.new("test/test_avatar.jpg")
352   - module Upfile
353   - # Infer the MIME-type of the file from the extension.
354   - def content_type
355   - type = self.path.match(/\.(\w+)$/)[1] || "data"
356   - case type
357   - when "jpg", "png", "gif" then "image/#{type}"
358   - when "txt", "csv", "xml", "html", "htm" then "text/#{type}"
359   - else "x-application/#{type}"
360   - end
361   - end
362   -
363   - # Returns the file's normal name.
364   - def original_filename
365   - self.path
366   - end
367   -
368   - # Returns the size of the file.
369   - def size
370   - File.size(self)
371   - end
372   - end
373   - end
374   -end
100 lib/paperclip/storage.rb
... ... @@ -1,100 +0,0 @@
1   -module Thoughtbot
2   - module Paperclip
3   - class Storage
4   - def interpolate attachment, source, style
5   - style ||= attachment[:default_style]
6   - file_name = attachment[:instance]["#{attachment[:name]}_file_name"]
7   - returning source.dup do |s|
8   - s.gsub!(/:rails_root/, RAILS_ROOT)
9   - s.gsub!(/:id/, attachment[:instance].id.to_s) if attachment[:instance].id
10   - s.gsub!(/:class/, attachment[:instance].class.to_s.underscore.pluralize)
11   - s.gsub!(/:style/, style.to_s )
12   - s.gsub!(/:attachment/, attachment[:name].to_s.pluralize)
13   - if file_name
14   - file_bits = file_name.split(".")
15   - s.gsub!(/:name/, file_name)
16   - s.gsub!(/:base/, [file_bits[0], *file_bits[1..-2]].join("."))
17   - s.gsub!(/:ext/, file_bits.last )
18   - end
19   - end
20   - end
21   -
22   - def make_thumbnails attachment
23   - attachment[:files] ||= {}
24   - attachment[:files][:original] ||= File.new( path_for(attachment, :original) )
25   - attachment[:thumbnails].each do |style, geometry|
26   - begin
27   - attachment[:files][style] = make_thumbnail(attachment, attachment[:files][:original], geometry)
28   - rescue PaperclipError => e
29   - attachment[:errors] << "thumbnail '#{style}' could not be created."
30   - end
31   - end
32   - end
33   -
34   - def make_thumbnail attachment, orig_io, geometry
35   - operator = geometry[-1,1]
36   - begin
37   - geometry, crop_geometry = geometry_for_crop(geometry, orig_io) if operator == '#'
38   - command = "#{path_for_command "convert"} - -scale '#{geometry}' #{operator == '#' ? "-crop '#{crop_geometry}'" : ""} - 2>/dev/null"
39   - thumb = IO.popen(command, "w+") do |io|
40   - orig_io.rewind
41   - io.write(orig_io.read)
42   - io.close_write
43   - StringIO.new(io.read)
44   - end
45   - rescue Errno::EPIPE => e
46   - raise PaperclipError.new(attachment), "Could not create thumbnail. Is ImageMagick or GraphicsMagick installed and available?"
47   - rescue SystemCallError => e
48   - raise PaperclipError.new(attachment), "Could not create thumbnail."
49   - end
50   - if ::Thoughtbot::Paperclip.options[:whiny_thumbnails] && !$?.success?
51   - raise PaperclipError.new(attachment), "Convert returned with result code #{$?.exitstatus}: #{thumb.read}"
52   - end
53   - thumb
54   - end
55   -
56   - def geometry_for_crop geometry, orig_io
57   - IO.popen("#{path_for_command "identify"} - 2>/dev/null", "w+") do |io|
58   - orig_io.rewind
59   - io.write(orig_io.read)
60   - io.close_write
61   - if match = io.read.split[2].match(/(\d+)x(\d+)/)
62   - src = match[1,2].map(&:to_f)
63   - srch = src[0] > src[1]
64   - dst = geometry.match(/(\d+)x(\d+)/)[1,2].map(&:to_f)
65   - dsth = dst[0] > dst[1]
66   - ar = src[0] / src[1]
67   -
68   - scale_geometry, scale = if dst[0] == dst[1]
69   - if srch
70   - [ "x#{dst[1]}", src[1] / dst[1] ]
71   - else
72   - [ "#{dst[0]}x", src[0] / dst[0] ]
73   - end
74   - elsif dsth
75   - [ "#{dst[0]}x", src[0] / dst[0] ]
76   - else
77   - [ "x#{dst[1]}", src[1] / dst[1] ]
78   - end
79   -
80   - crop_geometry = if dsth
81   - "%dx%d+%d+%d" % [ dst[0], dst[1], 0, (src[1] / scale - dst[1]) / 2 ]
82   - else
83   - "%dx%d+%d+%d" % [ dst[0], dst[1], (src[0] / scale - dst[0]) / 2, 0 ]
84   - end
85   -
86   - [ scale_geometry, crop_geometry ]
87   - end
88   - end
89   - end
90   -
91   - def path_for_command command
92   - File.join([::Thoughtbot::Paperclip.options[:image_magick_path], command].compact)
93   - end
94   -
95   - def to_s
96   - self.class.name
97   - end
98   - end
99   - end
100   -end

0 comments on commit bb51ba0

Please sign in to comment.
Something went wrong with that request. Please try again.