avatar 0.0.1

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.
Files changed (74) hide show
  1. data/.gitignore +11 -0
  2. data/History.txt +14 -0
  3. data/License.txt +20 -0
  4. data/Manifest.txt +73 -0
  5. data/README.txt +65 -0
  6. data/Rakefile +10 -0
  7. data/config/hoe.rb +70 -0
  8. data/config/requirements.rb +17 -0
  9. data/lib/avatar.rb +44 -0
  10. data/lib/avatar/source.rb +4 -0
  11. data/lib/avatar/source/abstract_source.rb +15 -0
  12. data/lib/avatar/source/file_column_source.rb +35 -0
  13. data/lib/avatar/source/gravatar_source.rb +78 -0
  14. data/lib/avatar/source/nil_source.rb +17 -0
  15. data/lib/avatar/source/source_chain.rb +51 -0
  16. data/lib/avatar/source/static_url_source.rb +25 -0
  17. data/lib/avatar/source/string_substitution_source.rb +48 -0
  18. data/lib/avatar/version.rb +9 -0
  19. data/lib/avatar/view.rb +4 -0
  20. data/lib/avatar/view/abstract_view_support.rb +15 -0
  21. data/lib/avatar/view/action_view_support.rb +23 -0
  22. data/script/destroy +14 -0
  23. data/script/generate +14 -0
  24. data/script/txt2html +74 -0
  25. data/setup.rb +1585 -0
  26. data/tasks/deployment.rake +34 -0
  27. data/tasks/environment.rake +7 -0
  28. data/tasks/testing.rake +37 -0
  29. data/tasks/website.rake +17 -0
  30. data/test/.gitignore +3 -0
  31. data/test/lib/database.rb +2 -0
  32. data/test/lib/database.yml +10 -0
  33. data/test/lib/file_column/CHANGELOG +69 -0
  34. data/test/lib/file_column/README +54 -0
  35. data/test/lib/file_column/Rakefile +36 -0
  36. data/test/lib/file_column/TODO +6 -0
  37. data/test/lib/file_column/init.rb +13 -0
  38. data/test/lib/file_column/lib/file_column.rb +720 -0
  39. data/test/lib/file_column/lib/file_column_helper.rb +150 -0
  40. data/test/lib/file_column/lib/file_compat.rb +28 -0
  41. data/test/lib/file_column/lib/magick_file_column.rb +260 -0
  42. data/test/lib/file_column/lib/rails_file_column.rb +19 -0
  43. data/test/lib/file_column/lib/test_case.rb +124 -0
  44. data/test/lib/file_column/lib/validations.rb +112 -0
  45. data/test/lib/file_column/test/abstract_unit.rb +63 -0
  46. data/test/lib/file_column/test/connection.rb +17 -0
  47. data/test/lib/file_column/test/file_column_helper_test.rb +97 -0
  48. data/test/lib/file_column/test/file_column_test.rb +650 -0
  49. data/test/lib/file_column/test/fixtures/entry.rb +32 -0
  50. data/test/lib/file_column/test/fixtures/invalid-image.jpg +1 -0
  51. data/test/lib/file_column/test/fixtures/kerb.jpg +0 -0
  52. data/test/lib/file_column/test/fixtures/mysql.sql +25 -0
  53. data/test/lib/file_column/test/fixtures/schema.rb +10 -0
  54. data/test/lib/file_column/test/fixtures/skanthak.png +0 -0
  55. data/test/lib/file_column/test/magick_test.rb +380 -0
  56. data/test/lib/file_column/test/magick_view_only_test.rb +21 -0
  57. data/test/lib/schema.rb +7 -0
  58. data/test/lib/user_suit.png +0 -0
  59. data/test/test_abstract_view_support.rb +22 -0
  60. data/test/test_action_view_support.rb +30 -0
  61. data/test/test_avatar.rb +12 -0
  62. data/test/test_file_column_source.rb +30 -0
  63. data/test/test_gravatar_source.rb +58 -0
  64. data/test/test_helper.rb +22 -0
  65. data/test/test_nil_source.rb +18 -0
  66. data/test/test_source_chain.rb +44 -0
  67. data/test/test_static_url_source.rb +18 -0
  68. data/test/test_string_substitution_source.rb +22 -0
  69. data/website/index.html +101 -0
  70. data/website/index.txt +44 -0
  71. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  72. data/website/stylesheets/screen.css +138 -0
  73. data/website/template.rhtml +48 -0
  74. metadata +141 -0
@@ -0,0 +1,150 @@
1
+ # This module contains helper methods for displaying and uploading files
2
+ # for attributes created by +FileColumn+'s +file_column+ method. It will be
3
+ # automatically included into ActionView::Base, thereby making this module's
4
+ # methods available in all your views.
5
+ module FileColumnHelper
6
+
7
+ # Use this helper to create an upload field for a file_column attribute. This will generate
8
+ # an additional hidden field to keep uploaded files during form-redisplays. For example,
9
+ # when called with
10
+ #
11
+ # <%= file_column_field("entry", "image") %>
12
+ #
13
+ # the following HTML will be generated (assuming the form is redisplayed and something has
14
+ # already been uploaded):
15
+ #
16
+ # <input type="hidden" name="entry[image_temp]" value="..." />
17
+ # <input type="file" name="entry[image]" />
18
+ #
19
+ # You can use the +option+ argument to pass additional options to the file-field tag.
20
+ #
21
+ # Be sure to set the enclosing form's encoding to 'multipart/form-data', by
22
+ # using something like this:
23
+ #
24
+ # <%= form_tag {:action => "create", ...}, :multipart => true %>
25
+ def file_column_field(object, method, options={})
26
+ result = ActionView::Helpers::InstanceTag.new(object.dup, method.to_s+"_temp", self).to_input_field_tag("hidden", {})
27
+ result << ActionView::Helpers::InstanceTag.new(object.dup, method, self).to_input_field_tag("file", options)
28
+ end
29
+
30
+ # Creates an URL where an uploaded file can be accessed. When called for an Entry object with
31
+ # id 42 (stored in <tt>@entry</tt>) like this
32
+ #
33
+ # <%= url_for_file_column(@entry, "image")
34
+ #
35
+ # the following URL will be produced, assuming the file "test.png" has been stored in
36
+ # the "image"-column of an Entry object stored in <tt>@entry</tt>:
37
+ #
38
+ # /entry/image/42/test.png
39
+ #
40
+ # This will produce a valid URL even for temporary uploaded files, e.g. files where the object
41
+ # they are belonging to has not been saved in the database yet.
42
+ #
43
+ # The URL produces, although starting with a slash, will be relative
44
+ # to your app's root. If you pass it to one rails' +image_tag+
45
+ # helper, rails will properly convert it to an absolute
46
+ # URL. However, this will not be the case, if you create a link with
47
+ # the +link_to+ helper. In this case, you can pass <tt>:absolute =>
48
+ # true</tt> to +options+, which will make sure, the generated URL is
49
+ # absolute on your server. Examples:
50
+ #
51
+ # <%= image_tag url_for_file_column(@entry, "image") %>
52
+ # <%= link_to "Download", url_for_file_column(@entry, "image", :absolute => true) %>
53
+ #
54
+ # If there is currently no uploaded file stored in the object's column this method will
55
+ # return +nil+.
56
+ def url_for_file_column(object, method, options=nil)
57
+ case object
58
+ when String, Symbol
59
+ object = instance_variable_get("@#{object.to_s}")
60
+ end
61
+
62
+ # parse options
63
+ subdir = nil
64
+ absolute = false
65
+ if options
66
+ case options
67
+ when Hash
68
+ subdir = options[:subdir]
69
+ absolute = options[:absolute]
70
+ when String, Symbol
71
+ subdir = options
72
+ end
73
+ end
74
+
75
+ relative_path = object.send("#{method}_relative_path", subdir)
76
+ return nil unless relative_path
77
+
78
+ url = ""
79
+ url << request.relative_url_root.to_s if absolute
80
+ url << "/"
81
+ url << object.send("#{method}_options")[:base_url] << "/"
82
+ url << relative_path
83
+ end
84
+
85
+ # Same as +url_for_file_colum+ but allows you to access different versions
86
+ # of the image that have been processed by RMagick.
87
+ #
88
+ # If your +options+ parameter is non-nil this will
89
+ # access a different version of an image that will be produced by
90
+ # RMagick. You can use the following types for +options+:
91
+ #
92
+ # * a <tt>:symbol</tt> will select a version defined in the model
93
+ # via FileColumn::Magick's <tt>:versions</tt> feature.
94
+ # * a <tt>geometry_string</tt> will dynamically create an
95
+ # image resized as specified by <tt>geometry_string</tt>. The image will
96
+ # be stored so that it does not have to be recomputed the next time the
97
+ # same version string is used.
98
+ # * <tt>some_hash</tt> will dynamically create an image
99
+ # that is created according to the options in <tt>some_hash</tt>. This
100
+ # accepts exactly the same options as Magick's version feature.
101
+ #
102
+ # The version produced by RMagick will be stored in a special sub-directory.
103
+ # The directory's name will be derived from the options you specified
104
+ # (via a hash function) but if you want
105
+ # to set it yourself, you can use the <tt>:name => name</tt> option.
106
+ #
107
+ # Examples:
108
+ #
109
+ # <%= url_for_image_column @entry, "image", "640x480" %>
110
+ #
111
+ # will produce an URL like this
112
+ #
113
+ # /entry/image/42/bdn19n/filename.jpg
114
+ # # "640x480".hash.abs.to_s(36) == "bdn19n"
115
+ #
116
+ # and
117
+ #
118
+ # <%= url_for_image_column @entry, "image",
119
+ # :size => "50x50", :crop => "1:1", :name => "thumb" %>
120
+ #
121
+ # will produce something like this:
122
+ #
123
+ # /entry/image/42/thumb/filename.jpg
124
+ #
125
+ # Hint: If you are using the same geometry string / options hash multiple times, you should
126
+ # define it in a helper to stay with DRY. Another option is to define it in the model via
127
+ # FileColumn::Magick's <tt>:versions</tt> feature and then refer to it via a symbol.
128
+ #
129
+ # The URL produced by this method is relative to your application's root URL,
130
+ # although it will start with a slash.
131
+ # If you pass this URL to rails' +image_tag+ helper, it will be converted to an
132
+ # absolute URL automatically.
133
+ # If there is currently no image uploaded, or there is a problem while loading
134
+ # the image this method will return +nil+.
135
+ def url_for_image_column(object, method, options=nil)
136
+ case object
137
+ when String, Symbol
138
+ object = instance_variable_get("@#{object.to_s}")
139
+ end
140
+ subdir = nil
141
+ if options
142
+ subdir = object.send("#{method}_state").create_magick_version_if_needed(options)
143
+ end
144
+ if subdir.nil?
145
+ nil
146
+ else
147
+ url_for_file_column(object, method, subdir)
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,28 @@
1
+ module FileColumn
2
+
3
+ # This bit of code allows you to pass regular old files to
4
+ # file_column. file_column depends on a few extra methods that the
5
+ # CGI uploaded file class adds. We will add the equivalent methods
6
+ # to file objects if necessary by extending them with this module. This
7
+ # avoids opening up the standard File class which might result in
8
+ # naming conflicts.
9
+
10
+ module FileCompat # :nodoc:
11
+ def original_filename
12
+ File.basename(path)
13
+ end
14
+
15
+ def size
16
+ File.size(path)
17
+ end
18
+
19
+ def local_path
20
+ path
21
+ end
22
+
23
+ def content_type
24
+ nil
25
+ end
26
+ end
27
+ end
28
+
@@ -0,0 +1,260 @@
1
+ module FileColumn # :nodoc:
2
+
3
+ class BaseUploadedFile # :nodoc:
4
+ def transform_with_magick
5
+ if needs_transform?
6
+ begin
7
+ img = ::Magick::Image::read(absolute_path).first
8
+ rescue ::Magick::ImageMagickError
9
+ if options[:magick][:image_required]
10
+ @magick_errors ||= []
11
+ @magick_errors << "invalid image"
12
+ end
13
+ return
14
+ end
15
+
16
+ if options[:magick][:versions]
17
+ options[:magick][:versions].each_pair do |version, version_options|
18
+ next if version_options[:lazy]
19
+ dirname = version_options[:name]
20
+ FileUtils.mkdir File.join(@dir, dirname)
21
+ transform_image(img, version_options, absolute_path(dirname))
22
+ end
23
+ end
24
+ if options[:magick][:size] or options[:magick][:crop] or options[:magick][:transformation] or options[:magick][:attributes]
25
+ transform_image(img, options[:magick], absolute_path)
26
+ end
27
+
28
+ GC.start
29
+ end
30
+ end
31
+
32
+ def create_magick_version_if_needed(version)
33
+ # RMagick might not have been loaded so far.
34
+ # We do not want to require it on every call of this method
35
+ # as this might be fairly expensive, so we just try if ::Magick
36
+ # exists and require it if not.
37
+ begin
38
+ ::Magick
39
+ rescue NameError
40
+ require 'RMagick'
41
+ end
42
+
43
+ if version.is_a?(Symbol)
44
+ version_options = options[:magick][:versions][version]
45
+ else
46
+ version_options = MagickExtension::process_options(version)
47
+ end
48
+
49
+ unless File.exists?(absolute_path(version_options[:name]))
50
+ begin
51
+ img = ::Magick::Image::read(absolute_path).first
52
+ rescue ::Magick::ImageMagickError
53
+ # we might be called directly from the view here
54
+ # so we just return nil if we cannot load the image
55
+ return nil
56
+ end
57
+ dirname = version_options[:name]
58
+ FileUtils.mkdir File.join(@dir, dirname)
59
+ transform_image(img, version_options, absolute_path(dirname))
60
+ end
61
+
62
+ version_options[:name]
63
+ end
64
+
65
+ attr_reader :magick_errors
66
+
67
+ def has_magick_errors?
68
+ @magick_errors and !@magick_errors.empty?
69
+ end
70
+
71
+ private
72
+
73
+ def needs_transform?
74
+ options[:magick] and just_uploaded? and
75
+ (options[:magick][:size] or options[:magick][:versions] or options[:magick][:transformation] or options[:magick][:attributes])
76
+ end
77
+
78
+ def transform_image(img, img_options, dest_path)
79
+ begin
80
+ if img_options[:transformation]
81
+ if img_options[:transformation].is_a?(Symbol)
82
+ img = @instance.send(img_options[:transformation], img)
83
+ else
84
+ img = img_options[:transformation].call(img)
85
+ end
86
+ end
87
+ if img_options[:crop]
88
+ dx, dy = img_options[:crop].split(':').map { |x| x.to_f }
89
+ w, h = (img.rows * dx / dy), (img.columns * dy / dx)
90
+ img = img.crop(::Magick::CenterGravity, [img.columns, w].min,
91
+ [img.rows, h].min, true)
92
+ end
93
+
94
+ if img_options[:size]
95
+ img = img.change_geometry(img_options[:size]) do |c, r, i|
96
+ i.resize(c, r)
97
+ end
98
+ end
99
+ ensure
100
+ img.write(dest_path) do
101
+ if img_options[:attributes]
102
+ img_options[:attributes].each_pair do |property, value|
103
+ self.send "#{property}=", value
104
+ end
105
+ end
106
+ end
107
+ File.chmod options[:permissions], dest_path
108
+ end
109
+ end
110
+ end
111
+
112
+ # If you are using file_column to upload images, you can
113
+ # directly process the images with RMagick,
114
+ # a ruby extension
115
+ # for accessing the popular imagemagick libraries. You can find
116
+ # more information about RMagick at http://rmagick.rubyforge.org.
117
+ #
118
+ # You can control what to do by adding a <tt>:magick</tt> option
119
+ # to your options hash. All operations are performed immediately
120
+ # after a new file is assigned to the file_column attribute (i.e.,
121
+ # when a new file has been uploaded).
122
+ #
123
+ # == Resizing images
124
+ #
125
+ # To resize the uploaded image according to an imagemagick geometry
126
+ # string, just use the <tt>:size</tt> option:
127
+ #
128
+ # file_column :image, :magick => {:size => "800x600>"}
129
+ #
130
+ # If the uploaded file cannot be loaded by RMagick, file_column will
131
+ # signal a validation error for the corresponding attribute. If you
132
+ # want to allow non-image files to be uploaded in a column that uses
133
+ # the <tt>:magick</tt> option, you can set the <tt>:image_required</tt>
134
+ # attribute to +false+:
135
+ #
136
+ # file_column :image, :magick => {:size => "800x600>",
137
+ # :image_required => false }
138
+ #
139
+ # == Multiple versions
140
+ #
141
+ # You can also create additional versions of your image, for example
142
+ # thumb-nails, like this:
143
+ # file_column :image, :magick => {:versions => {
144
+ # :thumb => {:size => "50x50"},
145
+ # :medium => {:size => "640x480>"}
146
+ # }
147
+ #
148
+ # These versions will be stored in separate sub-directories, named like the
149
+ # symbol you used to identify the version. So in the previous example, the
150
+ # image versions will be stored in "thumb", "screen" and "widescreen"
151
+ # directories, resp.
152
+ # A name different from the symbol can be set via the <tt>:name</tt> option.
153
+ #
154
+ # These versions can be accessed via FileColumnHelper's +url_for_image_column+
155
+ # method like this:
156
+ #
157
+ # <%= url_for_image_column "entry", "image", :thumb %>
158
+ #
159
+ # == Cropping images
160
+ #
161
+ # If you wish to crop your images with a size ratio before scaling
162
+ # them according to your version geometry, you can use the :crop directive.
163
+ # file_column :image, :magick => {:versions => {
164
+ # :square => {:crop => "1:1", :size => "50x50", :name => "thumb"},
165
+ # :screen => {:crop => "4:3", :size => "640x480>"},
166
+ # :widescreen => {:crop => "16:9", :size => "640x360!"},
167
+ # }
168
+ # }
169
+ #
170
+ # == Custom attributes
171
+ #
172
+ # To change some of the image properties like compression level before they
173
+ # are saved you can set the <tt>:attributes</tt> option.
174
+ # For a list of available attributes go to http://www.simplesystems.org/RMagick/doc/info.html
175
+ #
176
+ # file_column :image, :magick => { :attributes => { :quality => 30 } }
177
+ #
178
+ # == Custom transformations
179
+ #
180
+ # To perform custom transformations on uploaded images, you can pass a
181
+ # callback to file_column:
182
+ # file_column :image, :magick =>
183
+ # Proc.new { |image| image.quantize(256, Magick::GRAYColorspace) }
184
+ #
185
+ # The callback you give, receives one argument, which is an instance
186
+ # of Magick::Image, the RMagick image class. It should return a transformed
187
+ # image. Instead of passing a <tt>Proc</tt> object, you can also give a
188
+ # <tt>Symbol</tt>, the name of an instance method of your model.
189
+ #
190
+ # Custom transformations can be combined via the standard :size and :crop
191
+ # features, by using the :transformation option:
192
+ # file_column :image, :magick => {
193
+ # :transformation => Proc.new { |image| ... },
194
+ # :size => "640x480"
195
+ # }
196
+ #
197
+ # In this case, the standard resizing operations will be performed after the
198
+ # custom transformation.
199
+ #
200
+ # Of course, custom transformations can be used in versions, as well.
201
+ #
202
+ # <b>Note:</b> You'll need the
203
+ # RMagick extension being installed in order to use file_column's
204
+ # imagemagick integration.
205
+ module MagickExtension
206
+
207
+ def self.file_column(klass, attr, options) # :nodoc:
208
+ require 'RMagick'
209
+ options[:magick] = process_options(options[:magick],false) if options[:magick]
210
+ if options[:magick][:versions]
211
+ options[:magick][:versions].each_pair do |name, value|
212
+ options[:magick][:versions][name] = process_options(value, name.to_s)
213
+ end
214
+ end
215
+ state_method = "#{attr}_state".to_sym
216
+ after_assign_method = "#{attr}_magick_after_assign".to_sym
217
+
218
+ klass.send(:define_method, after_assign_method) do
219
+ self.send(state_method).transform_with_magick
220
+ end
221
+
222
+ options[:after_upload] ||= []
223
+ options[:after_upload] << after_assign_method
224
+
225
+ klass.validate do |record|
226
+ state = record.send(state_method)
227
+ if state.has_magick_errors?
228
+ state.magick_errors.each do |error|
229
+ record.errors.add attr, error
230
+ end
231
+ end
232
+ end
233
+ end
234
+
235
+
236
+ def self.process_options(options,create_name=true)
237
+ case options
238
+ when String then options = {:size => options}
239
+ when Proc, Symbol then options = {:transformation => options }
240
+ end
241
+ if options[:geometry]
242
+ options[:size] = options.delete(:geometry)
243
+ end
244
+ options[:image_required] = true unless options.key?(:image_required)
245
+ if options[:name].nil? and create_name
246
+ if create_name == true
247
+ hash = 0
248
+ for key in [:size, :crop]
249
+ hash = hash ^ options[key].hash if options[key]
250
+ end
251
+ options[:name] = hash.abs.to_s(36)
252
+ else
253
+ options[:name] = create_name
254
+ end
255
+ end
256
+ options
257
+ end
258
+
259
+ end
260
+ end
@@ -0,0 +1,19 @@
1
+ # require this file from your "config/environment.rb" (after rails has been loaded)
2
+ # to integrate the file_column extension into rails.
3
+
4
+ require 'file_column'
5
+ require 'file_column_helper'
6
+
7
+
8
+ module ActiveRecord # :nodoc:
9
+ class Base # :nodoc:
10
+ # make file_column method available in all active record decendants
11
+ include FileColumn
12
+ end
13
+ end
14
+
15
+ module ActionView # :nodoc:
16
+ class Base # :nodoc:
17
+ include FileColumnHelper
18
+ end
19
+ end