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,224 @@
1
+ class Striuct; module Subclassable; module Eigen
2
+ # @group Use Only Inner
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
+ private
13
+
14
+ def _names
15
+ @names
16
+ end
17
+
18
+ def _alias_member(aliased, original)
19
+ @aliases[aliased] = original
20
+ end
21
+
22
+ def _original_for(aliased)
23
+ @aliases[aliased]
24
+ end
25
+
26
+ def _aliases_for(original)
27
+ @aliases.group_by{|aliased, org|org}[original]
28
+ end
29
+
30
+ def _remove_inference(name)
31
+ @inferences.delete name
32
+ end
33
+
34
+ def _mark_inference(name)
35
+ @inferences[name] = true
36
+ end
37
+
38
+ def _set_flavor(name, flavor)
39
+ @flavors[name] = flavor
40
+ end
41
+
42
+ def _set_conditions(name, conditions)
43
+ @conditions[name] = conditions
44
+ end
45
+
46
+ def _set_default_value(name, value)
47
+ @defaults[name] = value
48
+ end
49
+
50
+ # @param [Symbol, String, #to_sym, #to_str] name
51
+ def originalkey_for(name)
52
+ name = keyable_for name
53
+
54
+ if _names.include? name
55
+ name
56
+ else
57
+ if original = _original_for(name)
58
+ original
59
+ else
60
+ raise NameError, "not defined member for #{name}"
61
+ end
62
+ end
63
+ end
64
+
65
+ # @param [Symbol, String, #to_sym, #to_str] name
66
+ # @return [Symbol] name(keyable)
67
+ def keyable_for(name)
68
+ return name if name.instance_of? Symbol
69
+
70
+ r = (
71
+ case name
72
+ when Symbol, String
73
+ name.to_sym
74
+ else
75
+ case
76
+ when name.respond_to?(:to_sym)
77
+ name.to_sym
78
+ when name.respond_to?(:to_str)
79
+ name.to_str.to_sym
80
+ else
81
+ raise TypeError
82
+ end
83
+ end
84
+ )
85
+
86
+ if r.instance_of? Symbol
87
+ r
88
+ else
89
+ raise 'must not happen'
90
+ end
91
+ end
92
+
93
+ # @param [Symbol] name
94
+ # @return [void]
95
+ # @yieldreturn [Boolean]
96
+ def _check_safety_naming(name)
97
+ estimation = _estimate_naming name
98
+ risk = NAMING_RISKS[estimation]
99
+ plevels = PROTECT_LEVELS[@protect_level]
100
+ caution = "undesirable naming '#{name}', because #{estimation}"
101
+
102
+ r = (
103
+ case
104
+ when risk >= plevels[:error]
105
+ raise NameError, caution unless block_given?
106
+ false
107
+ when risk >= plevels[:warn]
108
+ warn caution unless block_given?
109
+ false
110
+ else
111
+ true
112
+ end
113
+ )
114
+
115
+ yield r if block_given?
116
+ end
117
+
118
+ # @param [Symbol] name
119
+ # @return [Symbol]
120
+ def _estimate_naming(name)
121
+ if (instance_methods + private_instance_methods).include? name
122
+ return :conflict
123
+ end
124
+
125
+ return :no_ascii unless name.encoding.equal? Encoding::ASCII
126
+
127
+ case name
128
+ when /[\W]/, /\A[^a-zA-Z_]/, :''
129
+ :no_identifier
130
+ when /\Aeach/, /\A__[^_]*__\z/, /\A_[^_]*\z/, /[!?]\z/, /\Ato_/
131
+ :bad_manners
132
+ when /\A[a-zA-Z_]\w*\z/
133
+ :strict
134
+ else
135
+ raise 'must not happen'
136
+ end
137
+ end
138
+
139
+ def __getter__!(name)
140
+ define_method name do
141
+ __get__ name
142
+ end
143
+
144
+ nil
145
+ end
146
+
147
+ def __setter__!(name, *conditions, &flavor)
148
+ __set_conditions__! name, *conditions
149
+ __set_flavor__! name, &flavor if block_given?
150
+
151
+ define_method "#{name}=" do |value|
152
+ __set__ name, value
153
+ end
154
+
155
+ nil
156
+
157
+ end
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
170
+ end
171
+
172
+ nil
173
+ end
174
+
175
+ def __set_flavor__!(name, &flavor)
176
+ if (arity = flavor.arity) == 1
177
+ _set_flavor name, flavor
178
+ else
179
+ raise ArgumentError, "wrong number of block argument #{arity} for 1"
180
+ end
181
+
182
+ nil
183
+ end
184
+
185
+ def __found_family__!(_caller, name, our)
186
+ family = our.class
187
+
188
+ raise 'must not happen' unless name.instance_of?(Symbol) and
189
+ inference?(name) and
190
+ member?(name) and
191
+ _caller.instance_of?(self)
192
+
193
+ raise ArgumentError unless conditionable? family
194
+
195
+ _set_conditions name, [family]
196
+ _remove_inference name
197
+
198
+ nil
199
+ end
200
+
201
+ def _conditions_for(name)
202
+ @conditions[name]
203
+ end
204
+
205
+ # @param [Symbol, String] name
206
+ def conditions_for(name)
207
+ _conditions_for originalkey_for(keyable_for name)
208
+ end
209
+
210
+ def _flavor_for(name)
211
+ @flavors[name]
212
+ end
213
+
214
+ # @param [Symbol, String] name
215
+ def flavor_for(name)
216
+ _flavor_for originalkey_for(keyable_for name)
217
+ end
218
+
219
+ def _default_for(name)
220
+ @defaults[name]
221
+ end
222
+
223
+ # @endgroup
224
+ end; end; end
@@ -0,0 +1,108 @@
1
+ class Striuct; module Subclassable; module Eigen
2
+ # @group Macro for Definition
3
+
4
+ private
5
+
6
+ # @macro [attach] protect_level
7
+ # @param [Symbol] level
8
+ # @return [nil]
9
+ # change protect level for risk of naming members
10
+ def protect_level(level)
11
+ raise NameError unless PROTECT_LEVELS.has_key? level
12
+
13
+ @protect_level = level
14
+ nil
15
+ end
16
+
17
+ # @macro [attach] member
18
+ # @return [nil]
19
+ def define_member(name, *conditions, &flavor)
20
+ warn 'deprecated multiple conditions here, please use .#OR' if conditions.length >= 2
21
+ raise "already closed to add member in #{self}" if closed?
22
+ name = keyable_for name
23
+ raise ArgumentError, %Q!already exist name "#{name}"! if member? name
24
+ _check_safety_naming name
25
+
26
+ @names << name
27
+ __getter__! name
28
+ __setter__! name, *conditions, &flavor
29
+ nil
30
+ end
31
+
32
+ alias_method :def_member, :define_member
33
+ alias_method :member, :define_member
34
+
35
+ # @macro [attach] define_members
36
+ # @return [nil]
37
+ def define_members(*names)
38
+ raise "already closed to add members in #{self}" if closed?
39
+ unless names.length >= 1
40
+ raise ArgumentError, 'wrong number of arguments (0 for 1+)'
41
+ end
42
+
43
+ names.each do |name|
44
+ define_member name
45
+ end
46
+
47
+ nil
48
+ end
49
+
50
+ alias_method :def_members, :define_members
51
+
52
+ # @param [Symbol, String] aliased
53
+ # @param [Symbol, String] original
54
+ # @return [nil]
55
+ def alias_member(aliased, original)
56
+ raise "already closed to add members in #{self}" if closed?
57
+ original = keyable_for original
58
+ aliased = keyable_for aliased
59
+ raise NameError unless member? original
60
+ raise ArgumentError, %Q!already exist name "#{aliased}"! if member? aliased
61
+ _check_safety_naming aliased
62
+
63
+ alias_method aliased, original
64
+ alias_method "#{aliased}=", "#{original}="
65
+ _alias_member aliased, original
66
+
67
+ nil
68
+ end
69
+
70
+ # @macro [attach] default
71
+ # @return [nil]
72
+ def set_default_value(name, value=nil, &block)
73
+ raise "already closed to modify member attributes in #{self}" if closed?
74
+ name = originalkey_for(keyable_for name)
75
+ raise "already settled default value for #{name}" if has_default? name
76
+
77
+ value = (
78
+ if block_given?
79
+ if value.nil?
80
+ if (arity = block.arity) == 2
81
+ SpecificContainer.new block
82
+ else
83
+ raise ArgumentError, "wrong number of block parameter #{arity} for 2"
84
+ end
85
+ else
86
+ raise ArgumentError, 'can not use value and block arguments'
87
+ end
88
+ else
89
+ value
90
+ end
91
+ )
92
+
93
+ _set_default_value name, value
94
+ nil
95
+ end
96
+
97
+ alias_method :default, :set_default_value
98
+
99
+ # @return [self]
100
+ def fix_structural
101
+ [@names, @flavors, @defaults, @aliases].each(&:freeze)
102
+ self
103
+ end
104
+
105
+ alias_method :close, :fix_structural
106
+
107
+ # @endgroup
108
+ end; end; end
@@ -0,0 +1,56 @@
1
+ class Striuct; module Subclassable; module Eigen
2
+ # @group Struct+ Safety
3
+
4
+ # @return [INFERENCE] specific key of inference checker
5
+ def inference
6
+ INFERENCE
7
+ end
8
+
9
+ # @param [Symbol, String] name
10
+ # inference checker is waiting yet
11
+ def inference?(name)
12
+ name = originalkey_for(keyable_for name)
13
+
14
+ @inferences.has_key? name
15
+ end
16
+
17
+ # @param [Symbol, String] name
18
+ def has_conditions?(name)
19
+ name = originalkey_for(keyable_for name)
20
+
21
+ @conditions.has_key?(name)
22
+ end
23
+
24
+ alias_method :restrict?, :has_conditions?
25
+
26
+ # @param [Symbol, String] name
27
+ # @param [Object] value
28
+ # @param [Subclass] context - expect own instance
29
+ # value can set the member space
30
+ def sufficient?(name, value, context=nil)
31
+ name = originalkey_for(keyable_for name)
32
+
33
+ if restrict? name
34
+ conditions_for(name).any?{|c|pass? value, c, context}
35
+ else
36
+ true
37
+ end
38
+ end
39
+
40
+ alias_method :accept?, :sufficient?
41
+ alias_method :valid?, :sufficient?
42
+
43
+ # @param [Object] name
44
+ # accpeptable the name into own member, under protect level of runtime
45
+ def cname?(name)
46
+ _check_safety_naming(keyable_for name){|r|r}
47
+ rescue Exception
48
+ false
49
+ end
50
+
51
+ def closed?
52
+ [@names, @flavors, @defaults, @aliases].any?(&:frozen?)
53
+ end
54
+
55
+ # @endgroup
56
+ end; end; end
@@ -0,0 +1,33 @@
1
+ require_relative 'classutil'
2
+ require_relative 'eigen/frame'
3
+
4
+ class Striuct
5
+
6
+ # @author Kenichi Kamiya
7
+ module Subclassable
8
+ extend ClassUtil
9
+ include Enumerable
10
+
11
+ SpecificContainer = Struct.new :value
12
+
13
+ if respond_to? :private_constant
14
+ private_constant :SpecificContainer
15
+ end
16
+
17
+ class << self
18
+ private
19
+
20
+ def included(klass)
21
+ klass.extend Eigen
22
+ end
23
+ end
24
+ end
25
+
26
+ end
27
+
28
+ require_relative 'basic'
29
+ require_relative 'safety'
30
+ require_relative 'handy'
31
+ require_relative 'hashlike'
32
+ require_relative 'yaml'
33
+ require_relative 'inner'
@@ -0,0 +1,57 @@
1
+ class Striuct; module Subclassable
2
+ # @group Struct + Handy
3
+
4
+ # see self.class.*args
5
+ delegate_class_methods :has_default?, :default_for, :has_flavor?
6
+
7
+ # @yield [index]
8
+ # @yieldparam [Integer] index
9
+ # @yieldreturn [self]
10
+ # @return [Enumerator]
11
+ def each_index(&block)
12
+ return to_enum(__method__) unless block_given?
13
+ self.class.each_index(&block)
14
+ self
15
+ end
16
+
17
+ # @yield [value, index]
18
+ # @yieldparam [Integer] index
19
+ # @yieldreturn [self]
20
+ # @return [Enumerator]
21
+ def each_value_with_index(&block)
22
+ return to_enum(__method__) unless block_given?
23
+ each_value.with_index(&block)
24
+ self
25
+ end
26
+
27
+ alias_method :each_with_index, :each_value_with_index
28
+
29
+ # @param [Symbol, String] name
30
+ def assign?(name)
31
+ name = originalkey_for(keyable_for name)
32
+
33
+ @db.has_key? name
34
+ end
35
+
36
+ # @param [Symbol, String, Fixnum] key
37
+ def clear_at(key)
38
+ __subscript__(key){|name|__clear__ name}
39
+ end
40
+
41
+ alias_method :unassign, :clear_at
42
+ alias_method :reset_at, :clear_at
43
+
44
+ # @param [Symbol, String] name
45
+ def default?(name)
46
+ name = originalkey_for(keyable_for name)
47
+
48
+ default_for(name) == self[name]
49
+ end
50
+
51
+ # all members aren't assigned
52
+ def empty?
53
+ each_name.none?{|name|assign? name}
54
+ end
55
+
56
+ # @endgroup
57
+ end; end
@@ -0,0 +1,133 @@
1
+ class Striuct; module Subclassable
2
+ # @group HashLike
3
+
4
+ # @return [Hash]
5
+ def to_h(reject_no_assign=false)
6
+ return @db.dup if reject_no_assign
7
+
8
+ {}.tap {|h|
9
+ each_pair do |k, v|
10
+ h[k] = v
11
+ end
12
+ }
13
+ end
14
+
15
+ # @yield [name]
16
+ # @yieldparam [Symbol] name - sequential under defined
17
+ # @yieldreturn [self]
18
+ # @return [Enumerator]
19
+ def each_name(&block)
20
+ return to_enum(__method__) unless block_given?
21
+ self.class.each_name(&block)
22
+ self
23
+ end
24
+
25
+ alias_method :each_member, :each_name
26
+ alias_method :each_key, :each_name
27
+
28
+ def has_value?(value)
29
+ @db.has_value? value
30
+ end
31
+
32
+ alias_method :value?, :has_value?
33
+
34
+ # @yield [name, value]
35
+ # keep truthy only (unassign falsy member)
36
+ # @see #each_pair
37
+ # @return [Enumerator]
38
+ # @yieldreturn [self]
39
+ # @yieldreturn [nil]
40
+ def select!
41
+ raise "can't modify frozen #{self.class}" if frozen?
42
+ return to_enum(__method__) unless block_given?
43
+
44
+ modified = false
45
+ each_pair do |name, value|
46
+ unless yield name, value
47
+ unassign name
48
+ modified = true
49
+ end
50
+ end
51
+
52
+ modified ? self : nil
53
+ end
54
+
55
+ # @see #select!
56
+ # @yield [name, value]
57
+ # @return [Enumerator]
58
+ def keep_if(&block)
59
+ raise "can't modify frozen #{self.class}" if frozen?
60
+ return to_enum(__method__) unless block_given?
61
+ select!(&block)
62
+ self
63
+ end
64
+
65
+ # @see #select!
66
+ # keep falsy only (unassign truthy member)
67
+ # @yield [name, value]
68
+ # @return [Enumerator]
69
+ def reject!
70
+ raise "can't modify frozen #{self.class}" if frozen?
71
+ return to_enum(__method__) unless block_given?
72
+
73
+ modified = false
74
+ each_pair do |name, value|
75
+ if yield name, value
76
+ unassign name
77
+ modified = true
78
+ end
79
+ end
80
+
81
+ modified ? self : nil
82
+ end
83
+
84
+ # @see #reject!
85
+ # @yield [name, value]
86
+ # @return [Enumerator]
87
+ def delete_if(&block)
88
+ raise "can't modify frozen #{self.class}" if frozen?
89
+ return to_enum(__method__) unless block_given?
90
+
91
+ reject!(&block)
92
+ self
93
+ end
94
+
95
+ # @param [Symbol, String] name
96
+ # @return [Array] [name, value]
97
+ def assoc(name)
98
+ name = originalkey_for(keyable_for name)
99
+
100
+ [name, self[name]]
101
+ end
102
+
103
+ # @return [Array] [name, value]
104
+ def rassoc(value)
105
+ each_pair.find{|pair|pair[1] == value}
106
+ end
107
+
108
+ # @see Hash#flatten
109
+ # @return [Array]
110
+ def flatten(level=1)
111
+ each_pair.to_a.flatten level
112
+ end
113
+
114
+ # @see #select!
115
+ # @yield [name, value]
116
+ # @return [Subclass]
117
+ def select(&block)
118
+ return to_enum(__method__) unless block_given?
119
+
120
+ dup.tap {|r|r.select!(&block)}
121
+ end
122
+
123
+ # @see #reject!
124
+ # @yield [name, value]
125
+ # @return [Subclass]
126
+ def reject(&block)
127
+ return to_enum(__method__) unless block_given?
128
+
129
+ dup.tap {|r|r.reject!(&block)}
130
+ end
131
+
132
+ # @endgroup
133
+ end; end
@@ -0,0 +1,108 @@
1
+ class Striuct; module Subclassable
2
+ private
3
+
4
+ # @group Use Only Inner
5
+
6
+ # see self.class.*args
7
+ delegate_class_methods(
8
+ :keyable_for, :flavor_for, :conditions_for, :originalkey_for
9
+ )
10
+
11
+ def initialize_copy(original)
12
+ @db, @locks = @db.dup, {}
13
+ end
14
+
15
+ def __get__(name)
16
+ name = originalkey_for(keyable_for name)
17
+
18
+ @db[name]
19
+ end
20
+
21
+ def __set__(name, value)
22
+ raise "can't modify frozen #{self.class}" if frozen?
23
+ name = originalkey_for(keyable_for name)
24
+ raise "can't modify locked member #{name}" if lock? name
25
+
26
+ unless accept? name, value
27
+ raise ConditionError,
28
+ "#{value.inspect} is deficient for #{conditions_for(name).inspect}"
29
+ end
30
+
31
+ if has_flavor? name
32
+ value = instance_exec value, &flavor_for(name)
33
+ end
34
+
35
+ if inference? name
36
+ self.class.__send__ :__found_family__!, self, name, value
37
+ end
38
+
39
+ @db[name] = value
40
+ rescue ConditionError
41
+ unless /in \[\]=/ =~ caller[1].slice(/([^:]+)\z/)
42
+ $@.delete_if{|s|/#{Regexp.escape(File.dirname __FILE__)}/ =~ s}
43
+ $@.first.sub!(/([^:]+)\z/){"in `#{name}='"}
44
+ $@ << $@.last
45
+ end
46
+
47
+ raise
48
+ end
49
+
50
+ def __subscript__(key)
51
+ case key
52
+ when Symbol, String
53
+ name = keyable_for key
54
+ if member? name
55
+ yield originalkey_for(name)
56
+ else
57
+ raise NameError
58
+ end
59
+ when Fixnum
60
+ if name = members[key]
61
+ yield name
62
+ else
63
+ raise IndexError
64
+ end
65
+ else
66
+ raise ArgumentError
67
+ end
68
+ end
69
+
70
+ # @param [Symbol] name
71
+ def __clear__(name)
72
+ raise "can't modify frozen #{self.class}" if frozen?
73
+
74
+ @db.delete name
75
+ end
76
+
77
+ def replace_values(*values)
78
+ unless values.size <= size
79
+ raise ArgumentError, "struct size differs (max: #{size})"
80
+ end
81
+
82
+ values.each_with_index do |value, index|
83
+ self[index] = value
84
+ end
85
+
86
+ excess = members.last(size - values.size)
87
+
88
+ excess.each do |name|
89
+ if has_default? name
90
+ self[name] = (
91
+ if (value = default_for name).kind_of? SpecificContainer
92
+ value.value.call self, name
93
+ else
94
+ value
95
+ end
96
+ )
97
+ end
98
+ end
99
+ end
100
+
101
+ # @param [Symbol] method
102
+ def __compare_all__(other, method)
103
+ instance_of?(other.class) && \
104
+ each_pair.all?{|k, v|v.__send__ method, other[k]}
105
+ end
106
+
107
+ # @endgroup
108
+ end; end