looksist 0.0.1 → 0.0.2
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 +4 -4
- data/README.md +44 -11
- data/lib/looksist.rb +3 -1
- data/lib/looksist/hashed.rb +42 -0
- data/lib/looksist/redis_service.rb +54 -0
- data/lib/looksist/version.rb +1 -1
- data/spec/hashed_spec.rb +120 -0
- data/spec/looksist_spec.rb +14 -4
- data/spec/spec_helper.rb +2 -0
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 453912d57be9e4fc38f6616ffdce38e38f0385bb
|
4
|
+
data.tar.gz: 8f43edb7bf0cfd70addeabfc8fd999045d253599
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b7044cc4641fa67c4842a4c0a534a9182a6a3518764927aec3087041fbbdc8916597af8b98b018e480f2ef01daf07211bbe34e974c8affaf7e850ea22377d10
|
7
|
+
data.tar.gz: fb977003fff907b27036af080f3a870b0b5a798f6ca668a63fa75b3441251bdbb9d2d93d4488543d0786b8ea351e324cd27776b8a114c0e66b4560fc08bcec60
|
data/README.md
CHANGED
@@ -1,14 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# Looksist
|
2
2
|
|
3
3
|
[](https://travis-ci.org/jpsimonroy/herdis)
|
4
4
|
|
5
|
-
|
5
|
+
looksist (adj) - forming positive prejudices based on appearances
|
6
|
+
|
7
|
+
Use this gem when you have to lookup attributes from a key-value store based on another attribute as key. This supports redis out-of-the-box and it's blazing fast!
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
9
11
|
Add this line to your application's Gemfile:
|
10
12
|
|
11
|
-
gem '
|
13
|
+
gem 'looksist'
|
12
14
|
|
13
15
|
And then execute:
|
14
16
|
|
@@ -16,16 +18,47 @@ And then execute:
|
|
16
18
|
|
17
19
|
Or install it yourself as:
|
18
20
|
|
19
|
-
$ gem install
|
21
|
+
$ gem install looksist
|
20
22
|
|
21
23
|
## Usage
|
22
24
|
|
23
|
-
|
25
|
+
* Add an initializer to configure looksist
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
Looksist.lookup_store_client ||= Redis.new(:url => (ENV['REDIS_URL'], :driver => :hiredis)
|
29
|
+
Looksist.driver = Looksist::Serializers::Her
|
30
|
+
```
|
31
|
+
You need to specify the driver to manage the attributes. In this case, we use [HER](https://github.com/remiprev/her). You can add support for ActiveResource or ActiveRecord as needed (also refer to specs for free form usage without a driver).
|
32
|
+
|
33
|
+
* Please find the sample rspec to understand the usage and internals
|
34
|
+
|
35
|
+
``` ruby
|
36
|
+
it 'should generate declarative attributes on the model with simple lookup value' do
|
37
|
+
module SimpleLookup
|
38
|
+
class Employee
|
39
|
+
include Looksist
|
40
|
+
attr_accessor :id
|
41
|
+
lookup :name, using= :id
|
42
|
+
|
43
|
+
def initialize(id)
|
44
|
+
@id = id
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
expect(Looksist.lookup_store_client).to receive(:get).with('ids/1').and_return('Employee Name')
|
50
|
+
e = SimpleLookup::Employee.new(1)
|
51
|
+
expect(e.name).to eq('Employee Name')
|
52
|
+
end
|
53
|
+
```
|
54
|
+
lookup takes the following form:
|
55
|
+
|
56
|
+
``` ruby
|
57
|
+
lookup :name, using = :employee_id # will lookup "employees/#{employee_id}" from the store
|
58
|
+
|
59
|
+
lookup :name, using = :employee_id, bucket_name="stars" # will lookup "stars/#{employee_id}" from the store
|
60
|
+
|
61
|
+
lookup [:name, :location], using = :employee_id # will lookup "stars/#{employee_id}" from the store for an object with two attributes (name, location)
|
24
62
|
|
25
|
-
|
63
|
+
```
|
26
64
|
|
27
|
-
1. Fork it ( https://github.com/[my-github-username]/herdis/fork )
|
28
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
-
5. Create a new Pull Request
|
data/lib/looksist.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'looksist/version'
|
2
|
+
require 'looksist/redis_service'
|
3
|
+
require 'looksist/hashed'
|
2
4
|
|
3
5
|
module Looksist
|
4
6
|
extend ActiveSupport::Concern
|
@@ -19,7 +21,7 @@ module Looksist
|
|
19
21
|
what.each do |method_name|
|
20
22
|
define_method(method_name) do
|
21
23
|
key = [bucket, '/', self.send(using).try(:to_s)].join('')
|
22
|
-
JSON.parse(send(:memoized, key))[method_name.to_s]
|
24
|
+
JSON.parse(send(:memoized, key) || '{}')[method_name.to_s]
|
23
25
|
end
|
24
26
|
self.lookup_attributes << method_name
|
25
27
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Looksist
|
2
|
+
module Hashed
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
# inject after: :assortment, at: 'table', using: :supplier_id, populate: :supplier_name, bucket_name: 'suppliers'
|
6
|
+
|
7
|
+
class << self;
|
8
|
+
attr_accessor :redis_service
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def inject(opts)
|
13
|
+
raise 'Incorrect usage' unless [:after, :using, :populate].all? { |e| opts.keys.include? e }
|
14
|
+
@rules ||= {}
|
15
|
+
@rules[opts[:after]] ||= []
|
16
|
+
@rules[opts[:after]] << opts
|
17
|
+
return if @rules[opts[:after]].length > 1
|
18
|
+
|
19
|
+
define_method("#{opts[:after]}_with_inject") do
|
20
|
+
hash = send("#{opts[:after]}_without_inject".to_sym)
|
21
|
+
self.class.instance_variable_get(:@rules)[opts[:after]].each do |opts|
|
22
|
+
keys = hash[opts[:at]][opts[:using]]
|
23
|
+
entity_name = entity(opts[:using])
|
24
|
+
values = Hashed.redis_service.send("#{entity_name}_for", keys)
|
25
|
+
hash[opts[:at]][opts[:populate]] = values
|
26
|
+
end
|
27
|
+
hash
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method_chain opts[:after], :inject
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
included do |base|
|
35
|
+
base.class_attribute :rules
|
36
|
+
end
|
37
|
+
|
38
|
+
def entity(entity_id)
|
39
|
+
entity = entity_id.to_s.gsub('_id', '')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Looksist
|
2
|
+
class RedisService
|
3
|
+
attr_accessor :client, :buffer_size, :cache
|
4
|
+
|
5
|
+
def self.instance
|
6
|
+
@_instance_ ||= new
|
7
|
+
@_instance_.cache ||= {}
|
8
|
+
yield @_instance_ if block_given?
|
9
|
+
@_instance_.buffer_size ||= 50000
|
10
|
+
@_instance_
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_missing(m, *args, &block)
|
14
|
+
if m.to_s.ends_with?("_for")
|
15
|
+
entity = m.to_s.gsub('_for', '')
|
16
|
+
args.first.is_a?(Array) ? find_all(entity, args.first) : find(entity, args.first)
|
17
|
+
else
|
18
|
+
super(m, args)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def find(entity, id)
|
25
|
+
key = redis_key(entity, id)
|
26
|
+
hit_or_miss(key) do
|
27
|
+
@client.get(key)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def find_all(entity, ids)
|
33
|
+
@client.pipelined do
|
34
|
+
ids.uniq.each do |id|
|
35
|
+
find(entity, id)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
ids.each_with_object([]) { |k, acc| acc << cache[redis_key(entity, k)] }
|
39
|
+
end
|
40
|
+
|
41
|
+
def hit_or_miss(key, &block)
|
42
|
+
@cache[key] ||= lru(&block)
|
43
|
+
end
|
44
|
+
|
45
|
+
def lru
|
46
|
+
@cache.shift if @cache.length >= @buffer_size
|
47
|
+
yield
|
48
|
+
end
|
49
|
+
|
50
|
+
def redis_key(entity, id)
|
51
|
+
"#{entity.pluralize}/#{id}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/looksist/version.rb
CHANGED
data/spec/hashed_spec.rb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Looksist::Hashed do
|
4
|
+
before(:each) do
|
5
|
+
class MockRedis
|
6
|
+
def pipelined
|
7
|
+
yield
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
@mock = MockRedis.new
|
12
|
+
Looksist::Hashed.redis_service = Looksist::RedisService.instance do |lookup|
|
13
|
+
lookup.client = @mock
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
context 'inject ' do
|
19
|
+
it 'should inject single attribute to an existing hash' do
|
20
|
+
class HashService1
|
21
|
+
include Looksist::Hashed
|
22
|
+
|
23
|
+
def metrics
|
24
|
+
{
|
25
|
+
table: {
|
26
|
+
employee_id: [1, 2]
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
inject after: :metrics, at: :table, using: :employee_id, populate: :employee_name
|
32
|
+
end
|
33
|
+
|
34
|
+
expect(@mock).to receive(:get).with('employees/1').and_return('emp 1')
|
35
|
+
expect(@mock).to receive(:get).with('employees/2').and_return('emp 2')
|
36
|
+
|
37
|
+
HashService1.new.metrics.should eq({table: {
|
38
|
+
employee_id: [1, 2],
|
39
|
+
employee_name: ['emp 1', 'emp 2']
|
40
|
+
}})
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should inject multiple attribute to an existing hash' do
|
44
|
+
class HashService
|
45
|
+
include Looksist::Hashed
|
46
|
+
|
47
|
+
def metrics
|
48
|
+
{
|
49
|
+
table: {
|
50
|
+
employee_id: [5, 6],
|
51
|
+
employer_id: [3, 4]
|
52
|
+
}
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
inject after: :metrics, at: :table, using: :employee_id, populate: :employee_name
|
57
|
+
inject after: :metrics, at: :table, using: :employer_id, populate: :employer_name
|
58
|
+
end
|
59
|
+
|
60
|
+
expect(@mock).to receive(:get).with('employees/5').and_return('emp 5')
|
61
|
+
expect(@mock).to receive(:get).with('employees/6').and_return('emp 6')
|
62
|
+
|
63
|
+
expect(@mock).to receive(:get).with('employers/3').and_return('empr 3')
|
64
|
+
expect(@mock).to receive(:get).with('employers/4').and_return('empr 4')
|
65
|
+
|
66
|
+
HashService.new.metrics.should eq({table: {
|
67
|
+
employee_id: [5, 6],
|
68
|
+
employer_id: [3, 4],
|
69
|
+
employee_name: ['emp 5', 'emp 6'],
|
70
|
+
employer_name: ['empr 3', 'empr 4']
|
71
|
+
}})
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
context 'multiple methods and injections' do
|
77
|
+
it 'should inject multiple attribute to an existing hash' do
|
78
|
+
class HashServiceSuper
|
79
|
+
include Looksist::Hashed
|
80
|
+
|
81
|
+
def shrinkage
|
82
|
+
{
|
83
|
+
table: {
|
84
|
+
shrink_id: [1, 2]
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def stock
|
90
|
+
{
|
91
|
+
table: {
|
92
|
+
dc_id: [7, 8]
|
93
|
+
}
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
inject after: :shrinkage, at: :table, using: :shrink_id, populate: :shrink_name
|
98
|
+
inject after: :stock, at: :table, using: :dc_id, populate: :dc_name
|
99
|
+
end
|
100
|
+
|
101
|
+
expect(@mock).to receive(:get).with('shrinks/1').and_return('shrink 1')
|
102
|
+
expect(@mock).to receive(:get).with('shrinks/2').and_return('shrink 2')
|
103
|
+
|
104
|
+
expect(@mock).to receive(:get).with('dcs/7').and_return('dc 7')
|
105
|
+
expect(@mock).to receive(:get).with('dcs/8').and_return('dc 8')
|
106
|
+
|
107
|
+
hash_service_super = HashServiceSuper.new
|
108
|
+
hash_service_super.shrinkage.should eq({table: {
|
109
|
+
shrink_id: [1, 2],
|
110
|
+
shrink_name: ['shrink 1', 'shrink 2']
|
111
|
+
}})
|
112
|
+
|
113
|
+
hash_service_super.stock.should eq({table: {
|
114
|
+
dc_id: [7, 8],
|
115
|
+
dc_name: ['dc 7', 'dc 8']
|
116
|
+
}})
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
data/spec/looksist_spec.rb
CHANGED
@@ -71,39 +71,49 @@ describe Looksist do
|
|
71
71
|
module SimpleLookup
|
72
72
|
class Employee
|
73
73
|
include Looksist
|
74
|
-
attr_accessor :id
|
74
|
+
attr_accessor :id, :employee_id
|
75
75
|
lookup :name, using= :id
|
76
|
+
lookup :unavailable, using= :employee_id
|
76
77
|
|
77
78
|
def initialize(id)
|
78
|
-
@id = id
|
79
|
+
@id = @employee_id = id
|
79
80
|
end
|
80
81
|
end
|
81
82
|
end
|
82
83
|
|
83
84
|
expect(Looksist.lookup_store_client).to receive(:get).with('ids/1').and_return('Employee Name')
|
85
|
+
expect(Looksist.lookup_store_client).to receive(:get).with('employees/1').and_return(nil)
|
84
86
|
e = SimpleLookup::Employee.new(1)
|
85
87
|
expect(e.name).to eq('Employee Name')
|
88
|
+
expect(e.unavailable).to be(nil)
|
86
89
|
end
|
87
90
|
|
88
91
|
it 'should generate declarative attributes on the model with object based lookup value' do
|
89
92
|
module CompositeLookup
|
90
93
|
class Employee
|
91
94
|
include Looksist
|
92
|
-
attr_accessor :id
|
95
|
+
attr_accessor :id, :employee_id
|
93
96
|
|
94
97
|
lookup [:name, :location], using=:id
|
98
|
+
lookup [:age, :sex], using=:employee_id
|
95
99
|
|
96
100
|
def initialize(id)
|
97
|
-
@id = id
|
101
|
+
@id = @employee_id = id
|
98
102
|
end
|
99
103
|
end
|
100
104
|
end
|
101
105
|
|
102
106
|
expect(Looksist.lookup_store_client).to receive(:get).with('ids/1')
|
103
107
|
.and_return({name: 'Employee Name', location: 'Chennai'}.to_json)
|
108
|
+
expect(Looksist.lookup_store_client).to receive(:get).twice.with('employees/1')
|
109
|
+
.and_return(nil)
|
104
110
|
e = CompositeLookup::Employee.new(1)
|
111
|
+
|
105
112
|
expect(e.name).to eq('Employee Name')
|
106
113
|
expect(e.location).to eq('Chennai')
|
114
|
+
|
115
|
+
expect(e.age).to be(nil)
|
116
|
+
expect(e.sex).to be(nil)
|
107
117
|
end
|
108
118
|
end
|
109
119
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: looksist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RC
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-10-
|
12
|
+
date: 2014-10-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -155,8 +155,11 @@ files:
|
|
155
155
|
- README.md
|
156
156
|
- Rakefile
|
157
157
|
- lib/looksist.rb
|
158
|
+
- lib/looksist/hashed.rb
|
159
|
+
- lib/looksist/redis_service.rb
|
158
160
|
- lib/looksist/version.rb
|
159
161
|
- looksist.gemspec
|
162
|
+
- spec/hashed_spec.rb
|
160
163
|
- spec/looksist_spec.rb
|
161
164
|
- spec/spec_helper.rb
|
162
165
|
homepage: https://github.com/jpsimonroy/herdis
|
@@ -184,5 +187,6 @@ signing_key:
|
|
184
187
|
specification_version: 4
|
185
188
|
summary: Redis backed lookup for your her models
|
186
189
|
test_files:
|
190
|
+
- spec/hashed_spec.rb
|
187
191
|
- spec/looksist_spec.rb
|
188
192
|
- spec/spec_helper.rb
|