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
@@ -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)