safestruct 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +56 -3
- data/lib/safestruct.rb +5 -4
- data/lib/safestruct/safe_array.rb +2 -2
- data/lib/safestruct/safe_hash.rb +32 -18
- data/lib/safestruct/version.rb +2 -2
- data/test/test_hash.rb +2 -2
- data/test/voter.rb +11 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5b47433e234edeb8d8ddddfaa7d6eac51ce1845
|
4
|
+
data.tar.gz: 49d711cfbef0941d9cf91762c47858d790d96ef2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ea81799da3ab6d4a4dca8468a5b7515c6ee64717b5350577ad0f8cad32cc2db423fe90ed7d69e018da40044a9d70fa9f643f8723214109d998507f11216dd57
|
7
|
+
data.tar.gz: c4e4388b63a6771fbd98c34aa4bd8599e7a0d70a7efa8400c30461409af833fba0e8bef75a7171fee0e19ea0285b680f8c45c0213c2086b87c68a274206db484
|
data/README.md
CHANGED
@@ -94,11 +94,13 @@ Note: You can use `Struct` as an alias for `SafeStruct`
|
|
94
94
|
class method macro:
|
95
95
|
|
96
96
|
``` ruby
|
97
|
-
struct(
|
97
|
+
struct( :Voter, weight: 0, voted: false, vote: 0, delegate: '0x0000')
|
98
98
|
# or
|
99
|
-
struct
|
99
|
+
struct :Voter, { weight: 0, voted: false, vote: 0, delegate: '0x0000' }
|
100
100
|
# or
|
101
|
-
struct
|
101
|
+
struct :Voter, weight: 0, voted: false, vote: 0, delegate: '0x0000'
|
102
|
+
# or
|
103
|
+
struct :Voter,
|
102
104
|
weight: 0,
|
103
105
|
voted: false,
|
104
106
|
vote: 0,
|
@@ -211,6 +213,57 @@ allowances['0x2222'].delete( '0xaaaa' )
|
|
211
213
|
allowances['0x2222']['0xaaaa'] #=> 0
|
212
214
|
```
|
213
215
|
|
216
|
+
### Bonus: Auto-Generated Unicode (UTF-8) Class Constants / Names for Pretty Printing
|
217
|
+
|
218
|
+
Did you know? Yes, you can use unicode characters in your identifiers.
|
219
|
+
The safe data structures library auto-generates unicode class constants / names
|
220
|
+
for pretty printing and more. Examples:
|
221
|
+
|
222
|
+
| Class Builder | Class Constant / Name |
|
223
|
+
|----------------------------------------|-----------------------|
|
224
|
+
| `Array.of( Integer )` | `Array‹Integer›` |
|
225
|
+
| `Array.of( Bool )` | `Array‹Bool›` |
|
226
|
+
| `Array.of( Bool, 2 )` | `Array‹Bool›×2` |
|
227
|
+
| `Array.of( Vote )` | `Array‹Vote›` |
|
228
|
+
| `Array.of( Array.of( Integer, 3), 3 )` | `Array‹Array‹Integer›×3›×3` |
|
229
|
+
| `Hash.of( String => Integer )` | `Hash‹String→Integer›` |
|
230
|
+
| `Hash.of( String => Vote )` | `Hash‹String→Vote›` |
|
231
|
+
| `Hash.of( String => Hash.of( String => Integer ))` | `Hash‹String→Hash‹String→Integer››` |
|
232
|
+
| ... | |
|
233
|
+
|
234
|
+
|
235
|
+
Note, and yes if the typing is not too much - you can use
|
236
|
+
the "magic" names in your code too. Example:
|
237
|
+
|
238
|
+
``` ruby
|
239
|
+
ary = Array‹Integer›.new
|
240
|
+
ary.size #=> 0
|
241
|
+
ary[0] #=> IndexError: index 0 outside of array bounds
|
242
|
+
ary.size = 2 #=> [0,0]
|
243
|
+
ary[0] #=> 0
|
244
|
+
|
245
|
+
# or
|
246
|
+
|
247
|
+
another_ary = Array‹Bool›×2.new
|
248
|
+
another_ary.size #=> 2
|
249
|
+
another_ary[0] #=> false
|
250
|
+
|
251
|
+
# or
|
252
|
+
|
253
|
+
hash = Hash‹String→Integer›.new
|
254
|
+
hash['0x0000'] #=> 0
|
255
|
+
hash['0x0000'] += 42
|
256
|
+
hash['0x0000'] #=> 42
|
257
|
+
|
258
|
+
# or
|
259
|
+
|
260
|
+
allowances = Hash‹String→Hash‹String→Integer››.new
|
261
|
+
allowances['0x1111']['0xaaaa'] = 100
|
262
|
+
allowances['0x1111']['0xbbbb'] = 200
|
263
|
+
allowances['0x2222']['0xaaaa'] = 300
|
264
|
+
```
|
265
|
+
|
266
|
+
and so on.
|
214
267
|
|
215
268
|
|
216
269
|
### What about Safe Enumeration (Integer) Types?
|
data/lib/safestruct.rb
CHANGED
@@ -89,14 +89,15 @@ class Array
|
|
89
89
|
end
|
90
90
|
|
91
91
|
|
92
|
-
module
|
92
|
+
module Standard
|
93
93
|
############################
|
94
94
|
# note: HACK redefine built in struct in module Safe "context"
|
95
95
|
Struct = ::Struct ## save old classic struct class
|
96
|
-
|
97
|
-
|
96
|
+
Array = ::Array
|
97
|
+
Hash = ::Hash
|
98
98
|
end
|
99
|
-
|
99
|
+
## use/add Unsafe alias too - why? why not?
|
100
|
+
Std = Standard ## add alias lets use you use Std::Struct,Std::Array, Std::Hash etc.
|
100
101
|
|
101
102
|
|
102
103
|
|
@@ -40,12 +40,12 @@ class SafeArray
|
|
40
40
|
|
41
41
|
## note: also add a Constant to Safe for easy debugging and (re)use - will "auto"name class
|
42
42
|
class_name = "Array"
|
43
|
-
class_name << "#{size}" if size > 0 ## add size if non-zero
|
44
43
|
|
45
44
|
name = klass_value.name
|
46
45
|
name = name.sub( /\bSafe::/, '' ) ## remove safe module from name if present
|
47
46
|
name = name.gsub( '::', '' ) ## remove module separator if present
|
48
|
-
class_name << "
|
47
|
+
class_name << "‹#{name}›"
|
48
|
+
class_name << "×#{size}" if size > 0 ## add size if non-zero
|
49
49
|
Safe.const_set( class_name, klass )
|
50
50
|
end
|
51
51
|
klass
|
data/lib/safestruct/safe_hash.rb
CHANGED
@@ -7,6 +7,12 @@ class SafeHash
|
|
7
7
|
def self.debug?() @debug ||= false; end
|
8
8
|
def self.debug=(value) @debug = value; end
|
9
9
|
|
10
|
+
## let's you configure the class name used for auto-generation class constants
|
11
|
+
## e.g. use SafeHash.klass_name = 'Mapping' to rename from (default) 'Hash'
|
12
|
+
def self.klass_name() @@klass_name ||= 'Hash'; end
|
13
|
+
def self.klass_name=(value) @@klass_name = value; end
|
14
|
+
|
15
|
+
|
10
16
|
|
11
17
|
## e.g.
|
12
18
|
## Hash.of( Address => Money )
|
@@ -22,9 +28,13 @@ class SafeHash
|
|
22
28
|
|
23
29
|
## note: keep a class cache
|
24
30
|
cache = @@cache ||= {}
|
25
|
-
|
31
|
+
cache_all_values = cache[ klass_key ] ||= {}
|
32
|
+
klass = cache_all_values[ klass_value ]
|
33
|
+
|
26
34
|
if debug?
|
27
|
-
puts "[debug] SafeHash - build_class klass_value:"
|
35
|
+
puts "[debug] SafeHash - build_class( klass_key, klass_value ):"
|
36
|
+
pp klass_key
|
37
|
+
pp klass_key.to_s ## note: for "anonymous" class something like #<Class:>
|
28
38
|
pp klass_value
|
29
39
|
pp klass_value.to_s ## note: for "anonymous" class something like #<Class:>
|
30
40
|
end
|
@@ -54,16 +64,20 @@ class SafeHash
|
|
54
64
|
# RUBY
|
55
65
|
|
56
66
|
## add to cache for later (re)use
|
57
|
-
cache[ klass_value ] = klass
|
67
|
+
cache[ klass_key ][ klass_value ] = klass
|
58
68
|
|
59
69
|
## note: also add a Constant to Safe for easy debugging and (re)use - will "auto"name class
|
60
|
-
|
61
|
-
|
70
|
+
class_name = "#{klass_name}"
|
71
|
+
|
72
|
+
key_name = klass_key.name
|
73
|
+
key_name = key_name.sub( /\bSafe::/, '' ) ## remove safe module from name if present
|
74
|
+
key_name = key_name.gsub( '::', '' ) ## remove module separator if present
|
75
|
+
|
76
|
+
value_name = klass_value.name
|
77
|
+
value_name = value_name.sub( /\bSafe::/, '' ) ## remove safe module from name if present
|
78
|
+
value_name = value_name.gsub( '::', '' ) ## remove module separator if present
|
62
79
|
|
63
|
-
|
64
|
-
name = name.sub( /\bSafe::/, '' ) ## remove safe module from name if present
|
65
|
-
name = name.gsub( '::', '' ) ## remove module separator if present
|
66
|
-
class_name << "_#{name}"
|
80
|
+
class_name << "‹#{key_name}→#{value_name}›"
|
67
81
|
if debug?
|
68
82
|
puts "[debug] SafeHash - class_name >#{class_name}<"
|
69
83
|
end
|
@@ -87,18 +101,18 @@ class SafeHash
|
|
87
101
|
|
88
102
|
def initialize
|
89
103
|
## todo/check: if hash works if value is a (nested) hash
|
90
|
-
@
|
104
|
+
@table = {}
|
91
105
|
end
|
92
106
|
|
93
107
|
def freeze
|
94
108
|
super
|
95
|
-
@
|
109
|
+
@table.freeze ## note: pass on freeze to "wrapped" hash
|
96
110
|
self # return reference to self
|
97
111
|
end
|
98
112
|
|
99
113
|
def ==( other )
|
100
|
-
if other.is_a?( self.class ) ## note: must be same hash class
|
101
|
-
@
|
114
|
+
if other.is_a?( self.class ) ## note: must be same hash (table) class
|
115
|
+
@table == other.instance_variable_get( '@table' ) ## compare "wrapped" hash
|
102
116
|
else
|
103
117
|
false
|
104
118
|
end
|
@@ -109,11 +123,11 @@ class SafeHash
|
|
109
123
|
|
110
124
|
|
111
125
|
def []=(key, value)
|
112
|
-
@
|
126
|
+
@table[key] = value
|
113
127
|
end
|
114
128
|
|
115
129
|
def [](key)
|
116
|
-
item = @
|
130
|
+
item = @table[ key ]
|
117
131
|
if item.nil?
|
118
132
|
## pp self.class.klass_value
|
119
133
|
## pp self.class.klass_value.zero
|
@@ -126,17 +140,17 @@ class SafeHash
|
|
126
140
|
if self.class.klass_value.respond_to?( :new_zero )
|
127
141
|
## note: use a dup(licated) unfrozen copy of the zero object
|
128
142
|
## changes to the object MUST be possible (new "empty" modifable object expected)
|
129
|
-
item = @
|
143
|
+
item = @table[ key ] = self.class.klass_value.new_zero
|
130
144
|
else # assume value semantics e.g. Integer, Bool, etc. zero values gets replaced
|
131
145
|
## puts "use value semantics"
|
132
|
-
item = @
|
146
|
+
item = @table[ key ] = self.class.klass_value.zero
|
133
147
|
end
|
134
148
|
end
|
135
149
|
item
|
136
150
|
end
|
137
151
|
|
138
152
|
extend Forwardable
|
139
|
-
def_delegators :@
|
153
|
+
def_delegators :@table, :has_key?, :key?, :delete, :clear
|
140
154
|
|
141
155
|
## note: remove size and length for (safe) hash (for now) - follows solidity convention - why? why not?
|
142
156
|
## :size, :length,
|
data/lib/safestruct/version.rb
CHANGED
data/test/test_hash.rb
CHANGED
@@ -46,8 +46,8 @@ def test_integer
|
|
46
46
|
assert_equal false, h.has_key?( '0x1111' )
|
47
47
|
|
48
48
|
## todo/fix: remove size and length for (safe) hash - why? why not?
|
49
|
-
assert_equal 0, h.instance_variable_get('@
|
50
|
-
assert_equal 0, h.instance_variable_get('@
|
49
|
+
assert_equal 0, h.instance_variable_get('@table').size
|
50
|
+
assert_equal 0, h.instance_variable_get('@table').length
|
51
51
|
|
52
52
|
assert_equal true, Hash_X_Integer.zero == h
|
53
53
|
assert_equal true, Hash_X_Integer.zero == Hash_X_Integer.new
|
data/test/voter.rb
CHANGED
@@ -3,17 +3,25 @@
|
|
3
3
|
|
4
4
|
module Safe
|
5
5
|
|
6
|
-
##
|
6
|
+
##[sig(Integer, Bool, Integer, Address)]
|
7
|
+
##
|
7
8
|
## Struct.new( :Voter,
|
8
9
|
## weight: 0,
|
9
10
|
## voted: false,
|
10
11
|
## vote: 0,
|
11
12
|
## delegate: '0x0000' )
|
12
13
|
|
13
|
-
struct :Voter,
|
14
|
+
struct :Voter, {
|
14
15
|
weight: 0,
|
15
16
|
voted: false,
|
16
17
|
vote: 0,
|
17
|
-
delegate: '0x0000'
|
18
|
+
delegate: '0x0000' }
|
19
|
+
|
20
|
+
### -or-
|
21
|
+
# struct :Voter,
|
22
|
+
# weight: 0,
|
23
|
+
# voted: false,
|
24
|
+
# vote: 0,
|
25
|
+
# delegate: '0x0000'
|
18
26
|
|
19
27
|
end # module Safe
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: safestruct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-03-
|
11
|
+
date: 2019-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: enums
|