offline_lookup 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
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