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,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