collapsium 0.1.0 → 0.2.0
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/Gemfile.lock +1 -1
- data/lib/collapsium/prototype_match.rb +70 -0
- data/lib/collapsium/recursive_dup.rb +36 -0
- data/lib/collapsium/recursive_merge.rb +1 -1
- data/lib/collapsium/recursive_sort.rb +80 -0
- data/lib/collapsium/uber_hash.rb +6 -0
- data/lib/collapsium/version.rb +1 -1
- data/spec/prototype_match_spec.rb +67 -0
- data/spec/recursive_dup_spec.rb +22 -0
- data/spec/recursive_sort_spec.rb +83 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/uber_hash_spec.rb +17 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 39373bf60c53fa0099f0f3066725d0de62448e37
|
4
|
+
data.tar.gz: 460a9f149f29cd83210c72e5abd2715046329499
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1cf946152d25f4eadd5db380fc7907188b0152061b6d0be39e4676442ef272c8fb1efbfce2eba421be5e869466c09fced926dec919592d1cfc3d88228604acf
|
7
|
+
data.tar.gz: 39b05aa8b8d64e4608a56f241f7e97ade7a2379eb8867a315cd4480c2360d61cf4c51f90f2b5a67e421be6add9dacef01b96d3ef1c8d8d16c6d2485d4b1e570f
|
data/Gemfile.lock
CHANGED
@@ -0,0 +1,70 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# collapsium
|
4
|
+
# https://github.com/jfinkhaeuser/collapsium
|
5
|
+
#
|
6
|
+
# Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Collapsium
|
11
|
+
##
|
12
|
+
# Provides prototype matching for Hashes. See #prototype_match
|
13
|
+
module PrototypeMatch
|
14
|
+
##
|
15
|
+
# Given a prototype Hash, returns true if (recursively):
|
16
|
+
# - this hash contains all the prototype's keys, and
|
17
|
+
# - this hash contains all the prototype's values
|
18
|
+
# Note that this is not the same as equality. If the prototype provides a
|
19
|
+
# nil value for any key, then any value in this Hash is considered to be
|
20
|
+
# valid.
|
21
|
+
# @param prototype (Hash) The prototype to match against.
|
22
|
+
# @param strict (Boolean) If true, this Hash may not contain keys that are
|
23
|
+
# not present in the prototype.
|
24
|
+
# @return (Boolean) True if matching succeeds, false otherwise.
|
25
|
+
def prototype_match(prototype, strict = false)
|
26
|
+
# Prototype contains keys not in the Hash,so that's a failure.
|
27
|
+
if not (prototype.keys - keys).empty?
|
28
|
+
return false
|
29
|
+
end
|
30
|
+
|
31
|
+
# In strict evaluation, the Hash may also not contain keys that are not
|
32
|
+
# in the prototoype.
|
33
|
+
if strict and not (keys - prototype.keys).empty?
|
34
|
+
return false
|
35
|
+
end
|
36
|
+
|
37
|
+
# Now we have to examine the prototype's values.
|
38
|
+
prototype.each do |key, value|
|
39
|
+
# We can skip any nil values in the prototype. They exist only to ensure
|
40
|
+
# the key is present.
|
41
|
+
if value.nil?
|
42
|
+
next
|
43
|
+
end
|
44
|
+
|
45
|
+
# If the prototype value is a Hash, then the Hash value also has to be,
|
46
|
+
# and we have to recurse into this Hash.
|
47
|
+
if value.is_a?(Hash)
|
48
|
+
if not self[key].is_a?(Hash)
|
49
|
+
return false
|
50
|
+
end
|
51
|
+
|
52
|
+
self[key].extend(PrototypeMatch)
|
53
|
+
if not self[key].prototype_match(value)
|
54
|
+
return false
|
55
|
+
end
|
56
|
+
|
57
|
+
next
|
58
|
+
end
|
59
|
+
|
60
|
+
# Otherwise the prototype value must be equal to the Hash's value
|
61
|
+
if self[key] != value
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# All other cases must be true.
|
67
|
+
return true
|
68
|
+
end
|
69
|
+
end # module PrototypeMatch
|
70
|
+
end # module Collapsium
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# collapsium
|
4
|
+
# https://github.com/jfinkhaeuser/collapsium
|
5
|
+
#
|
6
|
+
# Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Collapsium
|
11
|
+
##
|
12
|
+
# Provides recursive (deep) dup function for hashes.
|
13
|
+
module RecursiveDup
|
14
|
+
def recursive_dup
|
15
|
+
ret = map do |k, v|
|
16
|
+
# Hash values, recurse into them.
|
17
|
+
if v.is_a?(Hash)
|
18
|
+
n = v.dup # we duplicate v to not extend it.
|
19
|
+
n.extend(RecursiveDup)
|
20
|
+
next [k, n.recursive_dup]
|
21
|
+
end
|
22
|
+
|
23
|
+
begin
|
24
|
+
# Other duplicatable values
|
25
|
+
next [k, v.dup]
|
26
|
+
rescue TypeError
|
27
|
+
# Values such as e.g. Fixnum
|
28
|
+
next [k, v]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
return Hash[ret]
|
32
|
+
end
|
33
|
+
|
34
|
+
alias deep_dup recursive_dup
|
35
|
+
end # module RecursiveDup
|
36
|
+
end # module Collapsium
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
#
|
3
|
+
# collapsium
|
4
|
+
# https://github.com/jfinkhaeuser/collapsium
|
5
|
+
#
|
6
|
+
# Copyright (c) 2016 Jens Finkhaeuser and other collapsium contributors.
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Collapsium
|
11
|
+
##
|
12
|
+
# Provides recursive sort functions for hashes.
|
13
|
+
module RecursiveSort
|
14
|
+
##
|
15
|
+
# Recursively sort a Hash by its keys. Without a block, this function will
|
16
|
+
# not be able to compare keys of different size.
|
17
|
+
def recursive_sort!(&block)
|
18
|
+
return keys.sort(&block).reduce(self) do |seed, key|
|
19
|
+
# Delete (and later re-insert) value for ordering
|
20
|
+
value = self[key]
|
21
|
+
delete(key)
|
22
|
+
|
23
|
+
# Recurse into Hash values
|
24
|
+
if value.is_a?(Hash)
|
25
|
+
value.extend(RecursiveSort)
|
26
|
+
value.recursive_sort!(&block)
|
27
|
+
end
|
28
|
+
|
29
|
+
# re-insert value
|
30
|
+
self[key] = value
|
31
|
+
|
32
|
+
next seed
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# Same as #recursive_sort!, but returns a copy.
|
38
|
+
def recursive_sort(&block)
|
39
|
+
ret = nil
|
40
|
+
if respond_to?(:recursive_dup)
|
41
|
+
ret = recursive_dup
|
42
|
+
else
|
43
|
+
ret = dup
|
44
|
+
end
|
45
|
+
ret.extend(RecursiveSort)
|
46
|
+
return ret.recursive_sort!(&block)
|
47
|
+
end
|
48
|
+
|
49
|
+
# def recursive_merge!(other, overwrite = true)
|
50
|
+
# if other.nil?
|
51
|
+
# return self
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# merger = proc do |_, v1, v2|
|
55
|
+
# # rubocop:disable Style/GuardClause
|
56
|
+
# if v1.is_a? Hash and v2.is_a? Hash
|
57
|
+
# next v1.merge(v2, &merger)
|
58
|
+
# elsif v1.is_a? Array and v2.is_a? Array
|
59
|
+
# next v1 + v2
|
60
|
+
# end
|
61
|
+
# if overwrite
|
62
|
+
# next v2
|
63
|
+
# else
|
64
|
+
# next v1
|
65
|
+
# end
|
66
|
+
# # rubocop:enable Style/GuardClause
|
67
|
+
# end
|
68
|
+
# merge!(other, &merger)
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# ##
|
72
|
+
# # Same as `dup.recursive_merge!`
|
73
|
+
# # @param (see #recursive_merge!)
|
74
|
+
# def recursive_merge(other, overwrite = true)
|
75
|
+
# copy = dup
|
76
|
+
# copy.extend(RecursiveMerge)
|
77
|
+
# return copy.recursive_merge!(other, overwrite)
|
78
|
+
# end
|
79
|
+
end # module RecursiveSort
|
80
|
+
end # module Collapsium
|
data/lib/collapsium/uber_hash.rb
CHANGED
@@ -8,15 +8,21 @@
|
|
8
8
|
#
|
9
9
|
|
10
10
|
require 'collapsium/recursive_merge'
|
11
|
+
require 'collapsium/recursive_dup'
|
12
|
+
require 'collapsium/recursive_sort'
|
11
13
|
require 'collapsium/indifferent_access'
|
12
14
|
require 'collapsium/pathed_access'
|
15
|
+
require 'collapsium/prototype_match'
|
13
16
|
|
14
17
|
module Collapsium
|
15
18
|
|
16
19
|
# A Hash that includes all the different Hash extensions in collapsium
|
17
20
|
class UberHash < Hash
|
18
21
|
include RecursiveMerge
|
22
|
+
include RecursiveDup
|
23
|
+
include RecursiveSort
|
19
24
|
include PathedAccess
|
25
|
+
include PrototypeMatch
|
20
26
|
|
21
27
|
def initialize(*args)
|
22
28
|
super
|
data/lib/collapsium/version.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/collapsium/prototype_match'
|
3
|
+
|
4
|
+
describe ::Collapsium::PrototypeMatch do
|
5
|
+
before :each do
|
6
|
+
@hash = {
|
7
|
+
'a' => 1,
|
8
|
+
:c => {
|
9
|
+
'd' => 4,
|
10
|
+
'f' => 6,
|
11
|
+
42 => 5,
|
12
|
+
},
|
13
|
+
'b' => 2,
|
14
|
+
}
|
15
|
+
@hash.extend(::Collapsium::PrototypeMatch)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "matches a prototype containing any individual key (non-strict)" do
|
19
|
+
# Keys exist in hash
|
20
|
+
expect(@hash.prototype_match('a' => nil)).to be_truthy
|
21
|
+
expect(@hash.prototype_match('b' => nil)).to be_truthy
|
22
|
+
expect(@hash.prototype_match(c: nil)).to be_truthy
|
23
|
+
|
24
|
+
# Key doesn't exist in hash
|
25
|
+
expect(@hash.prototype_match(foo: nil)).to be_falsy
|
26
|
+
end
|
27
|
+
|
28
|
+
it "does't match a prototype containing an individual key in strict mode" do
|
29
|
+
expect(@hash.prototype_match({ 'a' => nil }, true)).to be_falsy
|
30
|
+
end
|
31
|
+
|
32
|
+
it "matches nested prototypes (non-strict)" do
|
33
|
+
proto = {
|
34
|
+
c: {
|
35
|
+
'd' => nil,
|
36
|
+
}
|
37
|
+
}
|
38
|
+
expect(@hash.prototype_match(proto)).to be_truthy
|
39
|
+
end
|
40
|
+
|
41
|
+
it "doesn't match nested prototypes (strict)" do
|
42
|
+
proto = {
|
43
|
+
c: {
|
44
|
+
'd' => nil,
|
45
|
+
}
|
46
|
+
}
|
47
|
+
expect(@hash.prototype_match(proto, true)).to be_falsy
|
48
|
+
end
|
49
|
+
|
50
|
+
it "fails if a value type mismatches a prototype value's type" do
|
51
|
+
proto = {
|
52
|
+
c: {
|
53
|
+
'd' => {},
|
54
|
+
}
|
55
|
+
}
|
56
|
+
expect(@hash.prototype_match(proto)).to be_falsy
|
57
|
+
end
|
58
|
+
|
59
|
+
it "fails if a value mismatches a prototype value" do
|
60
|
+
proto = {
|
61
|
+
c: {
|
62
|
+
'd' => 42,
|
63
|
+
}
|
64
|
+
}
|
65
|
+
expect(@hash.prototype_match(proto)).to be_falsy
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/collapsium/recursive_dup'
|
3
|
+
|
4
|
+
describe ::Collapsium::RecursiveDup do
|
5
|
+
it "duplicates nested values" do
|
6
|
+
h = {
|
7
|
+
'a' => 1,
|
8
|
+
:c => {
|
9
|
+
'd' => 4,
|
10
|
+
'f' => 6,
|
11
|
+
42 => 5,
|
12
|
+
},
|
13
|
+
'b' => 2,
|
14
|
+
}
|
15
|
+
h.extend(::Collapsium::RecursiveDup)
|
16
|
+
|
17
|
+
h2 = h.deep_dup
|
18
|
+
|
19
|
+
expect(h2.object_id).not_to eql h.object_id
|
20
|
+
expect(h2[:c].object_id).not_to eql h[:c].object_id
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require_relative '../lib/collapsium/recursive_sort'
|
3
|
+
|
4
|
+
describe ::Collapsium::RecursiveSort do
|
5
|
+
before :each do
|
6
|
+
@tester = {}
|
7
|
+
@tester.extend(::Collapsium::RecursiveSort)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sorts a nested hash with string keys in place" do
|
11
|
+
h = {
|
12
|
+
'a' => 1,
|
13
|
+
'c' => {
|
14
|
+
'd' => 4,
|
15
|
+
'f' => 6,
|
16
|
+
'e' => 5,
|
17
|
+
},
|
18
|
+
'b' => 2,
|
19
|
+
}
|
20
|
+
h.extend(::Collapsium::RecursiveSort)
|
21
|
+
|
22
|
+
h.recursive_sort!
|
23
|
+
|
24
|
+
expect(h.keys).to eql %w(a b c)
|
25
|
+
expect(h['c'].keys).to eql %w(d e f)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "duplicates and sorts an outer hash (not deep)" do
|
29
|
+
h = {
|
30
|
+
'a' => 1,
|
31
|
+
'c' => {
|
32
|
+
'd' => 4,
|
33
|
+
'f' => 6,
|
34
|
+
'e' => 5,
|
35
|
+
},
|
36
|
+
'b' => 2,
|
37
|
+
}
|
38
|
+
h.extend(::Collapsium::RecursiveSort)
|
39
|
+
|
40
|
+
h2 = h.recursive_sort
|
41
|
+
|
42
|
+
# Only the new outer hash's keys are sorted
|
43
|
+
expect(h.keys).to eql %w(a c b)
|
44
|
+
expect(h2.keys).to eql %w(a b c)
|
45
|
+
|
46
|
+
# Both inner hashes are sorted because dup isn't deep
|
47
|
+
expect(h['c'].keys).to eql %w(d e f)
|
48
|
+
expect(h2['c'].keys).to eql %w(d e f)
|
49
|
+
|
50
|
+
# Similar with object IDs
|
51
|
+
expect(h.object_id).not_to eql h2.object_id
|
52
|
+
expect(h['c'].object_id).to eql h2['c'].object_id
|
53
|
+
end
|
54
|
+
|
55
|
+
it "it uses RecursiveDup if present" do
|
56
|
+
require_relative '../lib/collapsium/recursive_dup'
|
57
|
+
h = {
|
58
|
+
'a' => 1,
|
59
|
+
'c' => {
|
60
|
+
'd' => 4,
|
61
|
+
'f' => 6,
|
62
|
+
'e' => 5,
|
63
|
+
},
|
64
|
+
'b' => 2,
|
65
|
+
}
|
66
|
+
h.extend(::Collapsium::RecursiveSort)
|
67
|
+
h.extend(::Collapsium::RecursiveDup)
|
68
|
+
|
69
|
+
h2 = h.recursive_sort
|
70
|
+
|
71
|
+
# Only the new outer hash's keys are sorted
|
72
|
+
expect(h.keys).to eql %w(a c b)
|
73
|
+
expect(h2.keys).to eql %w(a b c)
|
74
|
+
|
75
|
+
# Only the new inner hash's keys are sorted
|
76
|
+
expect(h['c'].keys).to eql %w(d f e)
|
77
|
+
expect(h2['c'].keys).to eql %w(d e f)
|
78
|
+
|
79
|
+
# Similar with object IDs
|
80
|
+
expect(h.object_id).not_to eql h2.object_id
|
81
|
+
expect(h['c'].object_id).not_to eql h2['c'].object_id
|
82
|
+
end
|
83
|
+
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/uber_hash_spec.rb
CHANGED
@@ -41,4 +41,21 @@ describe Collapsium::UberHash do
|
|
41
41
|
x = ::Collapsium::UberHash.new
|
42
42
|
expect(x.empty?).to be_truthy
|
43
43
|
end
|
44
|
+
|
45
|
+
it "has recursive_dup support" do
|
46
|
+
x = ::Collapsium::UberHash.new
|
47
|
+
expect(x.respond_to?(:recursive_dup)).to be_truthy
|
48
|
+
expect(x.respond_to?(:deep_dup)).to be_truthy
|
49
|
+
end
|
50
|
+
|
51
|
+
it "has recursive_sort support" do
|
52
|
+
x = ::Collapsium::UberHash.new
|
53
|
+
expect(x.respond_to?(:recursive_sort)).to be_truthy
|
54
|
+
expect(x.respond_to?(:recursive_sort!)).to be_truthy
|
55
|
+
end
|
56
|
+
|
57
|
+
it "has prototype_match support" do
|
58
|
+
x = ::Collapsium::UberHash.new
|
59
|
+
expect(x.respond_to?(:prototype_match)).to be_truthy
|
60
|
+
end
|
44
61
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: collapsium
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jens Finkhaeuser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-05-
|
11
|
+
date: 2016-05-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -116,12 +116,18 @@ files:
|
|
116
116
|
- lib/collapsium.rb
|
117
117
|
- lib/collapsium/indifferent_access.rb
|
118
118
|
- lib/collapsium/pathed_access.rb
|
119
|
+
- lib/collapsium/prototype_match.rb
|
120
|
+
- lib/collapsium/recursive_dup.rb
|
119
121
|
- lib/collapsium/recursive_merge.rb
|
122
|
+
- lib/collapsium/recursive_sort.rb
|
120
123
|
- lib/collapsium/uber_hash.rb
|
121
124
|
- lib/collapsium/version.rb
|
122
125
|
- spec/indifferent_access_spec.rb
|
123
126
|
- spec/pathed_access_spec.rb
|
127
|
+
- spec/prototype_match_spec.rb
|
128
|
+
- spec/recursive_dup_spec.rb
|
124
129
|
- spec/recursive_merge_spec.rb
|
130
|
+
- spec/recursive_sort_spec.rb
|
125
131
|
- spec/spec_helper.rb
|
126
132
|
- spec/uber_hash_spec.rb
|
127
133
|
homepage: https://github.com/jfinkhaeuser/collapsium
|
@@ -151,7 +157,10 @@ summary: Provides various Hash extensions, and an UberHash class that uses them
|
|
151
157
|
test_files:
|
152
158
|
- spec/indifferent_access_spec.rb
|
153
159
|
- spec/pathed_access_spec.rb
|
160
|
+
- spec/prototype_match_spec.rb
|
161
|
+
- spec/recursive_dup_spec.rb
|
154
162
|
- spec/recursive_merge_spec.rb
|
163
|
+
- spec/recursive_sort_spec.rb
|
155
164
|
- spec/spec_helper.rb
|
156
165
|
- spec/uber_hash_spec.rb
|
157
166
|
has_rdoc:
|