lookup_by 0.2.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/Gemfile +1 -0
- data/Rakefile +0 -1
- data/lib/lookup_by.rb +3 -0
- data/lib/lookup_by/association.rb +9 -4
- data/lib/lookup_by/cache.rb +30 -15
- data/lib/lookup_by/lookup.rb +42 -13
- data/lib/lookup_by/version.rb +1 -1
- data/spec/dummy/Rakefile +8 -0
- data/spec/dummy/app/models/account.rb +0 -2
- data/spec/dummy/app/models/city.rb +0 -2
- data/spec/dummy/app/models/email_address.rb +0 -2
- data/spec/dummy/app/models/ip_address.rb +0 -2
- data/spec/dummy/app/models/path.rb +5 -0
- data/spec/dummy/app/models/postal_code.rb +0 -2
- data/spec/dummy/app/models/state.rb +0 -2
- data/spec/dummy/app/models/status.rb +0 -2
- data/spec/dummy/app/models/street.rb +0 -2
- data/spec/dummy/app/models/user_agent.rb +3 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +18 -10
- data/spec/dummy/config/boot.rb +4 -8
- data/spec/dummy/config/environment.rb +2 -2
- data/spec/dummy/config/environments/development.rb +19 -5
- data/spec/dummy/config/environments/production.rb +80 -0
- data/spec/dummy/config/environments/test.rb +25 -5
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +12 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/db/migrate/20121019040009_create_tables.rb +9 -6
- data/spec/dummy/db/seeds.rb +1 -0
- data/spec/dummy/db/structure.sql +616 -0
- data/spec/lookup_by_spec.rb +29 -2
- data/spec/spec_helper.rb +14 -1
- data/spec/support/shared_examples_for_a_lookup.rb +10 -8
- metadata +35 -3
- data/spec/dummy/db/schema.rb +0 -71
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 89c6960058f0ae2cbe8cb5654c37b331b0b25bd1
|
4
|
+
data.tar.gz: d13f7ed9c8e34d40b51e8c68983d19d9b5645cbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f09941d8870cde958762337e6f75d42bf88c44d37d06fe63f7fc91f60e4c79fc8b4c4cb183de0403dc02f0a43587e06f75f65ff43d0b3eea8297f9ef023839b1
|
7
|
+
data.tar.gz: 4e7c909cd63d81350726fc80066e211d92cdf8c5c447a78ae8830f6dcd5cbc7f2706c758d52a430ecf3cc0475e51ed674dba2ae030701dd12eedf83730698da2
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Rakefile
CHANGED
data/lib/lookup_by.rb
CHANGED
@@ -4,6 +4,9 @@ require "lookup_by/railtie" if defined? Rails
|
|
4
4
|
module LookupBy
|
5
5
|
class Error < StandardError; end
|
6
6
|
|
7
|
+
UUID_REGEX = /\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\Z/
|
8
|
+
UUID_REGEX_V4 = /\A\h{8}-\h{4}-4\h{3}-[89aAbB]\h{3}-\h{12}\Z/
|
9
|
+
|
7
10
|
autoload :Association, "lookup_by/association"
|
8
11
|
autoload :Cache, "lookup_by/cache"
|
9
12
|
autoload :Lookup, "lookup_by/lookup"
|
@@ -14,7 +14,12 @@ module LookupBy
|
|
14
14
|
module Association
|
15
15
|
module MacroMethods
|
16
16
|
def lookup_for field, options = {}
|
17
|
-
|
17
|
+
begin
|
18
|
+
return unless table_exists?
|
19
|
+
rescue => error
|
20
|
+
Rails.logger.error "lookup_by caught #{error.class.name} when connecting - skipping initialization (#{error.inspect})"
|
21
|
+
return
|
22
|
+
end
|
18
23
|
|
19
24
|
options.symbolize_keys!
|
20
25
|
options.assert_valid_keys(:class_name, :foreign_key, :symbolize, :strict, :scope)
|
@@ -84,9 +89,9 @@ module LookupBy
|
|
84
89
|
|
85
90
|
def #{field}=(arg)
|
86
91
|
value = case arg
|
87
|
-
when
|
92
|
+
when nil
|
88
93
|
nil
|
89
|
-
when String, Integer
|
94
|
+
when String, Integer, IPAddr
|
90
95
|
#{class_name}[arg].try(:id)
|
91
96
|
when Symbol
|
92
97
|
#{%Q(raise ArgumentError, "#{foreign_key}=(Symbol): use `lookup_for :column, symbolize: true` to allow symbols") unless options[:symbolize]}
|
@@ -95,7 +100,7 @@ module LookupBy
|
|
95
100
|
raise ArgumentError, "self.#{foreign_key}=(#{class_name}): must be saved" unless arg.id
|
96
101
|
arg.id
|
97
102
|
else
|
98
|
-
raise TypeError, "#{foreign_key}=(arg): arg must be a String, Symbol, Integer, nil, or #{class_name}"
|
103
|
+
raise TypeError, "#{foreign_key}=(arg): arg must be a String, Symbol, Integer, IPAddr, nil, or #{class_name}"
|
99
104
|
end
|
100
105
|
|
101
106
|
#{%Q(raise LookupBy::Error, "\#{arg.inspect} is not in the <#{class_name}> lookup cache" if arg.present? && value.nil?) if strict}
|
data/lib/lookup_by/cache.rb
CHANGED
@@ -4,18 +4,20 @@ module LookupBy
|
|
4
4
|
attr_accessor :testing
|
5
5
|
|
6
6
|
def initialize(klass, options = {})
|
7
|
-
@klass
|
8
|
-
@primary_key
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
17
|
-
|
18
|
-
@
|
7
|
+
@klass = klass
|
8
|
+
@primary_key = klass.primary_key
|
9
|
+
@primary_key_type = klass.columns_hash[@primary_key].type
|
10
|
+
@field = options[:field].to_sym
|
11
|
+
@cache = {}
|
12
|
+
@order = options[:order] || @field
|
13
|
+
@read = options[:find_or_create] || options[:find]
|
14
|
+
@write = options[:find_or_create]
|
15
|
+
@allow_blank = options[:allow_blank] || false
|
16
|
+
@normalize = options[:normalize]
|
17
|
+
@testing = false
|
18
|
+
@enabled = true
|
19
|
+
|
20
|
+
@stats = { db: Hash.new(0), cache: Hash.new(0) }
|
19
21
|
|
20
22
|
raise ArgumentError, %Q(unknown attribute "#{@field}" for <#{klass}>) unless klass.column_names.include?(@field.to_s)
|
21
23
|
|
@@ -62,7 +64,7 @@ module LookupBy
|
|
62
64
|
def fetch(value)
|
63
65
|
increment :cache, :get
|
64
66
|
|
65
|
-
value = normalize(value) if @normalize && !
|
67
|
+
value = normalize(value) if @normalize && !primary_key?(value)
|
66
68
|
|
67
69
|
found = cache_read(value) if cache?
|
68
70
|
found ||= db_read(value) if @read
|
@@ -83,6 +85,10 @@ module LookupBy
|
|
83
85
|
@read
|
84
86
|
end
|
85
87
|
|
88
|
+
def allow_blank?
|
89
|
+
@allow_blank
|
90
|
+
end
|
91
|
+
|
86
92
|
def enabled?
|
87
93
|
@enabled
|
88
94
|
end
|
@@ -103,12 +109,21 @@ module LookupBy
|
|
103
109
|
|
104
110
|
private
|
105
111
|
|
112
|
+
def primary_key?(value)
|
113
|
+
case @primary_key_type
|
114
|
+
when :integer
|
115
|
+
value.is_a? Integer
|
116
|
+
when :uuid
|
117
|
+
value =~ UUID_REGEX
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
106
121
|
def normalize(value)
|
107
122
|
@klass.new(@field => value).send(@field)
|
108
123
|
end
|
109
124
|
|
110
125
|
def cache_read(value)
|
111
|
-
if value
|
126
|
+
if primary_key?(value)
|
112
127
|
found = @cache[value]
|
113
128
|
else
|
114
129
|
found = @cache.values.detect { |o| o.send(@field) == value }
|
@@ -138,7 +153,7 @@ module LookupBy
|
|
138
153
|
end
|
139
154
|
|
140
155
|
def column_for(value)
|
141
|
-
|
156
|
+
primary_key?(value) ? @primary_key : @field
|
142
157
|
end
|
143
158
|
|
144
159
|
def cache?
|
data/lib/lookup_by/lookup.rb
CHANGED
@@ -18,8 +18,15 @@ module LookupBy
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def lookup_by(field, options = {})
|
21
|
+
begin
|
22
|
+
connection
|
23
|
+
rescue => error
|
24
|
+
Rails.logger.error "lookup_by caught #{error.class.name} when connecting - skipping initialization (#{error.inspect})"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
21
28
|
options.symbolize_keys!
|
22
|
-
options.assert_valid_keys :order, :cache, :normalize, :find, :find_or_create, :raise
|
29
|
+
options.assert_valid_keys :allow_blank, :order, :cache, :normalize, :find, :find_or_create, :raise
|
23
30
|
|
24
31
|
raise "#{self} already called lookup_by" if is_a? Lookup::ClassMethods
|
25
32
|
raise "#{self} responds_to :[], needed for lookup_by" if respond_to? :[]
|
@@ -51,7 +58,9 @@ module LookupBy
|
|
51
58
|
end
|
52
59
|
|
53
60
|
module ClassMethods
|
61
|
+
# TODO: Rails 4 needs to return a proxy object here
|
54
62
|
def all(*args)
|
63
|
+
return super if Rails::VERSION::MAJOR > 3
|
55
64
|
return super if @lookup.read_through?
|
56
65
|
return super if args.any?
|
57
66
|
|
@@ -76,10 +85,12 @@ module LookupBy
|
|
76
85
|
when 0 then raise ArgumentError, "#{name}[*args]: at least one argument is required"
|
77
86
|
when 1
|
78
87
|
case arg = args.first
|
79
|
-
when nil
|
88
|
+
when nil then nil
|
89
|
+
when "" then @lookup.allow_blank? ? @lookup.fetch(arg) : nil
|
80
90
|
when String then @lookup.fetch(arg)
|
81
|
-
when Symbol then @lookup.fetch(arg.to_s)
|
82
91
|
when Integer then @lookup.fetch(arg)
|
92
|
+
when Symbol then @lookup.fetch(arg.to_s)
|
93
|
+
when IPAddr then @lookup.fetch(arg.to_s)
|
83
94
|
when self then arg
|
84
95
|
else raise TypeError, "#{name}[arg]: arg must be at least one String, Symbol, Integer, nil, or #{name}"
|
85
96
|
end
|
@@ -91,7 +102,7 @@ module LookupBy
|
|
91
102
|
module InstanceMethods
|
92
103
|
def ===(arg)
|
93
104
|
case arg
|
94
|
-
when Symbol, String, Integer, nil
|
105
|
+
when Symbol, String, Integer, IPAddr, nil
|
95
106
|
return self == self.class[arg]
|
96
107
|
when Array
|
97
108
|
return arg.any? { |i| self === i }
|
@@ -102,22 +113,40 @@ module LookupBy
|
|
102
113
|
end
|
103
114
|
|
104
115
|
module SchemaMethods
|
105
|
-
def create_lookup_table(
|
106
|
-
|
107
|
-
|
116
|
+
def create_lookup_table(name, options = {})
|
117
|
+
options.symbolize_keys!
|
118
|
+
|
119
|
+
schema = options[:schema].to_s
|
108
120
|
|
109
|
-
|
110
|
-
|
121
|
+
if schema.present?
|
122
|
+
table = name.to_s
|
123
|
+
else
|
124
|
+
schema, table = name.to_s.split('.')
|
125
|
+
schema, table = nil, schema unless table
|
126
|
+
end
|
127
|
+
|
128
|
+
name = schema.blank? ? table : "#{schema}.#{table}"
|
129
|
+
|
130
|
+
lookup_column = options[:lookup_column] || table.singularize
|
131
|
+
lookup_type = options[:lookup_type] || :text
|
132
|
+
|
133
|
+
table_options = options.slice(:primary_key, :id)
|
134
|
+
table_options[:primary_key] ||= table.singularize + '_id'
|
135
|
+
|
136
|
+
create_table name, table_options do |t|
|
137
|
+
t.send lookup_type, lookup_column, null: false
|
111
138
|
|
112
139
|
yield t if block_given?
|
113
140
|
end
|
114
141
|
|
115
|
-
add_index
|
142
|
+
add_index name, lookup_column, unique: true, name: "#{table}__u_#{lookup_column}"
|
116
143
|
end
|
117
144
|
|
118
|
-
def create_lookup_tables(*
|
119
|
-
|
120
|
-
|
145
|
+
def create_lookup_tables(*names)
|
146
|
+
options = names.last.is_a?(Hash) ? names.pop : {}
|
147
|
+
|
148
|
+
names.each do |name|
|
149
|
+
create_lookup_table name, options
|
121
150
|
end
|
122
151
|
end
|
123
152
|
end
|
data/lib/lookup_by/version.rb
CHANGED
data/spec/dummy/Rakefile
CHANGED
data/spec/dummy/bin/rake
ADDED
@@ -1,20 +1,28 @@
|
|
1
1
|
require File.expand_path('../boot', __FILE__)
|
2
2
|
|
3
|
-
require "
|
3
|
+
require "rails/all"
|
4
|
+
|
5
|
+
# Require the gems listed in Gemfile, including any gems
|
6
|
+
# you've limited to :test, :development, or :production.
|
7
|
+
Bundler.require(:default, Rails.env)
|
4
8
|
|
5
|
-
Bundler.require
|
6
9
|
require "lookup_by"
|
7
10
|
|
8
11
|
module Dummy
|
9
12
|
class Application < Rails::Application
|
10
|
-
#
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
|
13
|
+
# Settings in config/environments/* take precedence over those specified here.
|
14
|
+
# Application configuration should go into files in config/initializers
|
15
|
+
# -- all .rb files in that directory are automatically loaded.
|
16
|
+
|
17
|
+
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
|
18
|
+
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
|
19
|
+
# config.time_zone = 'Central Time (US & Canada)'
|
20
|
+
|
21
|
+
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
22
|
+
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
23
|
+
# config.i18n.default_locale = :de
|
24
|
+
|
25
|
+
config.active_record.schema_format = :sql
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
data/spec/dummy/config/boot.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Set up gems listed in the Gemfile.
|
2
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
|
3
3
|
|
4
|
-
if File.
|
5
|
-
ENV['BUNDLE_GEMFILE'] = gemfile
|
6
|
-
require 'bundler'
|
7
|
-
Bundler.setup
|
8
|
-
end
|
4
|
+
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
9
5
|
|
10
|
-
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
6
|
+
$:.unshift File.expand_path('../../../../lib', __FILE__)
|
@@ -1,15 +1,29 @@
|
|
1
1
|
Dummy::Application.configure do
|
2
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
3
|
+
|
2
4
|
# In the development environment your application's code is reloaded on
|
3
5
|
# every request. This slows down response time but is perfect for development
|
4
6
|
# since you don't have to restart the web server when you make code changes.
|
5
7
|
config.cache_classes = false
|
6
8
|
|
7
|
-
#
|
8
|
-
config.
|
9
|
+
# Do not eager load code on boot.
|
10
|
+
config.eager_load = false
|
11
|
+
|
12
|
+
# Show full error reports and disable caching.
|
13
|
+
config.consider_all_requests_local = true
|
14
|
+
config.action_controller.perform_caching = false
|
9
15
|
|
10
|
-
#
|
16
|
+
# Don't care if the mailer can't send.
|
17
|
+
config.action_mailer.raise_delivery_errors = false
|
18
|
+
|
19
|
+
# Print deprecation notices to the Rails logger.
|
11
20
|
config.active_support.deprecation = :log
|
12
21
|
|
13
|
-
# Raise
|
14
|
-
config.active_record.
|
22
|
+
# Raise an error on page load if there are pending migrations
|
23
|
+
config.active_record.migration_error = :page_load
|
24
|
+
|
25
|
+
# Debug mode disables concatenation and preprocessing of assets.
|
26
|
+
# This option may cause significant delays in view rendering with a large
|
27
|
+
# number of complex assets.
|
28
|
+
config.assets.debug = true
|
15
29
|
end
|