avatar 0.0.4 → 0.0.5

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 (49) hide show
  1. data/History.txt +10 -0
  2. data/Manifest.txt +32 -6
  3. data/lib/avatar.rb +1 -1
  4. data/lib/avatar/source/gravatar_source.rb +7 -5
  5. data/lib/avatar/source/paperclip_source.rb +52 -0
  6. data/lib/avatar/source/wrapper.rb +6 -0
  7. data/lib/avatar/source/wrapper/abstract_source_wrapper.rb +33 -0
  8. data/lib/avatar/source/wrapper/rails_asset_source_wrapper.rb +36 -0
  9. data/lib/avatar/source/wrapper/string_substitution_source_wrapper.rb +55 -0
  10. data/lib/avatar/version.rb +1 -1
  11. data/test/lib/paperclip/README +32 -0
  12. data/test/lib/paperclip/Rakefile +41 -0
  13. data/test/lib/paperclip/generators/paperclip/USAGE +5 -0
  14. data/test/lib/paperclip/generators/paperclip/paperclip_generator.rb +27 -0
  15. data/test/lib/paperclip/generators/paperclip/templates/paperclip_migration.rb +17 -0
  16. data/test/lib/paperclip/init.rb +3 -0
  17. data/test/lib/paperclip/lib/paperclip.rb +197 -0
  18. data/test/lib/paperclip/lib/paperclip/attachment.rb +230 -0
  19. data/test/lib/paperclip/lib/paperclip/geometry.rb +109 -0
  20. data/test/lib/paperclip/lib/paperclip/iostream.rb +43 -0
  21. data/test/lib/paperclip/lib/paperclip/thumbnail.rb +80 -0
  22. data/test/lib/paperclip/lib/paperclip/upfile.rb +32 -0
  23. data/test/lib/paperclip/tasks/paperclip_tasks.rake +38 -0
  24. data/test/lib/paperclip/test/database.yml +5 -0
  25. data/test/lib/paperclip/test/fixtures/12k.png +0 -0
  26. data/test/lib/paperclip/test/fixtures/5k.png +0 -0
  27. data/test/lib/paperclip/test/fixtures/bad.png +1 -0
  28. data/test/lib/paperclip/test/helper.rb +38 -0
  29. data/test/lib/paperclip/test/test_attachment.rb +99 -0
  30. data/test/lib/paperclip/test/test_geometry.rb +142 -0
  31. data/test/lib/paperclip/test/test_integration.rb +76 -0
  32. data/test/lib/paperclip/test/test_iostream.rb +60 -0
  33. data/test/lib/paperclip/test/test_paperclip.rb +83 -0
  34. data/test/lib/paperclip/test/test_thumbnail.rb +76 -0
  35. data/test/lib/schema.rb +14 -1
  36. data/test/test_file_column_source.rb +8 -6
  37. data/test/test_gravatar_source.rb +5 -0
  38. data/test/test_helper.rb +7 -2
  39. data/test/test_paperclip_source.rb +52 -0
  40. data/test/test_rails_asset_source_wrapper.rb +37 -0
  41. data/test/test_string_substitution_source_wrapper.rb +25 -0
  42. data/website/index.html +1 -1
  43. metadata +43 -11
  44. data/lib/avatar/source/rails_asset_source.rb +0 -64
  45. data/lib/avatar/source/string_substitution_source.rb +0 -45
  46. data/lib/avatar/string_substitution.rb +0 -28
  47. data/test/test_rails_asset_source.rb +0 -50
  48. data/test/test_string_substitution.rb +0 -28
  49. data/test/test_string_substitution_source.rb +0 -22
@@ -0,0 +1,43 @@
1
+ # Provides method that can be included on File-type objects (IO, StringIO, Tempfile, etc) to allow stream copying
2
+ # and Tempfile conversion.
3
+ module IOStream
4
+
5
+ # Returns a Tempfile containing the contents of the readable object.
6
+ def to_tempfile
7
+ tempfile = Tempfile.new("stream")
8
+ tempfile.binmode
9
+ self.stream_to(tempfile)
10
+ end
11
+
12
+ # Copies one read-able object from one place to another in blocks, obviating the need to load
13
+ # the whole thing into memory. Defaults to 8k blocks. If this module is included in both
14
+ # both StringIO and Tempfile, then either can have its data copied anywhere else without typing
15
+ # worries or memory overhead worries. Returns a File if a String is passed in as the destination
16
+ # and returns the IO or Tempfile as passed in if one is sent as the destination.
17
+ def stream_to path_or_file, in_blocks_of = 8192
18
+ dstio = case path_or_file
19
+ when String then File.new(path_or_file, "wb+")
20
+ when IO then path_or_file
21
+ when Tempfile then path_or_file
22
+ end
23
+ buffer = ""
24
+ self.rewind
25
+ while self.read(in_blocks_of, buffer) do
26
+ dstio.write(buffer)
27
+ end
28
+ dstio.rewind
29
+ dstio
30
+ end
31
+ end
32
+
33
+ class IO
34
+ include IOStream
35
+ end
36
+
37
+ %w( Tempfile StringIO ).each do |klass|
38
+ if Object.const_defined? klass
39
+ Object.const_get(klass).class_eval do
40
+ include IOStream
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,80 @@
1
+ module Paperclip
2
+ # Handles thumbnailing images that are uploaded.
3
+ class Thumbnail
4
+
5
+ attr_accessor :file, :current_geometry, :target_geometry, :format, :whiny_thumbnails
6
+
7
+ # Creates a Thumbnail object set to work on the +file+ given. It
8
+ # will attempt to transform the image into one defined by +target_geometry+
9
+ # which is a "WxH"-style string. +format+ will be inferred from the +file+
10
+ # unless specified. Thumbnail creation will raise no errors unless
11
+ # +whiny_thumbnails+ is true (which it is, by default.
12
+ def initialize file, target_geometry, format = nil, whiny_thumbnails = true
13
+ @file = file
14
+ @crop = target_geometry[-1,1] == '#'
15
+ @target_geometry = Geometry.parse target_geometry
16
+ @current_geometry = Geometry.from_file file
17
+ @whiny_thumbnails = whiny_thumbnails
18
+
19
+ @current_format = File.extname(@file.path)
20
+ @basename = File.basename(@file.path, @current_format)
21
+
22
+ @format = format
23
+ end
24
+
25
+ # Creates a thumbnail, as specified in +initialize+, +make+s it, and returns the
26
+ # resulting Tempfile.
27
+ def self.make file, dimensions, format = nil, whiny_thumbnails = true
28
+ new(file, dimensions, format, whiny_thumbnails).make
29
+ end
30
+
31
+ # Returns true if the +target_geometry+ is meant to crop.
32
+ def crop?
33
+ @crop
34
+ end
35
+
36
+ # Performs the conversion of the +file+ into a thumbnail. Returns the Tempfile
37
+ # that contains the new image.
38
+ def make
39
+ src = @file
40
+ dst = Tempfile.new([@basename, @format].compact.join("."))
41
+ dst.binmode
42
+
43
+ command = <<-end_command
44
+ #{ Paperclip.path_for_command('convert') }
45
+ "#{ File.expand_path(src.path) }"
46
+ #{ transformation_command }
47
+ "#{ File.expand_path(dst.path) }"
48
+ end_command
49
+ success = system(command.gsub(/\s+/, " "))
50
+
51
+ if success && $?.exitstatus != 0 && @whiny_thumbnails
52
+ raise PaperclipError, "There was an error processing this thumbnail"
53
+ end
54
+
55
+ dst
56
+ end
57
+
58
+ # Returns the command ImageMagick's +convert+ needs to transform the image
59
+ # into the thumbnail.
60
+ def transformation_command
61
+ scale, crop = @current_geometry.transformation_to(@target_geometry, crop?)
62
+ trans = "-scale \"#{scale}\""
63
+ trans << " -crop \"#{crop}\" +repage" if crop
64
+ trans
65
+ end
66
+ end
67
+
68
+ # Due to how ImageMagick handles its image format conversion and how Tempfile
69
+ # handles its naming scheme, it is necessary to override how Tempfile makes
70
+ # its names so as to allow for file extensions. Idea taken from the comments
71
+ # on this blog post:
72
+ # http://marsorange.com/archives/of-mogrify-ruby-tempfile-dynamic-class-definitions
73
+ class Tempfile < ::Tempfile
74
+ # Replaces Tempfile's +make_tmpname+ with one that honors file extensions.
75
+ def make_tmpname(basename, n)
76
+ extension = File.extname(basename)
77
+ sprintf("%s,%d,%d%s", File.basename(basename, extension), $$, n, extension)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,32 @@
1
+ module Paperclip
2
+ # The Upfile module is a convenience module for adding uploaded-file-type methods
3
+ # to the +File+ class. Useful for testing.
4
+ # user.avatar = File.new("test/test_avatar.jpg")
5
+ module Upfile
6
+
7
+ # Infer the MIME-type of the file from the extension.
8
+ def content_type
9
+ type = self.path.match(/\.(\w+)$/)[1] rescue "octet-stream"
10
+ case type
11
+ when "jpg", "png", "gif" then "image/#{type}"
12
+ when "txt", "csv", "xml", "html", "htm", "css", "js" then "text/#{type}"
13
+ else "x-application/#{type}"
14
+ end
15
+ end
16
+
17
+ # Returns the file's normal name.
18
+ def original_filename
19
+ File.basename(self.path)
20
+ end
21
+
22
+ # Returns the size of the file.
23
+ def size
24
+ File.size(self)
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ class File #:nodoc:
31
+ include Paperclip::Upfile
32
+ end
@@ -0,0 +1,38 @@
1
+ require 'environment'
2
+
3
+ def obtain_class
4
+ class_name = ENV['CLASS'] || ENV['class']
5
+ @klass = Object.const_get(class_name)
6
+ end
7
+
8
+ def obtain_attachments
9
+ name = ENV['ATTACHMENT'] || ENV['attachment']
10
+ if !name.blank? && @klass.attachment_names.include?(name)
11
+ [ name ]
12
+ else
13
+ @klass.attachment_definitions.keys
14
+ end
15
+ end
16
+
17
+ namespace :paperclip do
18
+ desc "Regenerates thumbnails for a given CLASS (and optional ATTACHMENT)"
19
+ task :refresh do
20
+ klass = obtain_class
21
+ instances = klass.find(:all)
22
+ names = obtain_attachments
23
+
24
+ puts "Regenerating thumbnails for #{instances.length} instances of #{klass.name}:"
25
+ instances.each do |instance|
26
+ names.each do |name|
27
+ result = if instance.send("#{ name }?")
28
+ instance.send(name).send("post_process")
29
+ instance.send(name).save
30
+ else
31
+ true
32
+ end
33
+ print result ? "." : "x"; $stdout.flush
34
+ end
35
+ end
36
+ puts " Done."
37
+ end
38
+ end
@@ -0,0 +1,5 @@
1
+ test:
2
+ adapter: sqlite3
3
+ #dbfile: paperclip.db
4
+ database: ":memory:"
5
+
@@ -0,0 +1 @@
1
+ This is not an image.
@@ -0,0 +1,38 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+ require 'tempfile'
6
+
7
+ require 'active_record'
8
+ require 'ruby-debug'
9
+
10
+ ROOT = File.join(File.dirname(__FILE__), '..')
11
+ RAILS_ROOT = ROOT
12
+
13
+ $LOAD_PATH << File.join(ROOT, 'lib')
14
+ $LOAD_PATH << File.join(ROOT, 'lib', 'paperclip')
15
+
16
+ require File.join(ROOT, 'lib', 'paperclip.rb')
17
+
18
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), "fixtures")
19
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
20
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
21
+ ActiveRecord::Base.establish_connection(config[ENV['RAILS_ENV'] || 'test'])
22
+
23
+ def rebuild_model options = {}
24
+ ActiveRecord::Base.connection.create_table :dummies, :force => true do |table|
25
+ table.column :other, :string
26
+ table.column :avatar_file_name, :string
27
+ table.column :avatar_content_type, :string
28
+ table.column :avatar_file_size, :integer
29
+ end
30
+
31
+ ActiveRecord::Base.send(:include, Paperclip)
32
+ Object.send(:remove_const, "Dummy") rescue nil
33
+ Object.const_set("Dummy", Class.new(ActiveRecord::Base))
34
+ Dummy.class_eval do
35
+ include Paperclip
36
+ has_attached_file :avatar, options
37
+ end
38
+ end
@@ -0,0 +1,99 @@
1
+ require 'test/helper'
2
+
3
+ class Dummy
4
+ # This is a dummy class
5
+ end
6
+
7
+ class AttachmentTest < Test::Unit::TestCase
8
+ context "An attachment" do
9
+ setup do
10
+ @default_options = {
11
+ :path => ":rails_root/tmp/:attachment/:class/:style/:id/:basename.:extension"
12
+ }
13
+ @instance = stub
14
+ @instance.stubs(:id).returns(41)
15
+ @instance.stubs(:class).returns(Dummy)
16
+ @instance.stubs(:[]).with(:test_file_name).returns("5k.png")
17
+ @instance.stubs(:[]).with(:test_content_type).returns("image/png")
18
+ @instance.stubs(:[]).with(:test_file_size).returns(12345)
19
+ @attachment = Paperclip::Attachment.new(:test, @instance, @default_options)
20
+ @file = File.new(File.join(File.dirname(__FILE__), "fixtures", "5k.png"))
21
+ end
22
+
23
+ should "return its default_url when no file assigned" do
24
+ assert @attachment.file.nil?
25
+ assert_equal "/tests/original/missing.png", @attachment.url
26
+ assert_equal "/tests/blah/missing.png", @attachment.url(:blah)
27
+ end
28
+
29
+ context "when expecting three styles" do
30
+ setup do
31
+ @attachment = Paperclip::Attachment.new(:test, @instance, @default_options.merge({
32
+ :styles => { :large => ["400x400", :png],
33
+ :medium => ["100x100", :gif],
34
+ :small => ["32x32#", :jpg]}
35
+ }))
36
+ end
37
+
38
+ context "and assigned a file" do
39
+ setup do
40
+ @instance.expects(:[]=).with(:test_file_name, File.basename(@file.path))
41
+ @instance.expects(:[]=).with(:test_content_type, "image/png")
42
+ @instance.expects(:[]=).with(:test_file_size, @file.size)
43
+ @instance.expects(:[]=).with(:test_file_name, nil)
44
+ @instance.expects(:[]=).with(:test_content_type, nil)
45
+ @instance.expects(:[]=).with(:test_file_size, nil)
46
+ @attachment.assign(@file)
47
+ end
48
+
49
+ should "return the real url" do
50
+ assert @attachment.file
51
+ assert_equal "/tests/41/original/5k.png", @attachment.url
52
+ assert_equal "/tests/41/blah/5k.png", @attachment.url(:blah)
53
+ end
54
+
55
+ should "be dirty" do
56
+ assert @attachment.dirty?
57
+ end
58
+
59
+ should "have its image and attachments as tempfiles" do
60
+ [nil, :large, :medium, :small].each do |style|
61
+ assert File.exists?(@attachment.to_io(style))
62
+ end
63
+ end
64
+
65
+ context "and saved" do
66
+ setup do
67
+ @attachment.save
68
+ end
69
+
70
+ should "commit the files to disk" do
71
+ [nil, :large, :medium, :small].each do |style|
72
+ io = @attachment.to_io(style)
73
+ assert File.exists?(io)
74
+ assert ! io.is_a?(::Tempfile)
75
+ end
76
+ end
77
+
78
+ should "save the files as the right formats and sizes" do
79
+ [[:large, 400, 61, "PNG"], [:medium, 100, 15, "GIF"], [:small, 32, 32, "JPEG"]].each do |style|
80
+ out = `identify -format "%w %h %b %m" #{@attachment.to_io(style.first).path}`
81
+ width, height, size, format = out.split(" ")
82
+ assert_equal style[1].to_s, width.to_s
83
+ assert_equal style[2].to_s, height.to_s
84
+ assert_equal style[3].to_s, format.to_s
85
+ end
86
+ end
87
+
88
+ should "have #file be equal #to_io(:original)" do
89
+ assert @attachment.file == @attachment.to_io(:original)
90
+ end
91
+
92
+ should "still have its #file attribute not be nil" do
93
+ assert ! @attachment.file.nil?
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,142 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'paperclip', 'geometry.rb')
6
+
7
+ class GeometryTest < Test::Unit::TestCase
8
+ context "Paperclip::Geometry" do
9
+ should "correctly report its given dimensions" do
10
+ assert @geo = Paperclip::Geometry.new(1024, 768)
11
+ assert_equal 1024, @geo.width
12
+ assert_equal 768, @geo.height
13
+ end
14
+
15
+ should "correctly create a square if the height dimension is missing" do
16
+ assert @geo = Paperclip::Geometry.new(1024)
17
+ assert_equal 1024, @geo.width
18
+ assert_equal 1024, @geo.height
19
+ end
20
+
21
+ should "correctly create a square if the width dimension is missing" do
22
+ assert @geo = Paperclip::Geometry.new(nil, 768)
23
+ assert_equal 768, @geo.width
24
+ assert_equal 768, @geo.height
25
+ end
26
+
27
+ should "be generated from a WxH-formatted string" do
28
+ assert @geo = Paperclip::Geometry.parse("800x600")
29
+ assert_equal 800, @geo.width
30
+ assert_equal 600, @geo.height
31
+ end
32
+
33
+ should "be generated from a xH-formatted string" do
34
+ assert @geo = Paperclip::Geometry.parse("x600")
35
+ assert_equal 600, @geo.width
36
+ assert_equal 600, @geo.height
37
+ end
38
+
39
+ should "be generated from a Wx-formatted string" do
40
+ assert @geo = Paperclip::Geometry.parse("800x")
41
+ assert_equal 800, @geo.width
42
+ assert_equal 800, @geo.height
43
+ end
44
+
45
+ should "ensure the modifier is nil if only one dimension present" do
46
+ assert @geo = Paperclip::Geometry.parse("123x")
47
+ assert_nil @geo.modifier
48
+ end
49
+
50
+ should "ensure the modifier is nil if not present" do
51
+ assert @geo = Paperclip::Geometry.parse("123x456")
52
+ assert_nil @geo.modifier
53
+ end
54
+
55
+ ['>', '<', '#', '@', '%', '^', '!'].each do |mod|
56
+ should "ensure the modifier #{mod} is preserved" do
57
+ assert @geo = Paperclip::Geometry.parse("123x456#{mod}")
58
+ assert_equal mod, @geo.modifier
59
+ end
60
+ end
61
+
62
+ should "make sure the modifier gets passed during transformation_to" do
63
+ assert @src = Paperclip::Geometry.parse("123x456")
64
+ assert @dst = Paperclip::Geometry.parse("123x456>")
65
+ assert_equal "123x456>", @src.transformation_to(@dst).to_s
66
+ end
67
+
68
+ should "be generated from a file" do
69
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
70
+ file = File.new(file)
71
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
72
+ assert @geo.height > 0
73
+ assert @geo.width > 0
74
+ end
75
+
76
+ should "be generated from a file path" do
77
+ file = File.join(File.dirname(__FILE__), "fixtures", "5k.png")
78
+ assert_nothing_raised{ @geo = Paperclip::Geometry.from_file(file) }
79
+ assert @geo.height > 0
80
+ assert @geo.width > 0
81
+ end
82
+
83
+ should "not generate from a bad file" do
84
+ file = "/home/This File Does Not Exist.omg"
85
+ assert_raise(Errno::ENOENT){ @geo = Paperclip::Geometry.from_file(file) }
86
+ end
87
+
88
+ [['vertical', 900, 1440, true, false, false, 1440, 900, 0.625],
89
+ ['horizontal', 1024, 768, false, true, false, 1024, 768, 1.3333],
90
+ ['square', 100, 100, false, false, true, 100, 100, 1]].each do |args|
91
+ context "performing calculations on a #{args[0]} viewport" do
92
+ setup do
93
+ @geo = Paperclip::Geometry.new(args[1], args[2])
94
+ end
95
+
96
+ should "#{args[3] ? "" : "not"} be vertical" do
97
+ assert_equal args[3], @geo.vertical?
98
+ end
99
+
100
+ should "#{args[4] ? "" : "not"} be horizontal" do
101
+ assert_equal args[4], @geo.horizontal?
102
+ end
103
+
104
+ should "#{args[5] ? "" : "not"} be square" do
105
+ assert_equal args[5], @geo.square?
106
+ end
107
+
108
+ should "report that #{args[6]} is the larger dimension" do
109
+ assert_equal args[6], @geo.larger
110
+ end
111
+
112
+ should "report that #{args[7]} is the smaller dimension" do
113
+ assert_equal args[7], @geo.smaller
114
+ end
115
+
116
+ should "have an aspect ratio of #{args[8]}" do
117
+ assert_in_delta args[8], @geo.aspect, 0.0001
118
+ end
119
+ end
120
+ end
121
+
122
+ [[ [1000, 100], [64, 64], "x64", "64x64+288+0" ],
123
+ [ [100, 1000], [50, 950], "x950", "50x950+22+0" ],
124
+ [ [100, 1000], [50, 25], "50x", "50x25+0+237" ]]. each do |args|
125
+ context "of #{args[0].inspect} and given a Geometry #{args[1].inspect} and sent transform_to" do
126
+ setup do
127
+ @geo = Paperclip::Geometry.new(*args[0])
128
+ @dst = Paperclip::Geometry.new(*args[1])
129
+ @scale, @crop = @geo.transformation_to @dst, true
130
+ end
131
+
132
+ should "be able to return the correct scaling transformation geometry #{args[2]}" do
133
+ assert_equal args[2], @scale
134
+ end
135
+
136
+ should "be able to return the correct crop transformation geometry #{args[3]}" do
137
+ assert_equal args[3], @crop
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end