offline_lookup 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. checksums.yaml +7 -0
  2. data/lib/offline_lookup.rb +162 -0
  3. metadata +44 -0
@@ -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: []