safestruct 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/lib/safestruct.rb +20 -3
- data/lib/safestruct/safe_array.rb +22 -11
- data/lib/safestruct/safe_hash.rb +26 -13
- data/lib/safestruct/safe_struct.rb +8 -4
- data/lib/safestruct/version.rb +10 -3
- data/test/test_hash.rb +19 -0
- 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: f085259a240f99941fe60eef6a271a6066e649d3
|
4
|
+
data.tar.gz: a289d416c0ade1aa76eae8e0c897fac7b63e6700
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a71c903f7ecddfe2a42c48465f7a76969db5566e7d0cdf18bf53878f5bad067c7b7e86029a1516e5515124547a6ce5a2c9badc36f84e1a1ca05cb6fcd049e65
|
7
|
+
data.tar.gz: aade5b05f5666e89204cd5b95a4561829d7f70bae9380a7d204013527bdd03e21757c9f30f379c74f5ced2b558e25b702ccf1cbcaa13cd2d4e9df71c833688fb
|
data/Rakefile
CHANGED
@@ -3,7 +3,7 @@ require './lib/safestruct/version.rb'
|
|
3
3
|
|
4
4
|
Hoe.spec 'safestruct' do
|
5
5
|
|
6
|
-
self.version =
|
6
|
+
self.version = SaferStruct::VERSION
|
7
7
|
|
8
8
|
self.summary = "safestruct - safe data structures (array, hash, struct) - say goodbye to null / nil (and maybe) - say hello to zero"
|
9
9
|
self.description = summary
|
data/lib/safestruct.rb
CHANGED
@@ -19,19 +19,31 @@ require 'safestruct/safe_struct'
|
|
19
19
|
####################################
|
20
20
|
## add zero/zero_new machinery for builin classes
|
21
21
|
|
22
|
-
|
22
|
+
#########################
|
23
|
+
#### with value semantics
|
23
24
|
class Integer
|
24
25
|
def self.zero() 0; end ## note: 0.frozen? == true by default
|
26
|
+
def zero?() self == self.class.zero; end
|
25
27
|
end
|
26
28
|
|
27
29
|
class Bool
|
28
30
|
def self.zero() false; end ## note: false.frozen? == true by default
|
29
31
|
end
|
30
32
|
|
31
|
-
|
33
|
+
class TrueClass # note: ruby has no builtin/default bool (base) class only TrueClass|FalseClass
|
34
|
+
def zero?() false; end
|
35
|
+
end
|
36
|
+
|
37
|
+
class FalseClass
|
38
|
+
def zero?() true; end
|
39
|
+
end
|
40
|
+
|
41
|
+
##################
|
42
|
+
#### with reference semantics (new copy ALWAYS needed)
|
32
43
|
class String
|
33
44
|
def self.new_zero() new; end
|
34
45
|
def self.zero() @zero ||= new_zero.freeze; end
|
46
|
+
def zero?() self == self.class.zero; end
|
35
47
|
end
|
36
48
|
|
37
49
|
|
@@ -90,9 +102,14 @@ module Safe
|
|
90
102
|
def struct( class_name, **attributes )
|
91
103
|
SafeStruct.new( class_name, attributes )
|
92
104
|
end
|
105
|
+
|
106
|
+
### note: do NOT add helpers for
|
107
|
+
## - hash( class_name, ...) and
|
108
|
+
## - array( class_name, ...) for now
|
109
|
+
## why? why not? needs more testing/considerations for overloading / breaking builtin defaults
|
93
110
|
end # module ClassMethods
|
94
111
|
end # module Safe
|
95
112
|
|
96
113
|
|
97
114
|
|
98
|
-
puts
|
115
|
+
puts SaferStruct.banner ## say hello
|
@@ -18,14 +18,23 @@ class SafeArray
|
|
18
18
|
if klass.nil?
|
19
19
|
|
20
20
|
klass = Class.new( SafeArray )
|
21
|
-
klass.
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
klass.define_singleton_method( :klass_value ) do
|
22
|
+
@klass_value ||= klass_value
|
23
|
+
end
|
24
|
+
klass.define_singleton_method( :klass_size ) do
|
25
|
+
@klass_size ||= size
|
26
|
+
end
|
27
|
+
|
28
|
+
##### was: not working for anymous class e.g. klass_value.to_s => #<Class:>
|
29
|
+
# klass.class_eval( <<RUBY )
|
30
|
+
# def self.klass_value
|
31
|
+
# @klass_value ||= #{klass_value}
|
32
|
+
# end
|
33
|
+
# def self.klass_size
|
34
|
+
# @klass_size ||= #{size}
|
35
|
+
# end
|
36
|
+
# RUBY
|
37
|
+
|
29
38
|
## add to cache for later (re)use
|
30
39
|
cache[ klass_value ][ size ] = klass
|
31
40
|
end
|
@@ -36,6 +45,8 @@ RUBY
|
|
36
45
|
def self.new_zero() new; end
|
37
46
|
def self.zero() @zero ||= new_zero.freeze; end
|
38
47
|
|
48
|
+
def zero?() self == self.class.zero; end
|
49
|
+
|
39
50
|
|
40
51
|
def initialize( size=self.class.klass_size )
|
41
52
|
@ary = []
|
@@ -71,11 +82,11 @@ RUBY
|
|
71
82
|
## note: use a new unfrozen copy of the zero object
|
72
83
|
## changes to the object MUST be possible (new "empty" modifable object expected)
|
73
84
|
diff.times { @ary << self.class.klass_value.new_zero }
|
74
|
-
|
85
|
+
else # assume value semantics e.g. Integer, Bool, etc. zero values gets replaced
|
75
86
|
## puts "use value semantics"
|
76
87
|
diff.times { @ary << self.class.klass_value.zero }
|
77
|
-
|
78
|
-
|
88
|
+
end
|
89
|
+
self # return reference to self
|
79
90
|
end
|
80
91
|
alias_method :'length=', :'size='
|
81
92
|
|
data/lib/safestruct/safe_hash.rb
CHANGED
@@ -26,6 +26,7 @@ class SafeHash
|
|
26
26
|
if debug?
|
27
27
|
puts "[debug] SafeHash - build_class klass_value:"
|
28
28
|
pp klass_value
|
29
|
+
pp klass_value.to_s ## note: for "anonymous" class something like #<Class:>
|
29
30
|
end
|
30
31
|
|
31
32
|
if klass.nil?
|
@@ -34,14 +35,24 @@ class SafeHash
|
|
34
35
|
end
|
35
36
|
|
36
37
|
klass = Class.new( SafeHash )
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
38
|
+
|
39
|
+
klass.define_singleton_method( :klass_key ) do
|
40
|
+
@klass_key ||= klass_key
|
41
|
+
end
|
42
|
+
klass.define_singleton_method( :klass_value ) do
|
43
|
+
@klass_value ||= klass_value
|
44
|
+
end
|
45
|
+
|
46
|
+
### was: - NOT working for "anonymous" classes e.g. klass_value.to_s starting with #<Class:>
|
47
|
+
# klass.class_eval( <<RUBY )
|
48
|
+
# def self.klass_key
|
49
|
+
# @klass_key ||= #{klass_key}
|
50
|
+
# end
|
51
|
+
# def self.klass_value
|
52
|
+
# @klass_value ||= #{klass_value}
|
53
|
+
# end
|
54
|
+
# RUBY
|
55
|
+
|
45
56
|
## add to cache for later (re)use
|
46
57
|
cache[ klass_value ] = klass
|
47
58
|
else
|
@@ -58,6 +69,8 @@ RUBY
|
|
58
69
|
def self.new_zero() new; end
|
59
70
|
def self.zero() @zero ||= new_zero.freeze; end
|
60
71
|
|
72
|
+
def zero?() self == self.class.zero; end
|
73
|
+
|
61
74
|
|
62
75
|
def initialize
|
63
76
|
## todo/check: if hash works if value is a (nested) hash
|
@@ -100,11 +113,11 @@ RUBY
|
|
100
113
|
if self.class.klass_value.respond_to?( :new_zero )
|
101
114
|
## note: use a dup(licated) unfrozen copy of the zero object
|
102
115
|
## changes to the object MUST be possible (new "empty" modifable object expected)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
116
|
+
item = @h[ key ] = self.class.klass_value.new_zero
|
117
|
+
else # assume value semantics e.g. Integer, Bool, etc. zero values gets replaced
|
118
|
+
## puts "use value semantics"
|
119
|
+
item = @h[ key ] = self.class.klass_value.zero
|
120
|
+
end
|
108
121
|
end
|
109
122
|
item
|
110
123
|
end
|
@@ -21,7 +21,7 @@ def self.build_class( class_name, **attributes )
|
|
21
21
|
## check if valid class_name MUST start with uppercase letter etc.
|
22
22
|
## todo/fix: check if constant is undefined in Safe namespace!!!!
|
23
23
|
|
24
|
-
|
24
|
+
|
25
25
|
klass = Class.new( SafeStruct ) do
|
26
26
|
define_method( :initialize ) do |*args|
|
27
27
|
attributes.keys.zip( args ).each do |key, arg|
|
@@ -100,13 +100,13 @@ def self.build_class( class_name, **attributes )
|
|
100
100
|
end
|
101
101
|
|
102
102
|
|
103
|
-
## note: use
|
103
|
+
## note: use Kernel for "namespacing"
|
104
104
|
## make all enums convenience converters (always) global
|
105
105
|
## including uppercase methods (e.g. State(), Color(), etc.) does NOT work otherwise (with other module includes)
|
106
106
|
|
107
|
-
## add global convenience converter function
|
107
|
+
## add global "Kernel" convenience converter function
|
108
108
|
## e.g. Vote(0) is same as Vote.convert(0)
|
109
|
-
|
109
|
+
Kernel.class_eval( <<RUBY )
|
110
110
|
def #{class_name}( arg )
|
111
111
|
#{class_name}.convert( arg )
|
112
112
|
end
|
@@ -130,5 +130,9 @@ def self.zero
|
|
130
130
|
## freeze only works for now for "value" objects e.g. integer, bool, etc.
|
131
131
|
@zero ||= new_zero.freeze
|
132
132
|
end
|
133
|
+
|
134
|
+
def zero?() self == self.class.zero; end
|
135
|
+
|
136
|
+
|
133
137
|
end # class SafeStruct
|
134
138
|
end # module Safe
|
data/lib/safestruct/version.rb
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
|
4
|
-
|
4
|
+
###
|
5
|
+
# note: do not "pollute" Safe namespace / module
|
6
|
+
# use its own module
|
7
|
+
#
|
8
|
+
# note: SafeStruct is already taken :-), thus, use SaferStruct
|
9
|
+
|
10
|
+
|
11
|
+
module SaferStruct
|
5
12
|
|
6
13
|
MAJOR = 1
|
7
14
|
MINOR = 2
|
8
|
-
PATCH =
|
15
|
+
PATCH = 1
|
9
16
|
VERSION = [MAJOR,MINOR,PATCH].join('.')
|
10
17
|
|
11
18
|
def self.version
|
@@ -20,4 +27,4 @@ module Safe
|
|
20
27
|
"#{File.expand_path( File.dirname(File.dirname(File.dirname(__FILE__))) )}"
|
21
28
|
end
|
22
29
|
|
23
|
-
end # module
|
30
|
+
end # module SaferStruct
|
data/test/test_hash.rb
CHANGED
@@ -23,6 +23,20 @@ class TestHash < MiniTest::Test
|
|
23
23
|
## nested e.g. String => (String => Integer)
|
24
24
|
Hash_Hash_X_Integer = SafeHash.build_class( String, Hash_X_Integer )
|
25
25
|
|
26
|
+
SafeStruct.new( :Game123, host: '',
|
27
|
+
challenger: '',
|
28
|
+
turn: '')
|
29
|
+
|
30
|
+
def test_hash_of_hash
|
31
|
+
## note: use Game123 (with unique/unused name)
|
32
|
+
## for testing an "anonymous" hash class (e.g. without a class name)
|
33
|
+
h = Hash.of( String => Hash.of( String => Game123 ))
|
34
|
+
pp h
|
35
|
+
h2 = Hash.of( String => Hash.of( String => Game123 ))
|
36
|
+
pp h2
|
37
|
+
assert true
|
38
|
+
end
|
39
|
+
|
26
40
|
|
27
41
|
def test_integer
|
28
42
|
pp Hash_X_Integer
|
@@ -39,6 +53,11 @@ def test_integer
|
|
39
53
|
assert_equal true, Hash_X_Integer.zero == Hash_X_Integer.new
|
40
54
|
assert_equal true, Hash_X_Integer.zero == Hash_X_Integer.new_zero
|
41
55
|
|
56
|
+
assert_equal true, h.zero?
|
57
|
+
assert_equal true, Hash_X_Integer.zero.zero?
|
58
|
+
assert_equal true, Hash_X_Integer.new.zero?
|
59
|
+
assert_equal true, Hash_X_Integer.new_zero.zero?
|
60
|
+
|
42
61
|
pp Hash_X_Integer.zero
|
43
62
|
assert_equal true, Hash_X_Integer.zero.frozen?
|
44
63
|
assert_equal false, Hash_X_Integer.new.frozen?
|
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.2.
|
4
|
+
version: 1.2.1
|
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-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: enums
|