offline_lookup 1.0.0 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a980e6edb149fd22cc7c81f2986ddac4e6ca27dc
4
- data.tar.gz: dedadea949a7706a88188eb2bd0a03b31530ac34
3
+ metadata.gz: 3f2b36619ce0489bb3be9209e0c6f375d6ad7b7f
4
+ data.tar.gz: 2a8b0b21903a8010032c6f99b9cfa5cfb7b5069d
5
5
  SHA512:
6
- metadata.gz: 1bd3263c95eb71ea8a2a5f511ee075a8a893eaf56f9aedf5c40b84c5addd49ad1230e2506270f407010c719391602e713e0ec8ea641585f3af134df3ecb63a9d
7
- data.tar.gz: cdefda2de296628c482b77bd156b08213a1205d696674682524ba6e99cc3ceb1be595d50e1d280ad6fae148146e76ed7f91b1e20c6b2a80511454aadace64ac4
6
+ metadata.gz: b1e8325950ade06e5daeeece7c496d717c26412c7be90119395442ef69f8cbd03f78b9dff2e9e1afb04dbd64710b5c7439215dce37da6683ce81a3f18eead93a
7
+ data.tar.gz: bf7fa6108c54b9dc3946d6ead0338e56f4a0996db3aabd14d83c75dc682694118c060a8bd66b5bce289bccc45e01c8e677b2a2891b31635395ba27d73ae10978
data/README.md CHANGED
@@ -138,6 +138,21 @@ end
138
138
  Admin.id_for_name("John Doe")
139
139
  ```
140
140
 
141
+ You can also define your own method of generaing the lookup name using the `:transform` options. The default is to ust the field, or delimiter-concatentaed fields. To specify a transofmation, provide a lambda whose arguments are the fields being used by OfflineLookup
142
+
143
+ ```
144
+ class Admin < ActiveRecord::Base
145
+ use_offline_lookup :lastname, transform: ->(lastname){"lookup_#{lastname}"}
146
+ end
147
+ ```
148
+
149
+ Or for multiple fields
150
+ ```
151
+ class Admin < ActiveRecord::Base
152
+ use_offline_lookup :firstname, :lastname, transform: ->(first, last){"#{first.first}_#{last}"}
153
+ end
154
+ ```
155
+
141
156
  ## Known Issues
142
157
 
143
158
  If two entries in the table have the same value in the specified field, all but one will get overwritten.
@@ -3,7 +3,7 @@ module OfflineLookup
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- after_create :get_offline_lookup_values
6
+ after_create :get_offline_lookup_values, :add_offline_lookup
7
7
  after_destroy :get_offline_lookup_values
8
8
  end
9
9
 
@@ -11,6 +11,15 @@ module OfflineLookup
11
11
  self.class.get_offline_lookup_values
12
12
  end
13
13
 
14
+ def offline_lookup_value
15
+ self.class.offline_lookup_value(*offline_lookup_options[:fields].map{|f| self.attributes[f.to_s]})
16
+ end
17
+
18
+ def add_offline_lookup
19
+ builder = OfflineLookup::Builder.new(self.class, self.offline_lookup_options)
20
+ builder.add_lookup(self.attributes[builder.key], offline_lookup_value)
21
+ end
22
+
14
23
  module ClassMethods
15
24
  def use_offline_lookup(*fields, key: "id", identity_methods: false, lookup_methods: false, compact: false, delimiter: " ", name: fields.join(delimiter), transform: nil)
16
25
  class_attribute :offline_lookup_values, :offline_lookup_options
@@ -30,13 +39,22 @@ module OfflineLookup
30
39
  include OfflineLookup::Base
31
40
  end
32
41
 
42
+ def offline_lookup_value(*fields)
43
+ if offline_lookup_options[:transform].present?
44
+ offline_lookup_options[:transform].call(*fields.map(&:to_s))
45
+ else
46
+ fields.map(&:to_s).join(offline_lookup_options[:delimiter])
47
+ end
48
+ end
49
+
33
50
  def get_offline_lookup_values
34
51
  self.offline_lookup_values = self.all.pluck(offline_lookup_options[:key], *offline_lookup_options[:fields]).map do |key, *fields|
35
52
  fields.compact! if offline_lookup_options[:compact]
36
53
  value = offline_lookup_options[:transform].present? ? offline_lookup_options[:transform].call(*fields.map(&:to_s)) : fields.map(&:to_s).join(offline_lookup_options[:delimiter])
37
- [key, value]
54
+ [key, value.to_s]
38
55
  end.to_h.freeze
39
56
  end
57
+
40
58
  end
41
59
  end
42
60
  end
@@ -3,52 +3,7 @@ module OfflineLookup
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- builder = OfflineLookup::Builder.new(self.offline_lookup_options)
7
-
8
- ### define value-named methods such as :two_hour_id and :two_hour?
9
-
10
- self.offline_lookup_values.each do |key, value|
11
- # class method: get key value (e.g. FooType.bar_id)
12
- define_singleton_method(builder.key_method_name(value)) do
13
- key
14
- end
15
-
16
- # instance method: true if instance is of named type (e.g. FooType.first.bar?)
17
- if self.offline_lookup_options[:identity_methods]
18
- define_method(builder.indentiy_method_name(value)) do
19
- self.attributes[self.offline_lookup_options[:key]] == key
20
- end
21
- end
22
-
23
- # class method: get instance by named method (e.g. FooType.bar)
24
- # not "Offline", but lookup by indexed key. Also, synactic sugar.
25
- if self.offline_lookup_options[:lookup_methods]
26
- define_singleton_method(builder.lookup_method_name(value)) do
27
- key = self.offline_lookup_values.find{|k, v| v.to_s == value.to_s}.try(:first)
28
- find(key)
29
- end
30
- end
31
-
32
- # class method: get instance using more general `lookup` method
33
- # Just as not "offline" as above, but less dangerous / more robust to any db value
34
- define_singleton_method :lookup do |value|
35
- key = self.offline_lookup_values.find{|k, v| v.to_s == value.to_s}.try(:first)
36
- find_by(id: key)
37
- end
38
- end
39
-
40
-
41
- ### define statically-named methods where you pass in the named value, e.g., id_for_name(:two_hour)
42
- # e.g. FooType.name_for_id(1)
43
- define_singleton_method(builder.field_for_key_method_name) do |key_value|
44
- self.offline_lookup_values[key_value]
45
- end
46
-
47
- # e.g. FooType.id_for_name("Bar")
48
- define_singleton_method(builder.key_for_field_method_name) do |field_value|
49
- self.offline_lookup_values.find{|k, v| v.to_s == field_value.to_s}.try(:first)
50
- end
51
-
6
+ OfflineLookup::Builder.new(self, self.offline_lookup_options).build
52
7
  end
53
8
  end
54
9
  end
@@ -1,15 +1,46 @@
1
1
  module OfflineLookup
2
2
  class Builder
3
- def initialize(options)
3
+ attr_reader :fields, :key, :name
4
+ def initialize(model, options)
5
+ @model = model
4
6
  @fields = options[:fields]
5
7
  @key = options[:key]
6
8
  @name = options[:name]
9
+ @build_identity_methods = options[:identity_methods]
10
+ @build_lookup_methods = options[:lookup_methods]
11
+ @modyule = get_module || create_module
12
+ end
13
+
14
+ def get_module
15
+ @model.const_defined?("OfflineLookupMethods") && @model::OfflineLookupMethods
16
+ end
17
+
18
+ def create_module
19
+ @modyule = Module.new
20
+ @modyule.extend ActiveSupport::Concern
21
+ @modyule.const_set("ClassMethods", Module.new)
22
+ @model.const_set("OfflineLookupMethods", @modyule)
23
+ end
24
+
25
+ def build
26
+ @model.offline_lookup_values.each do |key, value|
27
+ add_lookup(key, value)
28
+ end
29
+ add_name_for_key_method
30
+ add_key_for_name_method
31
+ add_static_lookup_method
32
+ @model.include @modyule
33
+ end
34
+
35
+ def add_lookup(key, value)
36
+ add_key_lookup_method(key, value)
37
+ add_identity_method(key, value) if @build_identity_methods
38
+ add_lookup_method(key, value) if @build_lookup_methods
7
39
  end
8
40
 
9
41
  def sanitize(string)
10
- #:methodize went away. Where did it go?
11
42
  #1. Replace illegal chars and _ boundaries with " " boundary
12
- string = string.gsub(/[^a-zA-Z\d]+/," ").strip
43
+ string = string.to_s.gsub(/[^a-zA-Z\d]+/," ").strip
13
44
  #2. Insert " " boundary at snake-case boundaries
14
45
  string.gsub!(/([a-z])([A-Z])/){|s| "#{$1} #{$2}"}
15
46
  #3. underscore
@@ -20,28 +51,58 @@ module OfflineLookup
20
51
  return string
21
52
  end
22
53
 
23
- # e.g., :two_hour_id
24
- def key_method_name(value)
25
- sanitize "#{value}_#{@key}"
54
+ # Get key value (e.g. FooType.bar_id)
55
+ def add_key_lookup_method(key, value)
56
+ @modyule::ClassMethods.instance_exec(self, key, value) do |builder, key, value|
57
+ define_method builder.sanitize("#{value}_#{builder.key}") do
58
+ key
59
+ end
60
+ end
61
+ end
62
+
63
+ # Return true iff instance is of named type (e.g. FooType.first.bar?)
64
+ def add_identity_method(key, value)
65
+ @modyule.instance_exec(self, key, value) do |builder, key, value|
66
+ define_method builder.sanitize(value) + "?" do
67
+ self.attributes[builder.key] == key
68
+ end
69
+ end
26
70
  end
27
71
 
28
- def lookup_method_name(value)
29
- sanitize value.to_s
72
+ # Get instance by named method (e.g. FooType.bar) (Not offline, but syntactic sugar)
73
+ def add_lookup_method(key, value)
74
+ @modyule::ClassMethods.instance_exec(self, key, value) do |builder, key, value|
75
+ define_method builder.sanitize(value) do
76
+ find_by(builder.key => self.offline_lookup_values.key(value.to_s))
77
+ end
78
+ end
30
79
  end
31
80
 
32
- # e.g., :two_hour?
33
- def indentiy_method_name(value)
34
- lookup_method_name(value) + "?"
81
+ # e.g. FooType.name_for_id(1)
82
+ def add_name_for_key_method
83
+ @modyule::ClassMethods.instance_exec(self) do |builder|
84
+ define_method builder.sanitize("#{builder.name}_for_#{builder.key}") do |key|
85
+ self.offline_lookup_values[key]
86
+ end
87
+ end
35
88
  end
36
89
 
37
- # e.g. :name_for_id(id)
38
- def field_for_key_method_name
39
- sanitize "#{@name}_for_#{@key}"
90
+ # e.g. FooType.id_for_name("Bar")
91
+ def add_key_for_name_method
92
+ @modyule::ClassMethods.instance_exec(self) do |builder|
93
+ define_method builder.sanitize("#{builder.key}_for_#{builder.name}") do |value|
94
+ self.offline_lookup_values.key(value.to_s)
95
+ end
96
+ end
40
97
  end
41
98
 
42
- # e.g. :id_for_name(name)
43
- def key_for_field_method_name
44
- sanitize "#{@key}_for_#{@name}"
99
+ # e.g. FooType.lookup("Bar")
100
+ def add_static_lookup_method
101
+ @modyule::ClassMethods.instance_exec(self) do |builder|
102
+ define_method "lookup" do |value|
103
+ find_by(builder.key => self.offline_lookup_values.key(value.to_s))
104
+ end
105
+ end
45
106
  end
46
107
 
47
108
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: offline_lookup
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Schwartz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-19 00:00:00.000000000 Z
11
+ date: 2016-09-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Offline indexing of small tables syntactic sugar & less db touching
14
14
  email: ozydingo@gmail.com