offline_lookup 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/offline_lookup.rb +162 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 214a550c54e40d9f718478920e4f9ec0a4a8be16
|
4
|
+
data.tar.gz: 834b7a4a9b81da79a8fb10f23a0fe6a001c93579
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7d2994fff30186971db79cbf00d7e9f8cb6dbca51ade19522e73e7a74f765b1e4e798a982a3a98f1a9ed189b0fc33b7d710cc143e847601e483c619f2131cffc
|
7
|
+
data.tar.gz: 716e5f920f9492a1f3951eb5dc476625b4c2f031e875166602969c912577da1a65803462962cdd8ba69ccb7cc065b5a2f4c564afae7d98539e00d2d623833da7
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# IMPORTANT: don't use this for models that have a lot of data!!
|
2
|
+
#
|
3
|
+
# This is basically a in-memory pseudo-index intended to speed up quick, repeated
|
4
|
+
# finds of index table values without trips to an external db machine.
|
5
|
+
# It's also nicer syntax, e.g:
|
6
|
+
# TurnaroundLevel.two_hour_id
|
7
|
+
# TurnaroundLevel.quick_lookup("Two Hour")
|
8
|
+
# Service.last.turnaround_level.two_hour?
|
9
|
+
#
|
10
|
+
# In any ActiveRecord::Base subclass, use:
|
11
|
+
# >> use_offline_id_lookup column_name
|
12
|
+
# to define class methods that can convert between id and the corresponding
|
13
|
+
# value in column_name for the class, without going to the database
|
14
|
+
#
|
15
|
+
# column_name defaults to :name, but can be any column of the table
|
16
|
+
# use the :key keyword arg if you're interested in a key colun other than :id
|
17
|
+
#
|
18
|
+
# Usage example:
|
19
|
+
# class JobType < ActiveRecord::Base
|
20
|
+
# use_offline_id_lookup
|
21
|
+
# ...
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# This gives you:
|
25
|
+
# JobType.editing_id
|
26
|
+
# #=> 1
|
27
|
+
# JobType.name_for_id(1)
|
28
|
+
# #=> 'Editing'
|
29
|
+
# JobType.id_for_name('Editing')
|
30
|
+
# #=> 1
|
31
|
+
# with no db queries.
|
32
|
+
#
|
33
|
+
# You can use this on multiple column names (currently
|
34
|
+
# need to call use_offline_id_lookup once for each column name)
|
35
|
+
# class InvoiceLineItemType < ActiveRecord::Base
|
36
|
+
# use_offline_id_lookup :name
|
37
|
+
# use_offline_id_lookup :accounting_label
|
38
|
+
# ...
|
39
|
+
#
|
40
|
+
# You get InvoiceLineItemType.name_for_id(id) and
|
41
|
+
# InvoiceLineItemType.account_label_for_id(id), etc.
|
42
|
+
# Beware that if any value occurs more than once,
|
43
|
+
# either in the same column or different columns for
|
44
|
+
# which use_offline_id_lookup was called, the <name>_id
|
45
|
+
# method will only use the last column for which it was observed.
|
46
|
+
|
47
|
+
|
48
|
+
#!!!
|
49
|
+
# TODO: requires :methodize
|
50
|
+
#!!!
|
51
|
+
|
52
|
+
# TODO: provide multiple column names in a single call (e.g. firstname, lastname)
|
53
|
+
# TODO: support multiple offline lookups per model
|
54
|
+
# TODO: support scope arg in use_offline_lookup (partial index)
|
55
|
+
|
56
|
+
module OfflineLookup
|
57
|
+
module ActiveRecord
|
58
|
+
def use_offline_lookup(field = :name, key: :id, lookup_methods: true)
|
59
|
+
class_attribute :offline_lookup_values, :offline_lookup_options
|
60
|
+
self.offline_lookup_options = {field: field.to_s, key: key.to_s, lookup_methods: lookup_methods}.freeze
|
61
|
+
self.offline_lookup_values = self.all.pluck(key, field).to_h.freeze
|
62
|
+
|
63
|
+
include OfflineLookup::Base
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class Builder
|
68
|
+
def initialize(options)
|
69
|
+
@field = options[:field]
|
70
|
+
@key = options[:key]
|
71
|
+
end
|
72
|
+
|
73
|
+
def sanitize(string)
|
74
|
+
#:methodize went away. Where did it go?
|
75
|
+
#1. Replace illegal chars and _ boundaries with " " boundary
|
76
|
+
string = string.gsub(/[^a-zA-Z\d]+/," ").strip
|
77
|
+
#2. Insert " " boundary at snake-case boundaries
|
78
|
+
string.gsub!(/([a-z])([A-Z])/){|s| "#{$1} #{$2}"}
|
79
|
+
#3. underscore
|
80
|
+
string.gsub!(/\s+/, "_")
|
81
|
+
string.downcase!
|
82
|
+
#4. Append underscore if name begins with digit
|
83
|
+
string = "_#{string}" if string.length == 0 || string[0] =~ /\d/
|
84
|
+
return string
|
85
|
+
end
|
86
|
+
|
87
|
+
# e.g., :two_hour_id
|
88
|
+
def key_method_name(value)
|
89
|
+
sanitize "#{value}_#{@key}"
|
90
|
+
end
|
91
|
+
|
92
|
+
def lookup_method_name(value)
|
93
|
+
sanitize value.to_s
|
94
|
+
end
|
95
|
+
|
96
|
+
# e.g., :two_hour?
|
97
|
+
def indentiy_method_name(value)
|
98
|
+
lookup_method_name(value) + "?"
|
99
|
+
end
|
100
|
+
|
101
|
+
# e.g. :name_for_id(id)
|
102
|
+
def field_for_key_method_name
|
103
|
+
sanitize "#{@field}_for_#{@key}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# e.g. :id_for_name(name)
|
107
|
+
def key_for_field_method_name
|
108
|
+
sanitize "#{@key}_for_#{@field}"
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
module Base
|
114
|
+
extend ActiveSupport::Concern
|
115
|
+
|
116
|
+
included do
|
117
|
+
builder = OfflineLookup::Builder.new(self.offline_lookup_options)
|
118
|
+
|
119
|
+
### define value-named methods such as :two_hour_id and :two_hour?
|
120
|
+
|
121
|
+
self.offline_lookup_values.each do |key, value|
|
122
|
+
define_singleton_method(builder.key_method_name(value)) do
|
123
|
+
key
|
124
|
+
end
|
125
|
+
|
126
|
+
define_singleton_method(builder.indentiy_method_name(value)) do
|
127
|
+
self.attributes[self.offline_lookup_options[:key]] == key
|
128
|
+
end
|
129
|
+
|
130
|
+
# not "Offline", but lookup by indexed key. Also, synactic sugar.
|
131
|
+
if self.offline_lookup_options[:lookup_methods]
|
132
|
+
define_singleton_method(builder.lookup_method_name(value)) do
|
133
|
+
key = self.offline_lookup_values.find{|k, v| v.to_s == value.to_s}.first
|
134
|
+
find(key)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
### define statically-named methods where you pass in the named value, e.g., id_for_name(:two_hour)
|
141
|
+
|
142
|
+
define_singleton_method(builder.field_for_key_method_name) do |key_value|
|
143
|
+
self.offline_lookup_values[key_value]
|
144
|
+
end
|
145
|
+
|
146
|
+
define_singleton_method(builder.key_for_field_method_name) do |field_value|
|
147
|
+
self.offline_lookup_values.find{|k, v| v.to_s == field_value.to_s}.first
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
module ClassMethods
|
153
|
+
def quick_lookup(value)
|
154
|
+
key = self.offline_lookup_values.find{|k, v| v.to_s == value.to_s}.first
|
155
|
+
find(key)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
ActiveRecord::Base.extend OfflineLookup::ActiveRecord
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: offline_lookup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew Schwartz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-13 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Offline indexing of small tables for speed & convenience
|
14
|
+
email: ozydingo@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/offline_lookup.rb
|
20
|
+
homepage:
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.4.5
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Offline lookup
|
44
|
+
test_files: []
|