safestruct 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
  SHA1:
3
- metadata.gz: aabbb2a559ec2421cc0ac43cdcfb0764c8f01633
4
- data.tar.gz: 7c4aa56416aa26f67f06aa09260d0af12f28cf27
3
+ metadata.gz: 74b37cac746195871cc30eec8b8b54622958c6a5
4
+ data.tar.gz: 80def63037cd23ce8812529a4f208e1ebfbbab7a
5
5
  SHA512:
6
- metadata.gz: 3b51b663bc4580a435e39d74ea015bc6e407dec307126de09fe818977de527ced949d4d58a2a04f27a10a25074e76fcc17f47139152782804177b28bf0cd5d20
7
- data.tar.gz: 5285c818c0b4240f186bbc3f9c4221aa4cdf204ec20f0ac187da6b3b1d2a8a339fe5162802b9fabc8b09c80c2ce77e8a013bb3fb391074229dc978fb886024dd
6
+ metadata.gz: 508027ee5576e342154bc62d6d5b5e25cf2f829a075a7b942fc9a3af2bb2295f6e6d71eec58597b7de5c69106ecde9ee6fb1f8d0c503215ab7f15735afa01f62
7
+ data.tar.gz: a9172d32b881902e273bc54cb4e41875edb0c2dd40efd62ca19a07170e8cf01596457b31fa1c63fe244096c3a69b2ab9a280c93241656abedf99f1fd5eeb4c60
data/README.md CHANGED
@@ -6,16 +6,197 @@ safestruct gem / library - safe data structures (array, hash, struct) - say good
6
6
  * bugs :: [github.com/s6ruby/safestruct/issues](https://github.com/s6ruby/safestruct/issues)
7
7
  * gem :: [rubygems.org/gems/safestruct](https://rubygems.org/gems/safestruct)
8
8
  * rdoc :: [rubydoc.info/gems/safestruct](http://rubydoc.info/gems/safestruct)
9
- * forum :: [wwwmake](http://groups.google.com/group/wwwmake)
10
9
 
11
10
 
12
11
  ## Usage
13
12
 
14
- to be done
13
+ [Safe Struct](#safe-struct) •
14
+ [Safe Array](#safe-array) •
15
+ [Safe Hash](#safe-hash)
16
+
17
+
18
+ ### Null / Nil - The Billion Dollar Mistake ++ Zero - The Billion Dollar Fix
19
+
20
+ > I call it my billion-dollar mistake. It was the invention of the null reference in 1965.
21
+ > At that time, I was designing the first comprehensive type system for references
22
+ > in an object oriented language (ALGOL W).
23
+ > My goal was to ensure that all use of references should be absolutely safe,
24
+ > with checking performed automatically by the compiler.
25
+ > But I couldn't resist the temptation to put in a null reference,
26
+ > simply because it was so easy to implement.
27
+ > This has led to innumerable errors, vulnerabilities, and system crashes,
28
+ > which have probably caused a billion dollars of pain and damage in the last forty years.
29
+ >
30
+ > -- [Sir Tony Hoare](https://en.wikipedia.org/wiki/Tony_Hoare)
31
+
32
+
33
+ Let's make the code safer and
34
+ let's say goodbye to null / nil (and maybe).
35
+ How can the code work without nil?
36
+
37
+
38
+ Let's say hello to zero.
39
+ The new rule for NO null/nil ever (again) is:
40
+
41
+ **All variables - including structs, arrays and hash mappings -
42
+ MUST ALWAYS get set (initialized) to ZERO (default) values.**
43
+
44
+ What's zero?
45
+
46
+ | Type | Value |
47
+ |----------------|----------------------------|
48
+ | Integer | `0` or `Integer.zero` |
49
+ | Bool | `false` or `Bool.zero` |
50
+ | String | `''` or `String.zero` |
51
+ | Array | `[]` or `Array.zero` |
52
+ | Hash | `{}` or `Hash.zero` |
53
+ | Vote (Struct) | `Vote.new( 0, false, 0, '0x0000')` or `Vote.zero` |
54
+ | Address | `0x0000` or `Address.zero` or `Address(0)` |
55
+ | ... | |
56
+
57
+
58
+ ### Safe Struct
59
+
60
+ Let's you define (auto-build) new struct classes.
61
+ Example:
62
+
63
+ ``` ruby
64
+ Voter = SafeStruct.new( weight: 0, voted: false, vote: 0, delegate: '0x0000' )
65
+
66
+ voter1 = Voter.new # or Voter.new_zero
67
+ voter1.weight #=> 0
68
+ voter1.voted? #=> false
69
+ voter1.vote #=> 0
70
+ voter1.delegate #=> '0x0000'
71
+ voter1.frozen? #=> false
72
+
73
+ voter1 == Voter.zero #=> true
74
+
75
+ voter1.delegate = '0x1111'
76
+ voter1 == Voter.zero #=> false
77
+
78
+ voter2 = Voter.new( 0, false, 0, '0x0000')
79
+
80
+ voter2.voted = true
81
+ voter2.delegate = '0x2222'
82
+ voter2 == Voter.zero #=> false
83
+
84
+ Voter.zero.frozen? #=> true
85
+
86
+ voter3 = Voter.new( 0 ) #=> ArgumentError - wrong number of arguments
87
+ # for Voter.new - 1 for 4
88
+ ```
89
+
90
+
91
+ Note: You can use `Struct` as an alias for `SafeStruct`
92
+ (in the `Safe` namespace / module context).
93
+
94
+
95
+ ### Safe Array
96
+
97
+ Let's you define (auto-build) new (type safe) array classes.
98
+ Example:
99
+
100
+ ``` ruby
101
+ ArrayInteger = SafeArray.build_class( Integer )
102
+ ary = ArrayInteger.new
103
+ ary.size #=> 0
104
+ ary[0] #=> IndexError
105
+ ary.size = 2 #=> [0,0]
106
+ ary[0] #=> 0
107
+ ```
108
+
109
+ or use the `Array.of` convenience shortcut:
110
+
111
+ ``` ruby
112
+ ary = Array.of( Integer )
113
+ ary.size #=> 0
114
+ ary[0] #=> IndexError
115
+ ary.size = 2 #=> [0, 0]
116
+ ary[0] #=> 0
117
+
118
+ ## or
119
+
120
+ another_ary = Array.of( Bool )
121
+ another_ary.size #=> 0
122
+ another_ary[0] #=> IndexError
123
+ another_ary.size = 2 #=> [false, false]
124
+ another_ary[0] #=> false
125
+
126
+ ## or
127
+
128
+ another_ary = Array.of( Bool, 2 )
129
+ another_ary.size #=> 2
130
+ another_ary[0] #=> false
131
+ ```
132
+
133
+ Yes, Safe Array works with structs (or nested arrays or hash mappings) too. Example:
134
+
135
+ ``` ruby
136
+ ary = Array.of( Vote )
137
+
138
+ ary[0] #=> IndexError
139
+ ary.size = 2 #=> [#<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>,
140
+ # #<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>]
141
+ ary[0] #=> #<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>
142
+ ary[0].voted? #=> false
143
+ ```
144
+
145
+
146
+ ### Safe Hash
147
+
148
+ Let's you define (auto-build) new (type safe) hash classes.
149
+ Example:
150
+
151
+ ``` ruby
152
+ Hash_X_Integer = SafeHash.build_class( String, Integer )
153
+ hash = Hash_X_Integer.new
154
+
155
+ hash['0x0000'] #=> 0
156
+ ```
157
+
158
+ or use the `Hash.of` convenience shortcut:
159
+
160
+ ``` ruby
161
+ hash = Hash.of( String => Integer )
162
+
163
+ hash['0x0000'] #=> 0
164
+ hash['0x0000'] += 42
165
+ hash['0x0000'] #=> 42
166
+ ```
167
+
168
+ Note: Safe Hash will ALWAYS return a value.
169
+ If the key is missing in the hash mapping on lookup,
170
+ the key gets auto-added with a zero value.
171
+ Use `has_key?` or `key?` to check if a key is present.
172
+
173
+
174
+ Yes, Safe Hash works with structs (or arrays or nested hash mappings) too. Example:
175
+
176
+ ``` ruby
177
+ hash = Hash.of( String => Vote )
178
+
179
+ hash['0x0000'] #=> #<Vote @weight=0, @voted=false, @vote=0, @delegate='0x0000'>
180
+ hash['0x0000'].voted? #=> false
181
+ hash['0x0000'].voted = true
182
+ hash['0x0000'].voted? #=> true
183
+ ```
184
+
185
+
186
+
187
+
188
+ ## More "Real World" Safe Data Structures (Array, Hash, Struct) Samples
189
+
190
+ - [The "Red Paper" about sruby](https://github.com/s6ruby/redpaper) - Small, Smart, Secure, Safe, Solid & Sound (S6) Ruby - The Ruby Programming Language for Contract / Transaction Scripts on the Blockchain World Computer - Yes, It's Just Ruby
191
+ - [Programming Crypto Blockchain Contracts Step-by-Step Book / Guide](https://github.com/s6ruby/programming-cryptocontracts). Let's Start with Ponzi & Pyramid Schemes. Run Your Own Lotteries, Gambling Casinos and more on the Blockchain World Computer...
192
+ - [Ruby Sample Contracts for the Universum Blockchain/World Computer Runtime](https://github.com/s6ruby/universum-contracts)
193
+
15
194
 
16
195
 
17
196
  ## License
18
197
 
198
+ ![](https://publicdomainworks.github.io/buttons/zero88x31.png)
199
+
19
200
  The `safestruct` scripts are dedicated to the public domain.
20
201
  Use it as you please with no restrictions whatsoever.
21
202
 
data/lib/safestruct.rb CHANGED
@@ -28,7 +28,7 @@ end
28
28
  #####
29
29
  # add "beautiful" convenience helpers
30
30
 
31
- class Mapping
31
+ class Hash
32
32
 
33
33
  def self.of( *args )
34
34
  ## e.g. gets passed in [{Address=>Integer}]
@@ -38,7 +38,7 @@ class Mapping
38
38
  arg = args[0].to_a ## convert to array (for easier access)
39
39
  klass_key = arg[0][0]
40
40
  klass_value = arg[0][1]
41
- klass = SafeHash.build_class( klass_key, klass_value )
41
+ klass = Safe::SafeHash.build_class( klass_key, klass_value )
42
42
  klass.new
43
43
  else
44
44
  ## todo/fix: throw argument error/exception
@@ -52,17 +52,16 @@ class Array
52
52
  ## "typed" safe array "constructor"
53
53
  ## e.g. Array.of( Address ) or Array.of( Money ) or Array.of( Proposal, size: 2 ) etc.
54
54
  def self.of( klass_value )
55
- klass = SafeArray.build_class( klass_value )
55
+ klass = Safe::SafeArray.build_class( klass_value )
56
56
  klass.new ## todo: add klass.new( **kwargs ) for size: 2 etc.
57
57
  end
58
58
  end
59
59
 
60
-
61
- ############################
62
- # note: HACK redefine built in struct
63
- # => warning: already initialized constant Struct
64
- OldStruct = Struct ## save old struct class
65
- Struct = SafeStruct
66
-
60
+ module Safe
61
+ ############################
62
+ # note: HACK redefine built in struct in module Safe "context"
63
+ ClassicStruct = ::Struct ## save old classic struct class
64
+ Struct = SafeStruct
65
+ end
67
66
 
68
67
  puts Safe.banner ## say hello
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
+ module Safe
4
+
3
5
  class SafeArray
4
6
 
5
7
  ## e.g.
@@ -67,3 +69,4 @@ RUBY
67
69
  def size() @ary.size; end
68
70
  def length() size; end
69
71
  end # class SafeArray
72
+ end # module Safe
@@ -1,12 +1,13 @@
1
1
  # encoding: utf-8
2
2
 
3
+ module Safe
3
4
 
4
5
  class SafeHash
5
6
 
6
7
  ## e.g.
7
- ## Mapping.of( Address => Money )
8
+ ## Hash.of( Address => Money )
8
9
 
9
- ## note: need to create new class!! for every mapping
10
+ ## note: need to create new class!! for every safe hash
10
11
  ## make klass_key class and
11
12
  ## klass_value class into class instance variables
12
13
  ## that can get used by zero
@@ -75,3 +76,4 @@ RUBY
75
76
  def size() @h.size; end
76
77
  def length() size; end
77
78
  end # class SafeHash
79
+ end # module Safe
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
 
3
+ module Safe
4
+
3
5
  class SafeStruct
4
6
 
5
7
  def self.build_class( **attributes )
@@ -36,11 +38,15 @@ def self.build_class( **attributes )
36
38
 
37
39
  ## add self.new too - note: call/forward to "old" orginal self.new of Event (base) class
38
40
  klass.define_singleton_method( :new ) do |*args|
39
- if args.size != attributes.size
40
- ## check for required args/params - all MUST be passed in!!!
41
- raise ArgumentError.new( "[SafeStruct] wrong number of arguments for #{name}.new - #{args.size} for #{attributes.size}" )
41
+ if args.empty? ## no args - use new_zero and set (initialize) all ivars to zero
42
+ new_zero
43
+ else
44
+ if args.size != attributes.size
45
+ ## check for required args/params - all MUST be passed in!!!
46
+ raise ArgumentError.new( "[SafeStruct] wrong number of arguments for #{name}.new - #{args.size} for #{attributes.size}" )
47
+ end
48
+ old_new( *args )
42
49
  end
43
- old_new( *args )
44
50
  end
45
51
 
46
52
  klass.define_singleton_method( :new_zero ) do
@@ -77,3 +83,4 @@ def self.zero
77
83
  @zero ||= new_zero.freeze
78
84
  end
79
85
  end # class SafeStruct
86
+ end # module Safe
@@ -4,7 +4,7 @@
4
4
  module Safe
5
5
 
6
6
  MAJOR = 0
7
- MINOR = 1
7
+ MINOR = 2
8
8
  PATCH = 0
9
9
  VERSION = [MAJOR,MINOR,PATCH].join('.')
10
10
 
data/test/test_array.rb CHANGED
@@ -10,6 +10,8 @@ require 'helper'
10
10
 
11
11
  class TestArray < MiniTest::Test
12
12
 
13
+ include Safe
14
+
13
15
  Array_Integer = SafeArray.build_class( Integer )
14
16
  Array_Bool = SafeArray.build_class( Bool )
15
17
 
data/test/test_hash.rb CHANGED
@@ -10,6 +10,8 @@ require 'helper'
10
10
 
11
11
  class TestHash < MiniTest::Test
12
12
 
13
+ include Safe
14
+
13
15
  ## sig: [Integer, Bool, Integer, Address]
14
16
  Voter = SafeStruct.new( weight: 0, voted: false, vote: 0, delegate: '0x0000' )
15
17
 
@@ -30,8 +32,8 @@ def test_integer
30
32
  assert_equal 101, h['0x1111']
31
33
  assert_equal 102, h['0x2222']
32
34
 
33
- ## check Mapping.of (uses cached classes)
34
- assert_equal Hash_X_Integer, Mapping.of( String => Integer ).class
35
+ ## check Hash.of (uses cached classes)
36
+ assert_equal Hash_X_Integer, Hash.of( String => Integer ).class
35
37
  end
36
38
 
37
39
 
@@ -48,8 +50,8 @@ def test_bool
48
50
  assert_equal true, h['0x1111']
49
51
  assert_equal true, h['0x2222']
50
52
 
51
- ## check Mapping.of (uses cached classes)
52
- assert_equal Hash_X_Bool, Mapping.of( String => Bool ).class
53
+ ## check Hash.of (uses cached classes)
54
+ assert_equal Hash_X_Bool, Hash.of( String => Bool ).class
53
55
  end
54
56
 
55
57
 
@@ -69,8 +71,8 @@ def test_voter
69
71
  pp h['0x1111']
70
72
  pp h['0x2222']
71
73
 
72
- ## check Mapping.of (uses cached classes)
73
- assert_equal Hash_X_Voter, Mapping.of( String => Voter ).class
74
+ ## check Hash.of (uses cached classes)
75
+ assert_equal Hash_X_Voter, Hash.of( String => Voter ).class
74
76
  end
75
77
 
76
78
 
data/test/test_struct.rb CHANGED
@@ -10,6 +10,8 @@ require 'helper'
10
10
 
11
11
  class TestStruct < MiniTest::Test
12
12
 
13
+ include Safe
14
+
13
15
  ## sig: [Integer, Bool, Integer, Address]
14
16
  Voter = SafeStruct.new( weight: 0, voted: false, vote: 0, delegate: '0x0000' )
15
17
 
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: 0.1.0
4
+ version: 0.2.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-02-14 00:00:00.000000000 Z
11
+ date: 2019-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc