offline_lookup 1.1.0 → 1.2.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: 3f2b36619ce0489bb3be9209e0c6f375d6ad7b7f
4
- data.tar.gz: 2a8b0b21903a8010032c6f99b9cfa5cfb7b5069d
3
+ metadata.gz: 9df8ec8a2ac9076d35a4965141e8f7ddd64ef41e
4
+ data.tar.gz: cf5881b25c71c21378b012024dd6f9615264f5bb
5
5
  SHA512:
6
- metadata.gz: b1e8325950ade06e5daeeece7c496d717c26412c7be90119395442ef69f8cbd03f78b9dff2e9e1afb04dbd64710b5c7439215dce37da6683ce81a3f18eead93a
7
- data.tar.gz: bf7fa6108c54b9dc3946d6ead0338e56f4a0996db3aabd14d83c75dc682694118c060a8bd66b5bce289bccc45e01c8e677b2a2891b31635395ba27d73ae10978
6
+ metadata.gz: 0183aafc5868444dfe5d8452f43c65e02cd0ceee4abc50b93ac87ad9526d6ac376046576d83a4270e1fbcb9c68c9f6bc7aa34f783c30ad940db6f3e1cb9baa3b
7
+ data.tar.gz: a3ba577eb3860d3b906fe87984d003f4004b1c8495978695fba245f4637e8831b120e75df38a510154f40375d20282d6e881c95315781bf83660e9ed4c9fb68e
data/README.md CHANGED
@@ -31,6 +31,11 @@ Add `lookup` method to allow lookup by key'd name without risking bad / reserved
31
31
 
32
32
  You can now specify multiple columns for lookup! The values are by default joined with a " " (note this translates to "_" for method names). You can configure this delimiter and what to do with `nil` values.
33
33
 
34
+ v1.1.0
35
+ I forget. Probably a big bugfix.
36
+
37
+ v1.2.0
38
+ Definitely a big bugfix. The core OfflineLookup module was getting included in all of ActiveRecord, which mistakenly included callback methods that depended on the existence of `self.offline_lookup_options`. This has been fixed and this behavior is now only exhibited on models that explicitly call `use_offline_lookup`
34
39
 
35
40
 
36
41
  ## How To Use It
@@ -2,7 +2,7 @@
2
2
  # TODO: support scope arg in use_offline_lookup (partial index)
3
3
 
4
4
  require 'offline_lookup/active_record.rb'
5
- require 'offline_lookup/base.rb'
6
- require 'offline_lookup/builder.rb'
5
+ require 'offline_lookup/core.rb'
6
+ require 'offline_lookup/dynamic_module_builder.rb'
7
7
 
8
8
  ActiveRecord::Base.include OfflineLookup::ActiveRecord
@@ -2,27 +2,9 @@ module OfflineLookup
2
2
  module ActiveRecord
3
3
  extend ActiveSupport::Concern
4
4
 
5
- included do
6
- after_create :get_offline_lookup_values, :add_offline_lookup
7
- after_destroy :get_offline_lookup_values
8
- end
9
-
10
- def get_offline_lookup_values
11
- self.class.get_offline_lookup_values
12
- end
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
-
23
5
  module ClassMethods
24
6
  def use_offline_lookup(*fields, key: "id", identity_methods: false, lookup_methods: false, compact: false, delimiter: " ", name: fields.join(delimiter), transform: nil)
25
- class_attribute :offline_lookup_values, :offline_lookup_options
7
+ class_attribute :offline_lookup_options
26
8
  self.offline_lookup_options = {
27
9
  fields: fields.map(&:to_s),
28
10
  key: key.to_s,
@@ -32,29 +14,10 @@ module OfflineLookup
32
14
  delimiter: delimiter.to_s,
33
15
  name: name,
34
16
  transform: transform
35
- }.freeze
36
-
37
- get_offline_lookup_values
38
-
39
- include OfflineLookup::Base
40
- end
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
17
+ }
18
+ include OfflineLookup::Core
19
+ include OfflineLookup::DynamicModuleBuilder.new(self, self.offline_lookup_options).build_module
48
20
  end
49
-
50
- def get_offline_lookup_values
51
- self.offline_lookup_values = self.all.pluck(offline_lookup_options[:key], *offline_lookup_options[:fields]).map do |key, *fields|
52
- fields.compact! if offline_lookup_options[:compact]
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])
54
- [key, value.to_s]
55
- end.to_h.freeze
56
- end
57
-
58
21
  end
59
22
  end
60
23
  end
@@ -0,0 +1,44 @@
1
+ module OfflineLookup
2
+ module Core
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ class_attribute :offline_lookup_values
7
+ self.offline_lookup_values = get_offline_lookup_values
8
+
9
+ after_create :set_class_offline_lookup_values, :add_to_offline_lookup
10
+ after_destroy :set_class_offline_lookup_values
11
+ end
12
+
13
+ module ClassMethods
14
+ def offline_lookup_value(*field_values)
15
+ field_values.compact! if offline_lookup_options[:compact]
16
+ if offline_lookup_options[:transform].present?
17
+ offline_lookup_options[:transform].call(*field_values.map(&:to_s))
18
+ else
19
+ field_values.map(&:to_s).join(offline_lookup_options[:delimiter])
20
+ end
21
+ end
22
+
23
+ def get_offline_lookup_values
24
+ self.all.pluck(offline_lookup_options[:key], *offline_lookup_options[:fields]).map do |key_value, *field_values|
25
+ [key_value, offline_lookup_value(*field_values)]
26
+ end.to_h.freeze
27
+ end
28
+ end
29
+
30
+ def set_class_offline_lookup_values
31
+ self.class.offline_lookup_values = self.class.get_offline_lookup_values
32
+ end
33
+
34
+ def offline_lookup_value
35
+ self.class.offline_lookup_value(*offline_lookup_options[:fields].map{|f| self.attributes[f.to_s]})
36
+ end
37
+
38
+ def add_to_offline_lookup
39
+ builder = OfflineLookup::DynamicModuleBuilder.new(self.class, self.offline_lookup_options)
40
+ builder.add_dynamic_lookup_methods(self.attributes[self.offline_lookup_options[:key]], offline_lookup_value)
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,115 @@
1
+ module OfflineLookup
2
+ class DynamicModuleBuilder
3
+ def initialize(model, options)
4
+ @model = model
5
+ @fields = options[:fields].map(&:to_s)
6
+ @key_name = options[:key]
7
+ @name = options[:name]
8
+ @build_identity_methods = options[:identity_methods]
9
+ @build_lookup_methods = options[:lookup_methods]
10
+ @modyule = get_module || create_module
11
+ end
12
+
13
+ def get_module
14
+ @model.const_defined?("OfflineLookupMethods") && @model::OfflineLookupMethods
15
+ end
16
+
17
+ def create_module
18
+ modyule = Module.new
19
+ modyule.extend ActiveSupport::Concern
20
+ modyule.const_set("ClassMethods", Module.new)
21
+ @model.const_set("OfflineLookupMethods", modyule)
22
+ return modyule
23
+ end
24
+
25
+ def build_module
26
+ add_all_dynamic_lookups
27
+ add_name_for_key_method
28
+ add_key_for_name_method
29
+ add_static_lookup_method
30
+ return @modyule
31
+ end
32
+
33
+ def add_all_dynamic_lookups
34
+ @model.offline_lookup_values.each{|key_value, value| add_dynamic_lookup_methods(key_value, value)}
35
+ end
36
+
37
+ def add_dynamic_lookup_methods(key_value, value)
38
+ add_key_lookup_method(key_value, value)
39
+ add_identity_method(key_value, value) if @build_identity_methods
40
+ add_lookup_method(key_value, value) if @build_lookup_methods
41
+ end
42
+
43
+ # Get key value (e.g. FooType.bar_id)
44
+ def add_key_lookup_method(key_value, value)
45
+ key_lookup_method_name = sanitize("#{value}_#{@key_name}")
46
+ @modyule::ClassMethods.instance_exec(key_lookup_method_name, key_value, value) do |method_name, key_value|
47
+ define_method method_name do
48
+ key_value
49
+ end
50
+ end
51
+ end
52
+
53
+ # Return true iff instance is of named type (e.g. FooType.first.bar?)
54
+ def add_identity_method(key_value, value)
55
+ identify_method_name = sanitize(value) + "?"
56
+ @modyule.instance_exec(identify_method_name, @key_name, key_value) do |method_name, key_name, key_value|
57
+ define_method method_name do
58
+ self.attributes[key_name] == key_value
59
+ end
60
+ end
61
+ end
62
+
63
+ # Get instance by named method (e.g. FooType.bar) (Not offline, but syntactic sugar)
64
+ def add_lookup_method(key_value, value)
65
+ lookup_method_name = sanitize(value)
66
+ @modyule::ClassMethods.instance_exec(lookup_method_name, @key_name, key_value, value) do |method_name, key_name, key_value|
67
+ define_method method_name do
68
+ find_by(key_name => key_value)
69
+ end
70
+ end
71
+ end
72
+
73
+ # e.g. FooType.name_for_id(1)
74
+ def add_name_for_key_method
75
+ method_name = sanitize("#{@name}_for_#{@key_name}")
76
+ @modyule::ClassMethods.instance_exec(method_name) do |method_name|
77
+ define_method method_name do |key|
78
+ self.offline_lookup_values[key]
79
+ end
80
+ end
81
+ end
82
+
83
+ # e.g. FooType.id_for_name("Bar")
84
+ def add_key_for_name_method
85
+ method_name = sanitize("#{@key_name}_for_#{@name}")
86
+ @modyule::ClassMethods.instance_exec(method_name) do |method_name|
87
+ define_method method_name do |value|
88
+ self.offline_lookup_values.key(value.to_s)
89
+ end
90
+ end
91
+ end
92
+
93
+ # e.g. FooType.lookup("Bar")
94
+ def add_static_lookup_method
95
+ @modyule::ClassMethods.instance_exec(@key_name) do |key_name|
96
+ define_method "lookup" do |value|
97
+ find_by(key_name => self.offline_lookup_values.key(value.to_s))
98
+ end
99
+ end
100
+ end
101
+
102
+ def sanitize(string)
103
+ #1. Replace illegal chars and _ boundaries with " " boundary
104
+ string = string.to_s.gsub(/[^a-zA-Z\d]+/," ").strip
105
+ #2. Insert " " boundary at snake-case boundaries
106
+ string.gsub!(/([a-z])([A-Z])/){|s| "#{$1} #{$2}"}
107
+ #3. underscore
108
+ string.gsub!(/\s+/, "_")
109
+ string.downcase!
110
+ #4. Append underscore if name begins with digit
111
+ string = "_#{string}" if string.length == 0 || string[0] =~ /\d/
112
+ return string
113
+ end
114
+ end
115
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: offline_lookup
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Schwartz
@@ -19,9 +19,9 @@ files:
19
19
  - README.md
20
20
  - lib/offline_lookup.rb
21
21
  - lib/offline_lookup/active_record.rb
22
- - lib/offline_lookup/base.rb
23
- - lib/offline_lookup/builder.rb
24
- homepage:
22
+ - lib/offline_lookup/core.rb
23
+ - lib/offline_lookup/dynamic_module_builder.rb
24
+ homepage: http://github.com/ozydingo/offline_lookup
25
25
  licenses:
26
26
  - MIT
27
27
  metadata: {}
@@ -1,9 +0,0 @@
1
- module OfflineLookup
2
- module Base
3
- extend ActiveSupport::Concern
4
-
5
- included do
6
- OfflineLookup::Builder.new(self, self.offline_lookup_options).build
7
- end
8
- end
9
- end
@@ -1,109 +0,0 @@
1
- module OfflineLookup
2
- class Builder
3
- attr_reader :fields, :key, :name
4
- def initialize(model, options)
5
- @model = model
6
- @fields = options[:fields]
7
- @key = options[:key]
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
39
- end
40
-
41
- def sanitize(string)
42
- #1. Replace illegal chars and _ boundaries with " " boundary
43
- string = string.to_s.gsub(/[^a-zA-Z\d]+/," ").strip
44
- #2. Insert " " boundary at snake-case boundaries
45
- string.gsub!(/([a-z])([A-Z])/){|s| "#{$1} #{$2}"}
46
- #3. underscore
47
- string.gsub!(/\s+/, "_")
48
- string.downcase!
49
- #4. Append underscore if name begins with digit
50
- string = "_#{string}" if string.length == 0 || string[0] =~ /\d/
51
- return string
52
- end
53
-
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
70
- end
71
-
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
79
- end
80
-
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
88
- end
89
-
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
97
- end
98
-
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
106
- end
107
-
108
- end
109
- end