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.
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