striuct 0.0.11.1 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ require_relative 'subclassable/frame'
2
+
3
+ class Striuct; class << self
4
+ # @group Constructor
5
+
6
+ alias_method :new_instance, :new
7
+ private :new_instance
8
+
9
+ # @param [Symbol, String] *names
10
+ # @return [Class] - with Subclass, Subclass:Eigen
11
+ def new(*names, &block)
12
+ # warning for Ruby's Struct.new user
13
+ first = names.first
14
+ if first.instance_of?(String) and /\A[A-Z]/ =~ first
15
+ warn "no define constant #{first}"
16
+ end
17
+
18
+ Class.new self do
19
+ names.each do |name|
20
+ member name
21
+ end
22
+
23
+ class_eval(&block) if block_given?
24
+ end
25
+ end
26
+
27
+ # @yieldreturn [Class] (see Striuct.new) - reject floating class
28
+ # @return [void]
29
+ def define(&block)
30
+ raise ArgumentError, 'must with block' unless block_given?
31
+
32
+ new(&block).tap do |subclass|
33
+ subclass.instance_eval do
34
+ raise 'not yet finished' if members.empty?
35
+ close
36
+ end
37
+ end
38
+ end
39
+
40
+ # @groupend
41
+
42
+ private
43
+
44
+ alias_method :original_inherited, :inherited
45
+
46
+ def inherited(subclass)
47
+ attributes = (
48
+ if equal? ::Striuct
49
+ [[], {}, {}, {}, {}, {}, :prevent]
50
+ else
51
+ [*[@names, @conditions, @flavors, @defaults,\
52
+ @inferences, @aliases].map(&:dup), @protect_level]
53
+ end
54
+ )
55
+
56
+ eigen = self
57
+
58
+ subclass.class_eval do
59
+ original_inherited subclass
60
+ include Subclassable if ::Striuct.equal? eigen
61
+
62
+ @names, @conditions, @flavors, @defaults,\
63
+ @inferences, @aliases, @protect_level = *attributes
64
+
65
+ singleton_class.instance_eval do
66
+ define_method :initialize_copy do |original|
67
+ @names, @flavors, @defaults, @aliases =
68
+ *[@names, @flavors, @defaults, @aliases].map(&:dup)
69
+ @conditions, @inferences = @conditions.dup, @inferences.dup
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end; end
@@ -0,0 +1,228 @@
1
+ class Striuct
2
+
3
+ # Useful Condition Patterns
4
+ module Conditions
5
+ 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
15
+ end
16
+
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
25
+
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
35
+ else
36
+ condition === value
37
+ end ? true : false
38
+ end
39
+
40
+ # @return [lambda]
41
+ def NOT(condition)
42
+ unless conditionable? condition
43
+ raise TypeError, 'wrong object for condition'
44
+ end
45
+
46
+ ->v{! self.class.__send__(:pass?, v, condition, self)}
47
+ end
48
+
49
+ # @return [lambda]
50
+ def _logical_operator(delegated, *conditions)
51
+ unless conditions.all?{|c|conditionable? c}
52
+ raise TypeError, 'wrong object for condition'
53
+ end
54
+
55
+ ->v{
56
+ conditions.__send__(delegated) {|condition|
57
+ self.class.__send__(:pass?, v, condition, self)
58
+ }
59
+ }
60
+ end
61
+
62
+ # @return [lambda] check "match all conditions"
63
+ def AND(cond1, cond2, *conds)
64
+ _logical_operator :all?, cond1, cond2, *conds
65
+ end
66
+
67
+ alias_method :ALL, :AND
68
+ module_function :ALL
69
+
70
+ # @return [lambda]
71
+ def NAND(cond1, cond2, *conds)
72
+ ! AND(cond1, cond2, *conds)
73
+ end
74
+
75
+ # @return [lambda] check "match any condition"
76
+ def OR(cond1, cond2, *conds)
77
+ _logical_operator :any?, cond1, cond2, *conds
78
+ end
79
+
80
+ alias_method :ANY, :OR
81
+ module_function :ANY
82
+
83
+ # @return [lambda]
84
+ def NOR(cond1, cond2, *conds)
85
+ ! OR(cond1, cond2, *conds)
86
+ end
87
+
88
+ # @return [lambda]
89
+ def XOR(cond1, cond2, *conds)
90
+ _logical_operator :one?, cond1, cond2, *conds
91
+ end
92
+
93
+ alias_method :ONE, :XOR
94
+ module_function :ONE
95
+
96
+ # @return [lambda]
97
+ def XNOR(cond1, cond2, *conds)
98
+ ! XOR(cond1, cond2, *conds)
99
+ end
100
+
101
+ # @return [lambda] use #==
102
+ def EQUAL(obj)
103
+ ->v{obj == v}
104
+ end
105
+
106
+ # @return [lambda] use #equal?
107
+ def SAME(obj)
108
+ ->v{obj.equal? v}
109
+ end
110
+
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'
116
+ end
117
+
118
+ ->v{
119
+ names.all?{|name|v.respond_to? name}
120
+ }
121
+ end
122
+
123
+ alias_method :CAN, :RESPONSIBLE
124
+ alias_method :RESPOND_TO, :RESPONSIBLE
125
+ alias_method :responsible, :RESPONSIBLE
126
+ module_function :CAN, :responsible, :RESPOND_TO
127
+
128
+ # @return [lambda] true when faced no exceptions in checking all conditions
129
+ def NO_RAISES(condition1, *conditions)
130
+ conditions = [condition1, *conditions]
131
+ unless conditions.all?{|c|conditionable? c}
132
+ raise TypeError, 'wrong object for condition'
133
+ end
134
+
135
+ ->v{
136
+ conditions.all?{|condition|
137
+ begin
138
+ self.class.__send__(:pass?, v, condition, self)
139
+ rescue Exception
140
+ false
141
+ else
142
+ true
143
+ end
144
+ }
145
+ }
146
+ end
147
+
148
+ alias_method :STILL, :NO_RAISES
149
+ module_function :STILL
150
+
151
+ # @return [lambda] true when catch the exception
152
+ def CATCH(exception=Exception, &condition)
153
+ raise ArgumentError unless conditionable? condition
154
+ raise TypeError unless exception.ancestors.include? Exception
155
+
156
+ ->v{
157
+ begin
158
+ self.class.__send__(:pass?, v, condition, self)
159
+ rescue exception
160
+ true
161
+ rescue Exception
162
+ false
163
+ else
164
+ false
165
+ end
166
+ }
167
+ end
168
+
169
+ alias_method :RESCUE, :CATCH
170
+ module_function :RESCUE
171
+
172
+ # @return [lambda] check "all included objects match any conditions"
173
+ def GENERICS(condition1, *conditions)
174
+ conditions = [condition1, *conditions]
175
+ unless conditions.all?{|c|conditionable? c}
176
+ raise TypeError, 'wrong object for condition'
177
+ end
178
+
179
+ ->list{
180
+ conditions.all?{|condition|
181
+ (list.respond_to?(:each_value) ? list.each_value : list.each).all?{|v|
182
+ self.class.__send__(:pass?, v, condition, self)
183
+ }
184
+ }
185
+ }
186
+ end
187
+
188
+ alias_method :generics, :GENERICS
189
+ module_function :generics
190
+
191
+ # @return [lambda]
192
+ def MEMBER_OF(list1, *lists)
193
+ lists = [list1, *lists]
194
+ unless lists.all?{|l|l.respond_to? :all?}
195
+ raise TypeError, 'list must respond #all?'
196
+ end
197
+
198
+ ->v{
199
+ lists.all?{|list|list.include? v}
200
+ }
201
+ end
202
+
203
+ alias_method :member_of, :MEMBER_OF
204
+ module_function :member_of
205
+
206
+ BOOLEAN = OR(SAME(true), SAME(false))
207
+
208
+ # @return [BOOLEAN] "true or false"
209
+ def boolean
210
+ BOOLEAN
211
+ end
212
+
213
+ alias_method :bool, :boolean
214
+ module_function :bool
215
+
216
+ STRINGABLE = OR(String, Symbol, CAN(:to_str), CAN(:to_sym))
217
+
218
+ # @return [STRINGABLE] check "looks string family"
219
+ def stringable
220
+ STRINGABLE
221
+ end
222
+
223
+ class << self
224
+ private :_logical_operator
225
+ end
226
+ end
227
+
228
+ end
@@ -0,0 +1,8 @@
1
+ # @author Kenichi Kamiya
2
+ # @abstract
3
+ class Striuct
4
+ class ConditionError < ArgumentError; end
5
+ end
6
+
7
+ require_relative 'version'
8
+ require_relative 'abstract'
@@ -0,0 +1,135 @@
1
+ class Striuct; module Subclassable
2
+ # @group Basic
3
+
4
+ def initialize(*values)
5
+ @db, @locks = {}, {}
6
+ replace_values(*values)
7
+ end
8
+
9
+ # see self.class.*args
10
+ delegate_class_methods(
11
+ :members, :keys, :names,
12
+ :has_member?, :member?, :has_key?, :key?,
13
+ :length, :size
14
+ )
15
+
16
+ # @return [Boolean]
17
+ def ==(other)
18
+ __compare_all__ other, :==
19
+ end
20
+
21
+ alias_method :===, :==
22
+
23
+ def eql?(other)
24
+ __compare_all__ other, :eql?
25
+ end
26
+
27
+ # @return [Integer]
28
+ def hash
29
+ @db.hash
30
+ end
31
+
32
+ # @return [String]
33
+ def inspect
34
+ "#<#{self.class} (StrictStruct)".tap do |s|
35
+ each_pair do |name, value|
36
+ suffix = (has_default?(name) && default?(name)) ? '(default)' : nil
37
+ s << " #{name}=#{value.inspect}#{suffix}"
38
+ end
39
+
40
+ s << ">"
41
+ end
42
+ end
43
+
44
+ # @return [String]
45
+ def to_s
46
+ "#<struct #{self.class}".tap do |s|
47
+ each_pair do |name, value|
48
+ s << " #{name}=#{value.inspect}"
49
+ end
50
+
51
+ s << '>'
52
+ end
53
+ end
54
+
55
+ # @param [Symbol, String, Fixnum] key
56
+ def [](key)
57
+ __subscript__(key){|name|__get__ name}
58
+ end
59
+
60
+ # @param [Symbol, String, Fixnum] key
61
+ # @param [Object] value
62
+ # @return [value]
63
+ def []=(key, value)
64
+ true_name = nil
65
+ __subscript__(key){|name|true_name = name; __set__ name, value}
66
+ rescue ConditionError
67
+ $@ = [
68
+ "#{$@[-1].sub(/[^:]+\z/){''}}in `[#{key}(#{true_name})]=': #{$!.message}",
69
+ $@[-1]
70
+ ]
71
+
72
+ raise
73
+ end
74
+
75
+ alias_method :assign, :[]
76
+
77
+ # @yield [value]
78
+ # @yieldparam [Object] value - sequential under defined
79
+ # @see #each_name
80
+ # @yieldreturn [self]
81
+ # @return [Enumerator]
82
+ def each_value
83
+ return to_enum(__method__) unless block_given?
84
+ each_member{|member|yield self[member]}
85
+ end
86
+
87
+ alias_method :each, :each_value
88
+
89
+ # @yield [name, value]
90
+ # @yieldparam [Symbol] name
91
+ # @yieldparam [Object] value
92
+ # @yieldreturn [self]
93
+ # @return [Enumerator]
94
+ # @see #each_name
95
+ # @see #each_value
96
+ def each_pair
97
+ return to_enum(__method__) unless block_given?
98
+ each_name{|name|yield name, self[name]}
99
+ end
100
+
101
+ # @return [Array]
102
+ def values
103
+ each_value.to_a
104
+ end
105
+
106
+ alias_method :to_a, :values
107
+
108
+ # @param [Fixnum, Range] *keys
109
+ # @return [Array]
110
+ def values_at(*keys)
111
+ [].tap {|r|
112
+ keys.each do |key|
113
+ case key
114
+ when Fixnum
115
+ r << self[key]
116
+ when Range
117
+ key.each do |n|
118
+ raise TypeError unless n.instance_of? Fixnum
119
+ r << self[n]
120
+ end
121
+ else
122
+ raise TypeError
123
+ end
124
+ end
125
+ }
126
+ end
127
+
128
+ # @return [self]
129
+ def freeze
130
+ [@db, @locks].each(&:freeze)
131
+ super
132
+ end
133
+
134
+ # @endgroup
135
+ end; end
@@ -1,4 +1,4 @@
1
- class Striuct
1
+ class Striuct; module Subclassable
2
2
 
3
3
 
4
4
  # @author Kenichi Kamiya
@@ -6,16 +6,16 @@ module ClassUtil
6
6
 
7
7
  private
8
8
 
9
- # @macro delegate_class_method
10
9
  def delegate_class_method(name)
11
10
  define_method name do |*args, &block|
12
11
  self.class.__send__ name, *args, &block
13
12
  end
14
13
  end
15
14
 
16
- # @macro delegate_class_methods
17
15
  def delegate_class_methods(*names)
18
- raise ArgumentError, 'wrong number of argument 0 for 1+' unless names.length >= 1
16
+ unless names.length >= 1
17
+ raise ArgumentError, 'wrong number of argument 0 for 1+'
18
+ end
19
19
 
20
20
  names.each{|name|delegate_class_method name}
21
21
  end
@@ -23,4 +23,4 @@ module ClassUtil
23
23
  end
24
24
 
25
25
 
26
- end
26
+ end; end
@@ -0,0 +1,38 @@
1
+ class Striuct; module Subclassable; module Eigen
2
+ # @group Basic
3
+
4
+ # @return [Array<Symbol>]
5
+ def names
6
+ @names.dup
7
+ end
8
+
9
+ alias_method :members, :names
10
+ alias_method :keys, :names
11
+
12
+ def has_member?(name)
13
+ originalkey_for(keyable_for name)
14
+ rescue Exception
15
+ false
16
+ else
17
+ true
18
+ end
19
+
20
+ alias_method :member?, :has_member?
21
+ alias_method :has_key?, :has_member?
22
+ alias_method :key?, :has_key?
23
+
24
+ # @return [Integer]
25
+ def length
26
+ @names.length
27
+ end
28
+
29
+ alias_method :size, :length
30
+
31
+ # @return [self]
32
+ def freeze
33
+ __stores__.each(&:freeze)
34
+ super
35
+ end
36
+
37
+ # @endgroup
38
+ end; end; end
@@ -0,0 +1,58 @@
1
+ class Striuct; module Subclassable; module Eigen
2
+ # @group Constructor
3
+
4
+ # @return [Subclass]
5
+ def load_values(*values)
6
+ new_instance(*values)
7
+ end
8
+
9
+ alias_method :new, :load_values
10
+
11
+ # @param [#each_pair, #keys] pairs ex: Hash, Struct
12
+ # @return [Subclass]
13
+ def load_pairs(pairs)
14
+ unless pairs.respond_to?(:each_pair) and pairs.respond_to?(:keys)
15
+ raise TypeError, 'no pairs object'
16
+ end
17
+
18
+ raise ArgumentError, "different members" unless (pairs.keys - keys).empty?
19
+
20
+ new.tap {|instance|
21
+ pairs.each_pair do |name, value|
22
+ instance[name] = value
23
+ end
24
+ }
25
+ end
26
+
27
+ alias_method :[], :load_pairs
28
+
29
+ # @yieldparam [Subclass] instance
30
+ # @yieldreturn [Subclass] instance
31
+ # @return [void]
32
+ # for build the fixed object
33
+ def define(options={lock: true, strict: true})
34
+ raise TypeError, 'arguments have to be pairs object' unless options.respond_to? :keys
35
+ raise ArgumentError, 'Unknown parameters' unless (options.keys - [:lock, :strict]).empty?
36
+ raise ArgumentError, 'must with block' unless block_given?
37
+
38
+ lock, strict = options[:lock], options[:strict]
39
+
40
+ new.tap {|instance|
41
+ yield instance
42
+
43
+ unless (yets = each_name.select{|name|! instance.assign?(name)}).empty?
44
+ raise "not assigned members are, yet '#{yets.inspect} in #{self}'"
45
+ end
46
+
47
+ if strict &&
48
+ ! (invalids = each_name.select{|name|! instance.valid?(name)}).empty?
49
+
50
+ raise ConditionError, "invalids members are, yet '#{invalids.inspect} in #{self}'"
51
+ end
52
+
53
+ instance.lock if lock
54
+ }
55
+ end
56
+
57
+ # @endgroup
58
+ end; end; end
@@ -0,0 +1,39 @@
1
+ require_relative '../../conditions'
2
+
3
+ class Striuct; module Subclassable
4
+
5
+ # @author Kenichi Kamiya
6
+ module Eigen
7
+ include Conditions
8
+
9
+ NAMING_RISKS = {
10
+ conflict: 10,
11
+ no_identifier: 9,
12
+ bad_manners: 5,
13
+ no_ascii: 3,
14
+ strict: 0
15
+ }.freeze
16
+
17
+ PROTECT_LEVELS = {
18
+ struct: {error: 99, warn: 99},
19
+ warning: {error: 99, warn: 5},
20
+ error: {error: 9, warn: 5},
21
+ prevent: {error: 5, warn: 1},
22
+ nervous: {error: 1, warn: 1}
23
+ }.each(&:freeze).freeze
24
+
25
+ INFERENCE = Object.new.freeze
26
+
27
+ if respond_to? :private_constant
28
+ private_constant :INFERENCE
29
+ end
30
+ end
31
+
32
+ end; end
33
+
34
+ require_relative 'basic'
35
+ require_relative 'constructor'
36
+ require_relative 'safety'
37
+ require_relative 'handy'
38
+ require_relative 'macro'
39
+ require_relative 'inner'
@@ -0,0 +1,92 @@
1
+ class Striuct; module Subclassable; module Eigen
2
+ # @group Struct+ Handy
3
+
4
+ # @yield [name]
5
+ # @yieldparam [Symbol] name - sequential under defined
6
+ # @yieldreturn [self]
7
+ # @return [Enumerator]
8
+ def each_name(&block)
9
+ return to_enum(__method__) unless block_given?
10
+ _names.each(&block)
11
+ self
12
+ end
13
+
14
+ alias_method :each_member, :each_name
15
+ alias_method :each_key, :each_name
16
+
17
+ # @yield [index]
18
+ # @yieldparam [Integer] Index
19
+ # @yieldreturn [self]
20
+ # @return [Enumerator]
21
+ def each_index(&block)
22
+ return to_enum(__method__) unless block_given?
23
+ _names.each_index(&block)
24
+ self
25
+ end
26
+
27
+ # @param [Symbol, String] name
28
+ def original?(name)
29
+ if member? name
30
+ @names.include? name
31
+ else
32
+ raise NameError
33
+ end
34
+ end
35
+
36
+ # @param [Symbol, String] name
37
+ def aliased?(name)
38
+ if member? name
39
+ @aliases.has_key? name
40
+ else
41
+ raise NameError
42
+ end
43
+ end
44
+
45
+ # @param [Symbol, String] original
46
+ def has_aliases?(original)
47
+ if original? original
48
+ @aliases.has_value? original
49
+ else
50
+ raise NameError
51
+ end
52
+ end
53
+
54
+ # @param [Symbol, String] original
55
+ # @return [Array<Symbol>]
56
+ def aliases_for(original)
57
+ original = keyable_for original
58
+
59
+ if has_aliases? original
60
+ _aliases_for original
61
+ else
62
+ raise NameError
63
+ end
64
+ end
65
+
66
+ # @param [Symbol, String] name
67
+ def has_flavor?(name)
68
+ name = originalkey_for(keyable_for name)
69
+
70
+ ! flavor_for(name).nil?
71
+ end
72
+
73
+ # @param [Symbol, String] name
74
+ def has_default?(name)
75
+ name = originalkey_for(keyable_for name)
76
+
77
+ @defaults.has_key? name
78
+ end
79
+
80
+ # @param [Symbol, String] name
81
+ def default_for(name)
82
+ name = originalkey_for(keyable_for name)
83
+
84
+ if has_default? name
85
+ _default_for name
86
+ else
87
+ raise "#{name} has no default value"
88
+ end
89
+ end
90
+
91
+ # @endgroup
92
+ end; end; end