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
@@ -1,51 +1,54 @@
1
1
  class Striuct
2
2
 
3
- # Useful Condition Patterns
3
+ # Condition Builders and Useful Conditions
4
+ #
5
+ # Any conditions need #pass?(arg, condition) method
6
+ # @author Kenichi Kamiya
7
+ # @example overview
8
+ # class Person < Striuct
9
+ # member :name, OR(String, Symbol, CAN(:to_str))
10
+ # member :friends, GENERICS(AND(Person, NOT(->v{equal? v})))
4
11
  module Conditions
12
+ ANYTHING = Object.new.freeze
13
+ BOOLEAN = ->v{[true, false].any?{|bool|bool.equal? v}}
14
+
5
15
  module_function
6
-
7
- # @param [Object] condition
8
- def conditionable?(condition)
9
- case condition
10
- when Proc, Method
11
- condition.arity == 1
12
- else
13
- condition.respond_to? :===
14
- end
16
+
17
+ # The getter for a special condition.
18
+ # @return [ANYTHING] A condition always pass with any objects.
19
+ def ANYTHING?
20
+ ANYTHING
15
21
  end
16
22
 
17
- # @param [Object] value
18
- # @param [Proc, Method, #===] condition
19
- # @param [self(class)] context
20
- def pass?(value, condition, context)
21
- if context && ! context.instance_of?(self)
22
- raise ArgumentError,
23
- "to change context is allowed in instance of #{self}"
24
- end
23
+ alias_method :ANYTHING, :ANYTHING?
24
+ alias_method :anything, :ANYTHING?
25
+ module_function :anything, :ANYTHING
25
26
 
26
- case condition
27
- when Proc
28
- if context
29
- context.instance_exec value, &condition
30
- else
31
- condition.call value
32
- end
33
- when Method
34
- condition.call value
27
+ # true if object is sufficient for condition.
28
+ # @param [Object] object
29
+ def conditionable?(object)
30
+ case object
31
+ when ANYTHING
32
+ true
33
+ when Proc, Method
34
+ object.arity == 1
35
35
  else
36
- condition === value
37
- end ? true : false
36
+ object.respond_to? :===
37
+ end
38
38
  end
39
-
40
- # @return [lambda]
39
+
40
+ # A condition builder.
41
+ # @return [lambda] A condition invert the original condition.
41
42
  def NOT(condition)
42
43
  unless conditionable? condition
43
44
  raise TypeError, 'wrong object for condition'
44
45
  end
45
46
 
46
- ->v{! self.class.__send__(:pass?, v, condition, self)}
47
+ ->v{! pass?(v, condition)}
47
48
  end
48
49
 
50
+ # A innner method for some condition builders.
51
+ # For build conditions AND, NAND, OR, NOR, XOR, XNOR.
49
52
  # @return [lambda]
50
53
  def _logical_operator(delegated, *conditions)
51
54
  unless conditions.all?{|c|conditionable? c}
@@ -54,37 +57,38 @@ class Striuct
54
57
 
55
58
  ->v{
56
59
  conditions.__send__(delegated) {|condition|
57
- self.class.__send__(:pass?, v, condition, self)
60
+ pass? v, condition
58
61
  }
59
62
  }
60
63
  end
61
64
 
62
- # @return [lambda] check "match all conditions"
65
+ # A condition builder.
66
+ # @return [lambda]
67
+ # this lambda return true if match all conditions
63
68
  def AND(cond1, cond2, *conds)
64
69
  _logical_operator :all?, cond1, cond2, *conds
65
70
  end
66
-
67
- alias_method :ALL, :AND
68
- module_function :ALL
69
71
 
72
+ # A condition builder.
70
73
  # @return [lambda]
71
74
  def NAND(cond1, cond2, *conds)
72
- ! AND(cond1, cond2, *conds)
75
+ NOT AND(cond1, cond2, *conds)
73
76
  end
74
77
 
75
- # @return [lambda] check "match any condition"
78
+ # A condition builder.
79
+ # @return [lambda]
80
+ # this lambda return true if match a any condition
76
81
  def OR(cond1, cond2, *conds)
77
82
  _logical_operator :any?, cond1, cond2, *conds
78
83
  end
79
84
 
80
- alias_method :ANY, :OR
81
- module_function :ANY
82
-
85
+ # A condition builder.
83
86
  # @return [lambda]
84
87
  def NOR(cond1, cond2, *conds)
85
- ! OR(cond1, cond2, *conds)
88
+ NOT OR(cond1, cond2, *conds)
86
89
  end
87
90
 
91
+ # A condition builder.
88
92
  # @return [lambda]
89
93
  def XOR(cond1, cond2, *conds)
90
94
  _logical_operator :one?, cond1, cond2, *conds
@@ -93,30 +97,40 @@ class Striuct
93
97
  alias_method :ONE, :XOR
94
98
  module_function :ONE
95
99
 
100
+ # A condition builder.
96
101
  # @return [lambda]
97
102
  def XNOR(cond1, cond2, *conds)
98
- ! XOR(cond1, cond2, *conds)
103
+ NOT XOR(cond1, cond2, *conds)
99
104
  end
100
105
 
101
- # @return [lambda] use #==
106
+ # A condition builder.
107
+ # @return [lambda]
108
+ # this lambda return true if a argment match under #== method
102
109
  def EQUAL(obj)
103
110
  ->v{obj == v}
104
111
  end
105
-
106
- # @return [lambda] use #equal?
112
+
113
+ # A condition builder.
114
+ # @return [lambda]
115
+ # this lambda return true if a argment match under #equal? method
107
116
  def SAME(obj)
108
117
  ->v{obj.equal? v}
109
118
  end
110
119
 
111
- # @return [lambda] true when respond to all method names
112
- def RESPONSIBLE(name1, *names)
113
- names = [name1, *names]
114
- unless names.all?{|s|[Symbol, String].any?{|klass|s.kind_of? klass}}
115
- raise TypeError, 'only Symbol or String for name'
120
+ # A condition builder.
121
+ # @param [Symbol, String] messages
122
+ # @return [lambda]
123
+ # this lambda return true if a argment respond to all messages
124
+ def RESPONSIBLE(message1, *messages)
125
+ messages = [message1, *messages]
126
+ unless messages.all?{|s|
127
+ [Symbol, String].any?{|klass|s.kind_of? klass}
128
+ }
129
+ raise TypeError, 'only Symbol or String for message'
116
130
  end
117
131
 
118
132
  ->v{
119
- names.all?{|name|v.respond_to? name}
133
+ messages.all?{|message|v.respond_to? message}
120
134
  }
121
135
  end
122
136
 
@@ -124,8 +138,11 @@ class Striuct
124
138
  alias_method :RESPOND_TO, :RESPONSIBLE
125
139
  alias_method :responsible, :RESPONSIBLE
126
140
  module_function :CAN, :responsible, :RESPOND_TO
127
-
128
- # @return [lambda] true when faced no exceptions in checking all conditions
141
+
142
+ # A condition builder.
143
+ # @return [lambda]
144
+ # this lambda return true
145
+ # if face no exception when a argment checking under all conditions
129
146
  def NO_RAISES(condition1, *conditions)
130
147
  conditions = [condition1, *conditions]
131
148
  unless conditions.all?{|c|conditionable? c}
@@ -135,7 +152,7 @@ class Striuct
135
152
  ->v{
136
153
  conditions.all?{|condition|
137
154
  begin
138
- self.class.__send__(:pass?, v, condition, self)
155
+ pass? v, condition
139
156
  rescue Exception
140
157
  false
141
158
  else
@@ -147,15 +164,18 @@ class Striuct
147
164
 
148
165
  alias_method :STILL, :NO_RAISES
149
166
  module_function :STILL
150
-
151
- # @return [lambda] true when catch the exception
167
+
168
+ # A condition builder.
169
+ # @return [lambda]
170
+ # this lambda return true
171
+ # if catch a kindly exception when a argment checking in a block parameter
152
172
  def CATCH(exception=Exception, &condition)
153
173
  raise ArgumentError unless conditionable? condition
154
174
  raise TypeError unless exception.ancestors.include? Exception
155
175
 
156
176
  ->v{
157
177
  begin
158
- self.class.__send__(:pass?, v, condition, self)
178
+ pass? v, condition
159
179
  rescue exception
160
180
  true
161
181
  rescue Exception
@@ -169,7 +189,10 @@ class Striuct
169
189
  alias_method :RESCUE, :CATCH
170
190
  module_function :RESCUE
171
191
 
172
- # @return [lambda] check "all included objects match any conditions"
192
+ # A condition builder.
193
+ # @return [lambda]
194
+ # this lambda return true
195
+ # if all included objects match all conditions
173
196
  def GENERICS(condition1, *conditions)
174
197
  conditions = [condition1, *conditions]
175
198
  unless conditions.all?{|c|conditionable? c}
@@ -177,9 +200,16 @@ class Striuct
177
200
  end
178
201
 
179
202
  ->list{
203
+ enum = (
204
+ (list.respond_to?(:each_value) && list.each_value) or
205
+ (list.respond_to?(:all?) && list) or
206
+ (list.respond_to?(:each) && list.each) or
207
+ return false
208
+ )
209
+
180
210
  conditions.all?{|condition|
181
- (list.respond_to?(:each_value) ? list.each_value : list.each).all?{|v|
182
- self.class.__send__(:pass?, v, condition, self)
211
+ enum.all?{|v|
212
+ pass? v, condition
183
213
  }
184
214
  }
185
215
  }
@@ -187,8 +217,11 @@ class Striuct
187
217
 
188
218
  alias_method :generics, :GENERICS
189
219
  module_function :generics
190
-
220
+
221
+ # A condition builder.
191
222
  # @return [lambda]
223
+ # this lambda return true
224
+ # if all lists including the object
192
225
  def MEMBER_OF(list1, *lists)
193
226
  lists = [list1, *lists]
194
227
  unless lists.all?{|l|l.respond_to? :all?}
@@ -202,24 +235,32 @@ class Striuct
202
235
 
203
236
  alias_method :member_of, :MEMBER_OF
204
237
  module_function :member_of
205
-
206
- BOOLEAN = OR(SAME(true), SAME(false))
207
238
 
239
+ # A getter for a useful condition.
208
240
  # @return [BOOLEAN] "true or false"
209
- def boolean
241
+ def BOOLEAN?
210
242
  BOOLEAN
211
243
  end
212
244
 
213
- alias_method :bool, :boolean
214
- module_function :bool
245
+ alias_method :boolean, :BOOLEAN?
246
+ alias_method :bool, :BOOLEAN?
247
+ alias_method :BOOLEAN, :BOOLEAN?
248
+ alias_method :BOOL, :BOOLEAN?
249
+ alias_method :BOOL?, :BOOLEAN?
250
+ module_function :boolean, :bool, :BOOLEAN, :BOOL, :BOOL?
215
251
 
216
252
  STRINGABLE = OR(String, Symbol, CAN(:to_str), CAN(:to_sym))
217
253
 
254
+ # A getter for a useful condition.
218
255
  # @return [STRINGABLE] check "looks string family"
219
- def stringable
256
+ def STRINGABLE?
220
257
  STRINGABLE
221
258
  end
222
259
 
260
+ alias_method :stringable, :STRINGABLE?
261
+ alias_method :STRINGABLE, :STRINGABLE?
262
+ module_function :stringable, :STRINGABLE
263
+
223
264
  class << self
224
265
  private :_logical_operator
225
266
  end
@@ -1,4 +1,4 @@
1
- class Striuct; module Subclassable
1
+ class Striuct; module Containable
2
2
  # @group Basic
3
3
 
4
4
  def initialize(*values)
@@ -31,25 +31,25 @@ class Striuct; module Subclassable
31
31
 
32
32
  # @return [String]
33
33
  def inspect
34
- "#<#{self.class} (StrictStruct)".tap do |s|
34
+ "#<#{self.class} (Striuct)".tap {|s|
35
35
  each_pair do |name, value|
36
36
  suffix = (has_default?(name) && default?(name)) ? '(default)' : nil
37
37
  s << " #{name}=#{value.inspect}#{suffix}"
38
38
  end
39
39
 
40
40
  s << ">"
41
- end
41
+ }
42
42
  end
43
43
 
44
44
  # @return [String]
45
45
  def to_s
46
- "#<struct #{self.class}".tap do |s|
46
+ "#<struct #{self.class}".tap {|s|
47
47
  each_pair do |name, value|
48
48
  s << " #{name}=#{value.inspect}"
49
49
  end
50
50
 
51
51
  s << '>'
52
- end
52
+ }
53
53
  end
54
54
 
55
55
  # @param [Symbol, String, Fixnum] key
@@ -65,7 +65,7 @@ class Striuct; module Subclassable
65
65
  __subscript__(key){|name|true_name = name; __set__ name, value}
66
66
  rescue ConditionError
67
67
  $@ = [
68
- "#{$@[-1].sub(/[^:]+\z/){''}}in `[#{key}(#{true_name})]=': #{$!.message}",
68
+ "#{$@[-1].sub(/[^:]+\z/){''}}in `[#{key.inspect}(#{true_name})]=': #{$!.message}",
69
69
  $@[-1]
70
70
  ]
71
71
 
@@ -107,9 +107,9 @@ class Striuct; module Subclassable
107
107
 
108
108
  # @param [Fixnum, Range] *keys
109
109
  # @return [Array]
110
- def values_at(*keys)
110
+ def values_at(*_keys)
111
111
  [].tap {|r|
112
- keys.each do |key|
112
+ _keys.each do |key|
113
113
  case key
114
114
  when Fixnum
115
115
  r << self[key]
@@ -132,4 +132,4 @@ class Striuct; module Subclassable
132
132
  end
133
133
 
134
134
  # @endgroup
135
- end; end
135
+ end; end
@@ -0,0 +1,22 @@
1
+ class Striuct; module Containable
2
+
3
+
4
+ # @author Kenichi Kamiya
5
+ module ClassUtil
6
+
7
+ private
8
+
9
+ def delegate_class_method(name)
10
+ define_method name do |*args, &block|
11
+ self.class.__send__ name, *args, &block
12
+ end
13
+ end
14
+
15
+ def delegate_class_methods(name, *names)
16
+ [name, *names].each{|_name|delegate_class_method _name}
17
+ end
18
+
19
+ end
20
+
21
+
22
+ end; end
@@ -1,4 +1,4 @@
1
- class Striuct; module Subclassable; module Eigen
1
+ class Striuct; module Containable; module Eigen
2
2
  # @group Basic
3
3
 
4
4
  # @return [Array<Symbol>]
@@ -34,5 +34,13 @@ class Striuct; module Subclassable; module Eigen
34
34
  super
35
35
  end
36
36
 
37
+ def dup
38
+ r = super
39
+ @names, @flavors, @defaults, @aliases, @setter_validations, @getter_validations =
40
+ *[@names, @flavors, @defaults, @aliases, @setter_validations, @getter_validations].map(&:dup)
41
+ @conditions, @inferences = @conditions.dup, @inferences.dup
42
+ r
43
+ end
44
+
37
45
  # @endgroup
38
46
  end; end; end
@@ -1,4 +1,4 @@
1
- class Striuct; module Subclassable; module Eigen
1
+ class Striuct; module Containable; module Eigen
2
2
  # @group Constructor
3
3
 
4
4
  # @return [Subclass]
@@ -1,13 +1,13 @@
1
- class Striuct; module Subclassable; module Eigen
1
+ class Striuct; module Containable; module Eigen
2
2
  # @group Struct+ Handy
3
3
 
4
4
  # @yield [name]
5
5
  # @yieldparam [Symbol] name - sequential under defined
6
6
  # @yieldreturn [self]
7
7
  # @return [Enumerator]
8
- def each_name(&block)
8
+ def each_name
9
9
  return to_enum(__method__) unless block_given?
10
- _names.each(&block)
10
+ _names.each{|name|yield name}
11
11
  self
12
12
  end
13
13
 
@@ -18,12 +18,26 @@ class Striuct; module Subclassable; module Eigen
18
18
  # @yieldparam [Integer] Index
19
19
  # @yieldreturn [self]
20
20
  # @return [Enumerator]
21
- def each_index(&block)
21
+ def each_index
22
22
  return to_enum(__method__) unless block_given?
23
- _names.each_index(&block)
23
+ _names.each_index{|index|yield index}
24
+ self
25
+ end
26
+
27
+ # @yield [name, index]
28
+ # @yieldparam [Symbol] name
29
+ # @yieldparam [Integer] index
30
+ # @yieldreturn [self]
31
+ # @return [Enumerator]
32
+ def each_name_with_index
33
+ return to_enum(__method__) unless block_given?
34
+ _names.each_with_index{|name, index|yield name, index}
24
35
  self
25
36
  end
26
37
 
38
+ alias_method :each_member_with_index, :each_name_with_index
39
+ alias_method :each_key_with_index, :each_name_with_index
40
+
27
41
  # @param [Symbol, String] name
28
42
  def original?(name)
29
43
  if member? name
@@ -87,6 +101,25 @@ class Striuct; module Subclassable; module Eigen
87
101
  raise "#{name} has no default value"
88
102
  end
89
103
  end
104
+
105
+ # @return [Class]
106
+ def to_struct_class
107
+ raise 'No defined members' if names.empty?
108
+
109
+ struct_klass = Struct.new(*names)
110
+
111
+ if name
112
+ tail_name = name.slice(/[^:]+\z/)
113
+ if ::Striuct::Structs.const_defined?(tail_name) &&
114
+ ((already = ::Striuct::Structs.const_get(tail_name)).members == members)
115
+ already
116
+ else
117
+ ::Striuct::Structs.const_set tail_name, struct_klass
118
+ end
119
+ else
120
+ struct_klass
121
+ end
122
+ end
90
123
 
91
124
  # @endgroup
92
125
  end; end; end
@@ -1,14 +1,6 @@
1
- class Striuct; module Subclassable; module Eigen
1
+ class Striuct; module Containable; module Eigen
2
2
  # @group Use Only Inner
3
3
 
4
- def dup
5
- r = super
6
- @names, @flavors, @defaults, @aliases =
7
- *[@names, @flavors, @defaults, @aliases].map(&:dup)
8
- @conditions, @inferences = @conditions.dup, @inferences.dup
9
- r
10
- end
11
-
12
4
  private
13
5
 
14
6
  def _names
@@ -31,6 +23,14 @@ class Striuct; module Subclassable; module Eigen
31
23
  @inferences.delete name
32
24
  end
33
25
 
26
+ def _mark_setter_validation(name)
27
+ @setter_validations[name] = true
28
+ end
29
+
30
+ def _mark_getter_validation(name)
31
+ @getter_validations[name] = true
32
+ end
33
+
34
34
  def _mark_inference(name)
35
35
  @inferences[name] = true
36
36
  end
@@ -39,8 +39,8 @@ class Striuct; module Subclassable; module Eigen
39
39
  @flavors[name] = flavor
40
40
  end
41
41
 
42
- def _set_conditions(name, conditions)
43
- @conditions[name] = conditions
42
+ def _set_condition(name, condition)
43
+ @conditions[name] = condition
44
44
  end
45
45
 
46
46
  def _set_default_value(name, value)
@@ -144,8 +144,8 @@ class Striuct; module Subclassable; module Eigen
144
144
  nil
145
145
  end
146
146
 
147
- def __setter__!(name, *conditions, &flavor)
148
- __set_conditions__! name, *conditions
147
+ def __setter__!(name, condition, &flavor)
148
+ __set_condition__! name, condition unless ANYTHING.equal? condition
149
149
  __set_flavor__! name, &flavor if block_given?
150
150
 
151
151
  define_method "#{name}=" do |value|
@@ -156,17 +156,11 @@ class Striuct; module Subclassable; module Eigen
156
156
 
157
157
  end
158
158
 
159
- def __set_conditions__!(name, *conditions)
160
- if conditions.reject!{|c|INFERENCE.equal? c}
161
- _mark_inference name
162
- end
163
-
164
- unless conditions.empty?
165
- if conditions.all?{|c|conditionable? c}
166
- _set_conditions name, conditions
167
- else
168
- raise TypeError, 'wrong object for condition'
169
- end
159
+ def __set_condition__!(name, condition)
160
+ if conditionable? condition
161
+ _set_condition name, condition
162
+ else
163
+ raise TypeError, 'wrong object for condition'
170
164
  end
171
165
 
172
166
  nil
@@ -192,19 +186,19 @@ class Striuct; module Subclassable; module Eigen
192
186
 
193
187
  raise ArgumentError unless conditionable? family
194
188
 
195
- _set_conditions name, [family]
189
+ _set_condition name, family
196
190
  _remove_inference name
197
191
 
198
192
  nil
199
193
  end
200
194
 
201
- def _conditions_for(name)
195
+ def _condition_for(name)
202
196
  @conditions[name]
203
197
  end
204
198
 
205
199
  # @param [Symbol, String] name
206
- def conditions_for(name)
207
- _conditions_for originalkey_for(keyable_for name)
200
+ def condition_for(name)
201
+ _condition_for originalkey_for(keyable_for name)
208
202
  end
209
203
 
210
204
  def _flavor_for(name)