kashmir 0.1 → 0.1.1
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/{LICENSE.txt → LICENSE} +1 -1
- data/README.md +39 -33
- data/kashmir.gemspec +1 -4
- data/lib/kashmir.rb +1 -0
- data/lib/kashmir/caching.rb +9 -11
- data/lib/kashmir/patches/active_record.rb +4 -2
- data/lib/kashmir/plugins/ar_relation.rb +5 -1
- data/lib/kashmir/version.rb +1 -1
- data/test/caching_test.rb +6 -0
- metadata +6 -35
- data/Gemfile.lock +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e10560235dc4ce72083facd7ea74c69b3bedb255
|
4
|
+
data.tar.gz: b418df0a0a818e6f00683e5c0115b2c619c0134d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a63bfb22aad18c97ed7a477a35a752fbe82c8d90bb09caf1d9b3651312dae3fe9430e2cc7770423454a98776475279fa12b031406721f2c3dac7461c66e08847
|
7
|
+
data.tar.gz: c4723de817322bea9e4ab0069424a3d8144f3c2ec6bb314ea8c6d62688b143b4483b10bcad8dfe591e36c9f078b19bb636afd10da9c171bf3d6c3d54c37e8708
|
data/{LICENSE.txt → LICENSE}
RENAMED
data/README.md
CHANGED
@@ -1,18 +1,20 @@
|
|
1
|
-
|
1
|
+
[](http://ifttt.github.io)
|
2
2
|
|
3
|
-
Kashmir
|
4
|
-
Kashmir will turn these ruby objects into `Hash`es that represent the dependency tree you just described.
|
3
|
+

|
5
4
|
|
6
|
-
|
5
|
+
Kashmir is a DSL built to allow developers to describe representations of Ruby objects.
|
6
|
+
Kashmir will turn these Ruby objects into hashes that represent the dependency tree you just described.
|
7
7
|
|
8
|
-
`Kashmir::
|
9
|
-
|
8
|
+
`Kashmir::ActiveRecord` will also optimize and try to balance `ActiveRecord` queries so your application hits the database as little as possible.
|
9
|
+
|
10
|
+
`Kashmir::Caching` builds a dependency tree for complex object representations and caches each level of this tree separately. Kashmir will do so by creating cache views of each level as well as caching a complete tree.
|
11
|
+
The caching engine is smart enough to fill holes in the cache tree with fresh data from your data store.
|
10
12
|
|
11
13
|
Combine `Kashmir::Caching` + `Kashmir::ActiveRecord` for extra awesomeness.
|
12
14
|
|
13
15
|
### Example:
|
14
16
|
|
15
|
-
For example, a `Person` with
|
17
|
+
For example, a `Person` with `name` and `age` attributes:
|
16
18
|
```ruby
|
17
19
|
class Person
|
18
20
|
include Kashmir
|
@@ -34,18 +36,21 @@ could be represented as:
|
|
34
36
|
```
|
35
37
|
|
36
38
|
Representing an object is as simple as:
|
37
|
-
|
38
|
-
|
39
|
+
|
40
|
+
1. Add `include Kashmir` to the target class.
|
41
|
+
2. Whitelist all the fields you want to include in a representation.
|
42
|
+
|
39
43
|
```ruby
|
40
|
-
#
|
44
|
+
# Add fields and methods you want to be visible to Kashmir
|
41
45
|
representations do
|
42
|
-
rep(:name)
|
46
|
+
rep(:name)
|
43
47
|
rep(:age)
|
44
48
|
end
|
45
49
|
```
|
50
|
+
|
46
51
|
3. Instantiate an object and `#represent` it.
|
47
52
|
```ruby
|
48
|
-
#
|
53
|
+
# Pass in an array with all the fields you want included
|
49
54
|
Person.new('Netto Farah', 26).represent([:name, :age])
|
50
55
|
=> {:name=>"Netto Farah", :age=>"26"}
|
51
56
|
```
|
@@ -65,11 +70,11 @@ And then execute:
|
|
65
70
|
## Usage
|
66
71
|
Kashmir is better described with examples.
|
67
72
|
|
68
|
-
### Basic
|
73
|
+
### Basic Representations
|
69
74
|
|
70
|
-
#### Describing an
|
75
|
+
#### Describing an Object
|
71
76
|
Only whitelisted fields can be represented by Kashmir.
|
72
|
-
This is done so
|
77
|
+
This is done so sensitive fields (like passwords) cannot be accidentally exposed to clients.
|
73
78
|
|
74
79
|
``` ruby
|
75
80
|
class Recipe < OpenStruct
|
@@ -84,17 +89,17 @@ end
|
|
84
89
|
|
85
90
|
Instantiate a `Recipe`:
|
86
91
|
```ruby
|
87
|
-
recipe = Recipe.new(title: 'Beef
|
92
|
+
recipe = Recipe.new(title: 'Beef Stew', preparation_time: 60)
|
88
93
|
```
|
89
94
|
|
90
|
-
Kashmir automatically adds a `#represent` method to every instance of `Recipe
|
91
|
-
`#represent`
|
95
|
+
Kashmir automatically adds a `#represent` method to every instance of `Recipe`.
|
96
|
+
`#represent` takes an `Array` with all the fields you want as part of your representation.
|
92
97
|
|
93
98
|
```ruby
|
94
99
|
recipe.represent([:title, :preparation_time])
|
95
|
-
=> { title: 'Beef
|
100
|
+
=> { title: 'Beef Stew', preparation_time: 60 }
|
96
101
|
```
|
97
|
-
#### Calculated
|
102
|
+
#### Calculated Fields
|
98
103
|
You can represent any instance variable or method (basically anything that returns `true` for `respond_to?`).
|
99
104
|
``` ruby
|
100
105
|
class Recipe < OpenStruct
|
@@ -112,11 +117,11 @@ end
|
|
112
117
|
```
|
113
118
|
|
114
119
|
```ruby
|
115
|
-
Recipe.new(title: 'Beef
|
116
|
-
=> { title: 'Beef
|
120
|
+
Recipe.new(title: 'Beef Stew', steps: ['chop', 'cook']).represent([:title, :num_steps])
|
121
|
+
=> { title: 'Beef Stew', num_steps: 2 }
|
117
122
|
```
|
118
123
|
|
119
|
-
### Nested
|
124
|
+
### Nested Representations
|
120
125
|
You can nest Kashmir objects to represent complex relationships between your objects.
|
121
126
|
```ruby
|
122
127
|
class Recipe < OpenStruct
|
@@ -137,8 +142,7 @@ class Chef < OpenStruct
|
|
137
142
|
end
|
138
143
|
```
|
139
144
|
|
140
|
-
|
141
|
-
You can then pass in another array with all the properties you want to present in the nested object.
|
145
|
+
When you create a representation, nest hashes to create nested representations.
|
142
146
|
```ruby
|
143
147
|
netto = Chef.new(name: 'Netto Farah')
|
144
148
|
beef_stew = Recipe.new(title: 'Beef Stew', chef: netto)
|
@@ -153,8 +157,8 @@ beef_stew.represent([:title, { :chef => [ :name ] }])
|
|
153
157
|
```
|
154
158
|
Not happy with this syntax? Check out `Kashmir::DSL` or `Kashmir::InlineDSL` for prettier code.
|
155
159
|
|
156
|
-
#### Base
|
157
|
-
|
160
|
+
#### Base Representations
|
161
|
+
Are you tired of repeating the same fields over and over?
|
158
162
|
You can create a base representation of your objects, so Kashmir returns basic fields automatically.
|
159
163
|
```ruby
|
160
164
|
class Recipe
|
@@ -207,7 +211,7 @@ end
|
|
207
211
|
```
|
208
212
|
|
209
213
|
```ruby
|
210
|
-
bbq_joint = Restaurant.new(name: "Netto's BBQ Joint", rating: '5
|
214
|
+
bbq_joint = Restaurant.new(name: "Netto's BBQ Joint", rating: '5 Stars')
|
211
215
|
netto = Chef.new(name: 'Netto', restaurant: bbq_joint)
|
212
216
|
brisket = Recipe.new(title: 'BBQ Brisket', chef: netto)
|
213
217
|
|
@@ -223,7 +227,7 @@ brisket.represent([
|
|
223
227
|
name: 'Netto',
|
224
228
|
restaurant: {
|
225
229
|
name: "Netto's BBQ Joint",
|
226
|
-
rating: '5
|
230
|
+
rating: '5 Stars'
|
227
231
|
}
|
228
232
|
}
|
229
233
|
}
|
@@ -310,7 +314,7 @@ brisket.represent(RecipePresenter)
|
|
310
314
|
|
311
315
|
=> { title: 'BBQ Brisket', num_steps: 2 }
|
312
316
|
```
|
313
|
-
####
|
317
|
+
#### Embedded Representers
|
314
318
|
It is also possible to define nested representers with `embed(:property_name, RepresenterClass)`.
|
315
319
|
|
316
320
|
```ruby
|
@@ -388,7 +392,7 @@ end
|
|
388
392
|
=> { title: 'BBQ Brisket', num_steps: 2 }
|
389
393
|
```
|
390
394
|
|
391
|
-
#### Nested
|
395
|
+
#### Nested Inline Representations
|
392
396
|
You can nest inline representations using `inline(:field, &block)` the same way we did with `Kashmir::Dsl`.
|
393
397
|
|
394
398
|
```ruby
|
@@ -512,7 +516,7 @@ For more examples, check out: https://github.com/IFTTT/kashmir/blob/master/test/
|
|
512
516
|
Caching is the best feature in Kashmir.
|
513
517
|
The `Kashmir::Caching` module will cache every level of the dependency tree Kashmir generates when representing an object.
|
514
518
|
|
515
|
-

|
516
520
|
|
517
521
|
As you can see in the image above, Kashmir will build a dependency tree of the representation.
|
518
522
|
If you have Caching on, Kashmir will:
|
@@ -527,7 +531,7 @@ Kashmir will also be able to fill in blanks in the dependency tree and fetch mis
|
|
527
531
|
Caching is turned off by default, but you can use one of the two available implementations.
|
528
532
|
|
529
533
|
- [In Memory Caching] https://github.com/IFTTT/kashmir/blob/master/lib/kashmir/plugins/memory_caching.rb
|
530
|
-
- [Memcached] https://github.com/IFTTT/kashmir/blob/master/lib/kashmir/plugins/memcached_caching.rb
|
534
|
+
- [Memcached] https://github.com/IFTTT/kashmir/blob/master/lib/kashmir/plugins/memcached_caching.rb
|
531
535
|
|
532
536
|
You can also build your own custom caching engine by following the `NullCaching` protocol available at:
|
533
537
|
https://github.com/IFTTT/kashmir/blob/master/lib/kashmir/plugins/null_caching.rb
|
@@ -542,6 +546,8 @@ Kashmir.init(
|
|
542
546
|
|
543
547
|
##### With Memcached
|
544
548
|
```ruby
|
549
|
+
require 'kashmir/plugins/memcached_caching'
|
550
|
+
|
545
551
|
client = Dalli::Client.new(url, namespace: 'kashmir', compress: true)
|
546
552
|
default_ttl = 5.minutes
|
547
553
|
|
data/kashmir.gemspec
CHANGED
@@ -21,8 +21,6 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_runtime_dependency "colorize", "~> 0.7"
|
25
|
-
|
26
24
|
spec.add_development_dependency "bundler", "~> 1.7"
|
27
25
|
spec.add_development_dependency "rake", "~> 10.0"
|
28
26
|
spec.add_development_dependency "minitest", "~> 5.0"
|
@@ -30,6 +28,5 @@ Gem::Specification.new do |spec|
|
|
30
28
|
spec.add_development_dependency "mocha", "~> 1.1"
|
31
29
|
spec.add_development_dependency "sqlite3", "1.3.10"
|
32
30
|
|
33
|
-
spec.add_development_dependency "
|
34
|
-
spec.add_development_dependency "activerecord", "3.2.8"
|
31
|
+
spec.add_development_dependency "activerecord", "~> 4.2"
|
35
32
|
end
|
data/lib/kashmir.rb
CHANGED
data/lib/kashmir/caching.rb
CHANGED
@@ -1,39 +1,37 @@
|
|
1
1
|
require 'kashmir/plugins/memory_caching'
|
2
2
|
require 'kashmir/plugins/null_caching'
|
3
|
-
require 'kashmir/plugins/memcached_caching'
|
4
|
-
require 'colorize'
|
5
3
|
|
6
4
|
module Kashmir
|
7
5
|
module Caching
|
8
6
|
|
9
7
|
def from_cache(representation_definition, object)
|
10
|
-
log("
|
8
|
+
log("read: #{log_key(object, representation_definition)}", :debug)
|
11
9
|
|
12
10
|
cached_representation = Kashmir.caching.from_cache(representation_definition, object)
|
13
11
|
|
14
12
|
if cached_representation
|
15
|
-
log("
|
13
|
+
log("hit: #{log_key(object, representation_definition)}")
|
16
14
|
else
|
17
|
-
log("
|
15
|
+
log("miss: #{log_key(object, representation_definition)}")
|
18
16
|
end
|
19
17
|
|
20
18
|
cached_representation
|
21
19
|
end
|
22
20
|
|
23
21
|
def bulk_from_cache(representation_definition, objects)
|
24
|
-
class_name = objects.
|
25
|
-
log("
|
22
|
+
class_name = objects.length > 0 ? objects.first.class.to_s : ''
|
23
|
+
log("read_multi: [#{objects.length}]#{class_name} : #{representation_definition}", :debug)
|
26
24
|
Kashmir.caching.bulk_from_cache(representation_definition, objects)
|
27
25
|
end
|
28
26
|
|
29
27
|
def store_presenter(representation_definition, representation, object, ttl)
|
30
|
-
log("
|
28
|
+
log("write TTL: #{ttl}: #{log_key(object, representation_definition)}", :debug)
|
31
29
|
Kashmir.caching.store_presenter(representation_definition, representation, object, ttl)
|
32
30
|
end
|
33
31
|
|
34
32
|
def bulk_write(representation_definition, representations, objects, ttl)
|
35
|
-
class_name = objects.
|
36
|
-
log("
|
33
|
+
class_name = objects.length > 0 ? objects.first.class.to_s : ''
|
34
|
+
log("write_multi: TTL: #{ttl}: [#{objects.length}]#{class_name} : #{representation_definition}", :debug)
|
37
35
|
Kashmir.caching.bulk_write(representation_definition, representations, objects, ttl)
|
38
36
|
end
|
39
37
|
|
@@ -42,7 +40,7 @@ module Kashmir
|
|
42
40
|
end
|
43
41
|
|
44
42
|
def log(message, level=:info)
|
45
|
-
Kashmir.logger.send(level, ("\
|
43
|
+
Kashmir.logger.send(level, ("\nKashmir::Caching #{message}\n"))
|
46
44
|
end
|
47
45
|
|
48
46
|
module_function :from_cache, :bulk_from_cache, :bulk_write, :store_presenter, :log_key, :log
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# We have to reopen Preloader to allow for it
|
2
2
|
# to accept any random attribute name as a preloadable association.
|
3
3
|
#
|
4
|
-
# This allows us to send any
|
5
|
-
#
|
4
|
+
# This allows us to send any arbitrary Hash to Preloader, without
|
5
|
+
# requiring it to be an ActiveRecord relation in advance.
|
6
6
|
#
|
7
7
|
|
8
8
|
module ArV4Patch
|
@@ -26,6 +26,8 @@ module ArV4Patch
|
|
26
26
|
klasses = h[assoc.reflection] ||= {}
|
27
27
|
(klasses[assoc.klass] ||= []) << record
|
28
28
|
end
|
29
|
+
|
30
|
+
h.delete(nil)
|
29
31
|
h
|
30
32
|
end
|
31
33
|
end
|
@@ -12,7 +12,11 @@ module Kashmir
|
|
12
12
|
end
|
13
13
|
|
14
14
|
if to_load.any?
|
15
|
-
ActiveRecord::
|
15
|
+
if ActiveRecord::VERSION::STRING >= "4.0.2"
|
16
|
+
ActiveRecord::Associations::Preloader.new.preload(to_load, representation_definition)
|
17
|
+
else
|
18
|
+
ActiveRecord::Associations::Preloader.new(to_load, representation_definition).run
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
to_load_representations = to_load.map do |subject|
|
data/lib/kashmir/version.rb
CHANGED
data/test/caching_test.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kashmir
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- IFTTT
|
@@ -9,22 +9,8 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
12
|
+
date: 2015-07-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
-
- !ruby/object:Gem::Dependency
|
15
|
-
name: colorize
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
requirements:
|
18
|
-
- - "~>"
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: '0.7'
|
21
|
-
type: :runtime
|
22
|
-
prerelease: false
|
23
|
-
version_requirements: !ruby/object:Gem::Requirement
|
24
|
-
requirements:
|
25
|
-
- - "~>"
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
version: '0.7'
|
28
14
|
- !ruby/object:Gem::Dependency
|
29
15
|
name: bundler
|
30
16
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,33 +96,19 @@ dependencies:
|
|
110
96
|
- !ruby/object:Gem::Version
|
111
97
|
version: 1.3.10
|
112
98
|
- !ruby/object:Gem::Dependency
|
113
|
-
name:
|
99
|
+
name: activerecord
|
114
100
|
requirement: !ruby/object:Gem::Requirement
|
115
101
|
requirements:
|
116
102
|
- - "~>"
|
117
103
|
- !ruby/object:Gem::Version
|
118
|
-
version: '2
|
104
|
+
version: '4.2'
|
119
105
|
type: :development
|
120
106
|
prerelease: false
|
121
107
|
version_requirements: !ruby/object:Gem::Requirement
|
122
108
|
requirements:
|
123
109
|
- - "~>"
|
124
110
|
- !ruby/object:Gem::Version
|
125
|
-
version: '2
|
126
|
-
- !ruby/object:Gem::Dependency
|
127
|
-
name: activerecord
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
129
|
-
requirements:
|
130
|
-
- - '='
|
131
|
-
- !ruby/object:Gem::Version
|
132
|
-
version: 3.2.8
|
133
|
-
type: :development
|
134
|
-
prerelease: false
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
136
|
-
requirements:
|
137
|
-
- - '='
|
138
|
-
- !ruby/object:Gem::Version
|
139
|
-
version: 3.2.8
|
111
|
+
version: '4.2'
|
140
112
|
description: "\n Kashmir helps you easily define decorators/representers/presenters
|
141
113
|
for ruby objects.\n Optionally, Kashmir will also cache these views for faster
|
142
114
|
lookups.\n "
|
@@ -148,8 +120,7 @@ extensions: []
|
|
148
120
|
extra_rdoc_files: []
|
149
121
|
files:
|
150
122
|
- Gemfile
|
151
|
-
-
|
152
|
-
- LICENSE.txt
|
123
|
+
- LICENSE
|
153
124
|
- README.md
|
154
125
|
- Rakefile
|
155
126
|
- kashmir.gemspec
|
data/Gemfile.lock
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
kashmir (0.0.1)
|
5
|
-
colorize (~> 0.7)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (3.2.22)
|
11
|
-
activesupport (= 3.2.22)
|
12
|
-
builder (~> 3.0.0)
|
13
|
-
activerecord (3.2.22)
|
14
|
-
activemodel (= 3.2.22)
|
15
|
-
activesupport (= 3.2.22)
|
16
|
-
arel (~> 3.0.2)
|
17
|
-
tzinfo (~> 0.3.29)
|
18
|
-
activesupport (3.2.22)
|
19
|
-
i18n (~> 0.6, >= 0.6.4)
|
20
|
-
multi_json (~> 1.0)
|
21
|
-
arel (3.0.3)
|
22
|
-
builder (3.0.4)
|
23
|
-
colorize (0.7.7)
|
24
|
-
dalli (2.7.4)
|
25
|
-
i18n (0.7.0)
|
26
|
-
metaclass (0.0.4)
|
27
|
-
minitest (5.5.1)
|
28
|
-
minitest-around (0.3.2)
|
29
|
-
minitest (~> 5.0)
|
30
|
-
mocha (1.1.0)
|
31
|
-
metaclass (~> 0.0.1)
|
32
|
-
multi_json (1.11.1)
|
33
|
-
rake (10.4.2)
|
34
|
-
sqlite3 (1.3.10)
|
35
|
-
tzinfo (0.3.44)
|
36
|
-
|
37
|
-
PLATFORMS
|
38
|
-
ruby
|
39
|
-
|
40
|
-
DEPENDENCIES
|
41
|
-
activerecord (~> 3.2.8)
|
42
|
-
bundler (~> 1.7)
|
43
|
-
dalli (~> 2.7)
|
44
|
-
kashmir!
|
45
|
-
minitest (~> 5.0)
|
46
|
-
minitest-around (~> 0.3)
|
47
|
-
mocha (~> 1.1.0)
|
48
|
-
rake (~> 10.0)
|
49
|
-
sqlite3 (= 1.3.10)
|