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