striuct 0.3.5.1 → 0.4.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.
- data/.travis.yml +3 -0
- data/.yardopts +1 -1
- data/LICENSE +1 -1
- data/README.md +7 -3
- data/example/example1.rb +5 -4
- data/lib/striuct/classmethods/README.md +9 -4
- data/lib/striuct/classmethods/adjustment.rb +4 -15
- data/lib/striuct/{attributes.rb → classmethods/attributes.rb} +15 -17
- data/lib/striuct/classmethods/{prevent_conflicts.rb → conflict_management.rb} +37 -14
- data/lib/striuct/classmethods/constructor.rb +2 -4
- data/lib/striuct/classmethods/copy.rb +2 -2
- data/lib/striuct/classmethods/default.rb +9 -18
- data/lib/striuct/classmethods/enum.rb +3 -5
- data/lib/striuct/classmethods/inner.rb +6 -10
- data/lib/striuct/classmethods/macro.rb +33 -48
- data/lib/striuct/classmethods/names.rb +75 -0
- data/lib/striuct/classmethods/predicate.rb +128 -0
- data/lib/striuct/classmethods/{requiremnets.rb → requirements.rb} +6 -3
- data/lib/striuct/classmethods/validation.rb +5 -43
- data/lib/striuct/instancemethods/README.md +4 -4
- data/lib/striuct/instancemethods/assign.rb +11 -13
- data/lib/striuct/instancemethods/cast.rb +5 -8
- data/lib/striuct/instancemethods/compare.rb +6 -6
- data/lib/striuct/instancemethods/default.rb +28 -6
- data/lib/striuct/instancemethods/delegate_class_methods.rb +21 -21
- data/lib/striuct/instancemethods/enum.rb +3 -9
- data/lib/striuct/instancemethods/getter.rb +47 -0
- data/lib/striuct/instancemethods/hashy.rb +2 -6
- data/lib/striuct/instancemethods/keyvalidatable.rb +0 -5
- data/lib/striuct/instancemethods/lock.rb +35 -43
- data/lib/striuct/instancemethods/object.rb +3 -26
- data/lib/striuct/instancemethods/requirements.rb +16 -2
- data/lib/striuct/instancemethods/safety.rb +1 -1
- data/lib/striuct/instancemethods/setter.rb +58 -0
- data/lib/striuct/instancemethods/to_s.rb +2 -2
- data/lib/striuct/instancemethods/validation.rb +13 -7
- data/lib/striuct/instancemethods/values.rb +8 -7
- data/lib/striuct/requirements.rb +2 -5
- data/lib/striuct/{hashdeepdupulicatable.rb → singleton_class/hashdeepdupulicatable.rb} +2 -2
- data/lib/striuct/singleton_class.rb +3 -4
- data/striuct.gemspec +7 -4
- data/test/test_sglc-constructor.rb +36 -0
- data/test/test_subc-c-constructor.rb +88 -0
- data/test/{test_striuct-subclass-class-safety_naming.rb → test_subc-c-safety_naming.rb} +6 -5
- data/test/test_subc-f-enum.rb +139 -0
- data/test/test_subc-f-predicate.rb +647 -0
- data/test/{test_striuct-subclass-feature-validation_util.rb → test_subc-f-validation_util.rb} +10 -8
- data/test/test_subc-f_name.rb +525 -0
- data/test/{test_striuct-subclass-instance-accessor.rb → test_subc-i-accessor.rb} +3 -2
- data/test/test_subc-i-assign.rb +49 -0
- data/test/test_subc-i-cast.rb +27 -0
- data/test/{test_striuct-subclass-instance-default_value.rb → test_subc-i-default_value.rb} +2 -2
- data/test/{test_striuct-subclass-instance-hashlike.rb → test_subc-i-hashlike.rb} +0 -9
- data/test/{test_striuct-subclass-instance-lock.rb → test_subc-i-lock.rb} +8 -8
- data/test/{test_striuct-subclass-instance-to_s_family.rb → test_subc-i-to_s_family.rb} +1 -1
- data/test/{test_striuct-subclass-instance-validation_specific_conditions.rb → test_subc-i-validation_specific_conditions.rb} +50 -0
- data/test/test_version.rb +14 -0
- metadata +124 -80
- data/Manifest.txt +0 -97
- data/README.ja.old.rdoc +0 -298
- data/example/example.old.rdoc +0 -188
- data/lib/striuct/classmethods/hashy.rb +0 -22
- data/lib/striuct/classmethods/named.rb +0 -126
- data/lib/striuct/classmethods.rb +0 -1
- data/lib/striuct/instancemethods/inner_accessor.rb +0 -53
- data/lib/striuct/instancemethods/subscript.rb +0 -27
- data/lib/striuct/instancemethods.rb +0 -1
- data/lib/striuct/version.rb +0 -5
- data/test/test_striuct-singleton_class-define.rb +0 -19
- data/test/test_striuct-subclass-class-constructor.rb +0 -82
- data/test/test_striuct-subclass-class-validation.rb +0 -26
- data/test/test_striuct-subclass-instance-assign.rb +0 -30
- data/test/test_striuct-subclass-instance-enum.rb +0 -93
- data/test/test_striuct-subclass-instance-validation_functional_condition.rb +0 -51
- data/test/test_striuct-subclass-instance_names.rb +0 -18
- data/test/test_striuct-version.rb +0 -11
- /data/{History.rdoc → History.old(~0.3.n).rdoc} +0 -0
- /data/test/{test_striuct-subclass-class-macro.rb → test_subc-c-add_members.rb} +0 -0
- /data/test/{test_striuct-subclass-class-close.rb → test_subc-c-close_member.rb} +0 -0
- /data/test/{test_striuct-subclass-class-copy.rb → test_subc-c-copy.rb} +0 -0
- /data/test/{test_striuct-subclass-class-freeze.rb → test_subc-c-freeze.rb} +0 -0
- /data/test/{test_striuct-subclass-class-inheritable.rb → test_subc-c-inheritable.rb} +0 -0
- /data/test/{test_striuct-subclass-feature-alias_member.rb → test_subc-f-alias_member.rb} +0 -0
- /data/test/{test_striuct-subclass-feature-to_struct.rb → test_subc-f-to_struct.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-adjuster.rb → test_subc-i-adjuster.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-basic.rb → test_subc-i-basic.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-compare.rb → test_subc-i-compare.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-copy.rb → test_subc-i-copy.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-freeze.rb → test_subc-i-freeze.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-keyvalidatable.rb → test_subc-i-keyvalidatable.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-validation_inference.rb → test_subc-i-validation_inference.rb} +0 -0
- /data/test/{test_striuct-subclass-instance-validation_with_getter.rb → test_subc-i-validation_with_getter.rb} +0 -0
data/README.ja.old.rdoc
DELETED
@@ -1,298 +0,0 @@
|
|
1
|
-
= Striuct
|
2
|
-
|
3
|
-
* http://github.com/kachick/striuct
|
4
|
-
* https://rubygems.org/gems/striuct
|
5
|
-
* http://rubyforge.org/projects/striuct
|
6
|
-
|
7
|
-
== DESCRIPTION
|
8
|
-
|
9
|
-
Structっぽい手触りで扱える、多機能なStructを目指しています。
|
10
|
-
|
11
|
-
メンバ名にチェックがかかる&一つの新しいクラスとして扱えるStructは、場面によってはHashよりも好ましい事があるかと思います。
|
12
|
-
でもそうやってStructを使うぐらいなわけだから、値の方にもある程度のチェックをかけたいと思う事が多くありませんか?
|
13
|
-
|
14
|
-
RubyのStructを愛しつつも、こういった部分をなんとかしたいと感じている方へお勧めします。
|
15
|
-
|
16
|
-
1. ノーガードで参照を付けられるのがおっかないときもある
|
17
|
-
2. かといって、型チェックしか出来ないようじゃRubyのメリットが死ぬんではなかろうか
|
18
|
-
3. メンバ名でフツーのメソッド名を上書きしかねないのもおっかない
|
19
|
-
4. 最初に代入したオブジェクトのクラスで固定したい(これは無いか)
|
20
|
-
5. どうせなら、チェックだけじゃなくキャストなりやらせたものを参照したい
|
21
|
-
6. メンバによっては標準値も定義したい
|
22
|
-
7. Hashとの親和性を高くしたい
|
23
|
-
8. メンバ名にaliasかけたいけど、alias_methodだけだと添え字アクセス出来なくて歯がゆい
|
24
|
-
9. 構造体クラスでも継承を使った上で、更にメンバ追加がしたい
|
25
|
-
|
26
|
-
== FEATURES
|
27
|
-
|
28
|
-
* メンバ毎に、参照条件を簡単に定義できます。
|
29
|
-
* 型チェックではなく式チェックなので、動的型の良さを殺しません
|
30
|
-
* Proc(lambda)やMethod等 を使うことで、さらに柔軟なチェックが可能です
|
31
|
-
* どれか一つの構造体で最初に代入したオブジェクトのクラスに沿うようなメンバを作れます。
|
32
|
-
* 参照直前に、ちょっとした処理を加える事も可能です
|
33
|
-
* 構造体としてのメンバ追加時、Rubyの既存メソッドと干渉しないかを指定レベル別にチェック出来ます。
|
34
|
-
* 違和感のない継承利用
|
35
|
-
* なるべくStructの心地よい操作感を残したまま機能追加をしています。
|
36
|
-
* 既存クラスやメソッドの上書き等をしない、控えめな名前空間
|
37
|
-
* Pure Ruby
|
38
|
-
|
39
|
-
== SYNOPSIS
|
40
|
-
|
41
|
-
* setup
|
42
|
-
require 'striuct'
|
43
|
-
|
44
|
-
* この名前空間以外は汚しません。
|
45
|
-
Striuct
|
46
|
-
|
47
|
-
=== Struct+ "Safety"
|
48
|
-
|
49
|
-
==== 基本的な使い方
|
50
|
-
|
51
|
-
* memberというクラスマクロを使うことで構造体のメンバを定義できます。
|
52
|
-
引数2以降に、参照するための「条件」を渡して下さい。
|
53
|
-
何も条件を渡さなければ、Struct同様ノーチェックです。
|
54
|
-
class User < Striuct.new
|
55
|
-
member :id, Integer
|
56
|
-
member :age, (20..140)
|
57
|
-
member :name, OR(/\A\w+\z/, /\A\w+ \w+\z/)
|
58
|
-
end
|
59
|
-
|
60
|
-
# pass
|
61
|
-
user = User.new 128381, 20
|
62
|
-
|
63
|
-
# pass
|
64
|
-
user.age = 30
|
65
|
-
user[2] = 'taro yamada'
|
66
|
-
|
67
|
-
# fail
|
68
|
-
user[:id] = 10.0
|
69
|
-
user.age = 19
|
70
|
-
user[2] = nil
|
71
|
-
|
72
|
-
|
73
|
-
* 更に柔軟なチェッカが必要であれば関数的なオブジェクトを使って下さい。
|
74
|
-
この時Proc(lambda)を構造体インスタンスのコンテキストで評価する為、他のメンバと連携したチェックも簡単です。
|
75
|
-
module Game
|
76
|
-
class Character
|
77
|
-
end
|
78
|
-
|
79
|
-
class DB < Striuct.new
|
80
|
-
member :monsters, ->list{(list - characters).empty?}
|
81
|
-
member :characters, GENERICS(Character)
|
82
|
-
end
|
83
|
-
|
84
|
-
monster = Character.new
|
85
|
-
db = DB.new
|
86
|
-
|
87
|
-
# fail
|
88
|
-
db.characters = [1, 2]
|
89
|
-
|
90
|
-
# pass
|
91
|
-
db.characters = [monster, Character.new]
|
92
|
-
|
93
|
-
# fail
|
94
|
-
db.monsters = [:Character.new]
|
95
|
-
|
96
|
-
# pass
|
97
|
-
db.monsters = [monster]
|
98
|
-
end
|
99
|
-
|
100
|
-
* オプションパラメータにinferenceというキーワードをtrueで渡すと、
|
101
|
-
最初に参照したオブジェクトのクラスが以降全インスタンスでの参照条件となります。
|
102
|
-
class FlexibleContainer < Striuct.new
|
103
|
-
member :anything, anything, inference: true
|
104
|
-
member :number, Numeric, inference: true
|
105
|
-
end
|
106
|
-
|
107
|
-
fc1, fc2 = FlexibleContainer.new, FlexibleContainer.new
|
108
|
-
# pass
|
109
|
-
fc1.anything = 'str'
|
110
|
-
|
111
|
-
# fail
|
112
|
-
fc1.anything = :sym
|
113
|
-
fc2.anything = :sym
|
114
|
-
|
115
|
-
# pass
|
116
|
-
fc2.anything = 'string too'
|
117
|
-
|
118
|
-
# fail
|
119
|
-
fc1.number = 'str'
|
120
|
-
|
121
|
-
# pass
|
122
|
-
fc1.number = 1.0
|
123
|
-
|
124
|
-
# fail
|
125
|
-
fc2.number = 1
|
126
|
-
|
127
|
-
==== 意図しない名前干渉は避ける
|
128
|
-
|
129
|
-
* Structはこんな感じで、ノーガード上書き&メソッド定義出来ない物も無警告で進みます(object_id, __id__ なんかもそうですね)
|
130
|
-
NoGuard = Struct.new :__send__, :'? !'
|
131
|
-
noguard = NoGuard.new false
|
132
|
-
p noguard.__send__
|
133
|
-
p noguard.methods.include?(:'? !') # lost!!
|
134
|
-
|
135
|
-
* ということで、意図しない上書き等を防ぐために安全度を設定出来るようにしました。
|
136
|
-
標準値は上から2番目の「:prevent」です。
|
137
|
-
class SafetyNaming < Striuct.new
|
138
|
-
begin
|
139
|
-
member :__send__
|
140
|
-
rescue
|
141
|
-
p $!
|
142
|
-
end
|
143
|
-
|
144
|
-
begin
|
145
|
-
member :'? !'
|
146
|
-
rescue
|
147
|
-
p $!
|
148
|
-
end
|
149
|
-
|
150
|
-
# ここで下げると、定義可能に
|
151
|
-
protect_level :struct
|
152
|
-
|
153
|
-
member :__send__, :'? !'
|
154
|
-
end
|
155
|
-
|
156
|
-
==== この辺に関わる述語メソッド
|
157
|
-
|
158
|
-
* valid? / acccept? / sufficient? # そのメンバにその値が設定出来るか
|
159
|
-
* conditionable? # 条件式として受け入れ可能なオブジェクトか
|
160
|
-
* inference? # 定義時にinferenceを使った上で、一つも参照されていないか
|
161
|
-
* restrict? # そのメンバに参照条件がかけられているか
|
162
|
-
* strict? # 今時点で全てのメンバが参照条件を満たしているか
|
163
|
-
* secure? # インスタンスもクラスも変動することない状態で、インスタンスにfreezeがかかっているか
|
164
|
-
* cname? # そのメンバ名は、今のprotect level下で望ましいものか
|
165
|
-
|
166
|
-
|
167
|
-
=== Struct+ "Handy"
|
168
|
-
|
169
|
-
==== Flavor
|
170
|
-
|
171
|
-
* memberマクロへブロックを渡しておくと、チェック後一処理加えた値を参照可能です。
|
172
|
-
class User2 < Striuct.new
|
173
|
-
# 必ずInteger経由でキャスト
|
174
|
-
member :age, Fixnum, &->v{Integer v}
|
175
|
-
|
176
|
-
# Symbolに変換した上で代入。
|
177
|
-
member :name, Symbol, &->v{v.to_s.to_sym}
|
178
|
-
end
|
179
|
-
|
180
|
-
user2 = User2.new
|
181
|
-
user2.age = 9 #=> 9(Fixnum)
|
182
|
-
user2.age = 10.1 #=> 10(Fixnum)
|
183
|
-
user2.age = '10' #=> 10(Fixnum)
|
184
|
-
|
185
|
-
user2.name = 10 #=> :10(Symbol)
|
186
|
-
user2.name = Class #=> :Class(Symbol)
|
187
|
-
|
188
|
-
==== Default
|
189
|
-
|
190
|
-
* defaultマクロを用いることで、メンバ毎に標準値を定義することが出来ます。
|
191
|
-
ブロックを渡すと、初期化時にブロックの中身を評価して設定します。(Hash.newっぽく)
|
192
|
-
class User3 < Striuct.new
|
193
|
-
member :lank, Fixnum
|
194
|
-
default :lank, 3
|
195
|
-
member :name
|
196
|
-
end
|
197
|
-
|
198
|
-
user3 = User3.new
|
199
|
-
user3.lank #=> 3
|
200
|
-
|
201
|
-
* 「意図的なnil」との区別を付けられます。
|
202
|
-
user3.name #=> nil
|
203
|
-
user3.assign? :name #=> false
|
204
|
-
user3.name = nil
|
205
|
-
user3.assign? :name #=> true
|
206
|
-
|
207
|
-
==== Alias
|
208
|
-
|
209
|
-
* メンバ名を付与出来ます。(標準Structだと、添字アクセス可能にしたりするのが面倒。)
|
210
|
-
class User3
|
211
|
-
alias_member :position, :lank
|
212
|
-
end
|
213
|
-
|
214
|
-
user3.lank.equal? user3.position #=> true
|
215
|
-
user3[:lank].equal? user3[:position] #=> true
|
216
|
-
user3[:position] = 4
|
217
|
-
user3.lank #=> 4
|
218
|
-
|
219
|
-
==== Inherit
|
220
|
-
|
221
|
-
* (writing...)
|
222
|
-
|
223
|
-
==== Lock
|
224
|
-
|
225
|
-
* (writing...)
|
226
|
-
|
227
|
-
==== New Constructors
|
228
|
-
|
229
|
-
* Subclass.define は、生成時から先オブジェクトを変える必要が無いケースで使います。
|
230
|
-
* ブロックパラメータに新しいインスタンスがわたり、またこれが返り値となります
|
231
|
-
* すべてのメンバがアサイン済みかをチェックします
|
232
|
-
* ブロックを抜ける直前に、全て問題ない値かチェックします(オプション指定可)
|
233
|
-
* ブロックを抜ける直前に、全てlockをかけます(オプション指定可)
|
234
|
-
user3 = User3.define do |r|
|
235
|
-
r.lank = 10
|
236
|
-
r.name = 'foo'
|
237
|
-
end
|
238
|
-
|
239
|
-
* Subclass.[](load_pairs) は、HashなりHashっぽいものから作る時用です。
|
240
|
-
# Struct.[] の仕様とは異なります。
|
241
|
-
user3 = User3[lank:10, name: 'foo']
|
242
|
-
|
243
|
-
=== Structの良さは活かしたまま
|
244
|
-
|
245
|
-
* 基本的にはStruct使い(?)が余り違和感を感じ無いようにしたつもりです。
|
246
|
-
Sth2 = Striuct.new do
|
247
|
-
def my_special_method
|
248
|
-
end
|
249
|
-
end
|
250
|
-
|
251
|
-
Sth2.new.respond_to?(:my_special_method) #=> true
|
252
|
-
|
253
|
-
=== Hashとお近づきに
|
254
|
-
|
255
|
-
* どちらかというとStructはHashよりArray寄りな感じを受けるのですが、個人的にHash的な動きをしてくれると嬉しい事の方が多く感じます。
|
256
|
-
ということで、やり過ぎない範囲でHashっぽく使えるように調整しています。
|
257
|
-
|
258
|
-
* Hashへの変換も一発です。
|
259
|
-
user3.to_h #=> {:lank=>3, :name=>nil}
|
260
|
-
|
261
|
-
== Note
|
262
|
-
|
263
|
-
* 現状、このReadme含めてドキュメントは殆ど更新出来ていません。
|
264
|
-
|
265
|
-
== REQUIREMENTS
|
266
|
-
|
267
|
-
=== Ruby
|
268
|
-
|
269
|
-
* Ruby 1.9.2 and later (tested 1.9.2, 1.9.3)
|
270
|
-
|
271
|
-
== INSTALL
|
272
|
-
|
273
|
-
* sudo gem install striuct
|
274
|
-
|
275
|
-
== LICENSE
|
276
|
-
|
277
|
-
(The MIT License)
|
278
|
-
|
279
|
-
Copyright (c) 2011 Kenichi Kamiya
|
280
|
-
|
281
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
282
|
-
a copy of this software and associated documentation files (the
|
283
|
-
'Software'), to deal in the Software without restriction, including
|
284
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
285
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
286
|
-
permit persons to whom the Software is furnished to do so, subject to
|
287
|
-
the following conditions:
|
288
|
-
|
289
|
-
The above copyright notice and this permission notice shall be
|
290
|
-
included in all copies or substantial portions of the Software.
|
291
|
-
|
292
|
-
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
293
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
294
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
295
|
-
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
296
|
-
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
297
|
-
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
298
|
-
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/example/example.old.rdoc
DELETED
@@ -1,188 +0,0 @@
|
|
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}
|
@@ -1,22 +0,0 @@
|
|
1
|
-
require_relative 'named'
|
2
|
-
require_relative 'enum'
|
3
|
-
|
4
|
-
class Striuct; module ClassMethods
|
5
|
-
|
6
|
-
# @group Like Ruby's Hash
|
7
|
-
|
8
|
-
alias_method :keys, :autonyms
|
9
|
-
alias_method :has_key?, :has_member?
|
10
|
-
alias_method :key?, :has_key?
|
11
|
-
alias_method :each_key, :each_autonym
|
12
|
-
|
13
|
-
# @endgroup
|
14
|
-
|
15
|
-
|
16
|
-
# @group Like Ruby's Hash +
|
17
|
-
|
18
|
-
alias_method :each_key_with_index, :each_autonym_with_index
|
19
|
-
|
20
|
-
# @endgroup
|
21
|
-
|
22
|
-
end; end
|
@@ -1,126 +0,0 @@
|
|
1
|
-
class Striuct; module ClassMethods
|
2
|
-
|
3
|
-
# @group Named
|
4
|
-
|
5
|
-
# @return [Array<Symbol>]
|
6
|
-
def autonyms
|
7
|
-
@autonyms.dup
|
8
|
-
end
|
9
|
-
|
10
|
-
alias_method :names, :autonyms
|
11
|
-
alias_method :members, :autonyms
|
12
|
-
|
13
|
-
# @return [Array<Symbol>]
|
14
|
-
def all_members
|
15
|
-
@autonyms + @aliases.keys
|
16
|
-
end
|
17
|
-
|
18
|
-
def has_member?(name)
|
19
|
-
autonym_for_name name
|
20
|
-
rescue Exception
|
21
|
-
false
|
22
|
-
else
|
23
|
-
true
|
24
|
-
end
|
25
|
-
|
26
|
-
alias_method :member?, :has_member?
|
27
|
-
|
28
|
-
# @param [Symbol, String, #to_sym] name - autonym / aliased
|
29
|
-
# @return [Symbol]
|
30
|
-
def autonym_for_name(name)
|
31
|
-
name = _nameable_for name
|
32
|
-
|
33
|
-
return name if @autonyms.include? name
|
34
|
-
|
35
|
-
unless @aliases.has_key? name
|
36
|
-
raise NameError, "not defined member for #{name}"
|
37
|
-
end
|
38
|
-
|
39
|
-
@aliases.fetch name
|
40
|
-
end
|
41
|
-
|
42
|
-
alias_method :autonym_for, :autonym_for_name # todo modify to autonym_for_key
|
43
|
-
|
44
|
-
# @param [Symbol, String, Fixnum] key - autonym / aliased / index
|
45
|
-
# @return [Symbol] autonym
|
46
|
-
def autonym_for_key(key)
|
47
|
-
case key
|
48
|
-
when Symbol, String
|
49
|
-
name = _nameable_for key
|
50
|
-
if member? name
|
51
|
-
return autonym_for_name(name)
|
52
|
-
else
|
53
|
-
raise NameError
|
54
|
-
end
|
55
|
-
when Fixnum
|
56
|
-
if autonym = _autonyms[key]
|
57
|
-
return autonym
|
58
|
-
else
|
59
|
-
raise IndexError
|
60
|
-
end
|
61
|
-
else
|
62
|
-
raise ArgumentError
|
63
|
-
end
|
64
|
-
|
65
|
-
raise 'must not happen'
|
66
|
-
end
|
67
|
-
|
68
|
-
# @param [Symbol, String] name
|
69
|
-
def has_autonym?(name)
|
70
|
-
name = _nameable_for name
|
71
|
-
raise NameError unless member? name
|
72
|
-
|
73
|
-
@autonyms.include? name
|
74
|
-
end
|
75
|
-
|
76
|
-
alias_method :autonym?, :has_autonym?
|
77
|
-
alias_method :original?, :has_autonym? # obsolute
|
78
|
-
|
79
|
-
# @param [Symbol, String] name
|
80
|
-
def has_alias?(name)
|
81
|
-
name = _nameable_for name
|
82
|
-
raise NameError unless member? name
|
83
|
-
|
84
|
-
@aliases.has_key? name
|
85
|
-
end
|
86
|
-
|
87
|
-
alias_method :alias?, :has_alias?
|
88
|
-
alias_method :aliased?, :has_alias? # obsolute
|
89
|
-
|
90
|
-
# @param [Symbol, String] autonym
|
91
|
-
def has_aliases?(autonym)
|
92
|
-
raise NameError unless autonym? autonym
|
93
|
-
|
94
|
-
@aliases.has_value? autonym
|
95
|
-
end
|
96
|
-
|
97
|
-
# @param [Symbol, String] autonym
|
98
|
-
# @return [Array<Symbol>]
|
99
|
-
def aliases_for(autonym)
|
100
|
-
autonym = _nameable_for autonym
|
101
|
-
raise NameError unless has_aliases? autonym
|
102
|
-
|
103
|
-
@aliases.group_by{|aliased, an|an}.fetch(autonym)
|
104
|
-
end
|
105
|
-
|
106
|
-
# @return [Hash] alias => autonym
|
107
|
-
def aliases
|
108
|
-
@aliases.dup
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
|
113
|
-
# @param [Symbol, String, #to_sym] name
|
114
|
-
# @return [Symbol]
|
115
|
-
def _nameable_for(name)
|
116
|
-
name.to_sym
|
117
|
-
end
|
118
|
-
|
119
|
-
# for access from own instance
|
120
|
-
def _autonyms
|
121
|
-
@autonyms
|
122
|
-
end
|
123
|
-
|
124
|
-
# @endgroup
|
125
|
-
|
126
|
-
end; end
|
data/lib/striuct/classmethods.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require_relative 'classmethods/requiremnets'
|
@@ -1,53 +0,0 @@
|
|
1
|
-
class Striuct; module InstanceMethods
|
2
|
-
|
3
|
-
# @group These Accessor API using only inner
|
4
|
-
|
5
|
-
private
|
6
|
-
|
7
|
-
def _get(name)
|
8
|
-
autonym = autonym_for_name name
|
9
|
-
value = @db[autonym]
|
10
|
-
|
11
|
-
if safety_getter?(autonym) and !accept?(autonym, value)
|
12
|
-
raise ::Validation::InvalidReadingError,
|
13
|
-
"#{value.inspect} is deficient for #{name} in #{self.class}"
|
14
|
-
end
|
15
|
-
|
16
|
-
value
|
17
|
-
end
|
18
|
-
|
19
|
-
def _set(name, value)
|
20
|
-
raise "can't modify frozen #{self.class}" if frozen?
|
21
|
-
autonym = autonym_for_name name
|
22
|
-
raise "can't modify locked member #{name}" if lock? autonym
|
23
|
-
|
24
|
-
if has_adjuster? autonym
|
25
|
-
begin
|
26
|
-
value = instance_exec value, &adjuster_for(autonym)
|
27
|
-
rescue Exception
|
28
|
-
raise ::Validation::UnmanagebleError
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
if safety_setter?(autonym) and !accept?(autonym, value)
|
33
|
-
raise ::Validation::InvalidWritingError,
|
34
|
-
"#{value.inspect} is deficient for #{name} in #{self.class}"
|
35
|
-
end
|
36
|
-
|
37
|
-
if inference? autonym
|
38
|
-
self.class.__send__ :_found_family!, self, autonym, value
|
39
|
-
end
|
40
|
-
|
41
|
-
@db[autonym] = value
|
42
|
-
rescue ::Validation::InvalidError
|
43
|
-
unless /in \[\]=/ =~ caller[1].slice(/([^:]+)\z/)
|
44
|
-
$!.backtrace.delete_if{|s|/#{Regexp.escape(File.dirname __FILE__)}/ =~ s}
|
45
|
-
$!.backtrace.first.sub!(/([^:]+)\z/){"in `#{name}='"}
|
46
|
-
end
|
47
|
-
|
48
|
-
raise
|
49
|
-
end
|
50
|
-
|
51
|
-
# @endgroup
|
52
|
-
|
53
|
-
end; end
|