striuct 0.0.11.1 → 0.1.7

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