Permalink
Browse files

refactoring

  • Loading branch information...
1 parent a48ebe3 commit 79912eb61c6ff5c3f3c279d26d1106583a9d4b30 @qoobaa committed Dec 16, 2011
Showing with 42 additions and 387 deletions.
  1. +1 −3 Gemfile
  2. +1 −1 Gemfile.lock
  3. +0 −2 README.md
  4. +0 −159 extra/s3_attachment_fu.rb
  5. +0 −176 extra/s3_paperclip.rb
  6. +3 −7 lib/s3/bucket.rb
  7. +3 −4 lib/s3/buckets_extension.rb
  8. +4 −3 lib/s3/object.rb
  9. +7 −9 lib/s3/service.rb
  10. +23 −23 lib/s3/signature.rb
View
@@ -1,4 +1,2 @@
-source :gemcutter
-
-# Specify your gem's dependencies in s3.gemspec
+source "http://rubygems.org"
gemspec
View
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
- s3 (0.3.8)
+ s3 (0.3.9)
proxies (~> 0.2.0)
GEM
View
@@ -4,8 +4,6 @@ S3 library provides access to [Amazon's Simple Storage Service](http://aws.amazo
It supports both: European and US buckets through the [REST API](http://docs.amazonwebservices.com/AmazonS3/latest/API/APIRest.html).
-<a href="http://pledgie.com/campaigns/14173"><img alt="Click here to lend your support to: S3 and make a donation at www.pledgie.com!" src="http://pledgie.com/campaigns/14173.png?skin_name=chrome" border="0" /></a>
-
## Installation
gem install s3
View
@@ -1,159 +0,0 @@
-require "singleton"
-require "s3"
-
-# S3 Backend for attachment-fu plugin. After installing attachment-fu
-# plugin, copy the file to:
-# +vendor/plugins/attachment-fu/lib/technoweenie/attachment_fu/backends+
-#
-# To configure S3Backend create initializer file in your Rails
-# application, e.g. +config/initializers/s3_backend.rb+.
-#
-# Technoweenie::AttachmentFu::Backends::S3Backend.configuration do |config|
-# config.access_key_id = "..." # your access key id
-# config.secret_access_key = "..." # your secret access key
-# config.bucket_name = "..." # default bucket name to store attachments
-# config.use_ssl = false # pass true if you want to communicate via SSL
-# end
-
-module Technoweenie
- module AttachmentFu
- module Backends
- module S3Backend
-
- # S3Backend configuration class
- class Configuration
- include Singleton
-
- ATTRIBUTES = [:access_key_id, :secret_access_key, :use_ssl, :bucket_name]
-
- attr_accessor *ATTRIBUTES
- end
-
- # Method used to configure S3Backend, see the example above
- def self.configuration
- if block_given?
- yield Configuration.instance
- end
- Configuration.instance
- end
-
- # :nodoc:
- def self.included(base)
- include S3
-
- service = Service.new(:access_key_id => configuration.access_key_id,
- :secret_access_key => configuration.secret_access_key,
- :use_ssl => configuration.use_ssl)
-
- bucket_name = base.attachment_options[:bucket_name] || configuration.bucket_name
-
- base.cattr_accessor :bucket
- base.bucket = service.buckets.build(bucket_name) # don't connect
-
- base.before_update :rename_file
- end
-
- # The attachment ID used in the full path of a file
- def attachment_path_id
- ((respond_to?(:parent_id) && parent_id) || id).to_s
- end
-
- # The pseudo hierarchy containing the file relative to the bucket name
- # Example: <tt>:table_name/:id</tt>
- def base_path
- [attachment_options[:path_prefix], attachment_path_id].join("/")
- end
-
- # The full path to the file relative to the bucket name
- # Example: <tt>:table_name/:id/:filename</tt>
- def full_filename(thumbnail = nil)
- [base_path, thumbnail_name_for(thumbnail)].join("/")
- end
-
- # All public objects are accessible via a GET request to the S3 servers. You can generate a
- # url for an object using the s3_url method.
- #
- # @photo.s3_url
- #
- # The resulting url is in the form: <tt>http(s)://:server/:bucket_name/:table_name/:id/:file</tt> where
- # the <tt>:server</tt> variable defaults to <tt>AWS::S3 URL::DEFAULT_HOST</tt> (s3.amazonaws.com) and can be
- # set using the configuration parameters in <tt>RAILS_ROOT/config/amazon_s3.yml</tt>.
- #
- # The optional thumbnail argument will output the thumbnail's filename (if any).
- def s3_url(thumbnail = nil)
- if attachment_options[:cname]
- ["#{s3_protocol}#{bucket.name}", full_filename(thumbnail)].join("/")
- else
- ["#{s3_protocol}#{s3_hostname}#{bucket.path_prefix}", full_filename(thumbnail)].join("/")
- end
- end
- alias :public_url :s3_url
- alias :public_filename :s3_url
-
- # Name of the bucket used to store attachments
- def bucket_name
- self.class.bucket.name
- end
-
- # :nodoc:
- def create_temp_file
- write_to_temp_file current_data
- end
-
- # :nodoc:
- def current_data
- # Object.value full_filename, bucket_name
- object = self.class.bucket.objects.find(full_filename)
- object.content
- end
-
- # Returns http:// or https:// depending on use_ssl setting
- def s3_protocol
- attachment_options[:use_ssl] ? "https://" : "http://"
- end
-
- # Returns hostname of the bucket
- # e.g. +bucketname.com.s3.amazonaws.com+. Additionally you can
- # pass :cname => true option in has_attachment method to
- # return CNAME only, e.g. +bucketname.com+
- def s3_hostname
- attachment_options[:cname] ? self.class.bucket.name : self.class.bucket.host
- end
-
- protected
-
- # Frees the space in S3 bucket, used by after_destroy callback
- def destroy_file
- object = self.class.bucket.objects.find(full_filename)
- object.destroy
- end
-
- # Renames file if filename has been changed - copy the file to
- # new key and delete old one
- def rename_file
- return unless filename_changed?
-
- old_full_filename = [base_path, filename_was].join("/")
-
- object = self.class.bucket.objects.find(old_full_filename)
- new_object = object.copy(:key => full_filename, :acl => attachment_options[:acl])
- object.destroy
- true
- end
-
- # Saves the file to storage
- def save_to_storage
- if save_attachment?
- object = self.class.bucket.objects.build(full_filename)
-
- object.content_type = content_type
- object.acl = attachment_options[:acl]
- object.content = temp_path ? File.open(temp_path) : temp_data
- object.save
- end
- true
- end
- end
- end
- end
-end
View
@@ -1,176 +0,0 @@
-# S3 backend for paperclip plugin. Copy the file to:
-# +config/initializers/+ directory
-#
-# Example configuration for CNAME bucket:
-#
-# has_attached_file :image,
-# :s3_host_alias => "bucket.domain.tld",
-# :s3_headers => { :cache_control => 10.years.from_now.httpdate },
-# :url => ":s3_alias_url",
-# :styles => {
-# :medium => "300x300>",
-# :thumb => "100x100>"
-# },
-# :storage => :s3,
-# :s3_credentials => {
-# :access_key_id => "...",
-# :secret_access_key => "..."
-# },
-# :bucket => "bucket.domain.tld",
-# :path => ":attachment/:id/:style.:extension"
-module Paperclip
- module Storage
- module S3
- def self.extended base
- begin
- require "s3"
- rescue LoadError => e
- e.message << " (You may need to install the s3 gem)"
- raise e
- end
-
- base.instance_eval do
- @s3_credentials = parse_credentials(@options[:s3_credentials])
- @bucket_name = @options[:bucket] || @s3_credentials[:bucket]
- @bucket_name = @bucket_name.call(self) if @bucket_name.is_a?(Proc)
- @s3_options = @options[:s3_options] || {}
- @s3_permissions = @options[:s3_permissions] || :public_read
- @s3_storage_class = @options[:s3_storage_class] || :standard
- @s3_protocol = @options[:s3_protocol] || (@s3_permissions == :public_read ? "http" : "https")
- @s3_headers = @options[:s3_headers] || {}
- @s3_host_alias = @options[:s3_host_alias]
- @url = ":s3_path_url" unless @url.to_s.match(/^:s3.*url$/)
- @service = ::S3::Service.new(@s3_options.merge(
- :access_key_id => @s3_credentials[:access_key_id],
- :secret_access_key => @s3_credentials[:secret_access_key],
- :use_ssl => @s3_protocol == "https"
- ))
- @bucket = @service.buckets.build(@bucket_name)
- end
- Paperclip.interpolates(:s3_alias_url) do |attachment, style|
- "#{attachment.s3_protocol}://#{attachment.s3_host_alias}/#{Paperclip::Storage::S3.encode_path(attachment.path(style)).gsub(%r{^/}, "")}"
- end
- Paperclip.interpolates(:s3_path_url) do |attachment, style|
- "#{attachment.s3_protocol}://s3.amazonaws.com/#{attachment.bucket_name}/#{Paperclip::Storage::S3.encode_path(attachment.path(style)).gsub(%r{^/}, "")}"
- end
- Paperclip.interpolates(:s3_domain_url) do |attachment, style|
- "#{attachment.s3_protocol}://#{attachment.bucket_name}.s3.amazonaws.com/#{Paperclip::Storage::S3.encode_path(attachment.path(style)).gsub(%r{^/}, "")}"
- end
- end
-
- def expiring_url(style_name = default_style, time = 3600)
- bucket.objects.build(path(style_name)).temporary_url(Time.now + time)
- end
-
- def bucket_name
- @bucket_name
- end
-
- def bucket
- @bucket
- end
-
- def s3_host_alias
- @s3_host_alias
- end
-
- def content_disposition(style = default_style)
- cd = @s3_headers[:content_disposition]
- cd.respond_to?(:call) ? cd.call(self, style) : cd
- end
-
- def parse_credentials creds
- creds = find_credentials(creds).stringify_keys
- (creds[RAILS_ENV] || creds).symbolize_keys
- end
-
- def exists?(style = default_style)
- if original_filename
- bucket.objects.build(path(style)).exists?
- else
- false
- end
- end
-
- def s3_protocol
- @s3_protocol
- end
-
- # Returns representation of the data of the file assigned to the given
- # style, in the format most representative of the current storage.
- def to_file style = default_style
- return @queued_for_write[style] if @queued_for_write[style]
- begin
- filename = path(style)
- extname = File.extname(filename)
- basename = File.basename(filename, extname)
- file = Tempfile.new([basename, extname])
- file.binmode if file.respond_to?(:binmode)
- file.write(bucket.objects.find(path(style)).content)
- file.rewind
- rescue ::S3::Error::NoSuchKey
- file.close if file.respond_to?(:close)
- file = nil
- end
- file
- end
-
- # Encodes all characters except forward-slash (/) and explicitly legal URL characters
- def self.encode_path(path)
- URI.encode(path, /[^#{URI::REGEXP::PATTERN::UNRESERVED}\/]/)
- end
-
- def encoded_path(style)
- Paperclip::Storage::S3.encode_path(path(style))
- end
-
- def flush_writes #:nodoc:
- @queued_for_write.each do |style, file|
- begin
- log("saving #{path(style)}")
- object = bucket.objects.build(path(style))
- file.rewind
- object.content = file.read
- object.acl = @s3_permissions
- object.storage_class = @s3_storage_class
- object.content_type = instance_read(:content_type)
- object.cache_control = @s3_headers[:cache_control]
- object.content_disposition = content_disposition(style)
- object.content_encoding = @s3_headers[:content_encoding]
- object.save
- rescue ::S3::Error::ResponseError => e
- raise
- end
- end
- @queued_for_write = {}
- end
-
- def flush_deletes #:nodoc:
- @queued_for_delete.each do |path|
- begin
- log("deleting #{path}")
- bucket.objects.find(path).destroy
- rescue ::S3::Error::ResponseError
- # Ignore this.
- end
- end
- @queued_for_delete = []
- end
-
- def find_credentials creds
- case creds
- when File
- YAML::load(ERB.new(File.read(creds.path)).result)
- when String
- YAML::load(ERB.new(File.read(creds)).result)
- when Hash
- creds
- else
- raise ArgumentError, "Credentials are not a path, file, or hash."
- end
- end
- private :find_credentials
-
- end
- end
-end
View
@@ -19,11 +19,8 @@ def retrieve
# Returns location of the bucket, e.g. "EU"
def location(reload = false)
- if reload or @location.nil?
- @location = location_constraint
- else
- @location
- end
+ return @location if defined?(@location) and not reload
+ @location = location_constraint
end
# Compares the bucket with other bucket. Returns true if the names
@@ -88,8 +85,7 @@ def path_prefix
vhost? ? "" : "#@name/"
end
- # Returns the objects in the bucket and caches the result (see
- # #reload method).
+ # Returns the objects in the bucket and caches the result
def objects
Proxy.new(lambda { list_bucket }, :owner => self, :extend => ObjectsExtension)
end
Oops, something went wrong.

2 comments on commit 79912eb

Contributor

jcbpl replied Mar 1, 2012

I'm curious why you removed the Paperclip module. Do you still want to move it into a separate gem (indicated here) or was there another reason for removing it?

Owner

qoobaa replied Mar 1, 2012

No, there wasn't other reason. I haven't used paperclip for a long time, so I have no clue if the code is up to date. It's better to keep it separate.

Please sign in to comment.