lookup_by 0.2.0 → 0.3.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.
- 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
|