dm-paperclip 2.1.2

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/LICENSE ADDED
@@ -0,0 +1,26 @@
1
+
2
+ LICENSE
3
+
4
+ The MIT License
5
+
6
+ Copyright (c) 2008 Jon Yurek and thoughtbot, inc.
7
+
8
+ Permission is hereby granted, free of charge, to any person obtaining a copy
9
+ of this software and associated documentation files (the "Software"), to deal
10
+ in the Software without restriction, including without limitation the rights
11
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
+ copies of the Software, and to permit persons to whom the Software is
13
+ furnished to do so, subject to the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be included in
16
+ all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
+ THE SOFTWARE.
25
+
26
+
@@ -0,0 +1,103 @@
1
+ h1. DataMapper Paperclip
2
+
3
+ DM-Paperclip is a port of Thoughtbot's Paperclip plugin to work with DataMapper 0.9. This plugin is fully compatible with
4
+ the original ActiveRecord-oriented Paperclip. You could take an existing ActiveRecord database and use it with DataMapper.
5
+ The module also includes updates validation handling and automatic including of the necessary 'property' fields into
6
+ your model.
7
+
8
+ To use it within your models, you need to ensure the three database fields are included. They are {name}_file_name,
9
+ {name}_content_type, and {name}_file_size. The first two are strings, the final _file_size column is an integer. So
10
+ if your user model has an avatar field, then you would add avatar_file_name, avatar_content_type, and avatar_file_size.
11
+
12
+ As with the original Paperclip plugin, it allows processing of thumbnails at the time the record is saved though ImageMagick.
13
+ It processes the thumbnails through the command-line applications instead of using RMagick.
14
+
15
+ See the documentation for the +has_attached_file+ method for options.
16
+
17
+ h2. Code
18
+
19
+ The code DM-Paperclip is available at Github:
20
+
21
+ git clone git://github.com/krobertson/paperclip.git
22
+
23
+ It is regularly updated to keep in sync with the latest from Thoughtbot.
24
+
25
+ Releases are tagged within the repository and versioned the same as the original model. You can also get the latest release
26
+ packaged as a gem through Rubyforge:
27
+
28
+ sudo gem install dm-paperclip
29
+
30
+ h2. Usage
31
+
32
+ In your model:
33
+
34
+ class User
35
+ include DataMapper::Resource
36
+ include Paperclip::Resource
37
+ property :id, Integer, :serial => true
38
+ property :username, String
39
+ has_attached_file :avatar,
40
+ :styles => { :medium => "300x300>",
41
+ :thumb => "100x100>" }
42
+ end
43
+
44
+ Your database will need to add three columns, +avatar_file_name+ (varchar), +avatar_content_type+ (varchar), and
45
+ +avatar_file_size+ (integer). You can either add these manually, auto-migrate, or use the following migration:
46
+
47
+ migration( 1, :add_user_paperclip_fields ) do
48
+ up do
49
+ modify_table :users do
50
+ add_column :avatar_file_name, "varchar(255)"
51
+ add_column :avatar_content_type, "varchar(255)"
52
+ add_column :avatar_file_size, "integer"
53
+ end
54
+ end
55
+ down do
56
+ modify_table :users do
57
+ drop_columns :avatar_file_name, :avatar_content_type, :avatar_file_size
58
+ end
59
+ end
60
+ end
61
+
62
+ In your edit and new views:
63
+
64
+ <% form_for @user, { :action => url(:user), :multipart => true } do %>
65
+ <%= file_field :name => 'avatar' %>
66
+ <% end %>
67
+
68
+ In your controller:
69
+
70
+ def create
71
+ ...
72
+ @user.avatar = params[:avatar]
73
+ end
74
+
75
+ In your show view:
76
+
77
+ <%= image_tag @user.avatar.url %>
78
+ <%= image_tag @user.avatar.url(:medium) %>
79
+ <%= image_tag @user.avatar.url(:thumb) %>
80
+
81
+ The following validations are available:
82
+
83
+ validates_attachment_presence :avatar
84
+ validates_attachment_content_type :avatar, :content_type => "image/png"
85
+ validates_attachment_size :avatar, :in => 1..10240
86
+ validates_attachment_thumbnails :avatar
87
+
88
+ In order to use validations, you must have loaded the 'dm-validations' gem into your app
89
+ (available as a part of dm-more). If the gem isn't loaded before DM-Paperclip is loaded,
90
+ the validation methods will be excluded. You will also need to include DataMapper::Validate
91
+ into your mode:
92
+
93
+ class User
94
+ include DataMapper::Resource
95
+ include DataMapper::Validate
96
+ include Paperclip::Resource
97
+ property :id, Integer, :serial => true
98
+ property :username, String
99
+ has_attached_file :avatar,
100
+ :styles => { :medium => "300x300>",
101
+ :thumb => "100x100>" }
102
+ validates_attachment_size :avatar, :in => 1..5120
103
+ end
@@ -0,0 +1,99 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'rake/gempackagetask'
5
+
6
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
7
+ require 'dm-validations'
8
+ require 'dm-paperclip'
9
+
10
+ desc 'Default: run unit tests.'
11
+ task :default => [:clean, :test]
12
+
13
+ # Test tasks
14
+ desc 'Test the DM-Paperclip library.'
15
+ Rake::TestTask.new(:test) do |t|
16
+ t.libs << 'dm-paperclip'
17
+ t.pattern = 'test/**/test_*.rb'
18
+ t.verbose = true
19
+ end
20
+
21
+ # Console
22
+ desc "Open an irb session preloaded with this library"
23
+ task :console do
24
+ sh "irb -rubygems -r dm-validations -r dm-migrations -r ./lib/dm-paperclip.rb"
25
+ end
26
+
27
+ # Rdoc
28
+ desc 'Generate documentation for the paperclip plugin.'
29
+ Rake::RDocTask.new(:doc) do |rdoc|
30
+ rdoc.rdoc_dir = 'doc'
31
+ rdoc.title = 'DM-Paperclip'
32
+ rdoc.options << '--line-numbers' << '--inline-source'
33
+ rdoc.rdoc_files.include('README.textile')
34
+ rdoc.rdoc_files.include('lib/**/*.rb')
35
+ end
36
+
37
+ # Code coverage
38
+ task :coverage do
39
+ system("rm -fr coverage")
40
+ system("rcov test/test_*.rb")
41
+ system("open coverage/index.html")
42
+ end
43
+
44
+ # Clean house
45
+ desc 'Clean up files.'
46
+ task :clean do |t|
47
+ FileUtils.rm_rf "doc"
48
+ FileUtils.rm_rf "coverage"
49
+ FileUtils.rm_rf "tmp"
50
+ FileUtils.rm_rf "pkg"
51
+ FileUtils.rm_rf "log"
52
+ end
53
+
54
+ spec = Gem::Specification.new do |s|
55
+ s.name = "dm-paperclip"
56
+ s.version = Paperclip::VERSION
57
+ s.author = "Ken Robertson"
58
+ s.email = "ken@invalidlogic.com jyurek@thoughtbot.com"
59
+ s.homepage = "http://invalidlogic.com/dm-paperclip/"
60
+ s.platform = Gem::Platform::RUBY
61
+ s.summary = "File attachments as attributes for DataMapper, based on the original Paperclip by Jon Yurek at Thoughtbot"
62
+ s.files = FileList["README.textile",
63
+ "LICENSE",
64
+ "Rakefile",
65
+ "init.rb",
66
+ "{lib,tasks,test}/**/*"].to_a
67
+ s.require_path = "lib"
68
+ s.test_files = FileList["test/**/test_*.rb"].to_a
69
+ s.rubyforge_project = "dm-paperclip"
70
+ s.has_rdoc = true
71
+ s.extra_rdoc_files = ["README.textile"]
72
+ s.rdoc_options << '--line-numbers' << '--inline-source'
73
+ s.requirements << "ImageMagick"
74
+ s.requirements << "data_mapper"
75
+ end
76
+
77
+ Rake::GemPackageTask.new(spec) do |pkg|
78
+ pkg.need_tar = true
79
+ end
80
+
81
+ WIN32 = (PLATFORM =~ /win32|cygwin/) rescue nil
82
+ SUDO = WIN32 ? '' : ('sudo' unless ENV['SUDOLESS'])
83
+
84
+ desc "Install #{spec.name} #{spec.version}"
85
+ task :install => [ :package ] do
86
+ sh "#{SUDO} gem install pkg/#{spec.name}-#{spec.version} --no-update-sources", :verbose => false
87
+ end
88
+
89
+ desc "Release new version"
90
+ task :release => [:test, :gem] do
91
+ require 'rubygems'
92
+ require 'rubyforge'
93
+ r = RubyForge.new
94
+ r.login
95
+ r.add_release spec.rubyforge_project,
96
+ spec.name,
97
+ spec.version,
98
+ File.join("pkg", "#{spec.name}-#{spec.version}.gem")
99
+ end
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.join(File.dirname(__FILE__), 'lib', 'dm-paperclip')
2
+ File.send :include, Paperclip::Upfile
@@ -0,0 +1,229 @@
1
+ # Paperclip allows file attachments that are stored in the filesystem. All graphical
2
+ # transformations are done using the Graphics/ImageMagick command line utilities and
3
+ # are stored in Tempfiles until the record is saved. Paperclip does not require a
4
+ # separate model for storing the attachment's information, instead adding a few simple
5
+ # columns to your table.
6
+ #
7
+ # Author:: Jon Yurek
8
+ # Copyright:: Copyright (c) 2008 thoughtbot, inc.
9
+ # License:: MIT License (http://www.opensource.org/licenses/mit-license.php)
10
+ #
11
+ # Paperclip defines an attachment as any file, though it makes special considerations
12
+ # for image files. You can declare that a model has an attached file with the
13
+ # +has_attached_file+ method:
14
+ #
15
+ # class User < ActiveRecord::Base
16
+ # has_attached_file :avatar, :styles => { :thumb => "100x100" }
17
+ # end
18
+ #
19
+ # user = User.new
20
+ # user.avatar = params[:user][:avatar]
21
+ # user.avatar.url
22
+ # # => "/users/avatars/4/original_me.jpg"
23
+ # user.avatar.url(:thumb)
24
+ # # => "/users/avatars/4/thumb_me.jpg"
25
+ #
26
+ # See the +has_attached_file+ documentation for more details.
27
+
28
+ require 'tempfile'
29
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'upfile')
30
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'iostream')
31
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'geometry')
32
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'thumbnail')
33
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'storage')
34
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'attachment')
35
+
36
+ # Only include validations if dm-validations is loaded
37
+ require File.join(File.dirname(__FILE__), 'dm-paperclip', 'validations') unless defined?(DataMapper::Validate).nil?
38
+
39
+ module Paperclip
40
+ VERSION = "2.1.2"
41
+ class << self
42
+ # Provides configurability to Paperclip. There are a number of options available, such as:
43
+ # * whiny_thumbnails: Will raise an error if Paperclip cannot process thumbnails of
44
+ # an uploaded image. Defaults to true.
45
+ # * image_magick_path: Defines the path at which to find the +convert+ and +identify+
46
+ # programs if they are not visible to Rails the system's search path. Defaults to
47
+ # nil, which uses the first executable found in the search path.
48
+ def options
49
+ @options ||= {
50
+ :whiny_thumbnails => true,
51
+ :image_magick_path => nil
52
+ }
53
+ end
54
+
55
+ def path_for_command command #:nodoc:
56
+ path = [options[:image_magick_path], command].compact
57
+ File.join(*path)
58
+ end
59
+ end
60
+
61
+ class PaperclipError < StandardError #:nodoc:
62
+ end
63
+
64
+ class NotIdentifiedByImageMagickError < PaperclipError #:nodoc:
65
+ end
66
+
67
+ module Resource
68
+ def self.included(base)
69
+ base.extend Paperclip::ClassMethods
70
+ end
71
+ end
72
+
73
+ module ClassMethods
74
+ @@attachment_definitions = {}
75
+
76
+ # +has_attached_file+ gives the class it is called on an attribute that maps to a file. This
77
+ # is typically a file stored somewhere on the filesystem and has been uploaded by a user.
78
+ # The attribute returns a Paperclip::Attachment object which handles the management of
79
+ # that file. The intent is to make the attachment as much like a normal attribute. The
80
+ # thumbnails will be created when the new file is assigned, but they will *not* be saved
81
+ # until +save+ is called on the record. Likewise, if the attribute is set to +nil+ is
82
+ # called on it, the attachment will *not* be deleted until +save+ is called. See the
83
+ # Paperclip::Attachment documentation for more specifics. There are a number of options
84
+ # you can set to change the behavior of a Paperclip attachment:
85
+ # * +url+: The full URL of where the attachment is publically accessible. This can just
86
+ # as easily point to a directory served directly through Apache as it can to an action
87
+ # that can control permissions. You can specify the full domain and path, but usually
88
+ # just an absolute path is sufficient. The leading slash must be included manually for
89
+ # absolute paths. The default value is "/:class/:attachment/:id/:style_:filename". See
90
+ # Paperclip::Attachment#interpolate for more information on variable interpolaton.
91
+ # :url => "/:attachment/:id/:style_:basename:extension"
92
+ # :url => "http://some.other.host/stuff/:class/:id_:extension"
93
+ # * +default_url+: The URL that will be returned if there is no attachment assigned.
94
+ # This field is interpolated just as the url is. The default value is
95
+ # "/:class/:attachment/missing_:style.png"
96
+ # has_attached_file :avatar, :default_url => "/images/default_:style_avatar.png"
97
+ # User.new.avatar_url(:small) # => "/images/default_small_avatar.png"
98
+ # * +styles+: A hash of thumbnail styles and their geometries. You can find more about
99
+ # geometry strings at the ImageMagick website
100
+ # (http://www.imagemagick.org/script/command-line-options.php#resize). Paperclip
101
+ # also adds the "#" option (e.g. "50x50#"), which will resize the image to fit maximally
102
+ # inside the dimensions and then crop the rest off (weighted at the center). The
103
+ # default value is to generate no thumbnails.
104
+ # * +default_style+: The thumbnail style that will be used by default URLs.
105
+ # Defaults to +original+.
106
+ # has_attached_file :avatar, :styles => { :normal => "100x100#" },
107
+ # :default_style => :normal
108
+ # user.avatar.url # => "/avatars/23/normal_me.png"
109
+ # * +path+: The location of the repository of attachments on disk. This can be coordinated
110
+ # with the value of the +url+ option to allow files to be saved into a place where Apache
111
+ # can serve them without hitting your app. Defaults to
112
+ # ":merb_root/public/:class/:attachment/:id/:style_:filename".
113
+ # By default this places the files in the app's public directory which can be served
114
+ # directly. If you are using capistrano for deployment, a good idea would be to
115
+ # make a symlink to the capistrano-created system directory from inside your app's
116
+ # public directory.
117
+ # See Paperclip::Attachment#interpolate for more information on variable interpolaton.
118
+ # :path => "/var/app/attachments/:class/:id/:style/:filename"
119
+ # * +whiny_thumbnails+: Will raise an error if Paperclip cannot process thumbnails of an
120
+ # uploaded image. This will ovrride the global setting for this attachment.
121
+ # Defaults to true.
122
+ def has_attached_file name, options = {}
123
+ include InstanceMethods
124
+
125
+ @@attachment_definitions = {} if @@attachment_definitions.nil?
126
+ @@attachment_definitions[name] = {:validations => []}.merge(options)
127
+
128
+ property_options = options.delete_if { |k,v| ![ :public, :protected, :private, :accessor, :reader, :writer ].include?(key) }
129
+
130
+ property "#{name}_file_name".to_sym, String, property_options
131
+ property "#{name}_content_type".to_sym, String, property_options
132
+ property "#{name}_file_size".to_sym, Integer, property_options
133
+
134
+ after :save, :save_attached_files
135
+ before :destroy, :destroy_attached_files
136
+
137
+ define_method name do |*args|
138
+ a = attachment_for(name)
139
+ (args.length > 0) ? a.to_s(args.first) : a
140
+ end
141
+
142
+ define_method "#{name}=" do |file|
143
+ attachment_for(name).assign(file)
144
+ end
145
+
146
+ define_method "#{name}?" do
147
+ ! attachment_for(name).original_filename.blank?
148
+ end
149
+
150
+ unless defined?(DataMapper::Validate).nil?
151
+ add_validator_to_context(opts_from_validator_args([name]), [name], Paperclip::Validate::CopyAttachmentErrors)
152
+ end
153
+ end
154
+
155
+ unless defined?(DataMapper::Validate).nil?
156
+
157
+ # Places ActiveRecord-style validations on the size of the file assigned. The
158
+ # possible options are:
159
+ # * +in+: a Range of bytes (i.e. +1..1.megabyte+),
160
+ # * +less_than+: equivalent to :in => 0..options[:less_than]
161
+ # * +greater_than+: equivalent to :in => options[:greater_than]..Infinity
162
+ # * +message+: error message to display, use :min and :max as replacements
163
+ def validates_attachment_size(*fields)
164
+ opts = opts_from_validator_args(fields)
165
+ add_validator_to_context(opts, fields, Paperclip::Validate::SizeValidator)
166
+ end
167
+
168
+ # Adds errors if thumbnail creation fails. The same as specifying :whiny_thumbnails => true.
169
+ def validates_attachment_thumbnails name, options = {}
170
+ @@attachment_definitions[name][:whiny_thumbnails] = true
171
+ end
172
+
173
+ # Places ActiveRecord-style validations on the presence of a file.
174
+ def validates_attachment_presence(*fields)
175
+ opts = opts_from_validator_args(fields)
176
+ add_validator_to_context(opts, fields, Paperclip::Validate::RequiredFieldValidator)
177
+ end
178
+
179
+ # Places ActiveRecord-style validations on the content type of the file assigned. The
180
+ # possible options are:
181
+ # * +content_type+: Allowed content types. Can be a single content type or an array. Allows all by default.
182
+ # * +message+: The message to display when the uploaded file has an invalid content type.
183
+ def validates_attachment_content_type(*fields)
184
+ opts = opts_from_validator_args(fields)
185
+ add_validator_to_context(opts, fields, Paperclip::Validate::ContentTypeValidator)
186
+ end
187
+
188
+ end
189
+
190
+ # Returns the attachment definitions defined by each call to has_attached_file.
191
+ def attachment_definitions
192
+ @@attachment_definitions
193
+ end
194
+
195
+ end
196
+
197
+ module InstanceMethods #:nodoc:
198
+ def attachment_for name
199
+ @attachments ||= {}
200
+ @attachments[name] ||= Attachment.new(name, self, self.class.attachment_definitions[name])
201
+ end
202
+
203
+ def each_attachment
204
+ self.class.attachment_definitions.each do |name, definition|
205
+ yield(name, attachment_for(name))
206
+ end
207
+ end
208
+
209
+ def save_attached_files
210
+ each_attachment do |name, attachment|
211
+ attachment.send(:save)
212
+ end
213
+ end
214
+
215
+ def destroy_attached_files
216
+ each_attachment do |name, attachment|
217
+ attachment.queue_existing_for_delete
218
+ attachment.flush_deletes
219
+ end
220
+ end
221
+ end
222
+
223
+ end
224
+
225
+ # Set it all up.
226
+ if Object.const_defined?("ActiveRecord")
227
+ ActiveRecord::Base.send(:include, Paperclip)
228
+ File.send(:include, Paperclip::Upfile)
229
+ end