key_tree 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3adbed28729cba5c2b3878930ca08c02d9f0fb187ed678d198c0d590bb9f20b7
4
- data.tar.gz: 3ecaaa1c9e9df660af725ba6ed901337e886486b862fbd42ba9195db102422df
3
+ metadata.gz: 1785b5cb1b1cd95bcce54e395760a8fba2c3f18a1fe90ec6142a84371dcecebb
4
+ data.tar.gz: b2fce6710288a95c80db648556abe8e4b6a35289d743afd451e2b266bf2b3b2f
5
5
  SHA512:
6
- metadata.gz: cce5c2541a1195967488358d71d2e666a3a0b4a968bf85430a1d26bbf401e2cc3b9d58f62e95ec74886980558304affafc221fecfc6a907c3410d6e2f09f1a5f
7
- data.tar.gz: e32567fbee972c5f12547c9445ab1be6a78fe4e2245053f70d938bececd1a7143a897b34cd6533c7f3e41b2d82aa3c8e356cc49a67aae33e6c735925047b747e
6
+ metadata.gz: 5e6d082279a58dfb080872a193ffa2eaee310b97f64f34120edbe7814935feaebd9fdd73aa4e8071acedaadef4036a66e204b7194c1e1bd9429915b60ef2094e
7
+ data.tar.gz: bc50e45870118d9ad5c21a0bf2f19dc89f53ec54aba5eb1af7917f87cdf5476eaf6509643c4bb1189d7a8dba02d9ce17a153229cb83ad4bc95065f6cde4d8899
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
12
  /vendor
13
+ Gemfile.lock
@@ -0,0 +1,89 @@
1
+ require 'key_tree/tree'
2
+
3
+ module KeyTree
4
+ #
5
+ # A forest is a (possibly nested) collection of trees
6
+ #
7
+ class Forest < Array
8
+ def self.[](*contents)
9
+ contents.reduce(Forest.new) do |result, content|
10
+ result << KeyTree[content]
11
+ end.sort!
12
+ end
13
+
14
+ # For a numeric key, return the n:th tree in the forest
15
+ #
16
+ # For a key path convertable key, return the closest match in the forest
17
+ #
18
+ # When a closer tree contains a prefix of the key, this shadows any
19
+ # key path matches in trees further away, returning nil. This preserves
20
+ # the constraints that only leaves may contain a value.
21
+ #
22
+ def [](key)
23
+ case key
24
+ when Numeric
25
+ super(key)
26
+ else
27
+ each do |tree_or_forest|
28
+ return tree_or_forest[key] if tree_or_forest.key?(key)
29
+ return nil if tree_or_forest.prefix?(key)
30
+ end
31
+ end
32
+ end
33
+
34
+ # Trees are always smaller than forrests.
35
+ # Forests are compared by nesting depth, not number of trees.
36
+ #
37
+ def <=>(other)
38
+ return 0 if self == other
39
+
40
+ case other
41
+ when Forest
42
+ depth <=> other.depth
43
+ when Tree
44
+ 1
45
+ else
46
+ raise ArgumentError, 'only forests and trees are comparable'
47
+ end
48
+ end
49
+
50
+ # The nesting depth of a forest
51
+ def depth
52
+ reduce(1) do |result, tree_or_forest|
53
+ [result, content_depth(tree_or_forest) + 1].max
54
+ end
55
+ end
56
+
57
+ def key?(key)
58
+ any? { |tree_or_forest| tree_or_forest.key?(key) }
59
+ end
60
+
61
+ def prefix?(key)
62
+ any? { |tree_or_forest| tree_or_forest.prefix?(key) }
63
+ end
64
+
65
+ # Flattening a forest produces a tree with the equivalent view of key paths
66
+ #
67
+ def flatten
68
+ reduce(Tree[]) do |result, tree_or_forest|
69
+ case tree_or_forest
70
+ when Forest
71
+ tree_or_forest.flatten.merge(result)
72
+ else
73
+ tree_or_forest.merge(result)
74
+ end
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def content_depth(content)
81
+ case content
82
+ when Forest
83
+ content.depth
84
+ else
85
+ 0
86
+ end
87
+ end
88
+ end
89
+ end
data/lib/key_tree/tree.rb CHANGED
@@ -20,8 +20,8 @@ module KeyTree
20
20
  super(Path[key_or_path])
21
21
  end
22
22
 
23
- def fetch(key_or_path, *args, **kvargs, &proc)
24
- super(Path[key_or_path], *args, **kvargs, &proc)
23
+ def fetch(key_or_path, *args, &proc)
24
+ super(Path[key_or_path], *args, &proc)
25
25
  end
26
26
 
27
27
  def values_at(*keys)
@@ -31,7 +31,7 @@ module KeyTree
31
31
  def []=(key_or_path, new_value)
32
32
  path = Path[key_or_path]
33
33
 
34
- each_key { |key| delete(key) if path.conflict?(key) }
34
+ delete_if { |key, _| path.conflict?(key) }
35
35
 
36
36
  case new_value
37
37
  when Hash
@@ -40,5 +40,38 @@ module KeyTree
40
40
  super(path, new_value)
41
41
  end
42
42
  end
43
+
44
+ def key?(key_or_path)
45
+ super(Path[key_or_path])
46
+ end
47
+
48
+ def prefix?(key_or_path)
49
+ keys.any? { |key| key.prefix?(Path[key_or_path]) }
50
+ end
51
+
52
+ def conflict?(key_or_path)
53
+ keys.any? { |key| key.conflict?(Path[key_or_path]) }
54
+ end
55
+
56
+ # All trees are created equal. Forests are always larger than trees.
57
+ #
58
+ def <=>(other)
59
+ case other
60
+ when Forest
61
+ -1
62
+ when Tree
63
+ 0
64
+ else
65
+ raise ArgumentError, 'only trees and forests are comparable'
66
+ end
67
+ end
68
+
69
+ # The merging of trees needs some extra consideration; due to the
70
+ # nature of key paths, prefix conflicts must be deleted
71
+ #
72
+ def merge(other)
73
+ delete_if { |key, _| other.conflict?(key) }
74
+ super
75
+ end
43
76
  end
44
77
  end
@@ -1,3 +1,3 @@
1
1
  module KeyTree
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '0.2.0'.freeze
3
3
  end
data/lib/key_tree.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'key_tree/version'
2
2
  require 'key_tree/tree'
3
+ require 'key_tree/forest'
3
4
 
4
5
  # Manage a tree of keys
5
6
  #
@@ -15,6 +16,8 @@ module KeyTree
15
16
  case contents
16
17
  when Hash
17
18
  KeyTree::Tree[contents]
19
+ when Array
20
+ KeyTree::Forest[*contents]
18
21
  else
19
22
  raise ArgumentError, "can't load #{contents.class} into a KeyTree"
20
23
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: key_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Calle Englund
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-26 00:00:00.000000000 Z
11
+ date: 2018-01-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -79,7 +79,6 @@ files:
79
79
  - ".travis.yml"
80
80
  - CODE_OF_CONDUCT.md
81
81
  - Gemfile
82
- - Gemfile.lock
83
82
  - LICENSE.txt
84
83
  - README.md
85
84
  - Rakefile
@@ -87,6 +86,7 @@ files:
87
86
  - bin/setup
88
87
  - key_tree.gemspec
89
88
  - lib/key_tree.rb
89
+ - lib/key_tree/forest.rb
90
90
  - lib/key_tree/path.rb
91
91
  - lib/key_tree/tree.rb
92
92
  - lib/key_tree/version.rb
data/Gemfile.lock DELETED
@@ -1,51 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- key_tree (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- ast (2.3.0)
10
- diff-lcs (1.3)
11
- parallel (1.12.1)
12
- parser (2.4.0.2)
13
- ast (~> 2.3)
14
- powerpack (0.1.1)
15
- rainbow (3.0.0)
16
- rake (10.5.0)
17
- rspec (3.7.0)
18
- rspec-core (~> 3.7.0)
19
- rspec-expectations (~> 3.7.0)
20
- rspec-mocks (~> 3.7.0)
21
- rspec-core (3.7.1)
22
- rspec-support (~> 3.7.0)
23
- rspec-expectations (3.7.0)
24
- diff-lcs (>= 1.2.0, < 2.0)
25
- rspec-support (~> 3.7.0)
26
- rspec-mocks (3.7.0)
27
- diff-lcs (>= 1.2.0, < 2.0)
28
- rspec-support (~> 3.7.0)
29
- rspec-support (3.7.0)
30
- rubocop (0.52.1)
31
- parallel (~> 1.10)
32
- parser (>= 2.4.0.2, < 3.0)
33
- powerpack (~> 0.1)
34
- rainbow (>= 2.2.2, < 4.0)
35
- ruby-progressbar (~> 1.7)
36
- unicode-display_width (~> 1.0, >= 1.0.1)
37
- ruby-progressbar (1.9.0)
38
- unicode-display_width (1.3.0)
39
-
40
- PLATFORMS
41
- ruby
42
-
43
- DEPENDENCIES
44
- bundler (~> 1.16)
45
- key_tree!
46
- rake (~> 10.0)
47
- rspec (~> 3.0)
48
- rubocop (~> 0.52)
49
-
50
- BUNDLED WITH
51
- 1.16.0