striuct 0.1.7 → 0.2.3
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/History.rdoc +43 -1
- data/LICENSE +22 -0
- data/Manifest.txt +21 -17
- data/{README.ja.rdoc → README.ja.old.rdoc} +11 -16
- data/README.rdoc +36 -250
- data/Rakefile +2 -2
- data/example/example.old.rdoc +188 -0
- data/example/example.rb +11 -219
- data/example/example1.rb +234 -0
- data/example/example2.rb +22 -0
- data/lib/striuct/abstract.rb +7 -7
- data/lib/striuct/conditions.rb +110 -69
- data/lib/striuct/{subclassable → containable}/basic.rb +9 -9
- data/lib/striuct/containable/classutil.rb +22 -0
- data/lib/striuct/{subclassable → containable}/eigen/basic.rb +9 -1
- data/lib/striuct/{subclassable → containable}/eigen/constructor.rb +1 -1
- data/lib/striuct/{subclassable → containable}/eigen/handy.rb +38 -5
- data/lib/striuct/{subclassable → containable}/eigen/inner.rb +22 -28
- data/lib/striuct/{subclassable → containable}/eigen/macro.rb +34 -25
- data/lib/striuct/{subclassable → containable}/eigen/safety.rb +15 -19
- data/lib/striuct/{subclassable/eigen/frame.rb → containable/eigen.rb} +10 -14
- data/lib/striuct/containable/handy.rb +91 -0
- data/lib/striuct/{subclassable → containable}/hashlike.rb +1 -1
- data/lib/striuct/{subclassable → containable}/inner.rb +23 -11
- data/lib/striuct/{subclassable → containable}/safety.rb +24 -5
- data/lib/striuct/{subclassable → containable}/yaml.rb +1 -1
- data/lib/striuct/containable.rb +39 -0
- data/lib/striuct/flavors.rb +83 -0
- data/lib/striuct/version.rb +2 -2
- data/lib/striuct.rb +13 -2
- data/test/test_striuct.rb +194 -17
- metadata +43 -35
- data/lib/striuct/frame.rb +0 -8
- data/lib/striuct/subclassable/classutil.rb +0 -26
- data/lib/striuct/subclassable/frame.rb +0 -33
- data/lib/striuct/subclassable/handy.rb +0 -57
@@ -0,0 +1,188 @@
|
|
1
|
+
=== Struct+ "Safety"
|
2
|
+
|
3
|
+
==== "member" macro
|
4
|
+
|
5
|
+
* Use "member" and you get a accessor, it looks Struct with tester(validator)s.
|
6
|
+
class User < Striuct.new
|
7
|
+
member :id, Integer
|
8
|
+
member :age, (20..140)
|
9
|
+
member :name, OR(/\A\w+\z/, /\A\w+ \w+\z/)
|
10
|
+
end
|
11
|
+
|
12
|
+
# pass
|
13
|
+
user = User.new 128381, 20
|
14
|
+
user.age = 30
|
15
|
+
user[2] = 'foo bar'
|
16
|
+
|
17
|
+
# fail
|
18
|
+
user[:id] = 10.0
|
19
|
+
user.age = 19
|
20
|
+
user[2] = nil
|
21
|
+
|
22
|
+
* Use functional object and you get a tester on upstairs.
|
23
|
+
module Game
|
24
|
+
class Character
|
25
|
+
end
|
26
|
+
|
27
|
+
class DB < Striuct.new
|
28
|
+
member :monsters, ->list{(list - characters).empty?}
|
29
|
+
member :characters, GENERICS(Character)
|
30
|
+
end
|
31
|
+
|
32
|
+
monster = Character.new
|
33
|
+
db = DB.new
|
34
|
+
|
35
|
+
# fail
|
36
|
+
db.characters = [1, 2]
|
37
|
+
|
38
|
+
# pass
|
39
|
+
db.characters = [monster, Character.new]
|
40
|
+
|
41
|
+
# fail
|
42
|
+
db.monsters = [Character.new]
|
43
|
+
|
44
|
+
# pass
|
45
|
+
db.monsters = [monster]
|
46
|
+
end
|
47
|
+
|
48
|
+
* Use "inference" and all instance test under class of first passed object.
|
49
|
+
class FlexibleContainer < Striuct.new
|
50
|
+
member :anything, anything, inference: true
|
51
|
+
member :number, Numeric, inference: true
|
52
|
+
end
|
53
|
+
|
54
|
+
fc1, fc2 = FlexibleContainer.new, FlexibleContainer.new
|
55
|
+
# pass
|
56
|
+
fc1.anything = 'str'
|
57
|
+
|
58
|
+
# fail
|
59
|
+
fc1.anything = :sym
|
60
|
+
fc2.anything = :sym
|
61
|
+
|
62
|
+
# pass
|
63
|
+
fc2.anything = 'string too'
|
64
|
+
|
65
|
+
# fail
|
66
|
+
fc1.number = 'str'
|
67
|
+
|
68
|
+
# pass
|
69
|
+
fc1.number = 1.0
|
70
|
+
|
71
|
+
# fail
|
72
|
+
fc2.number = 1
|
73
|
+
|
74
|
+
==== Protect from risks in naming members
|
75
|
+
|
76
|
+
* Standard Struct dosen't check member-name.
|
77
|
+
NoGuard = Struct.new :object_id, :'? !'
|
78
|
+
noguard = NoGuard.new false
|
79
|
+
noguard.object_id #=> false
|
80
|
+
noguard.methods.include?(:'? !') #=> false(lost!!)
|
81
|
+
|
82
|
+
* Striuct provides safety levels for this. (default: :prevent)
|
83
|
+
class SafetyNaming < Striuct.new
|
84
|
+
begin
|
85
|
+
member :object_id
|
86
|
+
rescue
|
87
|
+
p $!
|
88
|
+
end
|
89
|
+
|
90
|
+
begin
|
91
|
+
member :'? !'
|
92
|
+
rescue
|
93
|
+
p $!
|
94
|
+
end
|
95
|
+
|
96
|
+
# set lower
|
97
|
+
protect_level :struct
|
98
|
+
|
99
|
+
member :object_id, :'? !'
|
100
|
+
end
|
101
|
+
|
102
|
+
=== Struct+ "Handy"
|
103
|
+
|
104
|
+
==== Flavor
|
105
|
+
|
106
|
+
* Block with member macro, it is called "flavor" at here.
|
107
|
+
Below cases for type cast.
|
108
|
+
class User2 < Striuct.new
|
109
|
+
member :age, Fixnum, &->v{Integer v}
|
110
|
+
member :name, Symbol, &->v{v.to_s.to_sym}
|
111
|
+
end
|
112
|
+
|
113
|
+
user2 = User2.new
|
114
|
+
user2.age = 9 #=> 9(Fixnum)
|
115
|
+
user2.age = 10.1 #=> 10(Fixnum)
|
116
|
+
user2.age = '10' #=> 10(Fixnum)
|
117
|
+
|
118
|
+
user2.name = 10 #=> :10(Symbol)
|
119
|
+
user2.name = Class #=> :Class(Symbol)
|
120
|
+
|
121
|
+
==== Default
|
122
|
+
|
123
|
+
* provides default value and can use block parameter(like Hash.new)
|
124
|
+
class User3 < Striuct.new
|
125
|
+
member :lank, Fixnum
|
126
|
+
default :lank, 3
|
127
|
+
member :name
|
128
|
+
end
|
129
|
+
|
130
|
+
user3 = User3.new
|
131
|
+
user3.lank #=> 3
|
132
|
+
|
133
|
+
* Standard Struct always define "nil is default". Realy?
|
134
|
+
user3.name #=> nil
|
135
|
+
user3.assign? :name #=> false
|
136
|
+
user3.name = nil
|
137
|
+
user3.assign? :name #=> true
|
138
|
+
|
139
|
+
==== Alias
|
140
|
+
|
141
|
+
* alias member name
|
142
|
+
class User3
|
143
|
+
alias_member :position, :lank
|
144
|
+
end
|
145
|
+
|
146
|
+
user3.lank.equal? user3.position #=> true
|
147
|
+
user3[:lank].equal? user3[:position] #=> true
|
148
|
+
user3[:position] = 4
|
149
|
+
user3.lank #=> 4
|
150
|
+
|
151
|
+
==== Inherit
|
152
|
+
|
153
|
+
* (writing...)
|
154
|
+
|
155
|
+
==== Lock
|
156
|
+
|
157
|
+
* (writing...)
|
158
|
+
|
159
|
+
==== New Constructors
|
160
|
+
|
161
|
+
* Subclass.define reject floating object.
|
162
|
+
* block parameter is new instance
|
163
|
+
* except if no finished to assign each member
|
164
|
+
* returning object is tested strict(optional)
|
165
|
+
* returning object is locked(optional)
|
166
|
+
user3 = User3.define do |r|
|
167
|
+
r.lank = 10
|
168
|
+
r.name = 'foo'
|
169
|
+
end
|
170
|
+
|
171
|
+
* Subclass.[](load_pairs) make from Hash and like Hash
|
172
|
+
user3 = User3[lank: 10, name: 'foo']
|
173
|
+
|
174
|
+
=== Almost interfaces are keeping Struct has.
|
175
|
+
|
176
|
+
Sth1 = Striuct.new do
|
177
|
+
def my_special_method
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
Sth1.new.respond_to?(:my_special_method) #=> true
|
182
|
+
|
183
|
+
=== HashLike
|
184
|
+
|
185
|
+
* some interfaces import from Hash
|
186
|
+
|
187
|
+
* easy cast to Hash
|
188
|
+
user3.to_h #=> {:lank=>3, :name=>nil}
|
data/example/example.rb
CHANGED
@@ -1,225 +1,17 @@
|
|
1
|
-
|
1
|
+
$VERBOSE = true
|
2
2
|
|
3
|
-
|
3
|
+
require '../lib/striuct'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
puts message.inspect, '-' * 80
|
5
|
+
Person = Striuct.define do
|
6
|
+
member :name, AND(String, /\A\w+( \w+)?\z/)
|
8
7
|
end
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# macro "member" provides to use condtions
|
14
|
-
class User < Striuct.new
|
15
|
-
member :id, Integer
|
16
|
-
member :age, (20..140)
|
17
|
-
member :name, OR(/\A\w+\z/, /\A\w+ \w+\z/)
|
18
|
-
end
|
19
|
-
|
20
|
-
user = User.new 128381, 20
|
21
|
-
debug user
|
22
|
-
|
23
|
-
user.age = 30
|
24
|
-
user[2] = 'taro yamada'
|
25
|
-
debug user
|
26
|
-
|
27
|
-
# fail (Exception Striuct::ConditionError)
|
28
|
-
begin
|
29
|
-
user[:id] = 10.0
|
30
|
-
rescue
|
31
|
-
debug $!
|
32
|
-
end
|
33
|
-
|
34
|
-
begin
|
35
|
-
user.age = 19
|
36
|
-
rescue
|
37
|
-
debug $!
|
38
|
-
end
|
39
|
-
|
40
|
-
begin
|
41
|
-
user[2] = 'typo! name'
|
42
|
-
rescue
|
43
|
-
debug $!
|
44
|
-
end
|
45
|
-
|
46
|
-
# more detail checker do you need, use functional object
|
47
|
-
module Game
|
48
|
-
class Character
|
49
|
-
end
|
50
|
-
|
51
|
-
class DB < Striuct.new
|
52
|
-
member :monsters, ->list{(list - characters).empty?}
|
53
|
-
member :characters, GENERICS(Character)
|
54
|
-
end
|
55
|
-
|
56
|
-
monster = Character.new
|
57
|
-
db = DB.new
|
58
|
-
|
59
|
-
begin
|
60
|
-
db.characters = [1, 2]
|
61
|
-
rescue
|
62
|
-
debug $!
|
63
|
-
end
|
64
|
-
|
65
|
-
db.characters = [monster, Character.new]
|
66
|
-
debug db
|
67
|
-
|
68
|
-
begin
|
69
|
-
db.monsters = [Character.new]
|
70
|
-
rescue
|
71
|
-
debug $!
|
72
|
-
end
|
73
|
-
|
74
|
-
db.monsters = [monster]
|
75
|
-
debug db
|
76
|
-
end
|
77
|
-
|
78
|
-
# through "inference", and check under first passed object class
|
79
|
-
class FlexibleContainer < Striuct.new
|
80
|
-
member :anything, inference
|
81
|
-
member :number, Numeric, inference
|
82
|
-
end
|
83
|
-
|
84
|
-
fc1, fc2 = FlexibleContainer.new, FlexibleContainer.new
|
85
|
-
fc1.anything = 'str'
|
86
|
-
debug fc1
|
87
|
-
begin
|
88
|
-
fc1.anything = :sym
|
89
|
-
rescue
|
90
|
-
debug $!
|
91
|
-
end
|
92
|
-
|
93
|
-
begin
|
94
|
-
fc2.anything = :sym
|
95
|
-
rescue
|
96
|
-
debug $!
|
97
|
-
end
|
98
|
-
|
99
|
-
fc2.anything = 'string too'
|
100
|
-
|
101
|
-
debug fc2
|
102
|
-
|
103
|
-
begin
|
104
|
-
fc1.number = 'str'
|
105
|
-
rescue
|
106
|
-
debug $!
|
107
|
-
end
|
108
|
-
|
109
|
-
fc1.number = 1.0
|
110
|
-
debug fc1
|
111
|
-
|
112
|
-
begin
|
113
|
-
fc2.number = 1
|
114
|
-
rescue
|
115
|
-
debug $!
|
116
|
-
end
|
117
|
-
|
118
|
-
# Standard Struct not check member name.
|
119
|
-
NoGuard = Struct.new :__send__, :'? !'
|
120
|
-
noguard = NoGuard.new false
|
121
|
-
debug noguard.__send__
|
122
|
-
debug noguard.methods.include?(:'? !') # lost!!
|
123
|
-
|
124
|
-
# Striuct provides safety levels for naming.
|
125
|
-
class SafetyNaming < Striuct.new
|
126
|
-
begin
|
127
|
-
member :__send__
|
128
|
-
rescue
|
129
|
-
debug $!
|
130
|
-
end
|
131
|
-
|
132
|
-
begin
|
133
|
-
member :'? !'
|
134
|
-
rescue
|
135
|
-
debug $!
|
136
|
-
end
|
137
|
-
|
138
|
-
# set lower
|
139
|
-
protect_level :struct
|
140
|
-
|
141
|
-
member :__send__, :'? !'
|
142
|
-
end
|
143
|
-
|
144
|
-
# 2. Struct+ "Handy"
|
145
|
-
|
146
|
-
# to through block called "flavor"
|
147
|
-
# below case for type cast
|
148
|
-
class User2 < Striuct.new
|
149
|
-
member :age, /\A\d+\z/, Numeric do |arg|
|
150
|
-
Integer arg
|
151
|
-
end
|
152
|
-
|
153
|
-
member :name, ->v{v.respond_to? :to_s} do |v|
|
154
|
-
v.to_s.to_sym
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
user2 = User2.new
|
159
|
-
user2.age = 9
|
160
|
-
debug user2
|
161
|
-
|
162
|
-
user2.age = 10.1
|
163
|
-
debug user2
|
164
|
-
|
165
|
-
user2.age = '10'
|
166
|
-
debug user2
|
167
|
-
|
168
|
-
user2.name = 10
|
169
|
-
debug user2
|
170
|
-
user2.name = Class
|
171
|
-
debug user2
|
172
|
-
|
173
|
-
# Default value
|
174
|
-
|
175
|
-
class User3 < Striuct.new
|
176
|
-
member :lank, Fixnum
|
177
|
-
default :lank, 3
|
178
|
-
member :name
|
179
|
-
end
|
180
|
-
|
181
|
-
user3 = User3.new
|
182
|
-
user3
|
183
|
-
debug user3
|
184
|
-
|
185
|
-
# Standard Struct always define "nil is default". ...realy?
|
186
|
-
debug user3.assign?(:name)
|
187
|
-
user3.name = nil
|
188
|
-
debug user3.assign?(:name)
|
189
|
-
|
190
|
-
# Alias
|
191
|
-
|
192
|
-
class User3
|
193
|
-
alias_member :position, :lank
|
194
|
-
end
|
195
|
-
|
196
|
-
debug user3.lank.equal?(user3.position)
|
197
|
-
debug user3[:lank].equal?(user3[:position])
|
198
|
-
user3[:position] = 4
|
199
|
-
debug user3.lank
|
200
|
-
|
201
|
-
# New Constructors
|
202
|
-
|
203
|
-
# Subclass.define reject floating object
|
204
|
-
# * except if no finished assign each members
|
205
|
-
# * return object is frozen
|
206
|
-
user3 = User3.define do |r|
|
207
|
-
r.lank = 10
|
208
|
-
r.name = 'foo'
|
209
|
-
end
|
210
|
-
|
211
|
-
debug user3
|
212
|
-
|
213
|
-
# Subclass.load_pairs easy make from Hash and like Hash
|
214
|
-
user3 = User3[lank:10, name: 'foo']
|
215
|
-
|
216
|
-
debug user3
|
217
|
-
|
218
|
-
# 3. Keeping Struct's good interface
|
219
|
-
|
220
|
-
Sth1 = Striuct.new do
|
221
|
-
def my_special_method
|
222
|
-
end
|
9
|
+
class User < Person
|
10
|
+
member :id, AND(Integer, 1..99999)
|
223
11
|
end
|
224
12
|
|
225
|
-
|
13
|
+
user = User.new
|
14
|
+
p user.members #=> [:name, :id]
|
15
|
+
p user.name = :Ken #=> error
|
16
|
+
p user.name = '' #=> error
|
17
|
+
p user.name = 'Ken' #=> pass
|
data/example/example1.rb
ADDED
@@ -0,0 +1,234 @@
|
|
1
|
+
#/usr/bin/ruby -w
|
2
|
+
|
3
|
+
require_relative '../lib/striuct'
|
4
|
+
|
5
|
+
def debug(message)
|
6
|
+
puts "line: #{caller.first.slice(/:(\w+)/, 1)}"
|
7
|
+
puts message.inspect, '-' * 80
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
# 1. Struct+ "Secure"
|
12
|
+
|
13
|
+
# macro "member" provides to use condtions
|
14
|
+
class User < Striuct.new
|
15
|
+
member :id, Integer
|
16
|
+
member :age, (20..140)
|
17
|
+
member :name, OR(/\A\w+\z/, /\A\w+ \w+\z/)
|
18
|
+
end
|
19
|
+
|
20
|
+
user = User.new 128381, 20
|
21
|
+
debug user
|
22
|
+
|
23
|
+
user.age = 30
|
24
|
+
user[2] = 'taro yamada'
|
25
|
+
debug user
|
26
|
+
|
27
|
+
# fail (Exception Striuct::ConditionError)
|
28
|
+
begin
|
29
|
+
user[:id] = 10.0
|
30
|
+
rescue
|
31
|
+
debug $!
|
32
|
+
end
|
33
|
+
|
34
|
+
begin
|
35
|
+
user.age = 19
|
36
|
+
rescue
|
37
|
+
debug $!
|
38
|
+
end
|
39
|
+
|
40
|
+
begin
|
41
|
+
user[2] = 'typo! name'
|
42
|
+
rescue
|
43
|
+
debug $!
|
44
|
+
end
|
45
|
+
|
46
|
+
# more detail checker do you need, use functional object
|
47
|
+
module Game
|
48
|
+
class Character
|
49
|
+
end
|
50
|
+
|
51
|
+
class DB < Striuct.new
|
52
|
+
member :monsters, ->list{(list - characters).empty?}
|
53
|
+
member :characters, GENERICS(Character)
|
54
|
+
end
|
55
|
+
|
56
|
+
monster = Character.new
|
57
|
+
db = DB.new
|
58
|
+
|
59
|
+
begin
|
60
|
+
db.characters = [1, 2]
|
61
|
+
rescue
|
62
|
+
debug $!
|
63
|
+
end
|
64
|
+
|
65
|
+
db.characters = [monster, Character.new]
|
66
|
+
debug db
|
67
|
+
|
68
|
+
begin
|
69
|
+
db.monsters = [Character.new]
|
70
|
+
rescue
|
71
|
+
debug $!
|
72
|
+
end
|
73
|
+
|
74
|
+
db.monsters = [monster]
|
75
|
+
debug db
|
76
|
+
end
|
77
|
+
|
78
|
+
# through "inference", and check under first passed object class
|
79
|
+
class FlexibleContainer < Striuct.new
|
80
|
+
member :anything, anything, inference: true
|
81
|
+
member :number, Numeric, inference: true
|
82
|
+
end
|
83
|
+
|
84
|
+
fc1, fc2 = FlexibleContainer.new, FlexibleContainer.new
|
85
|
+
fc1.anything = 'str'
|
86
|
+
debug fc1
|
87
|
+
begin
|
88
|
+
fc1.anything = :sym
|
89
|
+
rescue
|
90
|
+
debug $!
|
91
|
+
end
|
92
|
+
|
93
|
+
begin
|
94
|
+
fc2.anything = :sym
|
95
|
+
rescue
|
96
|
+
debug $!
|
97
|
+
end
|
98
|
+
|
99
|
+
fc2.anything = 'string too'
|
100
|
+
|
101
|
+
debug fc2
|
102
|
+
|
103
|
+
begin
|
104
|
+
fc1.number = 'str'
|
105
|
+
rescue
|
106
|
+
debug $!
|
107
|
+
end
|
108
|
+
|
109
|
+
fc1.number = 1.0
|
110
|
+
debug fc1
|
111
|
+
|
112
|
+
begin
|
113
|
+
fc2.number = 1
|
114
|
+
rescue
|
115
|
+
debug $!
|
116
|
+
end
|
117
|
+
|
118
|
+
# Standard Struct not check member name.
|
119
|
+
NoGuard = Struct.new :__send__, :'? !'
|
120
|
+
noguard = NoGuard.new false
|
121
|
+
debug noguard.__send__
|
122
|
+
debug noguard.methods.include?(:'? !') # lost!!
|
123
|
+
|
124
|
+
# Striuct provides safety levels for naming.
|
125
|
+
class SafetyNaming < Striuct.new
|
126
|
+
begin
|
127
|
+
member :__send__
|
128
|
+
rescue
|
129
|
+
debug $!
|
130
|
+
end
|
131
|
+
|
132
|
+
begin
|
133
|
+
member :'? !'
|
134
|
+
rescue
|
135
|
+
debug $!
|
136
|
+
end
|
137
|
+
|
138
|
+
# set lower
|
139
|
+
protect_level :struct
|
140
|
+
|
141
|
+
member :__send__, :'? !'
|
142
|
+
end
|
143
|
+
|
144
|
+
# 2. Struct+ "Handy"
|
145
|
+
|
146
|
+
# to through block called "flavor"
|
147
|
+
# below case for type cast
|
148
|
+
class User2 < Striuct.new
|
149
|
+
member :age, OR(/\A\d+\z/, Numeric) do |arg|
|
150
|
+
Integer arg
|
151
|
+
end
|
152
|
+
|
153
|
+
member :name, ->v{v.respond_to? :to_s} do |v|
|
154
|
+
v.to_s.to_sym
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
user2 = User2.new
|
159
|
+
user2.age = 9
|
160
|
+
debug user2
|
161
|
+
|
162
|
+
user2.age = 10.1
|
163
|
+
debug user2
|
164
|
+
|
165
|
+
user2.age = '10'
|
166
|
+
debug user2
|
167
|
+
|
168
|
+
user2.name = 10
|
169
|
+
debug user2
|
170
|
+
user2.name = Class
|
171
|
+
debug user2
|
172
|
+
|
173
|
+
# Default value
|
174
|
+
|
175
|
+
class User3 < Striuct.new
|
176
|
+
member :lank, Fixnum
|
177
|
+
default :lank, 3
|
178
|
+
member :name
|
179
|
+
end
|
180
|
+
|
181
|
+
user3 = User3.new
|
182
|
+
user3
|
183
|
+
debug user3
|
184
|
+
|
185
|
+
# Standard Struct always define "nil is default". ...realy?
|
186
|
+
debug user3.assign?(:name)
|
187
|
+
user3.name = nil
|
188
|
+
debug user3.assign?(:name)
|
189
|
+
|
190
|
+
# Alias
|
191
|
+
|
192
|
+
class User3
|
193
|
+
alias_member :position, :lank
|
194
|
+
end
|
195
|
+
|
196
|
+
debug user3.lank.equal?(user3.position)
|
197
|
+
debug user3[:lank].equal?(user3[:position])
|
198
|
+
user3[:position] = 4
|
199
|
+
debug user3.lank
|
200
|
+
|
201
|
+
# New Constructors
|
202
|
+
|
203
|
+
# Subclass.define reject floating object
|
204
|
+
# * except if no finished assign each members
|
205
|
+
# * return object is frozen
|
206
|
+
user3 = User3.define do |r|
|
207
|
+
r.lank = 10
|
208
|
+
r.name = 'foo'
|
209
|
+
end
|
210
|
+
|
211
|
+
debug user3
|
212
|
+
|
213
|
+
# Subclass.load_pairs easy make from Hash and like Hash
|
214
|
+
user3 = User3[lank:10, name: 'foo']
|
215
|
+
|
216
|
+
debug user3
|
217
|
+
|
218
|
+
# 3. Keeping Struct's good interface
|
219
|
+
|
220
|
+
Sth1 = Striuct.new do
|
221
|
+
def my_special_method
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
debug Sth1.new.respond_to?(:my_special_method)
|
226
|
+
|
227
|
+
# to_struct
|
228
|
+
MyC = Striuct.new :a, :b
|
229
|
+
a = MyC.to_struct_class
|
230
|
+
p a
|
231
|
+
|
232
|
+
p MyC.new.to_struct
|
233
|
+
myc = Striuct.new :a, :b
|
234
|
+
p myc.new.to_struct
|
data/example/example2.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/local/bin/ruby -w
|
2
|
+
|
3
|
+
$VERBOSE = true
|
4
|
+
|
5
|
+
require_relative 'lib/striuct'
|
6
|
+
|
7
|
+
User = Striuct.define do # other way "class User < Striuct.new"
|
8
|
+
member :firstname, /\w+/ # look like case syntax in Ruby
|
9
|
+
member :lank, AND(Fixnum, 1..10) # easy build multiple validation
|
10
|
+
default :lank, 3 # set a normal default value
|
11
|
+
member :registered, Time # look like type variable
|
12
|
+
default :registered, &->{Time.now} # evaluate with construction
|
13
|
+
p members #=> [firstname, lank, registered]
|
14
|
+
end
|
15
|
+
|
16
|
+
class MyUser < User
|
17
|
+
p members #=> [firstname, lank, registered]
|
18
|
+
member :foo # no validation, just an accessor
|
19
|
+
p members #=> [firstname, lank, registered, :foo]
|
20
|
+
end
|
21
|
+
|
22
|
+
user = MyUser.new
|
data/lib/striuct/abstract.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
require_relative '
|
1
|
+
require_relative 'containable'
|
2
2
|
|
3
3
|
class Striuct; class << self
|
4
4
|
# @group Constructor
|
@@ -46,10 +46,10 @@ class Striuct; class << self
|
|
46
46
|
def inherited(subclass)
|
47
47
|
attributes = (
|
48
48
|
if equal? ::Striuct
|
49
|
-
[[], {}, {}, {}, {}, {}, :prevent]
|
49
|
+
[[], {}, {}, {}, {}, {}, {}, {}, :prevent]
|
50
50
|
else
|
51
51
|
[*[@names, @conditions, @flavors, @defaults,\
|
52
|
-
@inferences, @aliases].map(&:dup), @protect_level]
|
52
|
+
@inferences, @aliases, @setter_validations, @getter_validations].map(&:dup), @protect_level]
|
53
53
|
end
|
54
54
|
)
|
55
55
|
|
@@ -57,15 +57,15 @@ class Striuct; class << self
|
|
57
57
|
|
58
58
|
subclass.class_eval do
|
59
59
|
original_inherited subclass
|
60
|
-
include
|
60
|
+
include Containable if ::Striuct.equal? eigen
|
61
61
|
|
62
62
|
@names, @conditions, @flavors, @defaults,\
|
63
|
-
@inferences, @aliases, @protect_level = *attributes
|
63
|
+
@inferences, @aliases, @setter_validations, @getter_validations, @protect_level = *attributes
|
64
64
|
|
65
65
|
singleton_class.instance_eval do
|
66
66
|
define_method :initialize_copy do |original|
|
67
|
-
@names, @flavors, @defaults, @aliases =
|
68
|
-
*[@names, @flavors, @defaults, @aliases].map(&:dup)
|
67
|
+
@names, @flavors, @defaults, @aliases, @setter_validations, @getter_validations =
|
68
|
+
*[@names, @flavors, @defaults, @aliases, @setter_validations, @getter_validations].map(&:dup)
|
69
69
|
@conditions, @inferences = @conditions.dup, @inferences.dup
|
70
70
|
end
|
71
71
|
end
|