avatar 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,3 +1,13 @@
1
+ == 0.0.5 2008-04-01
2
+ * 4 major enhancements:
3
+ * added PaperclipSource for use with the Paperclip plugin
4
+ * added AbstractSourceWrapper
5
+ * changed StringSubstitutionSource to a SourceWrapper
6
+ * changed RailsAssetSource to a SourceWrapper
7
+
8
+ * 1 minor change:
9
+ * moved StringSubstitution out of separate module and into new StringSubstitutionSourceWrapper
10
+
1
11
  == 0.0.4 2008-03-28
2
12
  * 2 major fixes:
3
13
  * GravatarSource downcases email to comply with Gravatar standards
@@ -13,11 +13,13 @@ lib/avatar/source/abstract_source.rb
13
13
  lib/avatar/source/file_column_source.rb
14
14
  lib/avatar/source/gravatar_source.rb
15
15
  lib/avatar/source/nil_source.rb
16
- lib/avatar/source/rails_asset_source.rb
16
+ lib/avatar/source/paperclip_source.rb
17
17
  lib/avatar/source/source_chain.rb
18
18
  lib/avatar/source/static_url_source.rb
19
- lib/avatar/source/string_substitution_source.rb
20
- lib/avatar/string_substitution.rb
19
+ lib/avatar/source/wrapper.rb
20
+ lib/avatar/source/wrapper/abstract_source_wrapper.rb
21
+ lib/avatar/source/wrapper/rails_asset_source_wrapper.rb
22
+ lib/avatar/source/wrapper/string_substitution_source_wrapper.rb
21
23
  lib/avatar/version.rb
22
24
  lib/avatar/view.rb
23
25
  lib/avatar/view/abstract_view_support.rb
@@ -57,6 +59,30 @@ test/lib/file_column/test/fixtures/schema.rb
57
59
  test/lib/file_column/test/fixtures/skanthak.png
58
60
  test/lib/file_column/test/magick_test.rb
59
61
  test/lib/file_column/test/magick_view_only_test.rb
62
+ test/lib/paperclip/README
63
+ test/lib/paperclip/Rakefile
64
+ test/lib/paperclip/generators/paperclip/USAGE
65
+ test/lib/paperclip/generators/paperclip/paperclip_generator.rb
66
+ test/lib/paperclip/generators/paperclip/templates/paperclip_migration.rb
67
+ test/lib/paperclip/init.rb
68
+ test/lib/paperclip/lib/paperclip.rb
69
+ test/lib/paperclip/lib/paperclip/attachment.rb
70
+ test/lib/paperclip/lib/paperclip/geometry.rb
71
+ test/lib/paperclip/lib/paperclip/iostream.rb
72
+ test/lib/paperclip/lib/paperclip/thumbnail.rb
73
+ test/lib/paperclip/lib/paperclip/upfile.rb
74
+ test/lib/paperclip/tasks/paperclip_tasks.rake
75
+ test/lib/paperclip/test/database.yml
76
+ test/lib/paperclip/test/fixtures/12k.png
77
+ test/lib/paperclip/test/fixtures/5k.png
78
+ test/lib/paperclip/test/fixtures/bad.png
79
+ test/lib/paperclip/test/helper.rb
80
+ test/lib/paperclip/test/test_attachment.rb
81
+ test/lib/paperclip/test/test_geometry.rb
82
+ test/lib/paperclip/test/test_integration.rb
83
+ test/lib/paperclip/test/test_iostream.rb
84
+ test/lib/paperclip/test/test_paperclip.rb
85
+ test/lib/paperclip/test/test_thumbnail.rb
60
86
  test/lib/schema.rb
61
87
  test/lib/user_suit.png
62
88
  test/test_abstract_view_support.rb
@@ -66,11 +92,11 @@ test/test_file_column_source.rb
66
92
  test/test_gravatar_source.rb
67
93
  test/test_helper.rb
68
94
  test/test_nil_source.rb
69
- test/test_rails_asset_source.rb
95
+ test/test_paperclip_source.rb
96
+ test/test_rails_asset_source_wrapper.rb
70
97
  test/test_source_chain.rb
71
98
  test/test_static_url_source.rb
72
- test/test_string_substitution.rb
73
- test/test_string_substitution_source.rb
99
+ test/test_string_substitution_source_wrapper.rb
74
100
  website/index.html
75
101
  website/index.txt
76
102
  website/javascripts/rounded_corners_lite.inc.js
@@ -8,7 +8,7 @@ require 'avatar/source/gravatar_source'
8
8
  # include Avatar::ActionView::Support
9
9
  #
10
10
  # # in app/views/profiles/show.html.erb:
11
- # <%= avatar_for @person =>
11
+ # <%= avatar_for @person => current_person %>
12
12
  #
13
13
  # By default, Avatar::source is a GravatarSource
14
14
  module Avatar
@@ -56,7 +56,9 @@ module Avatar # :nodoc:
56
56
 
57
57
  returning(self.class.base_url) do |url|
58
58
  url << Digest::MD5::hexdigest(email).strip
59
- options.each do |k, v|
59
+ # default must be last or the other options will be parameters to that URL, not the Gravatar one
60
+ [:size, :rating, :default].each do |k|
61
+ v = options[k]
60
62
  next if v.nil?
61
63
  url << (url.include?('?') ? '&' : '?')
62
64
  url << "#{k}=#{v}"
@@ -65,10 +67,10 @@ module Avatar # :nodoc:
65
67
  end
66
68
 
67
69
  # Returns a Hash containing
68
- # * :field - passed through; defaults to <code>self.default_field</code>
69
- # * :default - passed through; defaults to <code>self.default_avatar_url_for(+person+, +options+)</code>
70
- # * :size - :gravatar_size or :size or :s passed through <em>only if a number</em>
71
- # * :rating - :gravatar_rating or :rating or :r passed through <em>only if one of <code>self.class.allowed_ratings</code></em>
70
+ # * :field - value of :gravatar_field; defaults to <code>self.default_field</code>
71
+ # * :default - value of :gravatar_default_url; defaults to <code>self.default_avatar_url_for(+person+, +options+)</code>
72
+ # * :size - value of :gravatar_size or :size or :s passed through <em>only if a number</em>
73
+ # * :rating - value of :gravatar_rating or :rating or :r passed through <em>only if one of <code>self.class.allowed_ratings</code></em>
72
74
  def parse_options(person, options)
73
75
  returning({}) do |result|
74
76
  result[:gravatar_field] = options[:gravatar_field] || default_field
@@ -0,0 +1,52 @@
1
+ require 'avatar/object_support'
2
+ require 'avatar/source/abstract_source'
3
+
4
+ module Avatar # :nodoc:
5
+ module Source # :nodoc:
6
+ # Source for a file attachment using Paperclip.
7
+ # See http://giantrobots.thoughtbot.com/2008/3/18/for-attaching-files-use-paperclip
8
+ class PaperclipSource
9
+ include AbstractSource
10
+
11
+ attr_accessor :default_field, :default_style
12
+
13
+ # Create a new FileColumnSource with a +default_field+ (by default, :avatar),
14
+ # and a +default_style+ (by default, nil)
15
+ def initialize(default_field = :avatar, default_style = nil)
16
+ @default_field = default_field
17
+ @default_style = default_style
18
+ end
19
+
20
+ # Returns a URL for a has_attached_file attribute, via
21
+ # <code>person.<paperclip_field>.url</code>, passing in :paperclip_style if present.
22
+ # Returns nil under any of the following circumstances:
23
+ # * person is nil
24
+ # * person.<paperclip_field> is nil
25
+ # * person.<paperclip_field>? returns false
26
+ # * person.<paperclip_field>.styles does not include :paperclip_style (if present)
27
+ # Options:
28
+ # * <code>:paperclip_field</code> - the has_attached_file column within +person+; by default, self.default_field
29
+ # * <code>:paperclip_style</code> - one of the styles of the has_attached_file; by default, self.default_style
30
+ def avatar_url_for(person, options = {})
31
+ return nil if person.nil?
32
+ options = parse_options(person, options)
33
+ field = options[:paperclip_field]
34
+ return nil if field.nil?
35
+ return nil unless person.send("#{field}?".to_sym)
36
+ avatar = person.send(field)
37
+ style = options[:paperclip_style]
38
+ return nil if style && !avatar.styles.keys.include?(style)
39
+ avatar.url(style)
40
+ end
41
+
42
+ # Copies :paperclip_field and :paperclip_style from +options+, adding defaults if necessary.
43
+ def parse_options(person, options)
44
+ returning({}) do |result|
45
+ result[:paperclip_field] = options[:paperclip_field] || default_field
46
+ result[:paperclip_style] = options[:paperclip_style] || default_style
47
+ end
48
+ end
49
+
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,6 @@
1
+ module Avatar
2
+ module Source
3
+ module Wrapper
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,33 @@
1
+ require 'avatar/source/abstract_source'
2
+
3
+ module Avatar
4
+ module Source
5
+ module Wrapper
6
+ class AbstractSourceWrapper
7
+ include Avatar::Source::AbstractSource
8
+
9
+ attr_reader :underlying_source
10
+
11
+ # Create a new Wrapper
12
+ def initialize(underlying_source)
13
+ raise ArgumentError.new("underlying_source must be Source") unless underlying_source.kind_of?(Avatar::Source::AbstractSource)
14
+ @underlying_source = underlying_source
15
+ end
16
+
17
+ # Return nil if the underlying_source does; otherwise, calls <code>wrap</code>,
18
+ # passing the returned URL and the person and options passed.
19
+ def avatar_url_for(person, options = {})
20
+ url = @underlying_source.avatar_url_for(person, options)
21
+ url.nil? ? nil : wrap(url, person, options)
22
+ end
23
+
24
+ # Apply appropriate wrapping of the +url+ returned by <code>underlying_source</code>.
25
+ # Will never be called with a nil +url+.
26
+ def wrap(url, person, options)
27
+ raise NotImplementedError('subclasses must override wrap(url, person, options)')
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ require 'avatar/source/wrapper/abstract_source_wrapper'
2
+ require 'action_view/helpers/asset_tag_helper'
3
+
4
+ module Avatar # :nodoc:
5
+ module Source # :nodoc:
6
+ module Wrapper
7
+ # Wraps a Source using Rails' <code>AssetTagHelper#image_path</code>,
8
+ # which can turn path URLs (e.g. '/images/my_avatar.png')
9
+ # into absolute URLs( e.g. 'http://assets.mysite.com/images/my_avatar.png').
10
+ class RailsAssetSourceWrapper < AbstractSourceWrapper
11
+
12
+ attr_reader :url_helper
13
+
14
+ private :url_helper
15
+
16
+ def initialize(source)
17
+ super
18
+ @url_helper = Object.new
19
+ @url_helper.extend(ActionView::Helpers::AssetTagHelper)
20
+ end
21
+
22
+ # Passes +url+ to <code>AssetTagHelper#image_path</code>. Raises
23
+ # an error if it cannot generate a fully-qualified URI. Try
24
+ # setting <code>ActionController::Base.asset_host</code> to
25
+ # avoid this error.
26
+ def wrap(url, person, options = {})
27
+ # url will never be nil b/c of guarantee in AbstractSourceWrapper
28
+ result = url_helper.image_path(url)
29
+ raise "could not generate protocol and host for #{url}. Have you set ActionController::Base.asset_host?" unless result =~ /^http[s]?\:\/\//
30
+ result
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,55 @@
1
+ require 'avatar/source/wrapper/abstract_source_wrapper'
2
+ require 'action_view/helpers/asset_tag_helper'
3
+
4
+ module Avatar # :nodoc:
5
+ module Source # :nodoc:
6
+ module Wrapper
7
+ # Wraps a Source using Rails' <code>AssetTagHelper#image_path</code>,
8
+ # which can turn path URLs (e.g. '/images/my_avatar.png')
9
+ # into absolute URLs( e.g. 'http://assets.mysite.com/images/my_avatar.png').
10
+ class StringSubstitutionSourceWrapper < AbstractSourceWrapper
11
+
12
+ attr_accessor :default_options
13
+
14
+ def initialize(source, default_options = {})
15
+ super(source)
16
+ self.default_options = default_options || {}
17
+ end
18
+
19
+ # Passes +url+ to <code>AssetTagHelper#image_path</code>. Raises
20
+ # an error if it cannot generate a fully-qualified URI. Try
21
+ # setting <code>ActionController::Base.asset_host</code> to
22
+ # avoid this error.
23
+ def wrap(url, person, options = {})
24
+ # url will never be nil b/c of guarantee in AbstractSourceWrapper
25
+ result = apply_substitution(url, self.default_options.merge(options))
26
+ substitution_needed?(result) ? nil : result
27
+ end
28
+
29
+ def default_options=(opts)
30
+ @default_options = opts || {}
31
+ end
32
+
33
+ # For each key in +options+ replaces '#{key}' in +string+ with the
34
+ # corresponding value in +options+.
35
+ # +string+ should
36
+ # be of the form '...#{variable_a}...#{variable_b}...'. <em>Note the
37
+ # single quotes</em>. Double quotes will cause the variables to be
38
+ # substituted before this method is run, which is almost
39
+ # certainly <strong>not</strong> what you want.
40
+ def apply_substitution(string, options)
41
+ returning(string.dup) do |result|
42
+ options.each do |k,v|
43
+ result.gsub!(Regexp.new('#\{' + "#{k}" + '\}'), "#{v}")
44
+ end
45
+ end
46
+ end
47
+
48
+ def substitution_needed?(string)
49
+ string =~ /#\{.*\}/
50
+ end
51
+
52
+ end
53
+ end
54
+ end
55
+ end
@@ -2,7 +2,7 @@ module Avatar #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 0
5
- TINY = 4
5
+ TINY = 5
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -0,0 +1,32 @@
1
+ =Paperclip
2
+
3
+ Paperclip is intended as an easy file attachment library for ActiveRecord. The intent behind it was to keep setup as easy as possible and to treat files as much like other attributes as possible. This means they aren't saved to their final locations on disk, nor are they deleted if set to nil, until ActiveRecord::Base#save is called. It manages validations based on size and presence, if required. It can transform its assigned image into thumbnails if needed, and the prerequisites are as simple as installing ImageMagick (which, for most modern Unix-based systems, is as easy as installing the right packages). Attached files are saved to the filesystem and referenced in the browser by an easily understandable specification, which has sensible and useful defaults.
4
+
5
+ See the documentation for the +has_attached_file+ method for options.
6
+
7
+ ==Usage
8
+
9
+ In your model:
10
+
11
+ class User < ActiveRecord::Base
12
+ has_attached_file :avatar, :styles => { :medium => "300x300>", :thumb => "100x100>" }
13
+ end
14
+
15
+ In your edit and new views:
16
+
17
+ <% form_for :user, @user, :url => user_path, :html => { :multipart => true } do |form| %>
18
+ <%= form.file_field :avatar %>
19
+ <% end %>
20
+
21
+ In your controller:
22
+
23
+ def create
24
+ @user = User.create( params[:user] )
25
+ end
26
+
27
+ In your show view:
28
+
29
+ <%= image_tag @user.avatar.url %>
30
+ <%= image_tag @user.avatar.url(:medium) %>
31
+ <%= image_tag @user.avatar.url(:thumb) %>
32
+
@@ -0,0 +1,41 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => [:clean, :test]
7
+
8
+ desc 'Test the paperclip plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib' << 'profile'
11
+ t.pattern = 'test/**/test_*.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Start an IRB session with all necessary files required.'
16
+ task :shell do |t|
17
+ chdir File.dirname(__FILE__)
18
+ exec 'irb -I lib/ -I lib/paperclip -r rubygems -r active_record -r tempfile -r init'
19
+ end
20
+
21
+ desc 'Generate documentation for the paperclip plugin.'
22
+ Rake::RDocTask.new(:rdoc) do |rdoc|
23
+ rdoc.rdoc_dir = 'doc'
24
+ rdoc.title = 'Paperclip'
25
+ rdoc.options << '--line-numbers' << '--inline-source'
26
+ rdoc.rdoc_files.include('README')
27
+ rdoc.rdoc_files.include('lib/**/*.rb')
28
+ end
29
+
30
+ desc 'Update documentation on website'
31
+ task :sync_docs => 'rdoc' do
32
+ `rsync -ave ssh doc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/paperclip`
33
+ end
34
+
35
+ desc 'Clean up files.'
36
+ task :clean do |t|
37
+ FileUtils.rm_rf "doc"
38
+ FileUtils.rm_rf "tmp"
39
+ FileUtils.rm "test/debug.log" rescue nil
40
+ FileUtils.rm "test/paperclip.db" rescue nil
41
+ end
@@ -0,0 +1,5 @@
1
+ Usage:
2
+
3
+ script/generate attachment Class attachment1 attachment2
4
+
5
+ This will create a migration that will add the proper columns to your class's table.
@@ -0,0 +1,27 @@
1
+ class PaperclipGenerator < Rails::Generator::NamedBase
2
+ attr_accessor :attachments, :migration_name
3
+
4
+ def initialize(args, options = {})
5
+ super
6
+ @class_name, @attachments = args[0], args[1..-1]
7
+ end
8
+
9
+ def manifest
10
+ file_name = generate_file_name
11
+ @migration_name = file_name.camelize
12
+ record do |m|
13
+ m.migration_template "paperclip_migration.rb",
14
+ File.join('db', 'migrate'),
15
+ :migration_file_name => file_name
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def generate_file_name
22
+ names = attachments.map{|a| a.underscore }
23
+ names = names[0..-2] + ["and", names[-1]] if names.length > 1
24
+ "add_attachments_#{names.join("_")}_to_#{@class_name.underscore}"
25
+ end
26
+
27
+ end
@@ -0,0 +1,17 @@
1
+ class <%= migration_name %> < ActiveRecord::Migration
2
+ def self.up
3
+ <% attachments.each do |attachment| -%>
4
+ add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name, :string
5
+ add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type, :string
6
+ add_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size, :integer
7
+ <% end -%>
8
+ end
9
+
10
+ def self.down
11
+ <% attachments.each do |attachment| -%>
12
+ remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_name
13
+ remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_content_type
14
+ remove_column :<%= class_name.underscore.camelize.tableize %>, :<%= attachment %>_file_size
15
+ <% end -%>
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ require File.join(File.dirname(__FILE__), "lib", "paperclip")
2
+ ActiveRecord::Base.extend( Paperclip::ClassMethods )
3
+ File.send :include, Paperclip::Upfile