perforated 0.7.0 → 0.8.1

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: 2188079862ccf0f34ad99dc8ef2575101f54f6a4
4
- data.tar.gz: 1083c36661390745858282f788f483ac434fb7c2
3
+ metadata.gz: 76ef0f033815d6f9f08736cd6139bb8e068c3a26
4
+ data.tar.gz: f01094c162fa104f22388c4b2096484aba0e74f6
5
5
  SHA512:
6
- metadata.gz: 850b58a8bea4aed87934f41e03f47fb3a459eeaa1dd513dad53eaf5e41efc7e268cfbf5ee7688e01eaf6573ca0c98477ea1683c11aa4e956eaabdcbec160f4b6
7
- data.tar.gz: 55afde3e6a522aac92ce38cf4891b774065c7d69c59da9a3ff59f7fa5eb8d7cdc5854aa32c0b5e65b91abb4d2a3508db8ab2191250e644a1156d9d8e4db628a8
6
+ metadata.gz: 5dd441e560b300baf5b92b7e51a73a8e0371d0215b95fea05fb65909c8b43a64cc4b992f0b292d6ea45cc6da2bf6d12e35acce9fe2335143445af059d3c28eb3
7
+ data.tar.gz: 089d0af967d27c8632418adb021a8d9ab239a62e386325abadcba5df7dd9ddbaa792736185ecd30f77e1d4333521bbd1d64717d06509de0c759b5f2a1edbb705
data/.travis.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.0.0
4
+ - 2.1.0
4
5
  services:
5
6
  script: bundle exec rspec spec
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## Version 0.8.1
2
+
3
+ * Force use of custom implementation of `fetch_multi`. This makes using the
4
+ default ActiveSupport stores (Memory, Null) possible in versions of Rails
5
+ between 4.0 and 4.1.
6
+ * Use array extract option support in custom fetch.
7
+
8
+ ## Version 0.8.0
9
+
10
+ * Support reconstructing collections of rooted objects and associations.
11
+
1
12
  ## Version 0.7.0
2
13
 
3
14
  * Alter the implementation of `fetch_multi` to return a hash rather than an
data/Gemfile CHANGED
@@ -1,4 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in perforated-cache.gemspec
4
3
  gemspec
4
+
5
+ gem 'dalli'
6
+ gem 'redis'
7
+ gem 'redis-activesupport'
data/README.md CHANGED
@@ -1,5 +1,6 @@
1
1
  [![Build Status](https://travis-ci.org/sorentwo/perforated.png?branch=master)](https://travis-ci.org/sorentwo/perforated)
2
2
  [![Code Climate](https://codeclimate.com/github/sorentwo/perforated.png)](https://codeclimate.com/github/sorentwo/perforated)
3
+ [![Gem Version](https://badge.fury.io/rb/perforated.png)](http://badge.fury.io/rb/perforated)
3
4
 
4
5
  # Perforated
5
6
 
@@ -20,7 +21,7 @@ if you are so inclined you can customize the backing cache. The default cache
20
21
  store is `ActiveSupport::Cache::MemoryStore`, which is fast but has no
21
22
  persistence.
22
23
 
23
- Within a Rails project the simplest option is to lock with the Rails cache.
24
+ Within a Rails project the simplest option is to lock with the Rails cache:
24
25
 
25
26
  ```ruby
26
27
  Perforated.configure do |config|
@@ -36,9 +37,20 @@ Perforated.configure do |config|
36
37
  end
37
38
  ```
38
39
 
40
+ The standard library's JSON parser is great for most usage, and thus it is the
41
+ default. However, sometimes you may want a bit more control or performance:
42
+
43
+ ```ruby
44
+ require 'oj'
45
+
46
+ Perforated.configure do |config|
47
+ config.json = Oj
48
+ end
49
+ ```
50
+
39
51
  ## Usage
40
52
 
41
- Wrap any collection that you want to serialize in an a cache instance and then
53
+ Wrap any collection that you want to serialize in a cache instance and then
42
54
  call `as_json` or `to_json` on it. Not much to it!
43
55
 
44
56
  ```ruby
@@ -51,6 +63,35 @@ Any objects that have been cached will be retrieved unaltered. Any missing
51
63
  objects (cache misses) will be serialized, inserted back into the collection,
52
64
  and written into the cache.
53
65
 
66
+ Perforated supports reconstructing rooted objects, the likes of which can be
67
+ output by [ActiveModelSerializers][ams]. Serialized object collections may also
68
+ have associations serialized within the same cache key. After the cached
69
+ objects are fetched they will be merged together into flattened namespaces. For
70
+ example, given a serialized representation like this:
71
+
72
+ ```json
73
+ { "posts": { "id": 1, "author_id": 1, "title": "Greatness" },
74
+ "authors": [{ "id": 1, "name": "Myself" }] }
75
+
76
+ { "posts": { "id": 2, "author_id": 2, "title": "Failure" },
77
+ "authors": [{ "id": 2, "name": "Somebody" }] }
78
+ ```
79
+
80
+ The reconstructed and flattened represenation can be retrieved:
81
+
82
+ ```ruby
83
+ perforated.to_json(rooted: true) #=> {
84
+ "posts": [
85
+ { "id": 1, "author_id": 1, "title": "Greatness" },
86
+ { "id": 2, "author_id": 2, "title": "Failure" }
87
+ ],
88
+ "authors": [
89
+ { "id": 1, "name": "Myself" },
90
+ { "id": 2, "name": "Somebody" }
91
+ ]
92
+ }
93
+ ```
94
+
54
95
  ### Custom Key Strategy
55
96
 
56
97
  The default cache key strategy is to delegate back to each object to construct
@@ -88,7 +129,7 @@ perforated = Perforated::Cache.new(array, CustomStrategy)
88
129
 
89
130
  Add this line to your application's Gemfile:
90
131
 
91
- gem 'perforated-cache'
132
+ gem 'perforated'
92
133
 
93
134
  And then execute:
94
135
 
@@ -96,7 +137,7 @@ And then execute:
96
137
 
97
138
  Or install it yourself as:
98
139
 
99
- $ gem install perforated-cache
140
+ $ gem install perforated
100
141
 
101
142
  ## Contributing
102
143
 
@@ -105,3 +146,5 @@ Or install it yourself as:
105
146
  3. Commit your changes (`git commit -am 'Add some feature'`)
106
147
  4. Push to the branch (`git push origin my-new-feature`)
107
148
  5. Create new Pull Request
149
+
150
+ [ams]: https://github.com/rails-api/active_model_serializers
data/bench/giant.rb ADDED
@@ -0,0 +1,48 @@
1
+ require 'bundler'
2
+
3
+ Bundler.setup
4
+
5
+ require 'benchmark'
6
+ require 'dalli'
7
+ require 'perforated'
8
+ require 'active_support/core_ext/object'
9
+ require 'active_support/cache/dalli_store'
10
+ require 'redis'
11
+ require 'redis-activesupport'
12
+
13
+ Structure = Struct.new(:id) do
14
+ def to_json
15
+ { id: id, answers: %w[a b c d e f g], tags: [] }.to_json
16
+ end
17
+ end
18
+
19
+ module Strategy
20
+ def self.expand_cache_key(object, suffix)
21
+ "perf-#{object}"
22
+ end
23
+ end
24
+
25
+ perforated = Perforated::Cache.new((0..20_000).map { |i| Structure.new(i) }, Strategy)
26
+
27
+ Benchmark.bm do |x|
28
+ x.report('memory-1') { perforated.to_json }
29
+ x.report('memory-2') { perforated.to_json }
30
+
31
+ Perforated.configure do |config|
32
+ config.cache = ActiveSupport::Cache::RedisStore.new(host: 'localhost', db: 5)
33
+ end
34
+
35
+ Perforated.cache.clear
36
+
37
+ x.report('redis-1') { perforated.to_json }
38
+ x.report('redis-2') { perforated.to_json }
39
+
40
+ Perforated.configure do |config|
41
+ config.cache = ActiveSupport::Cache::DalliStore.new('localhost')
42
+ end
43
+
44
+ Perforated.cache.clear
45
+
46
+ x.report('dalli-1') { perforated.to_json }
47
+ x.report('dalli-2') { perforated.to_json }
48
+ end
@@ -7,32 +7,45 @@ module Perforated
7
7
  @key_strategy = key_strategy
8
8
  end
9
9
 
10
- def as_json(*)
11
- keyed = keyed_enumerable('as-json')
12
- keys = keyed.keys.map(&:dup)
13
-
14
- fetch_multi(keys) { |key| keyed[key].as_json }.values
10
+ def as_json(options = {})
11
+ keyed = keyed_enumerable('as-json')
12
+ objects = fetch_multi(keyed) { |key| keyed[key].as_json }.values
13
+
14
+ if options[:rooted]
15
+ Perforated::Rooted.merge(objects)
16
+ else
17
+ objects
18
+ end
15
19
  end
16
20
 
17
- def to_json(*)
21
+ def to_json(options = {})
18
22
  keyed = keyed_enumerable('to-json')
19
- keys = keyed.keys.map(&:dup)
20
- objects = fetch_multi(keys) { |key| keyed[key].to_json }
23
+ objects = fetch_multi(keyed) { |key| keyed[key].to_json }
24
+ concat = concatenate(objects)
21
25
 
22
- "[#{objects.values.join(',')}]"
26
+ if options[:rooted]
27
+ Perforated::Rooted.reconstruct(concat)
28
+ else
29
+ concat
30
+ end
23
31
  end
24
32
 
25
33
  private
26
34
 
27
35
  def keyed_enumerable(suffix = '')
28
- enumerable.inject({}) do |memo, object|
36
+ enumerable.each_with_object({}) do |object, memo|
29
37
  memo[key_strategy.expand_cache_key(object, suffix)] = object
30
- memo
31
38
  end
32
39
  end
33
40
 
34
- def fetch_multi(keys, &block)
35
- Perforated::Compatibility.fetch_multi *keys, &block
41
+ def fetch_multi(keyed, &block)
42
+ keys = keyed.keys.map(&:dup)
43
+
44
+ Perforated::Compatibility.fetch_multi(*keys, &block)
45
+ end
46
+
47
+ def concatenate(objects)
48
+ "[#{objects.values.join(',')}]"
36
49
  end
37
50
  end
38
51
  end
@@ -1,27 +1,31 @@
1
+ require 'active_support/core_ext/array/extract_options'
2
+
1
3
  module Perforated
2
4
  module Compatibility
3
5
  def self.fetch_multi(*names, &block)
4
- if Perforated.cache.respond_to?(:fetch_multi)
6
+ if supports_fetch_multi?
5
7
  Perforated.cache.fetch_multi(*names, &block)
6
8
  else
7
9
  custom_fetch_multi(*names, &block)
8
10
  end
9
11
  end
10
12
 
11
- # Backward compatible implementation of fetch multi.
12
13
  def self.custom_fetch_multi(*names)
13
- options = {}
14
+ options = names.extract_options!
14
15
  results = Perforated.cache.read_multi(*names, options)
15
16
 
16
- names.inject({}) do |memo, (name, _)|
17
+ names.each_with_object({}) do |(name, _), memo|
17
18
  memo[name] = results.fetch(name) do
18
19
  value = yield name
19
20
  Perforated.cache.write(name, value, options)
20
21
  value
21
22
  end
22
-
23
- memo
24
23
  end
25
24
  end
25
+
26
+ def self.supports_fetch_multi?
27
+ Perforated.cache.respond_to?(:fetch_multi) &&
28
+ !Perforated.cache.instance_of?(ActiveSupport::Cache::MemoryStore)
29
+ end
26
30
  end
27
31
  end
@@ -0,0 +1,33 @@
1
+ require 'set'
2
+
3
+ module Perforated
4
+ module Rooted
5
+ def self.merge(objects)
6
+ merged = objects.each_with_object({}) do |object, memo|
7
+ object.each do |key, value|
8
+ memo[key] ||= Set.new
9
+
10
+ if value.is_a?(Array)
11
+ memo[key].merge(value)
12
+ else
13
+ memo[key].add(value)
14
+ end
15
+ end
16
+ end
17
+
18
+ sets_to_arrays(merged)
19
+ end
20
+
21
+ def self.reconstruct(objects, parser = Perforated.json)
22
+ parser.dump(merge(parser.load(objects)))
23
+ end
24
+
25
+ def self.sets_to_arrays(object)
26
+ object.each do |key, value|
27
+ object[key] = value.to_a
28
+ end
29
+
30
+ object
31
+ end
32
+ end
33
+ end
@@ -1,3 +1,3 @@
1
1
  module Perforated
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.1'
3
3
  end
data/lib/perforated.rb CHANGED
@@ -2,6 +2,7 @@ require 'active_support/cache'
2
2
  require 'json'
3
3
  require 'perforated/cache'
4
4
  require 'perforated/compatibility/fetch_multi'
5
+ require 'perforated/rooted'
5
6
  require 'perforated/strategy/default'
6
7
  require 'perforated/version'
7
8
 
@@ -14,7 +15,20 @@ module Perforated
14
15
  @cache ||= ActiveSupport::Cache::MemoryStore.new
15
16
  end
16
17
 
18
+ def self.json=(new_json)
19
+ @json = new_json
20
+ end
21
+
22
+ def self.json
23
+ @json ||= JSON
24
+ end
25
+
17
26
  def self.configure
18
27
  yield self
19
28
  end
29
+
30
+ def self.reset!
31
+ @cache = nil
32
+ @json = nil
33
+ end
20
34
  end
data/perforated.gemspec CHANGED
@@ -24,7 +24,7 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_dependency 'activesupport', '> 3.0.0'
26
26
 
27
- spec.add_development_dependency 'bundler', '~> 1.3'
28
- spec.add_development_dependency 'rake', '~> 10.1.0'
29
- spec.add_development_dependency 'rspec', '~> 2.14.0'
27
+ spec.add_development_dependency 'bundler'
28
+ spec.add_development_dependency 'rake'
29
+ spec.add_development_dependency 'rspec', '~> 2.14'
30
30
  end
@@ -17,12 +17,25 @@ describe Perforated::Cache do
17
17
  end
18
18
  end
19
19
 
20
+ Family = Struct.new(:name, :languages) do
21
+ def as_json
22
+ { languages: languages }
23
+ end
24
+
25
+ def to_json
26
+ as_json.to_json
27
+ end
28
+
29
+ def cache_key
30
+ ['Family', name]
31
+ end
32
+ end
33
+
20
34
  describe '#as_json' do
21
35
  it 'constructs an automatically cached serialized' do
22
36
  ruby = Language.new('Ruby')
23
37
  elixir = Language.new('Elixir')
24
- array = [ruby, elixir]
25
- cache = Perforated::Cache.new(array)
38
+ cache = Perforated::Cache.new([ruby, elixir])
26
39
 
27
40
  expect(cache.as_json).to eq([{ name: 'Ruby' }, { name: 'Elixir' }])
28
41
 
@@ -38,6 +51,16 @@ describe Perforated::Cache do
38
51
 
39
52
  expect(Perforated.cache.read('Language/Erlang/as-json')).to eq(name: 'Elixir')
40
53
  end
54
+
55
+ it 'merges objects comprised of rooted arrays' do
56
+ lisps = Family.new('Lisp', ['scheme', 'clojure'])
57
+ scripts = Family.new('Script', ['perl', 'ruby'])
58
+ cache = Perforated::Cache.new([lisps, scripts])
59
+
60
+ expect(cache.as_json(rooted: true)).to eq(
61
+ languages: %w[scheme clojure perl ruby]
62
+ )
63
+ end
41
64
  end
42
65
 
43
66
  describe '#to_json' do
@@ -45,8 +68,18 @@ describe Perforated::Cache do
45
68
  cache = Perforated::Cache.new([Language.new('Ruby'), Language.new('Elixir')])
46
69
 
47
70
  expect(cache.to_json).to eq(%([{"name":"Ruby"},{"name":"Elixir"}]))
48
- expect(Perforated.cache.exist?('Language/Ruby/to-json')).to be_true
49
- expect(Perforated.cache.exist?('Language/Elixir/to-json')).to be_true
71
+ expect(Perforated.cache.exist?('Language/Ruby/to-json')).to be_truthy
72
+ expect(Perforated.cache.exist?('Language/Elixir/to-json')).to be_truthy
73
+ end
74
+
75
+ it 'reconstructs rooted objects into a single merged object' do
76
+ lisps = Family.new('Lisp', ['scheme', 'clojure'])
77
+ scripts = Family.new('Script', ['perl', 'ruby'])
78
+ cache = Perforated::Cache.new([lisps, scripts])
79
+
80
+ expect(cache.to_json(rooted: true)).to eq(
81
+ '{"languages":["scheme","clojure","perl","ruby"]}'
82
+ )
50
83
  end
51
84
  end
52
85
  end
@@ -5,11 +5,11 @@ describe Perforated::Compatibility do
5
5
 
6
6
  describe '.fetch_multi' do
7
7
  it 'uses the fetch_multi method on the configured cache if present' do
8
- cache = Perforated.cache = double(:cache, fetch_multi: true)
8
+ Perforated.cache = double(:store)
9
9
 
10
- Perforated::Compatibility.fetch_multi(:one, :two)
10
+ expect(Perforated.cache).to receive(:fetch_multi).with(:one, :two)
11
11
 
12
- expect(cache).to have_received(:fetch_multi).with(:one, :two)
12
+ Perforated::Compatibility.fetch_multi(:one, :two) { |key| key }
13
13
  end
14
14
 
15
15
  it 'falls back to the custom backfill if the cache does not support it' do
@@ -0,0 +1,26 @@
1
+ require 'perforated'
2
+
3
+ describe Perforated::Rooted do
4
+ describe '.merge' do
5
+ it 'merges all nested objects' do
6
+ obj_a = { languages: [{ name: 'scheme' }] }
7
+ obj_b = { languages: [{ name: 'clojure' }] }
8
+
9
+ expect(Perforated::Rooted.merge([obj_a, obj_b])).to eq(
10
+ languages: [{ name: 'scheme' }, { name: 'clojure' }]
11
+ )
12
+ end
13
+ end
14
+
15
+ describe '.reconstruct' do
16
+ it 'merges stringified json' do
17
+ obj_a = JSON.dump({ languages: [{ name: 'scheme' }] })
18
+ obj_b = JSON.dump({ languages: [{ name: 'clojure' }] })
19
+ concat = "[#{obj_a},#{obj_b}]"
20
+
21
+ expect(Perforated::Rooted.reconstruct(concat)).to eq(
22
+ '{"languages":[{"name":"scheme"},{"name":"clojure"}]}'
23
+ )
24
+ end
25
+ end
26
+ end
@@ -1,23 +1,32 @@
1
1
  require 'perforated'
2
2
 
3
3
  describe Perforated do
4
- after { Perforated.cache = nil }
4
+ after { Perforated.reset! }
5
5
 
6
6
  describe '#configuration' do
7
7
  it 'stores an injected cache object' do
8
8
  custom_cache = Object.new
9
+ custom_parse = Object.new
9
10
 
10
11
  Perforated.configure do |config|
11
12
  config.cache = custom_cache
13
+ config.json = custom_parse
12
14
  end
13
15
 
14
- Perforated.cache.should be(custom_cache)
16
+ expect(Perforated.cache).to be(custom_cache)
17
+ expect(Perforated.json).to be(custom_parse)
18
+ end
19
+ end
20
+
21
+ describe '#json' do
22
+ it 'falls back to core library json' do
23
+ expect(Perforated.json).to eq(JSON)
15
24
  end
16
25
  end
17
26
 
18
27
  describe '#cache' do
19
28
  it 'falls back to ActiveSupport::Cache::MemoryStore' do
20
- Perforated.cache.should be_instance_of(ActiveSupport::Cache::MemoryStore)
29
+ expect(Perforated.cache).to be_instance_of(ActiveSupport::Cache::MemoryStore)
21
30
  end
22
31
  end
23
32
  end
metadata CHANGED
@@ -1,71 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: perforated
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Parker Selbert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-21 00:00:00.000000000 Z
11
+ date: 2014-06-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>'
17
+ - - ">"
18
18
  - !ruby/object:Gem::Version
19
19
  version: 3.0.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>'
24
+ - - ">"
25
25
  - !ruby/object:Gem::Version
26
26
  version: 3.0.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '1.3'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '1.3'
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rake
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 10.1.0
47
+ version: '0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 10.1.0
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rspec
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 2.14.0
61
+ version: '2.14'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 2.14.0
68
+ version: '2.14'
69
69
  description: Intellgent json collection caching
70
70
  email:
71
71
  - parker@sorentwo.com
@@ -73,22 +73,25 @@ executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
- - .gitignore
77
- - .rspec
78
- - .travis.yml
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
79
  - CHANGELOG.md
80
80
  - Gemfile
81
81
  - LICENSE.txt
82
82
  - README.md
83
83
  - Rakefile
84
+ - bench/giant.rb
84
85
  - lib/perforated.rb
85
86
  - lib/perforated/cache.rb
86
87
  - lib/perforated/compatibility/fetch_multi.rb
88
+ - lib/perforated/rooted.rb
87
89
  - lib/perforated/strategy/default.rb
88
90
  - lib/perforated/version.rb
89
91
  - perforated.gemspec
90
92
  - spec/perforated/cache_spec.rb
91
93
  - spec/perforated/compatibility/fetch_multi_spec.rb
94
+ - spec/perforated/rooted_spec.rb
92
95
  - spec/perforated_spec.rb
93
96
  - spec/spec_helper.rb
94
97
  homepage: https://github.com/sorentwo/perforated
@@ -101,17 +104,17 @@ require_paths:
101
104
  - lib
102
105
  required_ruby_version: !ruby/object:Gem::Requirement
103
106
  requirements:
104
- - - '>='
107
+ - - ">="
105
108
  - !ruby/object:Gem::Version
106
109
  version: '0'
107
110
  required_rubygems_version: !ruby/object:Gem::Requirement
108
111
  requirements:
109
- - - '>='
112
+ - - ">="
110
113
  - !ruby/object:Gem::Version
111
114
  version: '0'
112
115
  requirements: []
113
116
  rubyforge_project:
114
- rubygems_version: 2.0.0
117
+ rubygems_version: 2.2.0
115
118
  signing_key:
116
119
  specification_version: 4
117
120
  summary: 'The most expensive part of serving a JSON request is converting the serialized
@@ -121,5 +124,6 @@ summary: 'The most expensive part of serving a JSON request is converting the se
121
124
  test_files:
122
125
  - spec/perforated/cache_spec.rb
123
126
  - spec/perforated/compatibility/fetch_multi_spec.rb
127
+ - spec/perforated/rooted_spec.rb
124
128
  - spec/perforated_spec.rb
125
129
  - spec/spec_helper.rb