striuct 0.3.3 → 0.3.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +35 -34
- data/.travis.yml +6 -6
- data/Gemfile +12 -12
- data/History.rdoc +279 -273
- data/LICENSE +21 -21
- data/Manifest.txt +91 -90
- data/README.ja.old.rdoc +297 -297
- data/README.md +128 -128
- data/Rakefile +11 -11
- data/benchmark/basics.rb +56 -56
- data/example/README.rb +44 -44
- data/example/example.old.rdoc +187 -187
- data/example/example1.rb +233 -233
- data/example/example2.rb +22 -22
- data/example/see_trace.rb +32 -32
- data/lib/striuct/classmethods/README.md +5 -5
- data/lib/striuct/classmethods/adjustment.rb +32 -32
- data/lib/striuct/classmethods/constructor.rb +63 -63
- data/lib/striuct/classmethods/default.rb +27 -27
- data/lib/striuct/classmethods/enum.rb +48 -48
- data/lib/striuct/classmethods/inner.rb +91 -91
- data/lib/striuct/classmethods/length.rb +14 -14
- data/lib/striuct/classmethods/macro.rb +144 -144
- data/lib/striuct/classmethods/named.rb +113 -113
- data/lib/striuct/classmethods/object.rb +54 -54
- data/lib/striuct/classmethods/prevent_conflicts.rb +89 -89
- data/lib/striuct/classmethods/requiremnets.rb +11 -11
- data/lib/striuct/classmethods/to_struct.rb +23 -25
- data/lib/striuct/classmethods/validation.rb +55 -55
- data/lib/striuct/classmethods.rb +1 -1
- data/lib/striuct/instancemethods/README.md +5 -5
- data/lib/striuct/instancemethods/assign.rb +30 -30
- data/lib/striuct/instancemethods/cast.rb +34 -34
- data/lib/striuct/instancemethods/compare.rb +30 -30
- data/lib/striuct/instancemethods/default.rb +13 -13
- data/lib/striuct/instancemethods/delegate_class_methods.rb +28 -28
- data/lib/striuct/instancemethods/enum.rb +103 -103
- data/lib/striuct/instancemethods/hashy.rb +121 -121
- data/lib/striuct/instancemethods/inner.rb +60 -60
- data/lib/striuct/instancemethods/keyvalidatable.rb +14 -14
- data/lib/striuct/instancemethods/lock.rb +61 -61
- data/lib/striuct/instancemethods/object.rb +52 -52
- data/lib/striuct/instancemethods/requirements.rb +14 -14
- data/lib/striuct/instancemethods/safety.rb +11 -11
- data/lib/striuct/instancemethods/subscript.rb +55 -55
- data/lib/striuct/instancemethods/validation.rb +29 -25
- data/lib/striuct/instancemethods/values.rb +57 -57
- data/lib/striuct/instancemethods.rb +1 -1
- data/lib/striuct/requirements.rb +5 -5
- data/lib/striuct/singleton_class.rb +66 -66
- data/lib/striuct/specificcontainer.rb +19 -19
- data/lib/striuct/structs.rb +7 -7
- data/lib/striuct/version.rb +5 -5
- data/lib/striuct.rb +13 -13
- data/striuct.gemspec +24 -24
- data/test/helper.rb +5 -5
- data/test/test_striuct-singleton_class-define.rb +19 -19
- data/test/test_striuct-subclass-class-cloning.rb +20 -20
- data/test/test_striuct-subclass-class-close.rb +36 -36
- data/test/test_striuct-subclass-class-constructor.rb +82 -82
- data/test/test_striuct-subclass-class-freeze.rb +36 -36
- data/test/test_striuct-subclass-class-inheritable.rb +57 -57
- data/test/test_striuct-subclass-class-macro.rb +13 -13
- data/test/test_striuct-subclass-class-safety_naming.rb +72 -72
- data/test/test_striuct-subclass-class-validation.rb +26 -26
- data/test/test_striuct-subclass-feature-alias_member.rb +53 -53
- data/test/test_striuct-subclass-feature-to_struct.rb +61 -25
- data/test/test_striuct-subclass-feature-validation_util.rb +57 -0
- data/test/test_striuct-subclass-instance-accessor.rb +137 -137
- data/test/test_striuct-subclass-instance-adjuster.rb +94 -94
- data/test/test_striuct-subclass-instance-assign.rb +30 -30
- data/test/test_striuct-subclass-instance-basic.rb +32 -32
- data/test/test_striuct-subclass-instance-cloning.rb +22 -22
- data/test/test_striuct-subclass-instance-compare.rb +51 -51
- data/test/test_striuct-subclass-instance-default_value.rb +128 -128
- data/test/test_striuct-subclass-instance-enum.rb +92 -92
- data/test/test_striuct-subclass-instance-freeze.rb +19 -19
- data/test/test_striuct-subclass-instance-hashlike.rb +153 -153
- data/test/test_striuct-subclass-instance-keyvalidatable.rb +24 -24
- data/test/test_striuct-subclass-instance-lock.rb +39 -39
- data/test/test_striuct-subclass-instance-to_s_family.rb +25 -25
- data/test/test_striuct-subclass-instance-validation_functional_condition.rb +50 -50
- data/test/test_striuct-subclass-instance-validation_inference.rb +50 -50
- data/test/test_striuct-subclass-instance-validation_specific_conditions.rb +247 -247
- data/test/test_striuct-subclass-instance-validation_with_getter.rb +33 -33
- data/test/test_striuct-subclass-instance_names.rb +18 -18
- data/test/test_striuct-version.rb +10 -10
- metadata +4 -2
data/README.ja.old.rdoc
CHANGED
@@ -1,298 +1,298 @@
|
|
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
|
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
298
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|