quebert 0.0.0
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.
- data/.document +5 -0
- data/.gitignore +22 -0
- data/Gemfile +14 -0
- data/LICENSE +20 -0
- data/README.rdoc +113 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/lib/quebert.rb +29 -0
- data/lib/quebert/async_sender.rb +99 -0
- data/lib/quebert/backend.rb +11 -0
- data/lib/quebert/backend/beanstalk.rb +35 -0
- data/lib/quebert/backend/in_process.rb +14 -0
- data/lib/quebert/backend/sync.rb +11 -0
- data/lib/quebert/configuration.rb +16 -0
- data/lib/quebert/consumer.rb +9 -0
- data/lib/quebert/consumer/base.rb +21 -0
- data/lib/quebert/consumer/beanstalk.rb +30 -0
- data/lib/quebert/daemonizing.rb +144 -0
- data/lib/quebert/job.rb +62 -0
- data/lib/quebert/support.rb +28 -0
- data/lib/quebert/worker.rb +29 -0
- data/quebert.gemspec +92 -0
- data/spec/async_sender_spec.rb +85 -0
- data/spec/backend_spec.rb +70 -0
- data/spec/configuration_spec.rb +18 -0
- data/spec/consumer_spec.rb +65 -0
- data/spec/job_spec.rb +52 -0
- data/spec/jobs.rb +29 -0
- data/spec/quebert_spec.rb +8 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/worker_spec.rb +27 -0
- metadata +164 -0
| @@ -0,0 +1,9 @@ | |
| 1 | 
            +
            module Quebert
         | 
| 2 | 
            +
              # The basic glue between a job and the specific queue implementation. This
         | 
| 3 | 
            +
              # handles exceptions that may be thrown by the Job and how the Job should
         | 
| 4 | 
            +
              # be put back on the queue, if at all.
         | 
| 5 | 
            +
              module Consumer
         | 
| 6 | 
            +
                autoload :Base,       'quebert/consumer/base'
         | 
| 7 | 
            +
                autoload :Beanstalk,  'quebert/consumer/beanstalk'
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            module Quebert
         | 
| 2 | 
            +
              module Consumer
         | 
| 3 | 
            +
                # The most Consumer. Doesn't even accept the queue as an argument because there's nothing
         | 
| 4 | 
            +
                # a job can do to be rescheduled, etc.
         | 
| 5 | 
            +
                class Base
         | 
| 6 | 
            +
                  attr_reader :job
         | 
| 7 | 
            +
                  
         | 
| 8 | 
            +
                  def initialize(job)
         | 
| 9 | 
            +
                    @job = job
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                  
         | 
| 12 | 
            +
                  def perform
         | 
| 13 | 
            +
                    begin
         | 
| 14 | 
            +
                      job.perform(*job.args)
         | 
| 15 | 
            +
                    rescue Job::Action
         | 
| 16 | 
            +
                      # Nothing to do chief!
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,30 @@ | |
| 1 | 
            +
            module Quebert
         | 
| 2 | 
            +
              module Consumer
         | 
| 3 | 
            +
                # Handle interactions between a job and a Beanstalk queue.
         | 
| 4 | 
            +
                class Beanstalk < Base
         | 
| 5 | 
            +
                  attr_reader :beanstalk_job, :queue, :job
         | 
| 6 | 
            +
                  
         | 
| 7 | 
            +
                  def initialize(beanstalk_job, queue)
         | 
| 8 | 
            +
                    @beanstalk_job, @queue = beanstalk_job, queue
         | 
| 9 | 
            +
                    @job = Job.from_json(beanstalk_job.body)
         | 
| 10 | 
            +
                  end
         | 
| 11 | 
            +
                  
         | 
| 12 | 
            +
                  def perform
         | 
| 13 | 
            +
                    begin
         | 
| 14 | 
            +
                      result = job.perform(*job.args)
         | 
| 15 | 
            +
                      beanstalk_job.delete
         | 
| 16 | 
            +
                      result
         | 
| 17 | 
            +
                    rescue Job::Delete
         | 
| 18 | 
            +
                      beanstalk_job.delete
         | 
| 19 | 
            +
                    rescue Job::Release
         | 
| 20 | 
            +
                      beanstalk_job.release
         | 
| 21 | 
            +
                    rescue Job::Bury
         | 
| 22 | 
            +
                      beanstalk_job.bury
         | 
| 23 | 
            +
                    rescue Exception => e
         | 
| 24 | 
            +
                      beanstalk_job.bury
         | 
| 25 | 
            +
                      raise e
         | 
| 26 | 
            +
                    end
         | 
| 27 | 
            +
                  end
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
            end
         | 
| @@ -0,0 +1,144 @@ | |
| 1 | 
            +
            require 'etc'
         | 
| 2 | 
            +
            require 'daemons'
         | 
| 3 | 
            +
            require 'fileutils'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Process
         | 
| 6 | 
            +
              # Returns +true+ the process identied by +pid+ is running.
         | 
| 7 | 
            +
              def running?(pid)
         | 
| 8 | 
            +
                Process.getpgid(pid) != -1
         | 
| 9 | 
            +
              rescue Errno::EPERM
         | 
| 10 | 
            +
                true
         | 
| 11 | 
            +
              rescue Errno::ESRCH
         | 
| 12 | 
            +
                false
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
              module_function :running?
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            module Quebert
         | 
| 18 | 
            +
              module Daemonizable
         | 
| 19 | 
            +
                attr_accessor :pid_file, :log_file
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                PidFileExist = Class.new(RuntimeError)
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                def self.included(base)
         | 
| 24 | 
            +
                  base.extend ClassMethods
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                def daemonize
         | 
| 28 | 
            +
                  raise ArgumentError, 'You must specify a pid_file to daemonize' unless pid_file
         | 
| 29 | 
            +
                  
         | 
| 30 | 
            +
                  remove_stale_pid_file
         | 
| 31 | 
            +
                  
         | 
| 32 | 
            +
                  pwd = Dir.pwd # Current directory is changed during daemonization, so store it
         | 
| 33 | 
            +
                  # HACK we need to create the directory before daemonization to prevent a bug under 1.9
         | 
| 34 | 
            +
                  #      ignoring all signals when the directory is created after daemonization.
         | 
| 35 | 
            +
                  FileUtils.mkdir_p File.dirname(pid_file)
         | 
| 36 | 
            +
                  # Daemonize.daemonize(File.expand_path(@log_file), "quebert worker")
         | 
| 37 | 
            +
                  Daemonize.daemonize(File.expand_path(@log_file), "quebert")
         | 
| 38 | 
            +
                  Dir.chdir(pwd)
         | 
| 39 | 
            +
                  write_pid_file
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                def pid
         | 
| 43 | 
            +
                  File.exist?(pid_file) ? open(pid_file).read.to_i : nil
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                
         | 
| 46 | 
            +
                # Register a proc to be called to restart the server.
         | 
| 47 | 
            +
                def on_restart(&block)
         | 
| 48 | 
            +
                  @on_restart = block
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                # Restart the server.
         | 
| 52 | 
            +
                def restart
         | 
| 53 | 
            +
                  if @on_restart
         | 
| 54 | 
            +
                    log '>> Restarting ...'
         | 
| 55 | 
            +
                    stop
         | 
| 56 | 
            +
                    remove_pid_file
         | 
| 57 | 
            +
                    @on_restart.call
         | 
| 58 | 
            +
                    exit!
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                module ClassMethods
         | 
| 63 | 
            +
                  # Send a QUIT or INT (if timeout is +0+) signal the process which
         | 
| 64 | 
            +
                  # PID is stored in +pid_file+.
         | 
| 65 | 
            +
                  # If the process is still running after +timeout+, KILL signal is
         | 
| 66 | 
            +
                  # sent.
         | 
| 67 | 
            +
                  def kill(pid_file, timeout=60)
         | 
| 68 | 
            +
                    if timeout == 0
         | 
| 69 | 
            +
                      send_signal('INT', pid_file, timeout)
         | 
| 70 | 
            +
                    else
         | 
| 71 | 
            +
                      send_signal('QUIT', pid_file, timeout)
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
                  
         | 
| 75 | 
            +
                  # Restart the server by sending HUP signal.
         | 
| 76 | 
            +
                  def restart(pid_file)
         | 
| 77 | 
            +
                    send_signal('HUP', pid_file)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                  
         | 
| 80 | 
            +
                  # Send a +signal+ to the process which PID is stored in +pid_file+.
         | 
| 81 | 
            +
                  def send_signal(signal, pid_file, timeout=60)
         | 
| 82 | 
            +
                    if pid = read_pid_file(pid_file)
         | 
| 83 | 
            +
                      Logging.log "Sending #{signal} signal to process #{pid} ... "
         | 
| 84 | 
            +
                      Process.kill(signal, pid)
         | 
| 85 | 
            +
                      Timeout.timeout(timeout) do
         | 
| 86 | 
            +
                        sleep 0.1 while Process.running?(pid)
         | 
| 87 | 
            +
                      end
         | 
| 88 | 
            +
                    else
         | 
| 89 | 
            +
                      Logging.log "Can't stop process, no PID found in #{pid_file}"
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                  rescue Timeout::Error
         | 
| 92 | 
            +
                    Logging.log "Timeout!"
         | 
| 93 | 
            +
                    force_kill pid_file
         | 
| 94 | 
            +
                  rescue Interrupt
         | 
| 95 | 
            +
                    force_kill pid_file
         | 
| 96 | 
            +
                  rescue Errno::ESRCH # No such process
         | 
| 97 | 
            +
                    Logging.log "process not found!"
         | 
| 98 | 
            +
                    force_kill pid_file
         | 
| 99 | 
            +
                  end
         | 
| 100 | 
            +
                  
         | 
| 101 | 
            +
                  def force_kill(pid_file)
         | 
| 102 | 
            +
                    if pid = read_pid_file(pid_file)
         | 
| 103 | 
            +
                      Logging.log "Sending KILL signal to process #{pid} ... "
         | 
| 104 | 
            +
                      Process.kill("KILL", pid)
         | 
| 105 | 
            +
                      File.delete(pid_file) if File.exist?(pid_file)
         | 
| 106 | 
            +
                    else
         | 
| 107 | 
            +
                      Logging.log "Can't stop process, no PID found in #{pid_file}"
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                  
         | 
| 111 | 
            +
                  def read_pid_file(file)
         | 
| 112 | 
            +
                    if File.file?(file) && pid = File.read(file)
         | 
| 113 | 
            +
                      pid.to_i
         | 
| 114 | 
            +
                    else
         | 
| 115 | 
            +
                      nil
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
                
         | 
| 120 | 
            +
              protected
         | 
| 121 | 
            +
                def remove_pid_file
         | 
| 122 | 
            +
                  File.delete(pid_file) if pid_file && File.exists?(pid_file)
         | 
| 123 | 
            +
                end
         | 
| 124 | 
            +
                
         | 
| 125 | 
            +
                def write_pid_file
         | 
| 126 | 
            +
                  log ">> Writing PID to #{pid_file}"
         | 
| 127 | 
            +
                  open(pid_file,"w") { |f| f.write(Process.pid) }
         | 
| 128 | 
            +
                  File.chmod(0644, pid_file)
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
                
         | 
| 131 | 
            +
                # If PID file is stale, remove it.
         | 
| 132 | 
            +
                def remove_stale_pid_file
         | 
| 133 | 
            +
                  if File.exist?(pid_file)
         | 
| 134 | 
            +
                    if pid && Process.running?(pid)
         | 
| 135 | 
            +
                      raise PidFileExist, "#{pid_file} already exists, seems like it's already running (process ID: #{pid}). " +
         | 
| 136 | 
            +
                                          "Stop the process or delete #{pid_file}."
         | 
| 137 | 
            +
                    else
         | 
| 138 | 
            +
                      log ">> Deleting stale PID file #{pid_file}"
         | 
| 139 | 
            +
                      remove_pid_file
         | 
| 140 | 
            +
                    end
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
              end
         | 
| 144 | 
            +
            end
         | 
    
        data/lib/quebert/job.rb
    ADDED
    
    | @@ -0,0 +1,62 @@ | |
| 1 | 
            +
            require 'json'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Quebert
         | 
| 4 | 
            +
              class Job
         | 
| 5 | 
            +
                attr_reader :args
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                NotImplemented = Class.new(StandardError)
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                Action  = Class.new(Exception)
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                Bury    = Class.new(Action)
         | 
| 12 | 
            +
                Delete  = Class.new(Action)
         | 
| 13 | 
            +
                Release = Class.new(Action)
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                def initialize(args=[])
         | 
| 16 | 
            +
                  @args = args.dup.freeze
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                def perform(*args)
         | 
| 20 | 
            +
                  raise NotImplemented
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                def self.enqueue(*args)
         | 
| 24 | 
            +
                  backend.put(self, *args)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                def to_json
         | 
| 28 | 
            +
                  self.class.to_json(self)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
                
         | 
| 31 | 
            +
                def self.to_json(job, *args)
         | 
| 32 | 
            +
                  args, job = job.args, job.class if job.respond_to?(:args)
         | 
| 33 | 
            +
                  JSON.generate('job' => job.name, 'args' => args)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                def self.from_json(json)
         | 
| 37 | 
            +
                  if data = JSON.parse(json)
         | 
| 38 | 
            +
                    Support.constantize(data['job']).new(data['args'])
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
                
         | 
| 42 | 
            +
                def self.backend=(backend)
         | 
| 43 | 
            +
                  @backend = backend
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
                def self.backend
         | 
| 46 | 
            +
                  @backend || Quebert.configuration.backend
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
                
         | 
| 49 | 
            +
              protected
         | 
| 50 | 
            +
                def delete!
         | 
| 51 | 
            +
                  raise Delete
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
                
         | 
| 54 | 
            +
                def release!
         | 
| 55 | 
            +
                  raise Release
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
                
         | 
| 58 | 
            +
                def bury!
         | 
| 59 | 
            +
                  raise Bury
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
            end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            module Quebert
         | 
| 2 | 
            +
              module Support
         | 
| 3 | 
            +
                # Borrowed from Rails ActiveSupport
         | 
| 4 | 
            +
                def self.constantize(camel_cased_word) #:nodoc:
         | 
| 5 | 
            +
                  names = camel_cased_word.split('::')
         | 
| 6 | 
            +
                  names.shift if names.empty? || names.first.empty?
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  constant = Object
         | 
| 9 | 
            +
                  names.each do |name|
         | 
| 10 | 
            +
                    constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                  constant
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                def self.symbolize_keys(hash)
         | 
| 16 | 
            +
                  map_keys(hash, :to_sym)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                def self.stringify_keys(hash)
         | 
| 20 | 
            +
                  map_keys(hash, :to_s)
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
              private
         | 
| 24 | 
            +
                def self.map_keys(hash, meth)
         | 
| 25 | 
            +
                  hash.inject({}){|h, (k,v)| h[k.send(meth)] = v; h; }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            require 'logger'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Quebert
         | 
| 4 | 
            +
              class Worker
         | 
| 5 | 
            +
                attr_accessor :exception_handler, :log_file, :backend
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                include Quebert::Daemonizable
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                def initialize
         | 
| 10 | 
            +
                  yield self if block_given?
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                # Start the worker backend and intercept exceptions if a handler is provided
         | 
| 14 | 
            +
                def start
         | 
| 15 | 
            +
                  while job = backend.reserve do
         | 
| 16 | 
            +
                    begin
         | 
| 17 | 
            +
                      job.perform
         | 
| 18 | 
            +
                    rescue Exception => e
         | 
| 19 | 
            +
                      exception_handler ? exception_handler.call(e) : raise(e)
         | 
| 20 | 
            +
                    end
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
              protected
         | 
| 25 | 
            +
                def log(message)
         | 
| 26 | 
            +
                  puts message
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
    
        data/quebert.gemspec
    ADDED
    
    | @@ -0,0 +1,92 @@ | |
| 1 | 
            +
            # Generated by jeweler
         | 
| 2 | 
            +
            # DO NOT EDIT THIS FILE DIRECTLY
         | 
| 3 | 
            +
            # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
         | 
| 4 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            Gem::Specification.new do |s|
         | 
| 7 | 
            +
              s.name = %q{quebert}
         | 
| 8 | 
            +
              s.version = "0.0.0"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 | 
            +
              s.authors = ["Brad Gessler"]
         | 
| 12 | 
            +
              s.date = %q{2010-10-03}
         | 
| 13 | 
            +
              s.description = %q{A worker queue framework built around beanstalkd}
         | 
| 14 | 
            +
              s.email = %q{brad@bradgessler.com}
         | 
| 15 | 
            +
              s.extra_rdoc_files = [
         | 
| 16 | 
            +
                "LICENSE",
         | 
| 17 | 
            +
                 "README.rdoc"
         | 
| 18 | 
            +
              ]
         | 
| 19 | 
            +
              s.files = [
         | 
| 20 | 
            +
                ".document",
         | 
| 21 | 
            +
                 ".gitignore",
         | 
| 22 | 
            +
                 "Gemfile",
         | 
| 23 | 
            +
                 "LICENSE",
         | 
| 24 | 
            +
                 "README.rdoc",
         | 
| 25 | 
            +
                 "Rakefile",
         | 
| 26 | 
            +
                 "VERSION",
         | 
| 27 | 
            +
                 "lib/quebert.rb",
         | 
| 28 | 
            +
                 "lib/quebert/async_sender.rb",
         | 
| 29 | 
            +
                 "lib/quebert/backend.rb",
         | 
| 30 | 
            +
                 "lib/quebert/backend/beanstalk.rb",
         | 
| 31 | 
            +
                 "lib/quebert/backend/in_process.rb",
         | 
| 32 | 
            +
                 "lib/quebert/backend/sync.rb",
         | 
| 33 | 
            +
                 "lib/quebert/configuration.rb",
         | 
| 34 | 
            +
                 "lib/quebert/consumer.rb",
         | 
| 35 | 
            +
                 "lib/quebert/consumer/base.rb",
         | 
| 36 | 
            +
                 "lib/quebert/consumer/beanstalk.rb",
         | 
| 37 | 
            +
                 "lib/quebert/daemonizing.rb",
         | 
| 38 | 
            +
                 "lib/quebert/job.rb",
         | 
| 39 | 
            +
                 "lib/quebert/support.rb",
         | 
| 40 | 
            +
                 "lib/quebert/worker.rb",
         | 
| 41 | 
            +
                 "quebert.gemspec",
         | 
| 42 | 
            +
                 "spec/async_sender_spec.rb",
         | 
| 43 | 
            +
                 "spec/backend_spec.rb",
         | 
| 44 | 
            +
                 "spec/configuration_spec.rb",
         | 
| 45 | 
            +
                 "spec/consumer_spec.rb",
         | 
| 46 | 
            +
                 "spec/job_spec.rb",
         | 
| 47 | 
            +
                 "spec/jobs.rb",
         | 
| 48 | 
            +
                 "spec/quebert_spec.rb",
         | 
| 49 | 
            +
                 "spec/spec.opts",
         | 
| 50 | 
            +
                 "spec/spec_helper.rb",
         | 
| 51 | 
            +
                 "spec/worker_spec.rb"
         | 
| 52 | 
            +
              ]
         | 
| 53 | 
            +
              s.homepage = %q{http://github.com/bradgessler/quebert}
         | 
| 54 | 
            +
              s.rdoc_options = ["--charset=UTF-8"]
         | 
| 55 | 
            +
              s.require_paths = ["lib"]
         | 
| 56 | 
            +
              s.rubygems_version = %q{1.3.7}
         | 
| 57 | 
            +
              s.summary = %q{A worker queue framework built around beanstalkd}
         | 
| 58 | 
            +
              s.test_files = [
         | 
| 59 | 
            +
                "spec/async_sender_spec.rb",
         | 
| 60 | 
            +
                 "spec/backend_spec.rb",
         | 
| 61 | 
            +
                 "spec/configuration_spec.rb",
         | 
| 62 | 
            +
                 "spec/consumer_spec.rb",
         | 
| 63 | 
            +
                 "spec/job_spec.rb",
         | 
| 64 | 
            +
                 "spec/jobs.rb",
         | 
| 65 | 
            +
                 "spec/quebert_spec.rb",
         | 
| 66 | 
            +
                 "spec/spec_helper.rb",
         | 
| 67 | 
            +
                 "spec/worker_spec.rb"
         | 
| 68 | 
            +
              ]
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              if s.respond_to? :specification_version then
         | 
| 71 | 
            +
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         | 
| 72 | 
            +
                s.specification_version = 3
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
         | 
| 75 | 
            +
                  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
         | 
| 76 | 
            +
                  s.add_runtime_dependency(%q<json>, [">= 0"])
         | 
| 77 | 
            +
                  s.add_runtime_dependency(%q<daemons>, [">= 0"])
         | 
| 78 | 
            +
                  s.add_runtime_dependency(%q<beanstalk-client>, [">= 0"])
         | 
| 79 | 
            +
                else
         | 
| 80 | 
            +
                  s.add_dependency(%q<rspec>, [">= 1.2.9"])
         | 
| 81 | 
            +
                  s.add_dependency(%q<json>, [">= 0"])
         | 
| 82 | 
            +
                  s.add_dependency(%q<daemons>, [">= 0"])
         | 
| 83 | 
            +
                  s.add_dependency(%q<beanstalk-client>, [">= 0"])
         | 
| 84 | 
            +
                end
         | 
| 85 | 
            +
              else
         | 
| 86 | 
            +
                s.add_dependency(%q<rspec>, [">= 1.2.9"])
         | 
| 87 | 
            +
                s.add_dependency(%q<json>, [">= 0"])
         | 
| 88 | 
            +
                s.add_dependency(%q<daemons>, [">= 0"])
         | 
| 89 | 
            +
                s.add_dependency(%q<beanstalk-client>, [">= 0"])
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
            end
         | 
| 92 | 
            +
             | 
| @@ -0,0 +1,85 @@ | |
| 1 | 
            +
            require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
         | 
| 2 | 
            +
            require 'active_record'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            describe AsyncSender::Class do
         | 
| 5 | 
            +
              
         | 
| 6 | 
            +
              before(:all) do
         | 
| 7 | 
            +
                @q = Backend::InProcess.new
         | 
| 8 | 
            +
                Quebert::AsyncSender::Object::ObjectJob.backend = @q
         | 
| 9 | 
            +
                Quebert::AsyncSender::Instance::InstanceJob.backend = @q
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
              
         | 
| 12 | 
            +
              class Greeter
         | 
| 13 | 
            +
                include AsyncSender::Class
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                def initialize(name)
         | 
| 16 | 
            +
                  @name = name
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
                
         | 
| 19 | 
            +
                def hi(desc)
         | 
| 20 | 
            +
                  "hi #{@name}, you look #{desc}"
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
                
         | 
| 23 | 
            +
                def self.hi(name)
         | 
| 24 | 
            +
                  "hi #{name}!"
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
              
         | 
| 28 | 
            +
              it "should async send class methods" do
         | 
| 29 | 
            +
                Greeter.async_send(:hi, 'Jeannette')
         | 
| 30 | 
            +
                @q.reserve.perform.should eql(Greeter.send(:hi, 'Jeannette'))
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
              
         | 
| 33 | 
            +
              it "should async send instance methods" do
         | 
| 34 | 
            +
                Greeter.new("brad").async_send(:hi, 'stunning')
         | 
| 35 | 
            +
                @q.reserve.perform.should eql(Greeter.new("brad").send(:hi, 'stunning'))
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
              
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            describe AsyncSender::ActiveRecord do
         | 
| 41 | 
            +
              
         | 
| 42 | 
            +
              ActiveRecord::Base.establish_connection({
         | 
| 43 | 
            +
                :adapter => 'sqlite3',
         | 
| 44 | 
            +
                :database => ':memory:'
         | 
| 45 | 
            +
              })
         | 
| 46 | 
            +
              
         | 
| 47 | 
            +
              ActiveRecord::Schema.define do
         | 
| 48 | 
            +
                create_table "users", :force => true do |t|
         | 
| 49 | 
            +
                  t.column "first_name",  :text
         | 
| 50 | 
            +
                  t.column "last_name",  :text
         | 
| 51 | 
            +
                  t.column "email", :text
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
              
         | 
| 55 | 
            +
              class User < ActiveRecord::Base
         | 
| 56 | 
            +
                include Quebert::AsyncSender::ActiveRecord
         | 
| 57 | 
            +
                
         | 
| 58 | 
            +
                def name
         | 
| 59 | 
            +
                  "#{first_name} #{last_name}"
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
                
         | 
| 62 | 
            +
                def self.email(address)
         | 
| 63 | 
            +
                  address
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
              end
         | 
| 66 | 
            +
              
         | 
| 67 | 
            +
              before(:all) do
         | 
| 68 | 
            +
                @q = Backend::InProcess.new
         | 
| 69 | 
            +
                Quebert::AsyncSender::ActiveRecord::RecordJob.backend = @q
         | 
| 70 | 
            +
                Quebert::AsyncSender::Object::ObjectJob.backend = @q
         | 
| 71 | 
            +
                
         | 
| 72 | 
            +
                @user = User.create!(:first_name => 'Brad', :last_name => 'Gessler', :email => 'brad@bradgessler.com')
         | 
| 73 | 
            +
              end
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
              it "should async_send instance method" do
         | 
| 76 | 
            +
                User.first.async_send(:name)
         | 
| 77 | 
            +
                @q.reserve.perform.should eql(User.first.name)
         | 
| 78 | 
            +
              end
         | 
| 79 | 
            +
              
         | 
| 80 | 
            +
              it "should async_send class method" do
         | 
| 81 | 
            +
                email = "brad@bradgessler.com"
         | 
| 82 | 
            +
                User.async_send(:email, email)
         | 
| 83 | 
            +
                @q.reserve.perform.should eql(email)
         | 
| 84 | 
            +
              end
         | 
| 85 | 
            +
            end
         |