offline_lookup 0.0.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.
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: []