striuct 0.1.7 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/History.rdoc +43 -1
  2. data/LICENSE +22 -0
  3. data/Manifest.txt +21 -17
  4. data/{README.ja.rdoc → README.ja.old.rdoc} +11 -16
  5. data/README.rdoc +36 -250
  6. data/Rakefile +2 -2
  7. data/example/example.old.rdoc +188 -0
  8. data/example/example.rb +11 -219
  9. data/example/example1.rb +234 -0
  10. data/example/example2.rb +22 -0
  11. data/lib/striuct/abstract.rb +7 -7
  12. data/lib/striuct/conditions.rb +110 -69
  13. data/lib/striuct/{subclassable → containable}/basic.rb +9 -9
  14. data/lib/striuct/containable/classutil.rb +22 -0
  15. data/lib/striuct/{subclassable → containable}/eigen/basic.rb +9 -1
  16. data/lib/striuct/{subclassable → containable}/eigen/constructor.rb +1 -1
  17. data/lib/striuct/{subclassable → containable}/eigen/handy.rb +38 -5
  18. data/lib/striuct/{subclassable → containable}/eigen/inner.rb +22 -28
  19. data/lib/striuct/{subclassable → containable}/eigen/macro.rb +34 -25
  20. data/lib/striuct/{subclassable → containable}/eigen/safety.rb +15 -19
  21. data/lib/striuct/{subclassable/eigen/frame.rb → containable/eigen.rb} +10 -14
  22. data/lib/striuct/containable/handy.rb +91 -0
  23. data/lib/striuct/{subclassable → containable}/hashlike.rb +1 -1
  24. data/lib/striuct/{subclassable → containable}/inner.rb +23 -11
  25. data/lib/striuct/{subclassable → containable}/safety.rb +24 -5
  26. data/lib/striuct/{subclassable → containable}/yaml.rb +1 -1
  27. data/lib/striuct/containable.rb +39 -0
  28. data/lib/striuct/flavors.rb +83 -0
  29. data/lib/striuct/version.rb +2 -2
  30. data/lib/striuct.rb +13 -2
  31. data/test/test_striuct.rb +194 -17
  32. metadata +43 -35
  33. data/lib/striuct/frame.rb +0 -8
  34. data/lib/striuct/subclassable/classutil.rb +0 -26
  35. data/lib/striuct/subclassable/frame.rb +0 -33
  36. 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
- #/usr/bin/ruby -w
1
+ $VERBOSE = true
2
2
 
3
- require_relative '../lib/striuct'
3
+ require '../lib/striuct'
4
4
 
5
- def debug(message)
6
- puts "line: #{caller.first.slice(/:(\w+)/, 1)}"
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
- # 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, 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
- debug Sth1.new.respond_to?(:my_special_method)
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
@@ -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
@@ -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
@@ -1,4 +1,4 @@
1
- require_relative 'subclassable/frame'
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 Subclassable if ::Striuct.equal? eigen
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