falls_back_on 0.0.3 → 0.1.1
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 +11 -0
- data/.gitignore +11 -0
- data/Gemfile +4 -0
- data/LICENSE +1 -1
- data/Rakefile +25 -0
- data/falls_back_on.gemspec +34 -0
- data/lib/falls_back_on.rb +30 -48
- data/lib/falls_back_on/definition.rb +50 -0
- data/lib/falls_back_on/definition/storage.rb +8 -0
- data/lib/falls_back_on/version.rb +3 -0
- data/test/helper.rb +40 -0
- data/test/test_falls_back_on.rb +108 -0
- metadata +78 -68
- data/lib/falls_back_on/active_record_ext.rb +0 -5
- data/lib/falls_back_on/app/models/fallback.rb +0 -35
- data/spec/lib/falls_back_on/app/models/fallback_spec.rb +0 -19
- data/spec/lib/falls_back_on_spec.rb +0 -24
- data/spec/spec_helper.rb +0 -33
    
        data/.document
    ADDED
    
    | @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            # .document is used by rdoc and yard to know how to generate documentation 
         | 
| 2 | 
            +
            # for example, it can be used to control how rdoc gets built when you do `gem install foo`
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            README.rdoc
         | 
| 5 | 
            +
            lib/**/*.rb
         | 
| 6 | 
            +
            bin/*
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            # Files below this - are treated as 'extra files', and aren't parsed for ruby code
         | 
| 9 | 
            +
            - 
         | 
| 10 | 
            +
            features/**/*.feature
         | 
| 11 | 
            +
            LICENSE
         | 
    
        data/.gitignore
    ADDED
    
    
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE
    CHANGED
    
    
    
        data/Rakefile
    ADDED
    
    | @@ -0,0 +1,25 @@ | |
| 1 | 
            +
            require 'bundler'
         | 
| 2 | 
            +
            Bundler::GemHelper.install_tasks
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            require 'rake'
         | 
| 5 | 
            +
            require 'rake/testtask'
         | 
| 6 | 
            +
            Rake::TestTask.new(:test) do |test|
         | 
| 7 | 
            +
              test.libs << 'lib' << 'test'
         | 
| 8 | 
            +
              test.pattern = 'test/**/test_*.rb'
         | 
| 9 | 
            +
              test.verbose = true
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            begin
         | 
| 13 | 
            +
              require 'rake/rdoctask'
         | 
| 14 | 
            +
              Rake::RDocTask.new do |rdoc|
         | 
| 15 | 
            +
                rdoc.rdoc_dir = 'rdoc'
         | 
| 16 | 
            +
                rdoc.title = 'falls_back_on'
         | 
| 17 | 
            +
                rdoc.options << '--line-numbers' << '--inline-source'
         | 
| 18 | 
            +
                rdoc.rdoc_files.include('README*')
         | 
| 19 | 
            +
                rdoc.rdoc_files.include('lib/**/*.rb')
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            rescue LoadError
         | 
| 22 | 
            +
               puts "Rdoc is not available"
         | 
| 23 | 
            +
            end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            task :default => :test
         | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            $:.push File.expand_path("../lib", __FILE__)
         | 
| 3 | 
            +
            require "falls_back_on/version"
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            Gem::Specification.new do |s|
         | 
| 6 | 
            +
              s.name        = "falls_back_on"
         | 
| 7 | 
            +
              s.version     = FallsBackOn::VERSION
         | 
| 8 | 
            +
              s.platform    = Gem::Platform::RUBY
         | 
| 9 | 
            +
              s.authors     = ['Seamus Abshere', 'Derek Kastner']
         | 
| 10 | 
            +
              s.email       = ["seamus@abshere.net"]
         | 
| 11 | 
            +
              s.homepage    = 'http://github.com/dkastner/falls_back_on'
         | 
| 12 | 
            +
              s.summary     = 'Adds ActiveRecord::Base.falls_back_on and ActiveRecord::Base.fallback'
         | 
| 13 | 
            +
              s.description = 'ActiveRecord extension to intelligently fall back on another column when a given column is unavailable'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              s.rubyforge_project = "falls_back_on"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              s.files         = `git ls-files`.split("\n")
         | 
| 18 | 
            +
              s.test_files    = `git ls-files -- {test,spec,features}/*`.split("\n")
         | 
| 19 | 
            +
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         | 
| 20 | 
            +
              s.require_paths = ["lib"]
         | 
| 21 | 
            +
              
         | 
| 22 | 
            +
              s.add_dependency 'cache_method'
         | 
| 23 | 
            +
              s.add_dependency 'lock_method'
         | 
| 24 | 
            +
              s.add_development_dependency 'test-unit'
         | 
| 25 | 
            +
              s.add_development_dependency 'memcached'
         | 
| 26 | 
            +
              s.add_development_dependency 'activerecord'
         | 
| 27 | 
            +
              s.add_development_dependency 'sqlite3-ruby'
         | 
| 28 | 
            +
              s.add_development_dependency 'weighted_average'
         | 
| 29 | 
            +
              if RUBY_VERSION >= '1.9'
         | 
| 30 | 
            +
                s.add_development_dependency 'ruby-debug19'
         | 
| 31 | 
            +
              else
         | 
| 32 | 
            +
                s.add_development_dependency 'ruby-debug'
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
    
        data/lib/falls_back_on.rb
    CHANGED
    
    | @@ -1,54 +1,36 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
             | 
| 3 | 
            -
                class_eval do
         | 
| 4 | 
            -
                  class_inheritable_accessor :fallback_options
         | 
| 5 | 
            -
                end
         | 
| 6 | 
            -
                self.fallback_options = options
         | 
| 7 | 
            -
                extend FallsBackOn::InstanceMethods
         | 
| 8 | 
            -
              end
         | 
| 1 | 
            +
            require 'cache_method'
         | 
| 2 | 
            +
            require 'lock_method'
         | 
| 9 3 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
                def class_name
         | 
| 12 | 
            -
                  self.to_s
         | 
| 13 | 
            -
                end
         | 
| 4 | 
            +
            require 'falls_back_on/version'
         | 
| 14 5 |  | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
                
         | 
| 19 | 
            -
                def fallback_value_for(k)
         | 
| 20 | 
            -
                  v = fallback_options[k]
         | 
| 21 | 
            -
                  case v
         | 
| 22 | 
            -
                  when :random
         | 
| 23 | 
            -
                    fallback_value_for_random(k)
         | 
| 24 | 
            -
                  when Numeric
         | 
| 25 | 
            -
                    v
         | 
| 26 | 
            -
                  when String
         | 
| 27 | 
            -
                    v.upcase.starts_with?('SELECT') ? ActiveRecord::Base.connection.select_value(v) : v
         | 
| 28 | 
            -
                  when Proc
         | 
| 29 | 
            -
                    v.call
         | 
| 30 | 
            -
                  end
         | 
| 31 | 
            -
                end
         | 
| 32 | 
            -
                
         | 
| 33 | 
            -
                def fallback_value_for_name
         | 
| 34 | 
            -
                  { :name => "Fallback #{class_name.underscore.gsub('_', ' ')}" }
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
                
         | 
| 37 | 
            -
                def fallback_value_for_random(k)
         | 
| 38 | 
            -
                  random = rand(1e8)
         | 
| 39 | 
            -
                  return fallback_value_for_random(k) unless send("find_by_#{k}", random).nil?
         | 
| 40 | 
            -
                  random
         | 
| 41 | 
            -
                end
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                def destroy_fallback
         | 
| 44 | 
            -
                  Fallback.destroy_for(class_name)
         | 
| 45 | 
            -
                end
         | 
| 6 | 
            +
            module FallsBackOn
         | 
| 7 | 
            +
              autoload :Definition, 'falls_back_on/definition'
         | 
| 46 8 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 9 | 
            +
              def self.clear
         | 
| 10 | 
            +
                ::FallsBackOn::Definition.all.each { |definition| definition.clear }
         | 
| 11 | 
            +
              end
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
              def falls_back_on(attrs)
         | 
| 14 | 
            +
                definition = ::FallsBackOn::Definition.new self
         | 
| 15 | 
            +
                definition.attrs = attrs
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
              
         | 
| 18 | 
            +
              def fallback
         | 
| 19 | 
            +
                obj = new
         | 
| 20 | 
            +
                definition = ::FallsBackOn::Definition.new self
         | 
| 21 | 
            +
                begin
         | 
| 22 | 
            +
                  definition.attrs.each do |k, v|
         | 
| 23 | 
            +
                    obj.send "#{k}=", v
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                rescue ::LockMethod::Locked
         | 
| 26 | 
            +
                  $stderr.puts "#{self.to_s} was locked, retrying in 0.5 seconds..."
         | 
| 27 | 
            +
                  sleep 0.5
         | 
| 28 | 
            +
                  retry
         | 
| 52 29 | 
             
                end
         | 
| 30 | 
            +
                obj
         | 
| 53 31 | 
             
              end
         | 
| 54 32 | 
             
            end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
            unless ::Class.method_defined?(:falls_back_on)
         | 
| 35 | 
            +
              ::Class.send :include, ::FallsBackOn
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            module FallsBackOn
         | 
| 2 | 
            +
              class Definition
         | 
| 3 | 
            +
                autoload :Storage, 'falls_back_on/definition/storage'
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                def self.all
         | 
| 6 | 
            +
                  Storage.instance.keys.map { |parent| new parent }
         | 
| 7 | 
            +
                end
         | 
| 8 | 
            +
                
         | 
| 9 | 
            +
                attr_reader :parent
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                def initialize(parent)
         | 
| 12 | 
            +
                  @parent = parent.to_s
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                def clear
         | 
| 16 | 
            +
                  clear_method_cache :calculate
         | 
| 17 | 
            +
                  clear_method_cache :attrs
         | 
| 18 | 
            +
                  clear_method_lock :attrs
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                def attrs=(attrs)
         | 
| 22 | 
            +
                  Storage.instance[parent] = attrs
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                def attrs
         | 
| 26 | 
            +
                  Storage.instance[parent].inject({}) do |memo, (k, v)|
         | 
| 27 | 
            +
                    memo[k] = calculate k
         | 
| 28 | 
            +
                    memo
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
                lock_method :attrs
         | 
| 32 | 
            +
                cache_method :attrs
         | 
| 33 | 
            +
                    
         | 
| 34 | 
            +
                def calculate(k)
         | 
| 35 | 
            +
                  v = Storage.instance[parent][k]
         | 
| 36 | 
            +
                  case v
         | 
| 37 | 
            +
                  when Proc
         | 
| 38 | 
            +
                    v.call
         | 
| 39 | 
            +
                  else
         | 
| 40 | 
            +
                    v
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
                cache_method :calculate
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
                # for cache_method and lock_method
         | 
| 46 | 
            +
                def hash
         | 
| 47 | 
            +
                  parent.hash
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
    
        data/test/helper.rb
    ADDED
    
    | @@ -0,0 +1,40 @@ | |
| 1 | 
            +
            require 'rubygems'
         | 
| 2 | 
            +
            require 'bundler'
         | 
| 3 | 
            +
            Bundler.setup
         | 
| 4 | 
            +
            require 'test/unit'
         | 
| 5 | 
            +
            require 'active_record'
         | 
| 6 | 
            +
            require 'active_support/all'
         | 
| 7 | 
            +
            require 'weighted_average'
         | 
| 8 | 
            +
            require 'memcached'
         | 
| 9 | 
            +
            require 'timeout'
         | 
| 10 | 
            +
            require 'ruby-debug'
         | 
| 11 | 
            +
            $LOAD_PATH.unshift(File.dirname(__FILE__))
         | 
| 12 | 
            +
            $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
         | 
| 13 | 
            +
            require 'falls_back_on'
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            # thanks authlogic!
         | 
| 16 | 
            +
            ActiveRecord::Schema.verbose = false
         | 
| 17 | 
            +
            begin
         | 
| 18 | 
            +
              ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
         | 
| 19 | 
            +
            rescue ArgumentError
         | 
| 20 | 
            +
              ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :dbfile => ":memory:")
         | 
| 21 | 
            +
            end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            my_client = Memcached.new
         | 
| 24 | 
            +
            CacheMethod.config.storage = my_client
         | 
| 25 | 
            +
            LockMethod.config.storage = my_client
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            class Test::Unit::TestCase
         | 
| 28 | 
            +
              def setup
         | 
| 29 | 
            +
                CacheMethod.config.storage.flush
         | 
| 30 | 
            +
                LockMethod.config.storage.flush
         | 
| 31 | 
            +
                @old_abort_on_exception = Thread.abort_on_exception
         | 
| 32 | 
            +
                Thread.abort_on_exception = true
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
              
         | 
| 35 | 
            +
              def teardown
         | 
| 36 | 
            +
                Thread.abort_on_exception = @old_abort_on_exception
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            ENV['FALLS_BACK_ON_DEBUG'] = 'true'
         | 
| @@ -0,0 +1,108 @@ | |
| 1 | 
            +
            require 'helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Car1
         | 
| 4 | 
            +
              attr_accessor :fuel
         | 
| 5 | 
            +
              attr_accessor :random_number
         | 
| 6 | 
            +
              attr_accessor :some_place_in_the_mall
         | 
| 7 | 
            +
              falls_back_on :fuel => 'gasoline',
         | 
| 8 | 
            +
                            :random_number => lambda { rand },
         | 
| 9 | 
            +
                            :some_place_in_the_mall => lambda { some_place_in_the_mall }
         | 
| 10 | 
            +
              def self.some_place_in_the_mall
         | 
| 11 | 
            +
                "Orange Julius at #{Time.now}"
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
            end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            class Car2 < ActiveRecord::Base
         | 
| 16 | 
            +
              set_table_name :cars2
         | 
| 17 | 
            +
              def self.create_table
         | 
| 18 | 
            +
                connection.create_table :cars2, :force => true do |t|
         | 
| 19 | 
            +
                  t.string :fuel
         | 
| 20 | 
            +
                  t.float :efficiency
         | 
| 21 | 
            +
                  t.integer :popularity
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
              
         | 
| 25 | 
            +
              attr_accessor :efficiency2
         | 
| 26 | 
            +
              
         | 
| 27 | 
            +
              falls_back_on  :fuel => 'diesel',
         | 
| 28 | 
            +
                             :efficiency => lambda { calculate(:average, :efficiency) },
         | 
| 29 | 
            +
                             :efficiency2 => lambda { weighted_average(:efficiency, :weighted_by => :popularity ) }
         | 
| 30 | 
            +
            end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            Car2.create_table
         | 
| 33 | 
            +
            Car2.create! :efficiency => 10.0, :popularity => 1_000_000
         | 
| 34 | 
            +
            Car2.create! :efficiency => 1.0, :popularity => 1
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            class Car3
         | 
| 37 | 
            +
              attr_accessor :long_running_calculation
         | 
| 38 | 
            +
              falls_back_on :long_running_calculation => lambda { sleep 3 }
         | 
| 39 | 
            +
            end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            class TestFallsBackOn < Test::Unit::TestCase
         | 
| 42 | 
            +
              def test_fallback
         | 
| 43 | 
            +
                assert_equal 'gasoline', Car1.fallback.fuel
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
              
         | 
| 46 | 
            +
              def test_active_record
         | 
| 47 | 
            +
                assert_equal 'diesel', Car2.fallback.fuel
         | 
| 48 | 
            +
              end
         | 
| 49 | 
            +
              
         | 
| 50 | 
            +
              def test_proc
         | 
| 51 | 
            +
                assert Car1.fallback.random_number.is_a?(Numeric)
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
              
         | 
| 54 | 
            +
              def test_proc_calling_class_method
         | 
| 55 | 
            +
                assert(Car1.fallback.some_place_in_the_mall =~ /Orange Julius/)
         | 
| 56 | 
            +
              end
         | 
| 57 | 
            +
              
         | 
| 58 | 
            +
              def test_active_record_calculations
         | 
| 59 | 
            +
                assert_equal 5.5, Car2.fallback.efficiency
         | 
| 60 | 
            +
              end
         | 
| 61 | 
            +
              
         | 
| 62 | 
            +
              def test_weighted_average
         | 
| 63 | 
            +
                assert_equal 10, Car2.fallback.efficiency2.round
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
              
         | 
| 66 | 
            +
              def test_cache
         | 
| 67 | 
            +
                random_number = Car1.fallback.random_number
         | 
| 68 | 
            +
                assert_equal random_number, Car1.fallback.random_number
         | 
| 69 | 
            +
                assert_equal random_number, Car1.fallback.random_number
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
              
         | 
| 72 | 
            +
              def test_retries_if_lock
         | 
| 73 | 
            +
                blocker = Thread.new { Car3.fallback.long_running_calculation }
         | 
| 74 | 
            +
              
         | 
| 75 | 
            +
                assert_raises(::Timeout::Error) do
         | 
| 76 | 
            +
                  Timeout.timeout(2) do
         | 
| 77 | 
            +
                    Car3.fallback.long_running_calculation
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                end
         | 
| 80 | 
            +
                
         | 
| 81 | 
            +
                blocker.join
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
              
         | 
| 84 | 
            +
              def test_caches_calculations_separately
         | 
| 85 | 
            +
                definition = ::FallsBackOn::Definition.new Car3
         | 
| 86 | 
            +
                definition.calculate :long_running_calculation
         | 
| 87 | 
            +
              end
         | 
| 88 | 
            +
              
         | 
| 89 | 
            +
              def test_clear
         | 
| 90 | 
            +
                # sanity check
         | 
| 91 | 
            +
                assert_nothing_raised do
         | 
| 92 | 
            +
                  Timeout.timeout(4) do
         | 
| 93 | 
            +
                    blocker = Thread.new { Car3.fallback.long_running_calculation }
         | 
| 94 | 
            +
                    sleep 1
         | 
| 95 | 
            +
                    Car3.fallback.long_running_calculation
         | 
| 96 | 
            +
                  end
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                assert_raises(Timeout::Error) do
         | 
| 100 | 
            +
                  Timeout.timeout(4) do
         | 
| 101 | 
            +
                    blocker = Thread.new { Car3.fallback.long_running_calculation }
         | 
| 102 | 
            +
                    sleep 1
         | 
| 103 | 
            +
                    clearer = Thread.new { ::FallsBackOn.clear }
         | 
| 104 | 
            +
                    Car3.fallback.long_running_calculation
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version | |
| 5 5 | 
             
              prerelease: false
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 | 
            -
              -  | 
| 9 | 
            -
              -  | 
| 10 | 
            -
              version: 0. | 
| 8 | 
            +
              - 1
         | 
| 9 | 
            +
              - 1
         | 
| 10 | 
            +
              version: 0.1.1
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Seamus Abshere
         | 
| @@ -16,14 +16,13 @@ autorequire: | |
| 16 16 | 
             
            bindir: bin
         | 
| 17 17 | 
             
            cert_chain: []
         | 
| 18 18 |  | 
| 19 | 
            -
            date:  | 
| 19 | 
            +
            date: 2011-02-24 00:00:00 -06:00
         | 
| 20 20 | 
             
            default_executable: 
         | 
| 21 21 | 
             
            dependencies: 
         | 
| 22 22 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 23 | 
            -
               | 
| 23 | 
            +
              name: cache_method
         | 
| 24 24 | 
             
              prerelease: false
         | 
| 25 | 
            -
               | 
| 26 | 
            -
              version_requirements: &id001 !ruby/object:Gem::Requirement 
         | 
| 25 | 
            +
              requirement: &id001 !ruby/object:Gem::Requirement 
         | 
| 27 26 | 
             
                none: false
         | 
| 28 27 | 
             
                requirements: 
         | 
| 29 28 | 
             
                - - ">="
         | 
| @@ -32,12 +31,12 @@ dependencies: | |
| 32 31 | 
             
                    segments: 
         | 
| 33 32 | 
             
                    - 0
         | 
| 34 33 | 
             
                    version: "0"
         | 
| 35 | 
            -
               | 
| 34 | 
            +
              type: :runtime
         | 
| 35 | 
            +
              version_requirements: *id001
         | 
| 36 36 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 37 | 
            -
               | 
| 37 | 
            +
              name: lock_method
         | 
| 38 38 | 
             
              prerelease: false
         | 
| 39 | 
            -
               | 
| 40 | 
            -
              version_requirements: &id002 !ruby/object:Gem::Requirement 
         | 
| 39 | 
            +
              requirement: &id002 !ruby/object:Gem::Requirement 
         | 
| 41 40 | 
             
                none: false
         | 
| 42 41 | 
             
                requirements: 
         | 
| 43 42 | 
             
                - - ">="
         | 
| @@ -46,12 +45,12 @@ dependencies: | |
| 46 45 | 
             
                    segments: 
         | 
| 47 46 | 
             
                    - 0
         | 
| 48 47 | 
             
                    version: "0"
         | 
| 49 | 
            -
               | 
| 48 | 
            +
              type: :runtime
         | 
| 49 | 
            +
              version_requirements: *id002
         | 
| 50 50 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 51 | 
            -
               | 
| 51 | 
            +
              name: test-unit
         | 
| 52 52 | 
             
              prerelease: false
         | 
| 53 | 
            -
               | 
| 54 | 
            -
              version_requirements: &id003 !ruby/object:Gem::Requirement 
         | 
| 53 | 
            +
              requirement: &id003 !ruby/object:Gem::Requirement 
         | 
| 55 54 | 
             
                none: false
         | 
| 56 55 | 
             
                requirements: 
         | 
| 57 56 | 
             
                - - ">="
         | 
| @@ -60,12 +59,12 @@ dependencies: | |
| 60 59 | 
             
                    segments: 
         | 
| 61 60 | 
             
                    - 0
         | 
| 62 61 | 
             
                    version: "0"
         | 
| 63 | 
            -
              requirement: *id003
         | 
| 64 | 
            -
            - !ruby/object:Gem::Dependency 
         | 
| 65 62 | 
             
              type: :development
         | 
| 63 | 
            +
              version_requirements: *id003
         | 
| 64 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 65 | 
            +
              name: memcached
         | 
| 66 66 | 
             
              prerelease: false
         | 
| 67 | 
            -
               | 
| 68 | 
            -
              version_requirements: &id004 !ruby/object:Gem::Requirement 
         | 
| 67 | 
            +
              requirement: &id004 !ruby/object:Gem::Requirement 
         | 
| 69 68 | 
             
                none: false
         | 
| 70 69 | 
             
                requirements: 
         | 
| 71 70 | 
             
                - - ">="
         | 
| @@ -74,12 +73,12 @@ dependencies: | |
| 74 73 | 
             
                    segments: 
         | 
| 75 74 | 
             
                    - 0
         | 
| 76 75 | 
             
                    version: "0"
         | 
| 77 | 
            -
              requirement: *id004
         | 
| 78 | 
            -
            - !ruby/object:Gem::Dependency 
         | 
| 79 76 | 
             
              type: :development
         | 
| 77 | 
            +
              version_requirements: *id004
         | 
| 78 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 79 | 
            +
              name: activerecord
         | 
| 80 80 | 
             
              prerelease: false
         | 
| 81 | 
            -
               | 
| 82 | 
            -
              version_requirements: &id005 !ruby/object:Gem::Requirement 
         | 
| 81 | 
            +
              requirement: &id005 !ruby/object:Gem::Requirement 
         | 
| 83 82 | 
             
                none: false
         | 
| 84 83 | 
             
                requirements: 
         | 
| 85 84 | 
             
                - - ">="
         | 
| @@ -88,69 +87,81 @@ dependencies: | |
| 88 87 | 
             
                    segments: 
         | 
| 89 88 | 
             
                    - 0
         | 
| 90 89 | 
             
                    version: "0"
         | 
| 91 | 
            -
               | 
| 90 | 
            +
              type: :development
         | 
| 91 | 
            +
              version_requirements: *id005
         | 
| 92 92 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| 93 | 
            +
              name: sqlite3-ruby
         | 
| 94 | 
            +
              prerelease: false
         | 
| 95 | 
            +
              requirement: &id006 !ruby/object:Gem::Requirement 
         | 
| 96 | 
            +
                none: false
         | 
| 97 | 
            +
                requirements: 
         | 
| 98 | 
            +
                - - ">="
         | 
| 99 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 100 | 
            +
                    hash: 3
         | 
| 101 | 
            +
                    segments: 
         | 
| 102 | 
            +
                    - 0
         | 
| 103 | 
            +
                    version: "0"
         | 
| 93 104 | 
             
              type: :development
         | 
| 105 | 
            +
              version_requirements: *id006
         | 
| 106 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 107 | 
            +
              name: weighted_average
         | 
| 94 108 | 
             
              prerelease: false
         | 
| 95 | 
            -
               | 
| 96 | 
            -
              version_requirements: &id006 !ruby/object:Gem::Requirement 
         | 
| 109 | 
            +
              requirement: &id007 !ruby/object:Gem::Requirement 
         | 
| 97 110 | 
             
                none: false
         | 
| 98 111 | 
             
                requirements: 
         | 
| 99 112 | 
             
                - - ">="
         | 
| 100 113 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 101 | 
            -
                    hash:  | 
| 114 | 
            +
                    hash: 3
         | 
| 102 115 | 
             
                    segments: 
         | 
| 103 | 
            -
                    - 2
         | 
| 104 116 | 
             
                    - 0
         | 
| 117 | 
            +
                    version: "0"
         | 
| 118 | 
            +
              type: :development
         | 
| 119 | 
            +
              version_requirements: *id007
         | 
| 120 | 
            +
            - !ruby/object:Gem::Dependency 
         | 
| 121 | 
            +
              name: ruby-debug
         | 
| 122 | 
            +
              prerelease: false
         | 
| 123 | 
            +
              requirement: &id008 !ruby/object:Gem::Requirement 
         | 
| 124 | 
            +
                none: false
         | 
| 125 | 
            +
                requirements: 
         | 
| 126 | 
            +
                - - ">="
         | 
| 127 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 128 | 
            +
                    hash: 3
         | 
| 129 | 
            +
                    segments: 
         | 
| 105 130 | 
             
                    - 0
         | 
| 106 | 
            -
                     | 
| 107 | 
            -
             | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
             | 
| 112 | 
            -
              
         | 
| 113 | 
            -
              Description goes here.
         | 
| 114 | 
            -
              
         | 
| 115 | 
            -
              == Note on Patches/Pull Requests
         | 
| 116 | 
            -
               
         | 
| 117 | 
            -
              * Fork the project.
         | 
| 118 | 
            -
              * Make your feature addition or bug fix.
         | 
| 119 | 
            -
              * Add tests for it. This is important so I don't break it in a
         | 
| 120 | 
            -
                future version unintentionally.
         | 
| 121 | 
            -
              * Commit, do not mess with rakefile, version, or history.
         | 
| 122 | 
            -
                (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
         | 
| 123 | 
            -
              * Send me a pull request. Bonus points for topic branches.
         | 
| 124 | 
            -
              
         | 
| 125 | 
            -
              == Copyright
         | 
| 126 | 
            -
              
         | 
| 127 | 
            -
              Copyright (c) 2010 Derek Kastner. See LICENSE for details.
         | 
| 128 | 
            -
             | 
| 129 | 
            -
            email: seamus@brighterplanet.com
         | 
| 131 | 
            +
                    version: "0"
         | 
| 132 | 
            +
              type: :development
         | 
| 133 | 
            +
              version_requirements: *id008
         | 
| 134 | 
            +
            description: ActiveRecord extension to intelligently fall back on another column when a given column is unavailable
         | 
| 135 | 
            +
            email: 
         | 
| 136 | 
            +
            - seamus@abshere.net
         | 
| 130 137 | 
             
            executables: []
         | 
| 131 138 |  | 
| 132 139 | 
             
            extensions: []
         | 
| 133 140 |  | 
| 134 | 
            -
            extra_rdoc_files: 
         | 
| 141 | 
            +
            extra_rdoc_files: []
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            files: 
         | 
| 144 | 
            +
            - .document
         | 
| 145 | 
            +
            - .gitignore
         | 
| 146 | 
            +
            - Gemfile
         | 
| 135 147 | 
             
            - LICENSE
         | 
| 136 148 | 
             
            - README.rdoc
         | 
| 137 | 
            -
             | 
| 149 | 
            +
            - Rakefile
         | 
| 150 | 
            +
            - falls_back_on.gemspec
         | 
| 138 151 | 
             
            - lib/falls_back_on.rb
         | 
| 139 | 
            -
            - lib/falls_back_on/ | 
| 140 | 
            -
            - lib/falls_back_on/ | 
| 152 | 
            +
            - lib/falls_back_on/definition.rb
         | 
| 153 | 
            +
            - lib/falls_back_on/definition/storage.rb
         | 
| 154 | 
            +
            - lib/falls_back_on/version.rb
         | 
| 141 155 | 
             
            - rails/init.rb
         | 
| 142 | 
            -
            -  | 
| 143 | 
            -
            -  | 
| 144 | 
            -
            - spec/lib/falls_back_on/app/models/fallback_spec.rb
         | 
| 145 | 
            -
            - spec/lib/falls_back_on_spec.rb
         | 
| 146 | 
            -
            - spec/spec_helper.rb
         | 
| 156 | 
            +
            - test/helper.rb
         | 
| 157 | 
            +
            - test/test_falls_back_on.rb
         | 
| 147 158 | 
             
            has_rdoc: true
         | 
| 148 159 | 
             
            homepage: http://github.com/dkastner/falls_back_on
         | 
| 149 160 | 
             
            licenses: []
         | 
| 150 161 |  | 
| 151 162 | 
             
            post_install_message: 
         | 
| 152 | 
            -
            rdoc_options: 
         | 
| 153 | 
            -
             | 
| 163 | 
            +
            rdoc_options: []
         | 
| 164 | 
            +
             | 
| 154 165 | 
             
            require_paths: 
         | 
| 155 166 | 
             
            - lib
         | 
| 156 167 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| @@ -173,12 +184,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 173 184 | 
             
                  version: "0"
         | 
| 174 185 | 
             
            requirements: []
         | 
| 175 186 |  | 
| 176 | 
            -
            rubyforge_project: 
         | 
| 187 | 
            +
            rubyforge_project: falls_back_on
         | 
| 177 188 | 
             
            rubygems_version: 1.3.7
         | 
| 178 189 | 
             
            signing_key: 
         | 
| 179 190 | 
             
            specification_version: 3
         | 
| 180 | 
            -
            summary: ActiveRecord  | 
| 191 | 
            +
            summary: Adds ActiveRecord::Base.falls_back_on and ActiveRecord::Base.fallback
         | 
| 181 192 | 
             
            test_files: 
         | 
| 182 | 
            -
            -  | 
| 183 | 
            -
            -  | 
| 184 | 
            -
            - spec/spec_helper.rb
         | 
| 193 | 
            +
            - test/helper.rb
         | 
| 194 | 
            +
            - test/test_falls_back_on.rb
         | 
| @@ -1,35 +0,0 @@ | |
| 1 | 
            -
            class Fallback < ActiveRecord::Base
         | 
| 2 | 
            -
              index :name if respond_to? :index
         | 
| 3 | 
            -
              
         | 
| 4 | 
            -
              serialize :values
         | 
| 5 | 
            -
              
         | 
| 6 | 
            -
              class << self
         | 
| 7 | 
            -
                def get_for(name)
         | 
| 8 | 
            -
                  klass = name.constantize
         | 
| 9 | 
            -
                  if fallback = find_by_name(name)
         | 
| 10 | 
            -
                    begin
         | 
| 11 | 
            -
                      f = klass.new(fallback.values)
         | 
| 12 | 
            -
                    rescue ActiveRecord::UnknownAttributeError
         | 
| 13 | 
            -
                      raise $!, "while trying to use #{fallback.values.inspect} with #{name} #{$!.inspect}"
         | 
| 14 | 
            -
                    end
         | 
| 15 | 
            -
                    f.readonly!
         | 
| 16 | 
            -
                    f
         | 
| 17 | 
            -
                  elsif klass.set_fallback
         | 
| 18 | 
            -
                    get_for(name)
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
                
         | 
| 22 | 
            -
                def set_for(name, values = {})
         | 
| 23 | 
            -
                  raise "fallback race condition" if Fallback.count > 100
         | 
| 24 | 
            -
                  fallback = find_or_create_by_name(name)
         | 
| 25 | 
            -
                  fallback.update_attributes(:values => values)
         | 
| 26 | 
            -
                  true
         | 
| 27 | 
            -
                end
         | 
| 28 | 
            -
                
         | 
| 29 | 
            -
                def destroy_for(name)
         | 
| 30 | 
            -
                  fallback = find_by_name(name.to_s)
         | 
| 31 | 
            -
                  fallback.destroy unless fallback.nil?
         | 
| 32 | 
            -
                  true
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
            end
         | 
| @@ -1,19 +0,0 @@ | |
| 1 | 
            -
            require 'spec_helper'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class Arcade < ActiveRecord::Base
         | 
| 4 | 
            -
              attr_accessor :pinball_count, :video_game_count
         | 
| 5 | 
            -
             | 
| 6 | 
            -
              falls_back_on :pinball_count => 73
         | 
| 7 | 
            -
            end
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            describe Fallback do
         | 
| 10 | 
            -
              describe '.destroy_for' do
         | 
| 11 | 
            -
                it 'should destroy a fallback' do
         | 
| 12 | 
            -
                  Fallback.create :name => 'Arcade'
         | 
| 13 | 
            -
                  expect do
         | 
| 14 | 
            -
                    Fallback.destroy_for Arcade
         | 
| 15 | 
            -
                  end.should change(Fallback, :count).by(-1)
         | 
| 16 | 
            -
                end
         | 
| 17 | 
            -
              end
         | 
| 18 | 
            -
            end
         | 
| 19 | 
            -
             | 
| @@ -1,24 +0,0 @@ | |
| 1 | 
            -
            require 'spec_helper'
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            class State < ActiveRecord::Base
         | 
| 4 | 
            -
              falls_back_on :area => 10000
         | 
| 5 | 
            -
            end
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            describe FallsBackOn do
         | 
| 8 | 
            -
              describe '.class_name' do
         | 
| 9 | 
            -
                it 'should return the class name' do
         | 
| 10 | 
            -
                  State.class_name.should == 'State'
         | 
| 11 | 
            -
                end
         | 
| 12 | 
            -
              end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
              describe '.set_fallback' do
         | 
| 15 | 
            -
                it 'should create a Fallback for a class' do
         | 
| 16 | 
            -
                  State.set_fallback
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  fallback = Fallback.find_by_name 'State'
         | 
| 19 | 
            -
                  fallback.should be_an_instance_of(Fallback)
         | 
| 20 | 
            -
                  fallback.values.should == {:area => 10000 }
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
            end
         | 
| 24 | 
            -
             | 
    
        data/spec/spec_helper.rb
    DELETED
    
    | @@ -1,33 +0,0 @@ | |
| 1 | 
            -
            require 'rubygems'
         | 
| 2 | 
            -
            require 'bundler'
         | 
| 3 | 
            -
            begin
         | 
| 4 | 
            -
              Bundler.setup
         | 
| 5 | 
            -
            rescue Bundler::BundlerError => e
         | 
| 6 | 
            -
              $stderr.puts e.message
         | 
| 7 | 
            -
              $stderr.puts "Run `bundle install` to install missing gems"
         | 
| 8 | 
            -
              exit e.status_code
         | 
| 9 | 
            -
            end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            require 'active_record'
         | 
| 12 | 
            -
            require 'logger'
         | 
| 13 | 
            -
             | 
| 14 | 
            -
            $:.unshift File.expand_path('../lib', __FILE__)
         | 
| 15 | 
            -
            require 'falls_back_on'
         | 
| 16 | 
            -
            require 'falls_back_on/active_record_ext'
         | 
| 17 | 
            -
            require 'falls_back_on/app/models/fallback'
         | 
| 18 | 
            -
             | 
| 19 | 
            -
            ActiveRecord::Base.logger = Logger.new nil
         | 
| 20 | 
            -
            ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            ActiveRecord::Schema.define(:version => 1) do
         | 
| 23 | 
            -
              create_table "fallbacks", :force => true do |t|
         | 
| 24 | 
            -
                t.string   "name"
         | 
| 25 | 
            -
                t.text     "values"
         | 
| 26 | 
            -
                t.datetime "created_at"
         | 
| 27 | 
            -
                t.datetime "updated_at"
         | 
| 28 | 
            -
              end
         | 
| 29 | 
            -
             | 
| 30 | 
            -
              create_table 'states' do |t|
         | 
| 31 | 
            -
                t.integer 'area'
         | 
| 32 | 
            -
              end
         | 
| 33 | 
            -
            end
         |