hashery 1.5.0 → 2.0.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.
- data/.ruby +30 -17
- data/.yardopts +1 -0
- data/Config.rb +28 -0
- data/{QED.rdoc → DEMO.rdoc} +0 -0
- data/HISTORY.rdoc +37 -0
- data/LICENSE.txt +26 -0
- data/NOTICE.txt +46 -0
- data/README.rdoc +10 -7
- data/lib/hashery.rb +6 -6
- data/lib/hashery.yml +30 -17
- data/lib/hashery/association.rb +169 -109
- data/lib/hashery/casting_hash.rb +128 -135
- data/lib/hashery/core_ext.rb +89 -61
- data/lib/hashery/crud_hash.rb +365 -0
- data/lib/hashery/dictionary.rb +545 -345
- data/lib/hashery/fuzzy_hash.rb +177 -125
- data/lib/hashery/ini_hash.rb +321 -0
- data/lib/hashery/key_hash.rb +54 -179
- data/lib/hashery/linked_list.rb +245 -191
- data/lib/hashery/lru_hash.rb +292 -202
- data/lib/hashery/open_cascade.rb +133 -78
- data/lib/hashery/open_hash.rb +127 -61
- data/lib/hashery/ordered_hash.rb +128 -122
- data/lib/hashery/path_hash.rb +238 -0
- data/lib/hashery/property_hash.rb +144 -80
- data/lib/hashery/query_hash.rb +85 -29
- data/lib/hashery/stash.rb +7 -3
- data/lib/hashery/static_hash.rb +46 -41
- data/test/case_association.rb +65 -4
- data/test/case_dictionary.rb +149 -5
- data/test/{case_keyhash.rb → case_key_hash.rb} +20 -14
- data/test/case_lru_hash.rb +162 -0
- data/test/{case_opencascade.rb → case_open_cascade.rb} +4 -8
- data/test/case_open_hash.rb +87 -0
- data/test/case_query_hash.rb +226 -0
- data/test/helper.rb +8 -0
- metadata +33 -63
- data/COPYING.rdoc +0 -45
- data/lib/hashery/basic_object.rb +0 -74
- data/lib/hashery/basic_struct.rb +0 -288
- data/lib/hashery/basicobject.rb +0 -1
- data/lib/hashery/basicstruct.rb +0 -1
- data/lib/hashery/castinghash.rb +0 -1
- data/lib/hashery/fuzzyhash.rb +0 -1
- data/lib/hashery/ini.rb +0 -268
- data/lib/hashery/keyhash.rb +0 -1
- data/lib/hashery/linkedlist.rb +0 -1
- data/lib/hashery/lruhash.rb +0 -1
- data/lib/hashery/memoizer.rb +0 -64
- data/lib/hashery/open_object.rb +0 -1
- data/lib/hashery/opencascade.rb +0 -1
- data/lib/hashery/openhash.rb +0 -1
- data/lib/hashery/openobject.rb +0 -1
- data/lib/hashery/orderedhash.rb +0 -1
- data/lib/hashery/ostructable.rb +0 -186
- data/lib/hashery/propertyhash.rb +0 -1
- data/lib/hashery/queryhash.rb +0 -1
- data/lib/hashery/statichash.rb +0 -1
- data/qed/01_openhash.rdoc +0 -57
- data/qed/02_queryhash.rdoc +0 -21
- data/qed/03_castinghash.rdoc +0 -13
- data/qed/04_statichash.rdoc +0 -22
- data/qed/05_association.rdoc +0 -59
- data/qed/06_opencascade.rdoc +0 -58
- data/qed/07_fuzzyhash.rdoc +0 -141
- data/qed/08_properyhash.rdoc +0 -38
- data/qed/09_ostructable.rdoc +0 -56
- data/qed/applique/ae.rb +0 -1
- data/test/case_basicstruct.rb +0 -192
- data/test/case_openhash.rb +0 -22
data/lib/hashery/propertyhash.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'hashery/property_hash'
|
data/lib/hashery/queryhash.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'hashery/query_hash'
|
data/lib/hashery/statichash.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'hashery/static_hash'
|
data/qed/01_openhash.rdoc
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
= OpenHash
|
2
|
-
|
3
|
-
An OpenHash is a Hash that provides +open+ access to its entries via method
|
4
|
-
calls. Writers (methods ending in =-marks) assign entries. Methods without
|
5
|
-
special puncuation will retrieve entries.
|
6
|
-
|
7
|
-
require 'hashery/openhash'
|
8
|
-
|
9
|
-
o = OpenHash.new
|
10
|
-
o.a = 1
|
11
|
-
o.b = 2
|
12
|
-
o.a.assert == 1
|
13
|
-
o.b.assert == 2
|
14
|
-
|
15
|
-
Writers always use a Symbol for keys in the underlying Hash.
|
16
|
-
|
17
|
-
o.to_h.assert == { :a=>1, :b=>2 }
|
18
|
-
|
19
|
-
All the usual Hash methods are still available in an OpenHash.
|
20
|
-
|
21
|
-
o.map{ |k,v| [k,v] }
|
22
|
-
|
23
|
-
And they are protected from being overridden by writers.
|
24
|
-
|
25
|
-
o.map = 3
|
26
|
-
o.map{ |k,v| [k,v] }
|
27
|
-
|
28
|
-
Even so, the underlying Hash object does contain the entry even
|
29
|
-
when it can not be accessed via a reader method.
|
30
|
-
|
31
|
-
o.to_h.assert == {:a=>1, :b=>2, :map=>3 }
|
32
|
-
|
33
|
-
For some usecases it may be necessary to give up access to one or
|
34
|
-
more Hash methods in favor of access to the hash entries. This can
|
35
|
-
be done using the #omit! method.
|
36
|
-
|
37
|
-
o.omit!(:map, :merge)
|
38
|
-
o.map.assert == 3
|
39
|
-
o.merge = 4
|
40
|
-
o.merge.assert == 4
|
41
|
-
|
42
|
-
Becuase of nature of a writer, a certain set of Hash methods are always
|
43
|
-
protected, namely any of those ending in a puctuation mark. In addition,
|
44
|
-
the implementation protects all shadow methods (e.g. __id__).
|
45
|
-
|
46
|
-
o.__id__ = 4
|
47
|
-
o.__id__.assert! == 4
|
48
|
-
|
49
|
-
Even though writers alwasy use Symbols as keys, because an OpenHash
|
50
|
-
is a true Hash object, any object can be used as a key internally.
|
51
|
-
|
52
|
-
o = OpenHash.new
|
53
|
-
o[nil] = "Nothing"
|
54
|
-
o.to_h.assert == { nil=>"Nothing" }
|
55
|
-
|
56
|
-
It simply will not be accessible via a reader method.
|
57
|
-
|
data/qed/02_queryhash.rdoc
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
= QueryHash
|
2
|
-
|
3
|
-
A QueryHash is a Hash that provides open access much like
|
4
|
-
an OpenHash, but it limits readers to query methods (i.e.
|
5
|
-
method ending in ?-marks).
|
6
|
-
|
7
|
-
require 'hashery/queryhash'
|
8
|
-
|
9
|
-
q = QueryHash.new
|
10
|
-
q.a = 1
|
11
|
-
q.b = 2
|
12
|
-
q.a?.assert == 1
|
13
|
-
q.b?.assert == 2
|
14
|
-
|
15
|
-
Writers always use Symbols for entry keys.
|
16
|
-
|
17
|
-
q.assert == { :a=>1, :b=>2 }
|
18
|
-
|
19
|
-
A QueryHash is compatible with Ruby's standard Hash in
|
20
|
-
every other respect.
|
21
|
-
|
data/qed/03_castinghash.rdoc
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
= CastingHash
|
2
|
-
|
3
|
-
A CastingHash is a Hash that allows _casting_ procedures to
|
4
|
-
defined that the keys and values pass through upon assignment.
|
5
|
-
|
6
|
-
require 'hashery/castinghash'
|
7
|
-
|
8
|
-
c = CastingHash.new{ |x| x.to_s }
|
9
|
-
|
10
|
-
c[:a] = 1
|
11
|
-
|
12
|
-
c.assert == {'a'=>1}
|
13
|
-
|
data/qed/04_statichash.rdoc
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
= StaticHash
|
2
|
-
|
3
|
-
A StaticHash is simply a Hash that can only be assigned
|
4
|
-
once per key. Once assigned a subsequent attempt to assign
|
5
|
-
a value to the same key will raise an ArgumentError.
|
6
|
-
|
7
|
-
require 'hashery/statichash'
|
8
|
-
|
9
|
-
h = StaticHash.new
|
10
|
-
|
11
|
-
h["x"] = 1
|
12
|
-
|
13
|
-
expect ArgumentError do
|
14
|
-
h["x"] = 2
|
15
|
-
end
|
16
|
-
|
17
|
-
The same error will be raised when using #update or #merge!.
|
18
|
-
|
19
|
-
expect ArgumentError do
|
20
|
-
h.update( :x=>2 )
|
21
|
-
end
|
22
|
-
|
data/qed/05_association.rdoc
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
= Association
|
2
|
-
|
3
|
-
An Association is a class for creating simple pairings.
|
4
|
-
|
5
|
-
require 'hashery/association'
|
6
|
-
|
7
|
-
An Association can bew created through the usual means
|
8
|
-
of instantiation.
|
9
|
-
|
10
|
-
Association.new(:a, :b)
|
11
|
-
|
12
|
-
Or the shortcut method #>> can be used in most cases.
|
13
|
-
|
14
|
-
:x >> :z
|
15
|
-
|
16
|
-
An association provides two methods to access its content, #index and #value.
|
17
|
-
|
18
|
-
a = 'foo' >> 'bar'
|
19
|
-
|
20
|
-
a.index.assert == 'foo'
|
21
|
-
a.value.assert == 'bar'
|
22
|
-
|
23
|
-
Associations can be used to create ordered-hashes via normal
|
24
|
-
arrays.
|
25
|
-
|
26
|
-
keys = []
|
27
|
-
vals = []
|
28
|
-
|
29
|
-
ohash = [ 'A' >> '3', 'B' >> '2', 'C' >> '1' ]
|
30
|
-
|
31
|
-
ohash.each{ |k,v| keys << k ; vals << v }
|
32
|
-
|
33
|
-
keys.assert == ['A','B','C']
|
34
|
-
vals.assert == ['3','2','1']
|
35
|
-
|
36
|
-
|
37
|
-
Becuase Associations are objects in themselves more complex
|
38
|
-
collections can also be created.
|
39
|
-
|
40
|
-
complex = [
|
41
|
-
'parent' >> 'child',
|
42
|
-
'childless',
|
43
|
-
'another_parent' >> [
|
44
|
-
'subchildless',
|
45
|
-
'subparent' >> 'subchild'
|
46
|
-
]
|
47
|
-
]
|
48
|
-
|
49
|
-
An experimental feature of Association keeps a cache of all defined associations.
|
50
|
-
|
51
|
-
o = Object.new
|
52
|
-
o >> :a
|
53
|
-
o >> :b
|
54
|
-
o >> :c
|
55
|
-
|
56
|
-
o.associations.assert == [:a, :b, :c]
|
57
|
-
|
58
|
-
However this feature will probably be deprecated.
|
59
|
-
|
data/qed/06_opencascade.rdoc
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
= OpenCascade
|
2
|
-
|
3
|
-
OpenCascade is subclass of OpenObject. It differs in a few
|
4
|
-
significant ways.
|
5
|
-
|
6
|
-
require 'hashery/opencascade'
|
7
|
-
|
8
|
-
The reason this class is labeled "cascade", is that every internal
|
9
|
-
Hash is transformed into an OpenCascade dynamically upon access.
|
10
|
-
This makes it easy to create _cascading_ references.
|
11
|
-
|
12
|
-
h = { :x => { :y => { :z => 1 } } }
|
13
|
-
c = OpenCascade[h]
|
14
|
-
assert c.x.y.z == 1
|
15
|
-
|
16
|
-
As soon as you access a node it automatically becomes an OpenCascade.
|
17
|
-
|
18
|
-
c = OpenCascade.new
|
19
|
-
assert c.r.is_a?(OpenCascade)
|
20
|
-
assert c.a.b.is_a?(OpenCascade)
|
21
|
-
|
22
|
-
But if you set a node, then that will be it's value.
|
23
|
-
|
24
|
-
c.a.b = 4
|
25
|
-
assert c.a.b == 4
|
26
|
-
|
27
|
-
To query a node without causing the auto-creation of an OpenCasade
|
28
|
-
object, use the ?-mark.
|
29
|
-
|
30
|
-
assert c.a.z? == nil
|
31
|
-
|
32
|
-
OpenCascade also transforms Hashes within Arrays.
|
33
|
-
|
34
|
-
h = { :x=>[ {:a=>1}, {:a=>2} ], :y=>1 }
|
35
|
-
c = OpenCascade[h]
|
36
|
-
assert c.x.first.a == 1
|
37
|
-
assert c.x.last.a == 2
|
38
|
-
|
39
|
-
Like OpenObject, OpenCascade allows you to insert entries as array
|
40
|
-
pairs.
|
41
|
-
|
42
|
-
c = OpenCascade.new
|
43
|
-
c << [:x,8]
|
44
|
-
c << [:y,9]
|
45
|
-
|
46
|
-
assert c.x == 8
|
47
|
-
assert c.y == 9
|
48
|
-
|
49
|
-
Finally, you can call methods ending in a !-mark to access the
|
50
|
-
underlying hash (Note that these differ in behavior from the
|
51
|
-
built-in !-methods).
|
52
|
-
|
53
|
-
bk = c.map!{ |k,v| k.to_s.upcase }
|
54
|
-
bk.sort.assert == ['X', 'Y']
|
55
|
-
|
56
|
-
So you can see that for the most an OpenCascade is just like
|
57
|
-
OpenObject, but it allows you to conveniently build open sub-layers.
|
58
|
-
|
data/qed/07_fuzzyhash.rdoc
DELETED
@@ -1,141 +0,0 @@
|
|
1
|
-
= FuzzyHash
|
2
|
-
|
3
|
-
Require the library.
|
4
|
-
|
5
|
-
require 'hashery/fuzzyhash'
|
6
|
-
|
7
|
-
Should accept strings and retrieve based on them.
|
8
|
-
|
9
|
-
l = FuzzyHash.new
|
10
|
-
l['asd'] = 'qwe'
|
11
|
-
l['asd'].should == 'qwe'
|
12
|
-
|
13
|
-
Should accept strings, but the second time you set the same string, it should overwrite.
|
14
|
-
|
15
|
-
l = FuzzyHash.new
|
16
|
-
l['asd'] = 'asd'
|
17
|
-
l['asd'] = 'qwe'
|
18
|
-
l['asd'].should == 'qwe'
|
19
|
-
|
20
|
-
Should accept regexs too.
|
21
|
-
|
22
|
-
l = FuzzyHash.new
|
23
|
-
l[/asd.*/] = 'qwe'
|
24
|
-
l['asdqweasd'].should == 'qwe'
|
25
|
-
|
26
|
-
Should accept regexs too, but the second time you set the same regex, it should overwrite.
|
27
|
-
|
28
|
-
l = FuzzyHash.new
|
29
|
-
l[/asd/] = 'asd'
|
30
|
-
l[/asd/] = 'qwe'
|
31
|
-
l['asdqweasd'].should == 'qwe'
|
32
|
-
|
33
|
-
Should accept regexs too with the match.
|
34
|
-
|
35
|
-
l = FuzzyHash.new
|
36
|
-
l[/asd.*/] = 'qwe'
|
37
|
-
l.match_with_result('asdqweasd').should == ['qwe', 'asdqweasd']
|
38
|
-
|
39
|
-
Should accept regexs that match the whole strong too with the match.
|
40
|
-
|
41
|
-
l = FuzzyHash.new
|
42
|
-
l[/asd/] = 'qwe'
|
43
|
-
l.match_with_result('asd').should == ['qwe', 'asd']
|
44
|
-
|
45
|
-
Should prefer string to regex matches.
|
46
|
-
|
47
|
-
l = FuzzyHash.new
|
48
|
-
l['asd'] = 'qwe2'
|
49
|
-
l[/asd.*/] = 'qwe'
|
50
|
-
l['asd'].should == 'qwe2'
|
51
|
-
|
52
|
-
Should allow nil keys.
|
53
|
-
|
54
|
-
l = FuzzyHash.new
|
55
|
-
l[nil] = 'qwe2'
|
56
|
-
l['asd'] = 'qwe'
|
57
|
-
l['asd'].should == 'qwe'
|
58
|
-
l[nil].should == 'qwe2'
|
59
|
-
|
60
|
-
Should allow boolean keys.
|
61
|
-
|
62
|
-
l = FuzzyHash.new
|
63
|
-
l[false] = 'false'
|
64
|
-
l[true] = 'true'
|
65
|
-
l[/.*/] = 'everything else'
|
66
|
-
l[true].should == 'true'
|
67
|
-
l[false].should == 'false'
|
68
|
-
l['false'].should == 'everything else'
|
69
|
-
|
70
|
-
Should pick between the correct regex.
|
71
|
-
|
72
|
-
hash = FuzzyHash.new
|
73
|
-
hash[/^\d+$/] = 'number'
|
74
|
-
hash[/.*/] = 'something'
|
75
|
-
hash['123asd'].should == 'something'
|
76
|
-
|
77
|
-
Should be able to delete by value for hash.
|
78
|
-
|
79
|
-
l = FuzzyHash.new
|
80
|
-
l[nil] = 'qwe2'
|
81
|
-
l['asd'] = 'qwe'
|
82
|
-
l['asd'].should == 'qwe'
|
83
|
-
l[nil].should == 'qwe2'
|
84
|
-
l.delete_value('qwe2')
|
85
|
-
l[nil].should == nil
|
86
|
-
|
87
|
-
Should be able to delete by value for regex.
|
88
|
-
|
89
|
-
l = FuzzyHash.new
|
90
|
-
l[/qwe.*/] = 'qwe2'
|
91
|
-
l['asd'] = 'qwe'
|
92
|
-
l['asd'].should == 'qwe'
|
93
|
-
l['qweasd'].should == 'qwe2'
|
94
|
-
l.delete_value('qwe2')
|
95
|
-
l['qweasd'].should == nil
|
96
|
-
|
97
|
-
Should iterate through the keys.
|
98
|
-
|
99
|
-
l = FuzzyHash.new
|
100
|
-
l[/qwe.*/] = 'qwe2'
|
101
|
-
l['asd'] = 'qwe'
|
102
|
-
l['zxc'] = 'qwe'
|
103
|
-
l.keys.size.should == 3
|
104
|
-
|
105
|
-
Should iterate through the values.
|
106
|
-
|
107
|
-
l = FuzzyHash.new
|
108
|
-
l[/qwe.*/] = 'qwe2'
|
109
|
-
l['asd'] = 'qwe'
|
110
|
-
l['zxc'] = 'qwelkj'
|
111
|
-
(['qwe2','qwe','qwelkj'] & l.values).size.should == 3
|
112
|
-
|
113
|
-
Should clear.
|
114
|
-
|
115
|
-
l = FuzzyHash.new
|
116
|
-
l[/qwe.*/] = 'qwe2'
|
117
|
-
l['asd'] = 'qwe'
|
118
|
-
l['zxc'] = 'qwelkj'
|
119
|
-
l.clear
|
120
|
-
l.empty?.should == true
|
121
|
-
|
122
|
-
Should handle equality.
|
123
|
-
|
124
|
-
l_1 = FuzzyHash.new
|
125
|
-
l_1[/qwe.*/] = 'qwe2'
|
126
|
-
l_1['asd'] = 'qwelkj'
|
127
|
-
l_1['zxc'] = 'qwe'
|
128
|
-
l_2 = FuzzyHash.new
|
129
|
-
l_2['zxc'] = 'qwe'
|
130
|
-
l_2['asd'] = 'qwelkj'
|
131
|
-
l_2[/qwe.*/] = 'qwe2'
|
132
|
-
l_1.should == l_2
|
133
|
-
|
134
|
-
Should return the value when adding the value.
|
135
|
-
|
136
|
-
h = FuzzyHash.new
|
137
|
-
(h[/asd/] = '123').should == '123'
|
138
|
-
(h['qwe'] = '123').should == '123'
|
139
|
-
|
140
|
-
That's It.
|
141
|
-
|
data/qed/08_properyhash.rdoc
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
= PropertyHash
|
2
|
-
|
3
|
-
Require the library.
|
4
|
-
|
5
|
-
require 'hashery/propertyhash'
|
6
|
-
|
7
|
-
The Property hash can be used an object in itself.
|
8
|
-
|
9
|
-
h = PropertyHash.new(:a=>1, :b=>2)
|
10
|
-
h[:a] #=> 1
|
11
|
-
h[:a] = 3
|
12
|
-
h[:a] #=> 3
|
13
|
-
|
14
|
-
Becuase the properties are fixed, if we try to set a key that is not present,
|
15
|
-
then we will get an error.
|
16
|
-
|
17
|
-
expect ArgumentError do
|
18
|
-
h[:x] = 5
|
19
|
-
end
|
20
|
-
|
21
|
-
The PropertyHash can also be used as a superclass.
|
22
|
-
|
23
|
-
class MyPropertyHash < PropertyHash
|
24
|
-
property :a, :default => 1
|
25
|
-
property :b, :default => 2
|
26
|
-
end
|
27
|
-
|
28
|
-
h = MyPropertyHash.new
|
29
|
-
h[:a] #=> 1
|
30
|
-
h[:a] = 3
|
31
|
-
h[:a] #=> 3
|
32
|
-
|
33
|
-
Again, if we try to set key that was not fixed, then we will get an error.
|
34
|
-
|
35
|
-
expect ArgumentError do
|
36
|
-
h[:x] = 5
|
37
|
-
end
|
38
|
-
|
data/qed/09_ostructable.rdoc
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
= OpenStructable
|
2
|
-
|
3
|
-
OpensStructable is a mixin module which can provide OpenStruct behavior to
|
4
|
-
any class or object. OpenStructable allows extention of data objects
|
5
|
-
with arbitrary attributes.
|
6
|
-
|
7
|
-
require 'hashery/ostructable'
|
8
|
-
|
9
|
-
class Record
|
10
|
-
include OpenStructable
|
11
|
-
end
|
12
|
-
|
13
|
-
Now let's create a new record and see if we can assign values to open
|
14
|
-
properties.
|
15
|
-
|
16
|
-
record = Record.new
|
17
|
-
record.name = "John Smith"
|
18
|
-
record.age = 70
|
19
|
-
record.pension = 300
|
20
|
-
|
21
|
-
We can see that the values were set.
|
22
|
-
|
23
|
-
record.name.assert == "John Smith"
|
24
|
-
record.age.assert == 70
|
25
|
-
record.pension.assert == 300
|
26
|
-
|
27
|
-
If we havent' assigned a value to a property it should just return +nil+.
|
28
|
-
|
29
|
-
record.address.assert == nil
|
30
|
-
|
31
|
-
OpenStructable is also smart enough to adjust itself to work with a subclass
|
32
|
-
of a Hash.
|
33
|
-
|
34
|
-
class HashRecord < Hash
|
35
|
-
include OpenStructable
|
36
|
-
end
|
37
|
-
|
38
|
-
We can apply similar settings as above.
|
39
|
-
|
40
|
-
record = HashRecord.new
|
41
|
-
record.name = "John Doe"
|
42
|
-
record.age = 40
|
43
|
-
record.pension = 200
|
44
|
-
|
45
|
-
We can see that the values were set.
|
46
|
-
|
47
|
-
record.name.assert == "John Doe"
|
48
|
-
record.age.assert == 40
|
49
|
-
record.pension.assert == 200
|
50
|
-
|
51
|
-
The differnce here is that the data is accessible via the normal Hash
|
52
|
-
methods too.
|
53
|
-
|
54
|
-
record.assert == {:name=>"John Doe", :age=>40, :pension=>200}
|
55
|
-
|
56
|
-
Notice that entries are converted to Symbols, not Strings.
|