class AWS::S3::Base

AWS::S3::Base is the abstract super class of all classes who make requests against S3, such as the built in Service, Bucket and S3Object classes. It provides methods for making requests, inferring or setting response classes, processing request options, and accessing attributes from S3's response data.

Establishing a connection with the Base class is the entry point to using the library:

AWS::S3::Base.establish_connection!(:access_key_id => '...', :secret_access_key => '...')

The :access_key_id and :secret_access_key are the two required connection options. More details can be found in the docs for Connection::Management::ClassMethods.

Extensive examples can be found in the README.

Attributes

attributes[R]

Public Class Methods

current_bucket() click to toggle source

Called when a method which requires a bucket name is called without that bucket name specified. It will try to infer the current bucket by looking for it as the subdomain of the current connection's address. If no subdomain is found, CurrentBucketNotSpecified will be raised.

MusicBucket.establish_connection! :server => 'jukeboxzero.s3.amazonaws.com'
MusicBucket.connection.server
=> 'jukeboxzero.s3.amazonaws.com'
MusicBucket.current_bucket
=> 'jukeboxzero'

Rather than infering the current bucket from the subdomain, the current class' bucket can be explicitly set with set_current_bucket_to.

# File lib/aws/s3/base.rb, line 106
def current_bucket
  connection.subdomain or raise CurrentBucketNotSpecified.new(connection.http.address)
end
current_bucket=(name)
request(verb, path, options = {}, body = nil, attempts = 0, &block) click to toggle source

Wraps the current connection's request method and picks the appropriate response class to wrap the response in. If the response is an error, it will raise that error as an exception. All such exceptions can be caught by rescuing their superclass, the ResponseError exception class.

It is unlikely that you would call this method directly. Subclasses of Base have convenience methods for each http request verb that wrap calls to request.

# File lib/aws/s3/base.rb, line 66
def request(verb, path, options = {}, body = nil, attempts = 0, &block)
  Service.response = nil
  process_options!(options, verb)
  response = response_class.new(connection.request(verb, path, options, body, attempts, &block))
  Service.response = response

  Error::Response.new(response.response).error.raise if response.error?
  response
# Once in a while, a request to S3 returns an internal error. A glitch in the matrix I presume. Since these 
# errors are few and far between the request method will rescue InternalErrors the first three times they encouter them
# and will retry the request again. Most of the time the second attempt will work.
rescue InternalError, RequestTimeout
  if attempts == 3
    raise
  else
    attempts += 1
    retry
  end
end
set_current_bucket_to(name) click to toggle source

If you plan on always using a specific bucket for certain files, you can skip always having to specify the bucket by creating a subclass of Bucket or S3Object and telling it what bucket to use:

class JukeBoxSong < AWS::S3::S3Object
  set_current_bucket_to 'jukebox'
end

For all methods that take a bucket name as an argument, the current bucket will be used if the bucket name argument is omitted.

other_song = 'baby-please-come-home.mp3'
JukeBoxSong.store(other_song, open(other_song))

This time we didn't have to explicitly pass in the bucket name, as the JukeBoxSong class knows that it will always use the 'jukebox' bucket.

“Astute readers”, as they say, may have noticed that we used the third parameter to pass in the content type, rather than the fourth parameter as we had the last time we created an object. If the bucket can be inferred, or is explicitly set, as we've done in the JukeBoxSong class, then the third argument can be used to pass in options.

Now all operations that would have required a bucket name no longer do.

other_song = JukeBoxSong.find('baby-please-come-home.mp3')
# File lib/aws/s3/base.rb, line 133
        def set_current_bucket_to(name)
          raise ArgumentError, "`#{__method__}' must be called on a subclass of #{self.name}" if self == AWS::S3::Base
          instance_eval("            def current_bucket
              '#{name}'
            end
")
        end
Also aliased as: current_bucket=

Private Class Methods

bucket_name(name) click to toggle source
# File lib/aws/s3/base.rb, line 178
def bucket_name(name)
  name || current_bucket
end
process_options!(options, verb) click to toggle source
# File lib/aws/s3/base.rb, line 149
def process_options!(options, verb)
  options.replace(RequestOptions.process(options, verb))
end
respond_with(klass) { || ... } click to toggle source

Using the conventions layed out in the response_class works for more than 80% of the time. There are a few edge cases though where we want a given class to wrap its responses in different response classes depending on which method is being called.

# File lib/aws/s3/base.rb, line 156
          def respond_with(klass)
            eval("              def new_response_class
                #{klass}
              end

              class << self
                alias_method :old_response_class, :response_class
                alias_method :response_class, :new_response_class
              end
", binding, __FILE__, __LINE__)

            yield
          ensure
            # Restore the original version
            eval("              class << self
                alias_method :response_class, :old_response_class
              end
", binding, __FILE__, __LINE__)
          end
response_class() click to toggle source
# File lib/aws/s3/base.rb, line 145
def response_class
  FindResponseClass.for(self)
end

Private Instance Methods

connection() click to toggle source
# File lib/aws/s3/base.rb, line 216
def connection
  self.class.connection
end
http() click to toggle source
# File lib/aws/s3/base.rb, line 220
def http
  connection.http
end
method_missing(method, *args, &block) click to toggle source
Calls superclass method
# File lib/aws/s3/base.rb, line 228
def method_missing(method, *args, &block)
  case
  when attributes.has_key?(method.to_s) 
    attributes[method.to_s]
  when attributes.has_key?(method)
    attributes[method]
  else 
    super
  end
end
request(*args, &block) click to toggle source
# File lib/aws/s3/base.rb, line 224
def request(*args, &block)
  self.class.request(*args, &block)
end