key_tree 0.1.0 → 0.2.0

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
  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