lookup_by 0.9.1 → 0.10.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.
- checksums.yaml +4 -4
- data/.ruby-version +1 -1
- data/.travis.yml +5 -4
- data/.yardopts +1 -0
- data/Appraisals +1 -5
- data/Gemfile +1 -1
- data/README.md +39 -8
- data/gemfiles/rails_4.0.gemfile +1 -1
- data/gemfiles/rails_4.1.gemfile +1 -1
- data/gemfiles/rails_4.2.gemfile +2 -2
- data/lib/lookup_by/association.rb +16 -7
- data/lib/lookup_by/cache.rb +64 -25
- data/lib/lookup_by/lookup.rb +29 -5
- data/lib/lookup_by/version.rb +1 -1
- data/lib/lookup_by.rb +34 -0
- data/lookup_by.gemspec +2 -2
- data/spec/association_spec.rb +19 -2
- data/spec/dummy/app/models/account.rb +3 -1
- data/spec/dummy/app/models/country.rb +1 -0
- data/spec/dummy/app/models/phone_number.rb +5 -0
- data/spec/dummy/config/application.rb +0 -2
- data/spec/dummy/config/database.yml +0 -8
- data/spec/dummy/db/migrate/20121019040009_create_tables.rb +8 -2
- data/spec/dummy/db/structure.sql +61 -1
- data/spec/lookup_by_spec.rb +75 -10
- data/spec/rails_helper.rb +0 -2
- data/spec/spec_helper.rb +30 -19
- data/spec/support/shared_examples_for_a_lookup.rb +1 -1
- metadata +12 -10
- data/gemfiles/rails_3.2.gemfile +0 -22
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: b7b482a9755de8d24837b3555d53cc416b77ac87
         | 
| 4 | 
            +
              data.tar.gz: 087b776e7ad8c89b4fcb90a63769820c6279d81e
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 2d728f55c1da30eb53de8d33397bb4b6fbe1c1d1b9003d03f11db296d34455c65d5a0f16058f904b298b9050cc5b86ee69d88223cb942c6ff9419dadf34e2501
         | 
| 7 | 
            +
              data.tar.gz: 62479abc739d5125a2feffa8589236f4e1f83fd9a391b343bb5f49ac3510dd05293c221cb4b3521362a659804a021ce7a114556d045fc2644a223faa88a7afd9
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            ruby-2. | 
| 1 | 
            +
            ruby-2.2.0
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/.yardopts
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            --markup markdown
         | 
    
        data/Appraisals
    CHANGED
    
    | @@ -1,7 +1,3 @@ | |
| 1 | 
            -
            appraise 'rails-3.2' do
         | 
| 2 | 
            -
              gem 'rails', '~> 3.2.0'
         | 
| 3 | 
            -
            end
         | 
| 4 | 
            -
             | 
| 5 1 | 
             
            appraise 'rails-4.0' do
         | 
| 6 2 | 
             
              gem 'rails', '~> 4.0.0'
         | 
| 7 3 | 
             
            end
         | 
| @@ -11,5 +7,5 @@ appraise 'rails-4.1' do | |
| 11 7 | 
             
            end
         | 
| 12 8 |  | 
| 13 9 | 
             
            appraise 'rails-4.2' do
         | 
| 14 | 
            -
              gem 'rails', '~> 4.2.0 | 
| 10 | 
            +
              gem 'rails', '~> 4.2.0'
         | 
| 15 11 | 
             
            end
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -25,7 +25,8 @@ LookupBy is a thread-safe lookup table cache for ActiveRecord that reduces norma | |
| 25 25 |  | 
| 26 26 | 
             
            ### Dependencies
         | 
| 27 27 |  | 
| 28 | 
            -
            * Rails  | 
| 28 | 
            +
            * Rails 4.0+, _tested on Rails 4.0, 4.1, and 4.2_
         | 
| 29 | 
            +
            * Ruby 1.9.3+, _tested on Ruby 1.9.3, 2.0, 2.1, 2.2 and Rubinius 1.5.2_
         | 
| 29 30 | 
             
            * PostgreSQL
         | 
| 30 31 |  | 
| 31 32 | 
             
            ### Development
         | 
| @@ -64,12 +65,16 @@ Or install it manually: | |
| 64 65 | 
             
            LookupBy adds two "macro" methods to `ActiveRecord::Base`
         | 
| 65 66 |  | 
| 66 67 | 
             
            ```ruby
         | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
             | 
| 70 | 
            -
             | 
| 71 | 
            -
             | 
| 72 | 
            -
             | 
| 68 | 
            +
            class ExampleLookup < ActiveRecord::Base
         | 
| 69 | 
            +
              lookup_by :column_name
         | 
| 70 | 
            +
              # Defines .[], .lookup, .is_a_lookup?, and .seed class methods.
         | 
| 71 | 
            +
            end
         | 
| 72 | 
            +
              
         | 
| 73 | 
            +
            class ExampleObject < ActiveRecord::Base
         | 
| 74 | 
            +
              lookup_for :status
         | 
| 75 | 
            +
              # Defines #status and #status= instance methods that transparently reference the lookup table.
         | 
| 76 | 
            +
              # Defines .with_status(*names) and .without_status(*names) scopes on the model.
         | 
| 77 | 
            +
            end
         | 
| 73 78 | 
             
            ```
         | 
| 74 79 |  | 
| 75 80 | 
             
            ### Define the lookup model
         | 
| @@ -98,6 +103,9 @@ class Status < ActiveRecord::Base | |
| 98 103 | 
             
              lookup_by :status
         | 
| 99 104 | 
             
            end
         | 
| 100 105 |  | 
| 106 | 
            +
            # Seed some values
         | 
| 107 | 
            +
            Status.seed *%w[unpaid paid shipped]
         | 
| 108 | 
            +
             | 
| 101 109 | 
             
            # Aliases :name to the lookup attribute
         | 
| 102 110 | 
             
            Status.new(name: "paid")
         | 
| 103 111 | 
             
            ```
         | 
| @@ -140,6 +148,29 @@ Order.column_names | |
| 140 148 | 
             
            => ["order_id", "status_id"]
         | 
| 141 149 | 
             
            ```
         | 
| 142 150 |  | 
| 151 | 
            +
            ### Seed the lookup table
         | 
| 152 | 
            +
             | 
| 153 | 
            +
            ```ruby
         | 
| 154 | 
            +
            # Find or create each argument
         | 
| 155 | 
            +
            Status.seed *%w[unpaid paid shipped returned]
         | 
| 156 | 
            +
            ```
         | 
| 157 | 
            +
             | 
| 158 | 
            +
            ### Manage lookups globally
         | 
| 159 | 
            +
             | 
| 160 | 
            +
            ```ruby
         | 
| 161 | 
            +
            # Clear all caches
         | 
| 162 | 
            +
            LookupBy.clear
         | 
| 163 | 
            +
             | 
| 164 | 
            +
            # Disable all
         | 
| 165 | 
            +
            LookupBy.disable
         | 
| 166 | 
            +
             | 
| 167 | 
            +
            # Enable all, this will reload the caches
         | 
| 168 | 
            +
            LookupBy.enable
         | 
| 169 | 
            +
             | 
| 170 | 
            +
            # Reload all caches
         | 
| 171 | 
            +
            LookupBy.reload
         | 
| 172 | 
            +
            ```
         | 
| 173 | 
            +
             | 
| 143 174 | 
             
            # Configuration
         | 
| 144 175 |  | 
| 145 176 | 
             
            ### Symbolize
         | 
| @@ -239,7 +270,7 @@ lookup_by :column_name | |
| 239 270 | 
             
            lookup_by :column_name, cache: 20, find_or_create: true
         | 
| 240 271 | 
             
            ```
         | 
| 241 272 |  | 
| 242 | 
            -
            ### Raise on  | 
| 273 | 
            +
            ### Raise on miss
         | 
| 243 274 |  | 
| 244 275 | 
             
            Configure cache misses to raise a `LookupBy::RecordNotFound` error.
         | 
| 245 276 |  | 
    
        data/gemfiles/rails_4.0.gemfile
    CHANGED
    
    
    
        data/gemfiles/rails_4.1.gemfile
    CHANGED
    
    
    
        data/gemfiles/rails_4.2.gemfile
    CHANGED
    
    | @@ -2,10 +2,10 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            source "https://rubygems.org"
         | 
| 4 4 |  | 
| 5 | 
            -
            gem "rails", "~> 4.2.0 | 
| 5 | 
            +
            gem "rails", "~> 4.2.0"
         | 
| 6 6 |  | 
| 7 7 | 
             
            group :development, :test do
         | 
| 8 | 
            -
              gem "appraisal", "~> 1.0", :require => false
         | 
| 8 | 
            +
              gem "appraisal", "~> 1.0.0", :require => false
         | 
| 9 9 | 
             
              gem "rspec"
         | 
| 10 10 | 
             
              gem "rspec-its"
         | 
| 11 11 | 
             
              gem "rspec-rails"
         | 
| @@ -13,6 +13,7 @@ | |
| 13 13 | 
             
            module LookupBy
         | 
| 14 14 | 
             
              module Association
         | 
| 15 15 | 
             
                module MacroMethods
         | 
| 16 | 
            +
                  # @see https://practicingruby.com/articles/closures-are-complicated
         | 
| 16 17 | 
             
                  def lookup_for field, options = {}
         | 
| 17 18 | 
             
                    begin
         | 
| 18 19 | 
             
                      return unless table_exists?
         | 
| @@ -116,24 +117,32 @@ module LookupBy | |
| 116 117 | 
             
                      end
         | 
| 117 118 |  | 
| 118 119 | 
             
                      def #{field}=(arg)
         | 
| 119 | 
            -
                         | 
| 120 | 
            +
                        result = case arg
         | 
| 120 121 | 
             
                        when nil
         | 
| 121 122 | 
             
                          nil
         | 
| 122 123 | 
             
                        when String, Integer, IPAddr
         | 
| 123 | 
            -
                          #{class_name}[arg] | 
| 124 | 
            +
                          #{class_name}[arg]
         | 
| 124 125 | 
             
                        when Symbol
         | 
| 125 126 | 
             
                          #{%Q(raise ArgumentError, "#{foreign_key}=(Symbol): use `lookup_for :column, symbolize: true` to allow symbols") unless options[:symbolize]}
         | 
| 126 | 
            -
                          #{class_name}[arg] | 
| 127 | 
            +
                          #{class_name}[arg]
         | 
| 127 128 | 
             
                        when #{class_name}
         | 
| 128 | 
            -
                          raise ArgumentError, "self.#{foreign_key}=(#{class_name}): must be saved" unless arg. | 
| 129 | 
            -
                          arg | 
| 129 | 
            +
                          raise ArgumentError, "self.#{foreign_key}=(#{class_name}): must be saved" unless arg.persisted?
         | 
| 130 | 
            +
                          arg
         | 
| 130 131 | 
             
                        else
         | 
| 131 132 | 
             
                          raise TypeError, "#{foreign_key}=(arg): arg must be a String, Symbol, Integer, IPAddr, nil, or #{class_name}"
         | 
| 132 133 | 
             
                        end
         | 
| 133 134 |  | 
| 134 | 
            -
                        #{%Q(raise LookupBy::Error, "\#{arg.inspect} is not in the <#{class_name}> lookup cache" if arg.present? &&  | 
| 135 | 
            +
                        #{ %Q(raise LookupBy::Error, "\#{arg.inspect} is not in the <#{class_name}> lookup cache" if arg.present? && result.nil?) if strict }
         | 
| 135 136 |  | 
| 136 | 
            -
                         | 
| 137 | 
            +
                        if result.blank?
         | 
| 138 | 
            +
                          self.#{foreign_key} = nil
         | 
| 139 | 
            +
                        elsif result.persisted?
         | 
| 140 | 
            +
                          self.#{foreign_key} = result.id
         | 
| 141 | 
            +
                        elsif lookup_errors = result.errors[:#{lookup_field}]
         | 
| 142 | 
            +
                          lookup_errors.each do |msg|
         | 
| 143 | 
            +
                            errors.add :#{field}, msg
         | 
| 144 | 
            +
                          end
         | 
| 145 | 
            +
                        end
         | 
| 137 146 | 
             
                      end
         | 
| 138 147 | 
             
                    METHODS
         | 
| 139 148 | 
             
                  end
         | 
    
        data/lib/lookup_by/cache.rb
    CHANGED
    
    | @@ -9,6 +9,7 @@ module LookupBy | |
| 9 9 | 
             
                  @primary_key_type = klass.columns_hash[@primary_key].type
         | 
| 10 10 | 
             
                  @field            = options[:field].to_sym
         | 
| 11 11 | 
             
                  @cache            = {}
         | 
| 12 | 
            +
                  @reverse          = {}
         | 
| 12 13 | 
             
                  @order            = options[:order] || @field
         | 
| 13 14 | 
             
                  @read             = options[:find_or_create] || options[:find]
         | 
| 14 15 | 
             
                  @write            = options[:find_or_create]
         | 
| @@ -18,11 +19,13 @@ module LookupBy | |
| 18 19 | 
             
                  @testing          = false
         | 
| 19 20 | 
             
                  @enabled          = true
         | 
| 20 21 | 
             
                  @safe             = options[:safe] || concurrent?
         | 
| 22 | 
            +
                  @mutex            = Mutex.new if @safe
         | 
| 21 23 |  | 
| 22 24 | 
             
                  @stats            = { db: Hash.new(0), cache: Hash.new(0) }
         | 
| 23 25 |  | 
| 24 26 | 
             
                  raise ArgumentError, %Q(unknown attribute "#{@field}" for <#{klass}>) unless klass.column_names.include?(@field.to_s)
         | 
| 25 27 |  | 
| 28 | 
            +
                  # Order matters here, some instance variables depend on prior assignments.
         | 
| 26 29 | 
             
                  case options[:cache]
         | 
| 27 30 | 
             
                  when true
         | 
| 28 31 | 
             
                    @type    = :all
         | 
| @@ -35,6 +38,7 @@ module LookupBy | |
| 35 38 | 
             
                    @type    = :lru
         | 
| 36 39 | 
             
                    @limit   = options[:cache]
         | 
| 37 40 | 
             
                    @cache   = @safe ? Caching::SafeLRU.new(@limit) : Caching::LRU.new(@limit)
         | 
| 41 | 
            +
                    @reverse = @safe ? Caching::SafeLRU.new(@limit) : Caching::LRU.new(@limit)
         | 
| 38 42 | 
             
                    @read    = true
         | 
| 39 43 | 
             
                    @write ||= false
         | 
| 40 44 | 
             
                    @testing = true if Rails.env.test? && @write
         | 
| @@ -53,8 +57,8 @@ module LookupBy | |
| 53 57 | 
             
                  clear
         | 
| 54 58 |  | 
| 55 59 | 
             
                  ::ActiveRecord::Base.connection.send :log, "", "#{@klass.name} Load Cache All" do
         | 
| 56 | 
            -
                    @klass.order(@order).each do | | 
| 57 | 
            -
                       | 
| 60 | 
            +
                    @klass.order(@order).each do |object|
         | 
| 61 | 
            +
                      cache_write(object)
         | 
| 58 62 | 
             
                    end
         | 
| 59 63 | 
             
                  end
         | 
| 60 64 | 
             
                end
         | 
| @@ -65,19 +69,23 @@ module LookupBy | |
| 65 69 |  | 
| 66 70 | 
             
                def create(*args, &block)
         | 
| 67 71 | 
             
                  created = @klass.create(*args, &block)
         | 
| 68 | 
            -
             | 
| 72 | 
            +
             | 
| 73 | 
            +
                  cache_write(created) if cache?
         | 
| 74 | 
            +
             | 
| 69 75 | 
             
                  created
         | 
| 70 76 | 
             
                end
         | 
| 71 77 |  | 
| 72 78 | 
             
                def create!(*args, &block)
         | 
| 73 79 | 
             
                  created = @klass.create!(*args, &block)
         | 
| 74 | 
            -
             | 
| 80 | 
            +
             | 
| 81 | 
            +
                  cache_write(created) if cache?
         | 
| 82 | 
            +
             | 
| 75 83 | 
             
                  created
         | 
| 76 84 | 
             
                end
         | 
| 77 85 |  | 
| 78 86 | 
             
                def seed(*values)
         | 
| 79 87 | 
             
                  @klass.transaction(requires_new: true) do
         | 
| 80 | 
            -
                    values. | 
| 88 | 
            +
                    values.map { |value| @klass.where(@field => value).first_or_create! }
         | 
| 81 89 | 
             
                  end
         | 
| 82 90 | 
             
                end
         | 
| 83 91 |  | 
| @@ -89,7 +97,7 @@ module LookupBy | |
| 89 97 | 
             
                  found = cache_read(value) if cache?
         | 
| 90 98 | 
             
                  found ||= db_read(value)  if @read || !@enabled
         | 
| 91 99 |  | 
| 92 | 
            -
                   | 
| 100 | 
            +
                  cache_write(found) if cache?
         | 
| 93 101 |  | 
| 94 102 | 
             
                  found ||= db_write(value) if @write
         | 
| 95 103 |  | 
| @@ -132,13 +140,9 @@ module LookupBy | |
| 132 140 |  | 
| 133 141 | 
             
              private
         | 
| 134 142 |  | 
| 143 | 
            +
                # RAILS_ENV=test will not use the SafeLRU
         | 
| 135 144 | 
             
                def concurrent?
         | 
| 136 | 
            -
                   | 
| 137 | 
            -
                  when 4 then Rails.configuration.cache_classes && Rails.configuration.eager_load
         | 
| 138 | 
            -
                  when 3 then Rails.configuration.allow_concurrency
         | 
| 139 | 
            -
                  else
         | 
| 140 | 
            -
                    true
         | 
| 141 | 
            -
                  end
         | 
| 145 | 
            +
                  Rails.configuration.cache_classes && Rails.configuration.eager_load
         | 
| 142 146 | 
             
                end
         | 
| 143 147 |  | 
| 144 148 | 
             
                def primary_key?(value)
         | 
| @@ -154,26 +158,61 @@ module LookupBy | |
| 154 158 | 
             
                  @klass.new(@field => value).send(@field)
         | 
| 155 159 | 
             
                end
         | 
| 156 160 |  | 
| 157 | 
            -
             | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 161 | 
            +
             | 
| 162 | 
            +
                if Rails.env.production?
         | 
| 163 | 
            +
                  def cache_read(value)
         | 
| 164 | 
            +
                    if primary_key?(value)
         | 
| 165 | 
            +
                      @cache[value]
         | 
| 166 | 
            +
                    else
         | 
| 167 | 
            +
                      @reverse[value]
         | 
| 168 | 
            +
                    end
         | 
| 162 169 | 
             
                  end
         | 
| 170 | 
            +
                else
         | 
| 171 | 
            +
                  def cache_read(value)
         | 
| 172 | 
            +
                    found = if primary_key?(value)
         | 
| 173 | 
            +
                      @cache[value]
         | 
| 174 | 
            +
                    else
         | 
| 175 | 
            +
                      @reverse[value]
         | 
| 176 | 
            +
                    end
         | 
| 163 177 |  | 
| 164 | 
            -
             | 
| 178 | 
            +
                    increment :cache, found ? :hit : :miss
         | 
| 165 179 |  | 
| 166 | 
            -
             | 
| 180 | 
            +
                    found
         | 
| 181 | 
            +
                  end
         | 
| 167 182 | 
             
                end
         | 
| 168 183 |  | 
| 169 | 
            -
                 | 
| 170 | 
            -
                   | 
| 184 | 
            +
                if Rails.env.production?
         | 
| 185 | 
            +
                  def db_read(value)
         | 
| 186 | 
            +
                    @klass.where(column_for(value) => value).first
         | 
| 187 | 
            +
                  end
         | 
| 188 | 
            +
                else
         | 
| 189 | 
            +
                  def db_read(value)
         | 
| 190 | 
            +
                    increment :db, :get
         | 
| 171 191 |  | 
| 172 | 
            -
             | 
| 192 | 
            +
                    found = @klass.where(column_for(value) => value).first
         | 
| 173 193 |  | 
| 174 | 
            -
             | 
| 194 | 
            +
                    increment :db, found ? :hit : :miss
         | 
| 175 195 |  | 
| 176 | 
            -
             | 
| 196 | 
            +
                    found
         | 
| 197 | 
            +
                  end
         | 
| 198 | 
            +
                end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                if @safe
         | 
| 201 | 
            +
                  def cache_write(object)
         | 
| 202 | 
            +
                    return unless object
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    @mutex.synchronize do
         | 
| 205 | 
            +
                      @cache[object.id] = object
         | 
| 206 | 
            +
                      @reverse[object.send(@field)] = object
         | 
| 207 | 
            +
                    end
         | 
| 208 | 
            +
                  end
         | 
| 209 | 
            +
                else
         | 
| 210 | 
            +
                  def cache_write(object)
         | 
| 211 | 
            +
                    return unless object
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                    @cache[object.id] = object
         | 
| 214 | 
            +
                    @reverse[object.send(@field)] = object
         | 
| 215 | 
            +
                  end
         | 
| 177 216 | 
             
                end
         | 
| 178 217 |  | 
| 179 218 | 
             
                def db_write(value)
         | 
| @@ -182,7 +221,7 @@ module LookupBy | |
| 182 221 | 
             
                  return if column == @primary_key
         | 
| 183 222 |  | 
| 184 223 | 
             
                  @klass.transaction(requires_new: true) do
         | 
| 185 | 
            -
                    @klass.create | 
| 224 | 
            +
                    @klass.create(column => value)
         | 
| 186 225 | 
             
                  end
         | 
| 187 226 | 
             
                rescue ActiveRecord::RecordNotUnique
         | 
| 188 227 | 
             
                  db_read(value)
         | 
    
        data/lib/lookup_by/lookup.rb
    CHANGED
    
    | @@ -32,8 +32,8 @@ module LookupBy | |
| 32 32 | 
             
                    options.assert_valid_keys :allow_blank, :order, :cache, :normalize, :find, :find_or_create, :raise, :safe
         | 
| 33 33 |  | 
| 34 34 | 
             
                    raise "#{self} already called lookup_by" if is_a? Lookup::ClassMethods
         | 
| 35 | 
            -
                    raise "#{self} responds_to  | 
| 36 | 
            -
                    raise "#{self} responds_to  | 
| 35 | 
            +
                    raise "#{self} responds_to .[], needed for lookup_by"     if respond_to? :[]
         | 
| 36 | 
            +
                    raise "#{self} responds_to .lookup, needed for lookup_by" if respond_to? :lookup
         | 
| 37 37 |  | 
| 38 38 | 
             
                    extend ClassMethods
         | 
| 39 39 |  | 
| @@ -57,13 +57,15 @@ module LookupBy | |
| 57 57 | 
             
                      @lookup = Cache.new(self, options.merge(field: field))
         | 
| 58 58 | 
             
                      @lookup.reload
         | 
| 59 59 | 
             
                    end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    LookupBy.register self
         | 
| 60 62 | 
             
                  end
         | 
| 61 63 | 
             
                end
         | 
| 62 64 |  | 
| 63 65 | 
             
                module ClassMethods
         | 
| 64 66 | 
             
                  # TODO: Rails 4 needs to return a proxy object here
         | 
| 65 67 | 
             
                  def all(*args)
         | 
| 66 | 
            -
                    return super if Rails::VERSION::MAJOR  | 
| 68 | 
            +
                    return super if Rails::VERSION::MAJOR >= 4
         | 
| 67 69 | 
             
                    return super if @lookup.read_through?
         | 
| 68 70 | 
             
                    return super if args.any?
         | 
| 69 71 |  | 
| @@ -77,10 +79,11 @@ module LookupBy | |
| 77 79 | 
             
                    @lookup.cache.size
         | 
| 78 80 | 
             
                  end
         | 
| 79 81 |  | 
| 80 | 
            -
                  def pluck( | 
| 82 | 
            +
                  def pluck(*column_names)
         | 
| 81 83 | 
             
                    return super if @lookup.read_through?
         | 
| 84 | 
            +
                    return super if column_names.size > 1
         | 
| 82 85 |  | 
| 83 | 
            -
                    @lookup.cache.values.map { |o| o.send( | 
| 86 | 
            +
                    @lookup.cache.values.map { |o| o.send(column_names.first) }
         | 
| 84 87 | 
             
                  end
         | 
| 85 88 |  | 
| 86 89 | 
             
                  def [](*args)
         | 
| @@ -100,6 +103,12 @@ module LookupBy | |
| 100 103 | 
             
                    else return args.map { |arg| self[arg] } 
         | 
| 101 104 | 
             
                    end
         | 
| 102 105 | 
             
                  end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                  def seed(*args)
         | 
| 108 | 
            +
                    super if defined?(super)
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    @lookup.seed *args
         | 
| 111 | 
            +
                  end
         | 
| 103 112 | 
             
                end
         | 
| 104 113 |  | 
| 105 114 | 
             
                module InstanceMethods
         | 
| @@ -116,6 +125,21 @@ module LookupBy | |
| 116 125 | 
             
                end
         | 
| 117 126 |  | 
| 118 127 | 
             
                module SchemaMethods
         | 
| 128 | 
            +
                  # Create a lookup table.
         | 
| 129 | 
            +
                  #
         | 
| 130 | 
            +
                  # @example
         | 
| 131 | 
            +
                  #   create_lookup_table :statuses, schema: "custom", small: true
         | 
| 132 | 
            +
                  #
         | 
| 133 | 
            +
                  #   create_lookup_table :companies do |t|
         | 
| 134 | 
            +
                  #     t.string :short_name
         | 
| 135 | 
            +
                  #   end
         | 
| 136 | 
            +
                  #
         | 
| 137 | 
            +
                  # @param [Symbol] name
         | 
| 138 | 
            +
                  # @param [Hash] options
         | 
| 139 | 
            +
                  # @option options [Symbol] lookup_column Name of the lookup column.
         | 
| 140 | 
            +
                  # @option options [Symbol] lookup_type   Type of the lookup column, _e.g. :text, :uuid, or :inet_.
         | 
| 141 | 
            +
                  # @option options [String] primary_key   Name of the primary key.
         | 
| 142 | 
            +
                  # @option options [String] schema
         | 
| 119 143 | 
             
                  def create_lookup_table(name, options = {})
         | 
| 120 144 | 
             
                    options.symbolize_keys!
         | 
| 121 145 |  | 
    
        data/lib/lookup_by/version.rb
    CHANGED
    
    
    
        data/lib/lookup_by.rb
    CHANGED
    
    | @@ -4,6 +4,12 @@ require "lookup_by/railtie" if defined? Rails | |
| 4 4 | 
             
            module LookupBy
         | 
| 5 5 | 
             
              class Error < StandardError; end
         | 
| 6 6 |  | 
| 7 | 
            +
              mattr_accessor :classes
         | 
| 8 | 
            +
              self.classes = []
         | 
| 9 | 
            +
             | 
| 10 | 
            +
              mattr_accessor :mutex
         | 
| 11 | 
            +
              self.mutex = Mutex.new
         | 
| 12 | 
            +
             | 
| 7 13 | 
             
              UUID_REGEX    = /\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\Z/
         | 
| 8 14 | 
             
              UUID_REGEX_V4 = /\A\h{8}-\h{4}-4\h{3}-[89aAbB]\h{3}-\h{12}\Z/
         | 
| 9 15 |  | 
| @@ -16,6 +22,34 @@ module LookupBy | |
| 16 22 | 
             
                autoload :LRU,       "lookup_by/caching/lru"
         | 
| 17 23 | 
             
                autoload :SafeLRU,   "lookup_by/caching/safe_lru"
         | 
| 18 24 | 
             
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              class << self
         | 
| 27 | 
            +
                def register(klass)
         | 
| 28 | 
            +
                  mutex.synchronize do
         | 
| 29 | 
            +
                    self.classes << klass unless classes.include?(klass)
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def lookups
         | 
| 34 | 
            +
                  classes.map { |klass| klass.lookup }
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def clear
         | 
| 38 | 
            +
                  lookups.each { |lookup| lookup.clear }
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def disable
         | 
| 42 | 
            +
                  lookups.each { |lookup| lookup.disable! }
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def enable
         | 
| 46 | 
            +
                  lookups.each { |lookup| lookup.enable! }
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def reload
         | 
| 50 | 
            +
                  lookups.each { |lookup| lookup.reload }
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 19 53 | 
             
            end
         | 
| 20 54 |  | 
| 21 55 | 
             
            begin
         | 
    
        data/lookup_by.gemspec
    CHANGED
    
    | @@ -22,8 +22,8 @@ Gem::Specification.new do |gem| | |
| 22 22 | 
             
              gem.test_files     = gem.files.grep(%r{^(test|spec|features)/})
         | 
| 23 23 | 
             
              gem.require_paths = ["lib"]
         | 
| 24 24 |  | 
| 25 | 
            -
              gem.add_dependency "rails", ">=  | 
| 25 | 
            +
              gem.add_dependency "rails", ">= 4.0.0"
         | 
| 26 26 |  | 
| 27 | 
            -
              gem.add_development_dependency "bundler", " | 
| 27 | 
            +
              gem.add_development_dependency "bundler", ">= 1.7.0"
         | 
| 28 28 | 
             
              gem.add_development_dependency "rake"
         | 
| 29 29 | 
             
            end
         | 
    
        data/spec/association_spec.rb
    CHANGED
    
    | @@ -62,12 +62,12 @@ describe LookupBy::Association do | |
| 62 62 | 
             
                it_behaves_like "a lookup for", :city
         | 
| 63 63 |  | 
| 64 64 | 
             
                it "accepts Integers" do
         | 
| 65 | 
            -
                  subject.city = City | 
| 65 | 
            +
                  subject.city = City["New York"].id
         | 
| 66 66 | 
             
                  expect(subject.city).to eq "New York"
         | 
| 67 67 | 
             
                end
         | 
| 68 68 |  | 
| 69 69 | 
             
                it "rejects symbols" do
         | 
| 70 | 
            -
                  expect { subject.city = : | 
| 70 | 
            +
                  expect { subject.city = :invalid }.to raise_error ArgumentError
         | 
| 71 71 | 
             
                end
         | 
| 72 72 |  | 
| 73 73 | 
             
                it "returns strings" do
         | 
| @@ -100,6 +100,8 @@ describe LookupBy::Association do | |
| 100 100 | 
             
              end
         | 
| 101 101 |  | 
| 102 102 | 
             
              context "Address.lookup_for :street" do
         | 
| 103 | 
            +
                it_behaves_like "a lookup for", :street
         | 
| 104 | 
            +
             | 
| 103 105 | 
             
                it "accepts write-through values" do
         | 
| 104 106 | 
             
                  expect { subject.street = "Dearborn Street" }.to change(Street, :count)
         | 
| 105 107 | 
             
                end
         | 
| @@ -192,3 +194,18 @@ describe LookupBy::Association, 'scopes' do | |
| 192 194 | 
             
                end
         | 
| 193 195 | 
             
              end
         | 
| 194 196 | 
             
            end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
            context 'validation' do
         | 
| 199 | 
            +
              subject { Account.new(phone_number: "invalid") }
         | 
| 200 | 
            +
             | 
| 201 | 
            +
              # it { is_expected.to have(2).errors_on(:phone_number) }
         | 
| 202 | 
            +
              # it { expect(subject).to have(2).errors_on(:phone_number) }
         | 
| 203 | 
            +
             | 
| 204 | 
            +
              # it 'bubbles errors' do
         | 
| 205 | 
            +
              #   expect(subject).to have(2).errors_on(:phone_number)
         | 
| 206 | 
            +
              # end
         | 
| 207 | 
            +
             | 
| 208 | 
            +
              it 'bubbles errors' do
         | 
| 209 | 
            +
                expect(subject.errors[:phone_number].size).to eq(2)
         | 
| 210 | 
            +
              end
         | 
| 211 | 
            +
            end
         | 
| @@ -5,11 +5,13 @@ class CreateTables < ActiveRecord::Migration | |
| 5 5 | 
             
                create_lookup_table :user_agents
         | 
| 6 6 | 
             
                create_lookup_table :email_addresses
         | 
| 7 7 |  | 
| 8 | 
            -
             | 
| 8 | 
            +
             | 
| 9 9 | 
             
                create_lookup_table :statuses, small: true
         | 
| 10 10 |  | 
| 11 11 | 
             
                create_lookup_table :ip_addresses, lookup_type: :inet
         | 
| 12 12 |  | 
| 13 | 
            +
                create_lookup_table :phone_numbers
         | 
| 14 | 
            +
             | 
| 13 15 | 
             
                create_lookup_table :uncacheables
         | 
| 14 16 | 
             
                create_lookup_table :unfindables
         | 
| 15 17 |  | 
| @@ -24,7 +26,11 @@ class CreateTables < ActiveRecord::Migration | |
| 24 26 |  | 
| 25 27 | 
             
                create_lookup_table :paths, schema: 'traffic', id: :uuid
         | 
| 26 28 |  | 
| 27 | 
            -
                 | 
| 29 | 
            +
                create_lookup_table :accounts do |t|
         | 
| 30 | 
            +
                  t.belongs_to :phone_number
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                create_lookup_table :addresses do |t|
         | 
| 28 34 | 
             
                  t.belongs_to :city
         | 
| 29 35 | 
             
                  t.belongs_to :state
         | 
| 30 36 | 
             
                  t.belongs_to :postal_code
         | 
    
        data/spec/dummy/db/structure.sql
    CHANGED
    
    | @@ -56,7 +56,8 @@ SET default_with_oids = false; | |
| 56 56 |  | 
| 57 57 | 
             
            CREATE TABLE accounts (
         | 
| 58 58 | 
             
                account_id integer NOT NULL,
         | 
| 59 | 
            -
                account text NOT NULL
         | 
| 59 | 
            +
                account text NOT NULL,
         | 
| 60 | 
            +
                phone_number_id integer
         | 
| 60 61 | 
             
            );
         | 
| 61 62 |  | 
| 62 63 |  | 
| @@ -85,6 +86,7 @@ ALTER SEQUENCE accounts_account_id_seq OWNED BY accounts.account_id; | |
| 85 86 |  | 
| 86 87 | 
             
            CREATE TABLE addresses (
         | 
| 87 88 | 
             
                address_id integer NOT NULL,
         | 
| 89 | 
            +
                address text NOT NULL,
         | 
| 88 90 | 
             
                city_id integer,
         | 
| 89 91 | 
             
                state_id integer,
         | 
| 90 92 | 
             
                postal_code_id integer,
         | 
| @@ -228,6 +230,35 @@ CREATE SEQUENCE ip_addresses_ip_address_id_seq | |
| 228 230 | 
             
            ALTER SEQUENCE ip_addresses_ip_address_id_seq OWNED BY ip_addresses.ip_address_id;
         | 
| 229 231 |  | 
| 230 232 |  | 
| 233 | 
            +
            --
         | 
| 234 | 
            +
            -- Name: phone_numbers; Type: TABLE; Schema: public; Owner: -; Tablespace: 
         | 
| 235 | 
            +
            --
         | 
| 236 | 
            +
             | 
| 237 | 
            +
            CREATE TABLE phone_numbers (
         | 
| 238 | 
            +
                phone_number_id integer NOT NULL,
         | 
| 239 | 
            +
                phone_number text NOT NULL
         | 
| 240 | 
            +
            );
         | 
| 241 | 
            +
             | 
| 242 | 
            +
             | 
| 243 | 
            +
            --
         | 
| 244 | 
            +
            -- Name: phone_numbers_phone_number_id_seq; Type: SEQUENCE; Schema: public; Owner: -
         | 
| 245 | 
            +
            --
         | 
| 246 | 
            +
             | 
| 247 | 
            +
            CREATE SEQUENCE phone_numbers_phone_number_id_seq
         | 
| 248 | 
            +
                START WITH 1
         | 
| 249 | 
            +
                INCREMENT BY 1
         | 
| 250 | 
            +
                NO MINVALUE
         | 
| 251 | 
            +
                NO MAXVALUE
         | 
| 252 | 
            +
                CACHE 1;
         | 
| 253 | 
            +
             | 
| 254 | 
            +
             | 
| 255 | 
            +
            --
         | 
| 256 | 
            +
            -- Name: phone_numbers_phone_number_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
         | 
| 257 | 
            +
            --
         | 
| 258 | 
            +
             | 
| 259 | 
            +
            ALTER SEQUENCE phone_numbers_phone_number_id_seq OWNED BY phone_numbers.phone_number_id;
         | 
| 260 | 
            +
             | 
| 261 | 
            +
             | 
| 231 262 | 
             
            --
         | 
| 232 263 | 
             
            -- Name: postal_codes; Type: TABLE; Schema: public; Owner: -; Tablespace: 
         | 
| 233 264 | 
             
            --
         | 
| @@ -583,6 +614,13 @@ ALTER TABLE ONLY email_addresses ALTER COLUMN email_address_id SET DEFAULT nextv | |
| 583 614 | 
             
            ALTER TABLE ONLY ip_addresses ALTER COLUMN ip_address_id SET DEFAULT nextval('ip_addresses_ip_address_id_seq'::regclass);
         | 
| 584 615 |  | 
| 585 616 |  | 
| 617 | 
            +
            --
         | 
| 618 | 
            +
            -- Name: phone_number_id; Type: DEFAULT; Schema: public; Owner: -
         | 
| 619 | 
            +
            --
         | 
| 620 | 
            +
             | 
| 621 | 
            +
            ALTER TABLE ONLY phone_numbers ALTER COLUMN phone_number_id SET DEFAULT nextval('phone_numbers_phone_number_id_seq'::regclass);
         | 
| 622 | 
            +
             | 
| 623 | 
            +
             | 
| 586 624 | 
             
            --
         | 
| 587 625 | 
             
            -- Name: postal_code_id; Type: DEFAULT; Schema: public; Owner: -
         | 
| 588 626 | 
             
            --
         | 
| @@ -701,6 +739,14 @@ ALTER TABLE ONLY ip_addresses | |
| 701 739 | 
             
                ADD CONSTRAINT ip_addresses_pkey PRIMARY KEY (ip_address_id);
         | 
| 702 740 |  | 
| 703 741 |  | 
| 742 | 
            +
            --
         | 
| 743 | 
            +
            -- Name: phone_numbers_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
         | 
| 744 | 
            +
            --
         | 
| 745 | 
            +
             | 
| 746 | 
            +
            ALTER TABLE ONLY phone_numbers
         | 
| 747 | 
            +
                ADD CONSTRAINT phone_numbers_pkey PRIMARY KEY (phone_number_id);
         | 
| 748 | 
            +
             | 
| 749 | 
            +
             | 
| 704 750 | 
             
            --
         | 
| 705 751 | 
             
            -- Name: postal_codes_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: 
         | 
| 706 752 | 
             
            --
         | 
| @@ -800,6 +846,13 @@ SET search_path = public, pg_catalog; | |
| 800 846 | 
             
            CREATE UNIQUE INDEX accounts__u_account ON accounts USING btree (account);
         | 
| 801 847 |  | 
| 802 848 |  | 
| 849 | 
            +
            --
         | 
| 850 | 
            +
            -- Name: addresses__u_address; Type: INDEX; Schema: public; Owner: -; Tablespace: 
         | 
| 851 | 
            +
            --
         | 
| 852 | 
            +
             | 
| 853 | 
            +
            CREATE UNIQUE INDEX addresses__u_address ON addresses USING btree (address);
         | 
| 854 | 
            +
             | 
| 855 | 
            +
             | 
| 803 856 | 
             
            --
         | 
| 804 857 | 
             
            -- Name: cities__u_city; Type: INDEX; Schema: public; Owner: -; Tablespace: 
         | 
| 805 858 | 
             
            --
         | 
| @@ -828,6 +881,13 @@ CREATE UNIQUE INDEX email_addresses__u_email_address ON email_addresses USING bt | |
| 828 881 | 
             
            CREATE UNIQUE INDEX ip_addresses__u_ip_address ON ip_addresses USING btree (ip_address);
         | 
| 829 882 |  | 
| 830 883 |  | 
| 884 | 
            +
            --
         | 
| 885 | 
            +
            -- Name: phone_numbers__u_phone_number; Type: INDEX; Schema: public; Owner: -; Tablespace: 
         | 
| 886 | 
            +
            --
         | 
| 887 | 
            +
             | 
| 888 | 
            +
            CREATE UNIQUE INDEX phone_numbers__u_phone_number ON phone_numbers USING btree (phone_number);
         | 
| 889 | 
            +
             | 
| 890 | 
            +
             | 
| 831 891 | 
             
            --
         | 
| 832 892 | 
             
            -- Name: postal_codes__u_postal_code; Type: INDEX; Schema: public; Owner: -; Tablespace: 
         | 
| 833 893 | 
             
            --
         | 
    
        data/spec/lookup_by_spec.rb
    CHANGED
    
    | @@ -1,6 +1,42 @@ | |
| 1 1 | 
             
            require "rails_helper"
         | 
| 2 2 | 
             
            require "lookup_by"
         | 
| 3 3 |  | 
| 4 | 
            +
            describe LookupBy do
         | 
| 5 | 
            +
              describe ".register" do
         | 
| 6 | 
            +
                it "adds its argument to .lookups" do
         | 
| 7 | 
            +
                  LookupBy.register(Array)
         | 
| 8 | 
            +
                  expect(LookupBy.classes).to include(Array)
         | 
| 9 | 
            +
                  LookupBy.classes.delete(Array)
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                it "doesn't register classes twice" do
         | 
| 13 | 
            +
                  LookupBy.register(Array)
         | 
| 14 | 
            +
                  LookupBy.register(Array)
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  expect(LookupBy.classes.select { |l| l == Array }.size).to eq(1)
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  LookupBy.classes.delete(Array)
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              describe ".clear" do
         | 
| 23 | 
            +
                it "clears all lookup caches" do
         | 
| 24 | 
            +
                  Path.lookup.cache[1] = "remove-this"
         | 
| 25 | 
            +
                  expect { LookupBy.clear }.to change { Path.lookup.cache.size }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              describe ".disable and .enable" do
         | 
| 30 | 
            +
                it "affects all lookups" do
         | 
| 31 | 
            +
                  expect(City.lookup.enabled?).to eq(true)
         | 
| 32 | 
            +
                  LookupBy.disable
         | 
| 33 | 
            +
                  expect(City.lookup.enabled?).to eq(false)
         | 
| 34 | 
            +
                  LookupBy.enable
         | 
| 35 | 
            +
                  expect(City.lookup.enabled?).to eq(true)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| 39 | 
            +
             | 
| 4 40 | 
             
            describe ::ActiveRecord::Base do
         | 
| 5 41 | 
             
              describe "macro methods" do
         | 
| 6 42 | 
             
                subject { described_class }
         | 
| @@ -9,26 +45,50 @@ describe ::ActiveRecord::Base do | |
| 9 45 | 
             
                it { is_expected.to respond_to :is_a_lookup? }
         | 
| 10 46 | 
             
              end
         | 
| 11 47 |  | 
| 48 | 
            +
              describe ".lookup_by" do
         | 
| 49 | 
            +
                class CityTest < ActiveRecord::Base
         | 
| 50 | 
            +
                  self.table_name = "cities"
         | 
| 51 | 
            +
                  lookup_by :city
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                it "registers lookup models" do
         | 
| 55 | 
            +
                  expect(LookupBy.classes).to include(CityTest)
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
              end
         | 
| 58 | 
            +
             | 
| 12 59 | 
             
              describe "instance methods" do
         | 
| 13 60 | 
             
                subject { Status.new }
         | 
| 14 61 |  | 
| 15 62 | 
             
                it { is_expected.to respond_to :name }
         | 
| 16 63 | 
             
              end
         | 
| 17 | 
            -
             | 
| 18 64 | 
             
            end
         | 
| 19 65 |  | 
| 20 | 
            -
            describe LookupBy::Lookup do
         | 
| 21 | 
            -
              describe " | 
| 22 | 
            -
                it " | 
| 23 | 
            -
                  City. | 
| 24 | 
            -
                  City. | 
| 66 | 
            +
            describe LookupBy::Lookup::ClassMethods do
         | 
| 67 | 
            +
              describe "#seed" do
         | 
| 68 | 
            +
                it "accepts multiple values" do
         | 
| 69 | 
            +
                  City.seed 'Boston'
         | 
| 70 | 
            +
                  City.seed 'Chicago', 'New York City'
         | 
| 25 71 |  | 
| 26 | 
            -
                   | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 72 | 
            +
                  expect(City.pluck(:city).sort).to eq(['Boston', 'Chicago', 'New York City'])
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                it "accepts duplicates" do
         | 
| 76 | 
            +
                  expect { City.seed 'Chicago', 'Chicago' }.not_to raise_error
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  if Rails::VERSION::MAJOR == 4 && Rails::VERSION::MINOR == 0
         | 
| 79 | 
            +
                    expect(City.pluck(:city)).to eq(['Chicago'])
         | 
| 80 | 
            +
                  else
         | 
| 81 | 
            +
                    expect(City.pluck(:name)).to eq(['Chicago'])
         | 
| 82 | 
            +
                  end
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                it "returns objects" do
         | 
| 86 | 
            +
                  expect(City.seed 'Chicago').to eq(City.all)
         | 
| 29 87 | 
             
                end
         | 
| 30 88 | 
             
              end
         | 
| 89 | 
            +
            end
         | 
| 31 90 |  | 
| 91 | 
            +
            describe LookupBy::Lookup do
         | 
| 32 92 | 
             
              context "Uncacheable.lookup_by :column, cache: true, find_or_create: true" do
         | 
| 33 93 | 
             
                it "fails when trying to cache and write-through" do
         | 
| 34 94 | 
             
                  expect { Uncacheable }.to raise_error
         | 
| @@ -83,7 +143,12 @@ describe LookupBy::Lookup do | |
| 83 143 | 
             
                it_behaves_like "a strict cache"
         | 
| 84 144 |  | 
| 85 145 | 
             
                it "preloads the cache" do
         | 
| 86 | 
            -
                   | 
| 146 | 
            +
                  class StateTest < ActiveRecord::Base
         | 
| 147 | 
            +
                    self.table_name = "states"
         | 
| 148 | 
            +
                    lookup_by :state, cache: true
         | 
| 149 | 
            +
                  end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                  expect(StateTest.lookup.cache).not_to be_empty
         | 
| 87 152 | 
             
                end
         | 
| 88 153 | 
             
              end
         | 
| 89 154 |  | 
    
        data/spec/rails_helper.rb
    CHANGED
    
    | @@ -39,8 +39,6 @@ Dir[Rails.root.join(  "../support/**/*.rb")].each { |f| require f } | |
| 39 39 | 
             
            # If you are not using ActiveRecord, you can remove this line.
         | 
| 40 40 | 
             
            ActiveRecord::Migration.maintain_test_schema! if ActiveRecord::Migration.respond_to?(:maintain_test_schema!)
         | 
| 41 41 |  | 
| 42 | 
            -
            # ActiveRecord::Migration.maintain_test_schema! if defined?(ActiveRecord::Migration) && ActiveRecord::Migration.respond_to?(:maintain_test_schema!)
         | 
| 43 | 
            -
             | 
| 44 42 | 
             
            RSpec.configure do |config|
         | 
| 45 43 | 
             
              config.use_transactional_fixtures = true
         | 
| 46 44 |  | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -15,6 +15,32 @@ | |
| 15 15 | 
             
            #
         | 
| 16 16 | 
             
            # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
         | 
| 17 17 | 
             
            RSpec.configure do |config|
         | 
| 18 | 
            +
              # rspec-expectations config goes here. You can use an alternate
         | 
| 19 | 
            +
              # assertion/expectation library such as wrong or the stdlib/minitest
         | 
| 20 | 
            +
              # assertions if you prefer.
         | 
| 21 | 
            +
              config.expect_with :rspec do |expectations|
         | 
| 22 | 
            +
                # Enable only the newer, non-monkey-patching expect syntax.
         | 
| 23 | 
            +
                # For more details, see:
         | 
| 24 | 
            +
                #   - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
         | 
| 25 | 
            +
                expectations.syntax = :expect
         | 
| 26 | 
            +
              end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              # rspec-mocks config goes here. You can use an alternate test double
         | 
| 29 | 
            +
              # library (such as bogus or mocha) by changing the `mock_with` option here.
         | 
| 30 | 
            +
              config.mock_with :rspec do |mocks|
         | 
| 31 | 
            +
                # Enable only the newer, non-monkey-patching expect syntax.
         | 
| 32 | 
            +
                # For more details, see:
         | 
| 33 | 
            +
                #   - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
         | 
| 34 | 
            +
                mocks.syntax = :expect
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                # Prevents you from mocking or stubbing a method that does not exist on
         | 
| 37 | 
            +
                # a real object. This is generally recommended.
         | 
| 38 | 
            +
                mocks.verify_partial_doubles = true
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
              # The settings below are suggested to provide a good initial experience
         | 
| 42 | 
            +
              # with RSpec, but feel free to customize to your heart's content.
         | 
| 43 | 
            +
             | 
| 18 44 | 
             
              # These two settings work together to allow you to limit a spec run
         | 
| 19 45 | 
             
              # to individual examples or groups you care about by tagging them with
         | 
| 20 46 | 
             
              # `:focus` metadata. When nothing is tagged with `:focus`, all examples
         | 
| @@ -49,26 +75,11 @@ RSpec.configure do |config| | |
| 49 75 | 
             
              # as the one that triggered the failure.
         | 
| 50 76 | 
             
              Kernel.srand config.seed
         | 
| 51 77 |  | 
| 52 | 
            -
               | 
| 53 | 
            -
             | 
| 54 | 
            -
              # assertions if you prefer.
         | 
| 55 | 
            -
              config.expect_with :rspec do |expectations|
         | 
| 56 | 
            -
                # Enable only the newer, non-monkey-patching expect syntax.
         | 
| 57 | 
            -
                # For more details, see:
         | 
| 58 | 
            -
                #   - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
         | 
| 59 | 
            -
                expectations.syntax = :expect
         | 
| 78 | 
            +
              config.before(:each) do
         | 
| 79 | 
            +
                LookupBy.reload
         | 
| 60 80 | 
             
              end
         | 
| 61 81 |  | 
| 62 | 
            -
               | 
| 63 | 
            -
             | 
| 64 | 
            -
              config.mock_with :rspec do |mocks|
         | 
| 65 | 
            -
                # Enable only the newer, non-monkey-patching expect syntax.
         | 
| 66 | 
            -
                # For more details, see:
         | 
| 67 | 
            -
                #   - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
         | 
| 68 | 
            -
                mocks.syntax = :expect
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                # Prevents you from mocking or stubbing a method that does not exist on
         | 
| 71 | 
            -
                # a real object. This is generally recommended.
         | 
| 72 | 
            -
                mocks.verify_partial_doubles = true
         | 
| 82 | 
            +
              config.after(:each) do
         | 
| 83 | 
            +
                LookupBy.clear
         | 
| 73 84 | 
             
              end
         | 
| 74 85 | 
             
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: lookup_by
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.10.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Erik Peterson
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2015-02-19 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: rails
         | 
| @@ -16,28 +16,28 @@ dependencies: | |
| 16 16 | 
             
                requirements:
         | 
| 17 17 | 
             
                - - ">="
         | 
| 18 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version:  | 
| 19 | 
            +
                    version: 4.0.0
         | 
| 20 20 | 
             
              type: :runtime
         | 
| 21 21 | 
             
              prerelease: false
         | 
| 22 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 23 | 
             
                requirements:
         | 
| 24 24 | 
             
                - - ">="
         | 
| 25 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version:  | 
| 26 | 
            +
                    version: 4.0.0
         | 
| 27 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 28 28 | 
             
              name: bundler
         | 
| 29 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 30 | 
             
                requirements:
         | 
| 31 | 
            -
                - - " | 
| 31 | 
            +
                - - ">="
         | 
| 32 32 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version:  | 
| 33 | 
            +
                    version: 1.7.0
         | 
| 34 34 | 
             
              type: :development
         | 
| 35 35 | 
             
              prerelease: false
         | 
| 36 36 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 37 | 
             
                requirements:
         | 
| 38 | 
            -
                - - " | 
| 38 | 
            +
                - - ">="
         | 
| 39 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version:  | 
| 40 | 
            +
                    version: 1.7.0
         | 
| 41 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 42 | 
             
              name: rake
         | 
| 43 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -62,13 +62,13 @@ files: | |
| 62 62 | 
             
            - ".gitignore"
         | 
| 63 63 | 
             
            - ".ruby-version"
         | 
| 64 64 | 
             
            - ".travis.yml"
         | 
| 65 | 
            +
            - ".yardopts"
         | 
| 65 66 | 
             
            - Appraisals
         | 
| 66 67 | 
             
            - Gemfile
         | 
| 67 68 | 
             
            - MIT-LICENSE
         | 
| 68 69 | 
             
            - README.md
         | 
| 69 70 | 
             
            - Rakefile
         | 
| 70 71 | 
             
            - TODO.md
         | 
| 71 | 
            -
            - gemfiles/rails_3.2.gemfile
         | 
| 72 72 | 
             
            - gemfiles/rails_4.0.gemfile
         | 
| 73 73 | 
             
            - gemfiles/rails_4.1.gemfile
         | 
| 74 74 | 
             
            - gemfiles/rails_4.2.gemfile
         | 
| @@ -96,6 +96,7 @@ files: | |
| 96 96 | 
             
            - spec/dummy/app/models/email_address.rb
         | 
| 97 97 | 
             
            - spec/dummy/app/models/ip_address.rb
         | 
| 98 98 | 
             
            - spec/dummy/app/models/path.rb
         | 
| 99 | 
            +
            - spec/dummy/app/models/phone_number.rb
         | 
| 99 100 | 
             
            - spec/dummy/app/models/postal_code.rb
         | 
| 100 101 | 
             
            - spec/dummy/app/models/raisin.rb
         | 
| 101 102 | 
             
            - spec/dummy/app/models/read_through_raisin.rb
         | 
| @@ -151,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 151 152 | 
             
                  version: '0'
         | 
| 152 153 | 
             
            requirements: []
         | 
| 153 154 | 
             
            rubyforge_project: 
         | 
| 154 | 
            -
            rubygems_version: 2.4. | 
| 155 | 
            +
            rubygems_version: 2.4.5
         | 
| 155 156 | 
             
            signing_key: 
         | 
| 156 157 | 
             
            specification_version: 4
         | 
| 157 158 | 
             
            summary: A thread-safe lookup table cache for ActiveRecord
         | 
| @@ -167,6 +168,7 @@ test_files: | |
| 167 168 | 
             
            - spec/dummy/app/models/email_address.rb
         | 
| 168 169 | 
             
            - spec/dummy/app/models/ip_address.rb
         | 
| 169 170 | 
             
            - spec/dummy/app/models/path.rb
         | 
| 171 | 
            +
            - spec/dummy/app/models/phone_number.rb
         | 
| 170 172 | 
             
            - spec/dummy/app/models/postal_code.rb
         | 
| 171 173 | 
             
            - spec/dummy/app/models/raisin.rb
         | 
| 172 174 | 
             
            - spec/dummy/app/models/read_through_raisin.rb
         | 
    
        data/gemfiles/rails_3.2.gemfile
    DELETED
    
    | @@ -1,22 +0,0 @@ | |
| 1 | 
            -
            # This file was generated by Appraisal
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            source "https://rubygems.org"
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            gem "rails", "~> 3.2.0"
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            group :development, :test do
         | 
| 8 | 
            -
              gem "appraisal", "~> 1.0", :require => false
         | 
| 9 | 
            -
              gem "rspec"
         | 
| 10 | 
            -
              gem "rspec-its"
         | 
| 11 | 
            -
              gem "rspec-rails"
         | 
| 12 | 
            -
              gem "pg", :platform => :ruby
         | 
| 13 | 
            -
              gem "activerecord-jdbcpostgresql-adapter", :platform => :jruby
         | 
| 14 | 
            -
              gem "simplecov", :require => false
         | 
| 15 | 
            -
              gem "coveralls", :require => false
         | 
| 16 | 
            -
              gem "pry", :require => false
         | 
| 17 | 
            -
              gem "colored", :require => false
         | 
| 18 | 
            -
              gem "racc"
         | 
| 19 | 
            -
              gem "json"
         | 
| 20 | 
            -
            end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
            gemspec :path => "../"
         |