perforated 0.8.2 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +2 -2
- data/README.md +3 -3
- data/bench/giant.rb +11 -11
- data/bench/rebuilder.rb +23 -0
- data/lib/perforated.rb +1 -5
- data/lib/perforated/cache.rb +27 -29
- data/lib/perforated/compatibility/find_in_batches.rb +11 -0
- data/lib/perforated/rebuilder.rb +50 -0
- data/lib/perforated/strategy.rb +9 -0
- data/lib/perforated/version.rb +1 -1
- data/perforated.gemspec +1 -1
- data/spec/perforated/cache_spec.rb +27 -38
- data/spec/perforated/compatibility/find_in_batches_spec.rb +25 -0
- data/spec/perforated/rebuilder_spec.rb +18 -0
- metadata +12 -8
- data/lib/perforated/rooted.rb +0 -33
- data/lib/perforated/strategy/default.rb +0 -11
- data/spec/perforated/rooted_spec.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: af43ff72681ac3aa03057419afb02db11d89dcec
|
4
|
+
data.tar.gz: 52f9abfc9c9239e34fbde54958e22f8bdbf3d9e7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c84edc00c26382975abd7a028687c54e9cc2f99c1717324f95a60aa2fc3bb9471acff847a1b65cead2aaa62a03509c4af0a95f7083b6c4eecf49d46b201cec3
|
7
|
+
data.tar.gz: 01eba26e7cb2e63d9ac66cedebed88b2a2b7943aacbf9a928d3bfef8d6ebeaed53db168f748581cececc235c5f51643d86e1aac845c3a71ff9275ccd0204da8e
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## Version 0.9.0
|
2
|
+
|
3
|
+
* `as_json` and `to_json` now take a block. The block will be applied to each
|
4
|
+
model as it is being cached, allowing for serializers or presenters without
|
5
|
+
much additional memory overhead.
|
6
|
+
* `as_json` has been removed. The overhead from marshalling/unmarshalling had
|
7
|
+
enough overhead that it negated the caching benefits.
|
8
|
+
* Strategies no longer expect a `suffix` property, as anything cached is
|
9
|
+
expected to be a JSON string.
|
10
|
+
* Caching is performed in batches, which can be controlled by passing
|
11
|
+
`batch_size` through to `to_json`. Arrays are refined to support
|
12
|
+
`find_in_batches` in order to maintain compatibility with ActiveRecord
|
13
|
+
Relations. For especially large collections this can provide significant
|
14
|
+
memory savings (particularly when paired with passing a block through for
|
15
|
+
custom serialization).
|
16
|
+
|
1
17
|
## Version 0.8.2
|
2
18
|
|
3
19
|
* Really force the use of custom `fetch_multi` when using `NullStore`, not just
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -117,12 +117,12 @@ cache method you can provide a custom key caching strategy.
|
|
117
117
|
|
118
118
|
```ruby
|
119
119
|
module CustomStrategy
|
120
|
-
def self.expand_cache_key(object
|
121
|
-
[object.id, object.updated_at
|
120
|
+
def self.expand_cache_key(object)
|
121
|
+
[object.id, object.updated_at].join('/')
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
125
|
-
perforated = Perforated
|
125
|
+
perforated = Perforated.new(array, CustomStrategy)
|
126
126
|
```
|
127
127
|
|
128
128
|
## Installation
|
data/bench/giant.rb
CHANGED
@@ -3,10 +3,8 @@ require 'bundler'
|
|
3
3
|
Bundler.setup
|
4
4
|
|
5
5
|
require 'benchmark'
|
6
|
-
require 'dalli'
|
7
6
|
require 'perforated'
|
8
7
|
require 'active_support/core_ext/object'
|
9
|
-
require 'active_support/cache/dalli_store'
|
10
8
|
require 'redis'
|
11
9
|
require 'redis-activesupport'
|
12
10
|
|
@@ -17,7 +15,7 @@ Structure = Struct.new(:id) do
|
|
17
15
|
end
|
18
16
|
|
19
17
|
module Strategy
|
20
|
-
def self.expand_cache_key(object
|
18
|
+
def self.expand_cache_key(object)
|
21
19
|
"perf-#{object}"
|
22
20
|
end
|
23
21
|
end
|
@@ -25,24 +23,26 @@ end
|
|
25
23
|
perforated = Perforated::Cache.new((0..20_000).map { |i| Structure.new(i) }, Strategy)
|
26
24
|
|
27
25
|
Benchmark.bm do |x|
|
26
|
+
GC.disable
|
27
|
+
puts "Total Objects: #{ObjectSpace.count_objects[:TOTAL]}"
|
28
|
+
|
28
29
|
x.report('memory-1') { perforated.to_json }
|
29
30
|
x.report('memory-2') { perforated.to_json }
|
30
31
|
|
32
|
+
puts "Total Objects: #{ObjectSpace.count_objects[:TOTAL]}"
|
33
|
+
|
31
34
|
Perforated.configure do |config|
|
32
35
|
config.cache = ActiveSupport::Cache::RedisStore.new(host: 'localhost', db: 5)
|
33
36
|
end
|
34
37
|
|
35
38
|
Perforated.cache.clear
|
36
39
|
|
40
|
+
GC.enable
|
41
|
+
GC.start
|
42
|
+
GC.disable
|
43
|
+
|
37
44
|
x.report('redis-1') { perforated.to_json }
|
38
45
|
x.report('redis-2') { perforated.to_json }
|
39
46
|
|
40
|
-
|
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 }
|
47
|
+
puts "Total Objects: #{ObjectSpace.count_objects[:TOTAL]}"
|
48
48
|
end
|
data/bench/rebuilder.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
|
3
|
+
Bundler.setup
|
4
|
+
|
5
|
+
require 'benchmark'
|
6
|
+
require 'perforated'
|
7
|
+
require 'oj'
|
8
|
+
|
9
|
+
keys = %w[notes tags comments]
|
10
|
+
objects = (0..10_000).map do |num|
|
11
|
+
keys = keys.rotate
|
12
|
+
|
13
|
+
{ keys.first => num }
|
14
|
+
end
|
15
|
+
|
16
|
+
strings = objects.map { |obj| JSON.dump(obj) }
|
17
|
+
rebuilder = Perforated::Rebuilder.new(strings, Oj)
|
18
|
+
|
19
|
+
N = 100
|
20
|
+
|
21
|
+
Benchmark.bmbm do |x|
|
22
|
+
x.report('rebuild') { N.times { rebuilder.rebuild(rooted: true) } }
|
23
|
+
end
|
data/lib/perforated.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
require 'active_support/cache'
|
2
2
|
require 'json'
|
3
3
|
require 'perforated/cache'
|
4
|
-
require 'perforated/compatibility/fetch_multi'
|
5
|
-
require 'perforated/rooted'
|
6
|
-
require 'perforated/strategy/default'
|
7
|
-
require 'perforated/version'
|
8
4
|
|
9
5
|
module Perforated
|
10
6
|
extend self
|
11
7
|
|
12
8
|
def new(*args)
|
13
|
-
Perforated::Cache.new(args)
|
9
|
+
Perforated::Cache.new(*args)
|
14
10
|
end
|
15
11
|
|
16
12
|
def cache=(new_cache)
|
data/lib/perforated/cache.rb
CHANGED
@@ -1,40 +1,42 @@
|
|
1
|
+
require 'perforated/rebuilder'
|
2
|
+
require 'perforated/strategy'
|
3
|
+
require 'perforated/compatibility/find_in_batches'
|
4
|
+
require 'perforated/compatibility/fetch_multi'
|
5
|
+
|
1
6
|
module Perforated
|
2
7
|
class Cache
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(enumerable, key_strategy = Perforated::Strategy::Default)
|
6
|
-
@enumerable = enumerable
|
7
|
-
@key_strategy = key_strategy
|
8
|
-
end
|
8
|
+
using Perforated::Compatibility::FindInBatches
|
9
9
|
|
10
|
-
|
11
|
-
keyed = keyed_enumerable('as-json')
|
12
|
-
objects = fetch_multi(keyed) { |key| keyed[key].as_json }.values
|
10
|
+
attr_accessor :enumerable, :strategy
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
objects
|
18
|
-
end
|
12
|
+
def initialize(enumerable, strategy = Perforated::Strategy)
|
13
|
+
@enumerable = enumerable
|
14
|
+
@strategy = strategy
|
19
15
|
end
|
20
16
|
|
21
|
-
def to_json(
|
22
|
-
|
23
|
-
objects = fetch_multi(keyed) { |key| keyed[key].to_json }
|
24
|
-
concat = concatenate(objects)
|
17
|
+
def to_json(rooted: false, batch_size: 1000, &block)
|
18
|
+
results = []
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
20
|
+
enumerable.find_in_batches(batch_size: batch_size) do |subset|
|
21
|
+
keyed = key_mapped(subset)
|
22
|
+
|
23
|
+
results << fetch_multi(keyed) do |key|
|
24
|
+
if block_given?
|
25
|
+
(yield keyed[key]).to_json
|
26
|
+
else
|
27
|
+
keyed[key].to_json
|
28
|
+
end
|
29
|
+
end.values
|
30
30
|
end
|
31
|
+
|
32
|
+
Perforated::Rebuilder.new(results).rebuild(rooted: rooted)
|
31
33
|
end
|
32
34
|
|
33
35
|
private
|
34
36
|
|
35
|
-
def
|
36
|
-
|
37
|
-
memo[
|
37
|
+
def key_mapped(subset)
|
38
|
+
subset.each_with_object({}) do |object, memo|
|
39
|
+
memo[strategy.expand_cache_key(object)] = object
|
38
40
|
end
|
39
41
|
end
|
40
42
|
|
@@ -43,9 +45,5 @@ module Perforated
|
|
43
45
|
|
44
46
|
Perforated::Compatibility.fetch_multi(*keys, &block)
|
45
47
|
end
|
46
|
-
|
47
|
-
def concatenate(objects)
|
48
|
-
"[#{objects.values.join(',')}]"
|
49
|
-
end
|
50
48
|
end
|
51
49
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Perforated
|
4
|
+
class Rebuilder
|
5
|
+
attr_reader :parser, :strings
|
6
|
+
|
7
|
+
def initialize(strings, parser = Perforated.json)
|
8
|
+
@strings = strings
|
9
|
+
@parser = parser
|
10
|
+
end
|
11
|
+
|
12
|
+
def rebuild(rooted: false)
|
13
|
+
if rooted
|
14
|
+
parser.dump(merge(parser.load(concatenated)))
|
15
|
+
else
|
16
|
+
concatenated
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def concatenated
|
21
|
+
"[#{strings.join(',')}]"
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def merge(objects)
|
27
|
+
merged = objects.each_with_object({}) do |object, memo|
|
28
|
+
object.each do |key, value|
|
29
|
+
memo[key] ||= Set.new
|
30
|
+
|
31
|
+
if value.is_a?(Array)
|
32
|
+
memo[key].merge(value)
|
33
|
+
else
|
34
|
+
memo[key].add(value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
sets_to_arrays(merged)
|
40
|
+
end
|
41
|
+
|
42
|
+
def sets_to_arrays(merged)
|
43
|
+
merged.each do |key, value|
|
44
|
+
merged[key] = value.to_a
|
45
|
+
end
|
46
|
+
|
47
|
+
merged
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/perforated/version.rb
CHANGED
data/perforated.gemspec
CHANGED
@@ -4,12 +4,8 @@ describe Perforated::Cache do
|
|
4
4
|
after { Perforated.cache.clear }
|
5
5
|
|
6
6
|
Language = Struct.new(:name) do
|
7
|
-
def as_json
|
8
|
-
{ name: name }
|
9
|
-
end
|
10
|
-
|
11
7
|
def to_json
|
12
|
-
|
8
|
+
{ name: name }.to_json
|
13
9
|
end
|
14
10
|
|
15
11
|
def cache_key
|
@@ -18,12 +14,8 @@ describe Perforated::Cache do
|
|
18
14
|
end
|
19
15
|
|
20
16
|
Family = Struct.new(:name, :languages) do
|
21
|
-
def as_json
|
22
|
-
{ languages: languages }
|
23
|
-
end
|
24
|
-
|
25
17
|
def to_json
|
26
|
-
|
18
|
+
{ languages: languages }.to_json
|
27
19
|
end
|
28
20
|
|
29
21
|
def cache_key
|
@@ -31,54 +23,51 @@ describe Perforated::Cache do
|
|
31
23
|
end
|
32
24
|
end
|
33
25
|
|
34
|
-
describe '#
|
35
|
-
it 'constructs
|
26
|
+
describe '#to_json' do
|
27
|
+
it 'constructs a stringified json array of underlying values' do
|
36
28
|
ruby = Language.new('Ruby')
|
37
29
|
elixir = Language.new('Elixir')
|
38
30
|
cache = Perforated::Cache.new([ruby, elixir])
|
39
31
|
|
40
|
-
expect(cache.
|
41
|
-
|
42
|
-
expect(Perforated.cache.
|
43
|
-
expect(Perforated.cache.read('Language/Elixir/as-json')).to eq(elixir.as_json)
|
32
|
+
expect(cache.to_json).to eq(%([{"name":"Ruby"},{"name":"Elixir"}]))
|
33
|
+
expect(Perforated.cache.exist?('Language/Ruby')).to be_truthy
|
34
|
+
expect(Perforated.cache.exist?('Language/Elixir')).to be_truthy
|
44
35
|
end
|
45
36
|
|
46
37
|
it 'does not overwrite existing key values' do
|
47
38
|
erlang = Language.new('Erlang')
|
48
|
-
Perforated.cache.write('Language/Erlang
|
49
|
-
|
50
|
-
Perforated::Cache.new([erlang]).as_json
|
51
|
-
|
52
|
-
expect(Perforated.cache.read('Language/Erlang/as-json')).to eq(name: 'Elixir')
|
53
|
-
end
|
39
|
+
Perforated.cache.write('Language/Erlang', JSON.dump(name: 'Elixir'))
|
54
40
|
|
55
|
-
|
56
|
-
lisps = Family.new('Lisp', ['scheme', 'clojure'])
|
57
|
-
scripts = Family.new('Script', ['perl', 'ruby'])
|
58
|
-
cache = Perforated::Cache.new([lisps, scripts])
|
41
|
+
Perforated::Cache.new([erlang]).to_json
|
59
42
|
|
60
|
-
expect(cache.
|
61
|
-
languages: %w[scheme clojure perl ruby]
|
62
|
-
)
|
43
|
+
expect(Perforated.cache.read('Language/Erlang')).to eq(JSON.dump(name: 'Elixir'))
|
63
44
|
end
|
64
45
|
|
65
46
|
it 'safely returns an empty enumerable when empty' do
|
66
47
|
cache = Perforated::Cache.new([])
|
67
48
|
|
68
|
-
expect(cache.
|
69
|
-
expect(cache.
|
49
|
+
expect(cache.to_json).to eq('[]')
|
50
|
+
expect(cache.to_json(rooted: true)).to eq('{}')
|
70
51
|
end
|
71
|
-
end
|
72
52
|
|
73
|
-
|
74
|
-
|
75
|
-
cache = Perforated::Cache.new([
|
53
|
+
it 'applies a provided block to the object before caching' do
|
54
|
+
ruby = Language.new('Ruby')
|
55
|
+
cache = Perforated::Cache.new([ruby])
|
76
56
|
|
77
|
-
|
78
|
-
|
79
|
-
|
57
|
+
serializer = Struct.new(:lang) do
|
58
|
+
def to_json
|
59
|
+
{ name: lang.name.upcase }.to_json
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
results = cache.to_json do |lang|
|
64
|
+
serializer.new(lang)
|
65
|
+
end
|
66
|
+
|
67
|
+
expect(results).to eq(JSON.dump([{ name: 'RUBY' }]))
|
80
68
|
end
|
81
69
|
|
70
|
+
|
82
71
|
it 'reconstructs rooted objects into a single merged object' do
|
83
72
|
lisps = Family.new('Lisp', ['scheme', 'clojure'])
|
84
73
|
scripts = Family.new('Script', ['perl', 'ruby'])
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'perforated/compatibility/find_in_batches'
|
2
|
+
|
3
|
+
describe Perforated::Compatibility::FindInBatches do
|
4
|
+
FindBatches = Struct.new(:array) do
|
5
|
+
using Perforated::Compatibility::FindInBatches
|
6
|
+
|
7
|
+
def perform(&block)
|
8
|
+
array.find_in_batches(batch_size: 50, &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#find_in_batches' do
|
13
|
+
it 'iterates over an enumerable in batches' do
|
14
|
+
enumerable = [1] * 100
|
15
|
+
eachable = FindBatches.new(enumerable)
|
16
|
+
results = []
|
17
|
+
|
18
|
+
eachable.perform do |arr|
|
19
|
+
results << arr.reduce(&:+)
|
20
|
+
end
|
21
|
+
|
22
|
+
expect(results).to eq([50, 50])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'perforated/rebuilder'
|
3
|
+
|
4
|
+
describe Perforated::Rebuilder do
|
5
|
+
describe '#rebuild' do
|
6
|
+
it 'merges stringified json' do
|
7
|
+
string_a = JSON.dump(families: { name: 'lang' }, languages: [{ name: 'scheme' }])
|
8
|
+
string_b = JSON.dump(families: { name: 'lang' }, languages: [{ name: 'clojure' }])
|
9
|
+
string_c = JSON.dump(families: { name: 'lang' })
|
10
|
+
|
11
|
+
rooted = Perforated::Rebuilder.new([string_a, string_b], JSON)
|
12
|
+
|
13
|
+
expect(rooted.rebuild(rooted: true)).to eq(
|
14
|
+
'{"families":[{"name":"lang"}],"languages":[{"name":"scheme"},{"name":"clojure"}]}'
|
15
|
+
)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: perforated
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Parker Selbert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '3'
|
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: '
|
68
|
+
version: '3'
|
69
69
|
description: Intellgent json collection caching
|
70
70
|
email:
|
71
71
|
- parker@sorentwo.com
|
@@ -82,16 +82,19 @@ files:
|
|
82
82
|
- README.md
|
83
83
|
- Rakefile
|
84
84
|
- bench/giant.rb
|
85
|
+
- bench/rebuilder.rb
|
85
86
|
- lib/perforated.rb
|
86
87
|
- lib/perforated/cache.rb
|
87
88
|
- lib/perforated/compatibility/fetch_multi.rb
|
88
|
-
- lib/perforated/
|
89
|
-
- lib/perforated/
|
89
|
+
- lib/perforated/compatibility/find_in_batches.rb
|
90
|
+
- lib/perforated/rebuilder.rb
|
91
|
+
- lib/perforated/strategy.rb
|
90
92
|
- lib/perforated/version.rb
|
91
93
|
- perforated.gemspec
|
92
94
|
- spec/perforated/cache_spec.rb
|
93
95
|
- spec/perforated/compatibility/fetch_multi_spec.rb
|
94
|
-
- spec/perforated/
|
96
|
+
- spec/perforated/compatibility/find_in_batches_spec.rb
|
97
|
+
- spec/perforated/rebuilder_spec.rb
|
95
98
|
- spec/perforated_spec.rb
|
96
99
|
- spec/spec_helper.rb
|
97
100
|
homepage: https://github.com/sorentwo/perforated
|
@@ -124,6 +127,7 @@ summary: 'The most expensive part of serving a JSON request is converting the se
|
|
124
127
|
test_files:
|
125
128
|
- spec/perforated/cache_spec.rb
|
126
129
|
- spec/perforated/compatibility/fetch_multi_spec.rb
|
127
|
-
- spec/perforated/
|
130
|
+
- spec/perforated/compatibility/find_in_batches_spec.rb
|
131
|
+
- spec/perforated/rebuilder_spec.rb
|
128
132
|
- spec/perforated_spec.rb
|
129
133
|
- spec/spec_helper.rb
|
data/lib/perforated/rooted.rb
DELETED
@@ -1,33 +0,0 @@
|
|
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,26 +0,0 @@
|
|
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
|