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.
- data/History.rdoc +128 -35
- data/Manifest.txt +21 -6
- data/README.ja.rdoc +142 -83
- data/README.rdoc +130 -73
- data/Rakefile +5 -3
- data/example/benchmarks.rb +56 -0
- data/{example.rb → example/example.rb} +81 -70
- data/example/see_trace.rb +28 -0
- data/lib/striuct/abstract.rb +74 -0
- data/lib/striuct/conditions.rb +228 -0
- data/lib/striuct/frame.rb +8 -0
- data/lib/striuct/subclassable/basic.rb +135 -0
- data/lib/striuct/{classutil.rb → subclassable/classutil.rb} +5 -5
- data/lib/striuct/subclassable/eigen/basic.rb +38 -0
- data/lib/striuct/subclassable/eigen/constructor.rb +58 -0
- data/lib/striuct/subclassable/eigen/frame.rb +39 -0
- data/lib/striuct/subclassable/eigen/handy.rb +92 -0
- data/lib/striuct/subclassable/eigen/inner.rb +224 -0
- data/lib/striuct/subclassable/eigen/macro.rb +108 -0
- data/lib/striuct/subclassable/eigen/safety.rb +56 -0
- data/lib/striuct/subclassable/frame.rb +33 -0
- data/lib/striuct/subclassable/handy.rb +57 -0
- data/lib/striuct/subclassable/hashlike.rb +133 -0
- data/lib/striuct/subclassable/inner.rb +108 -0
- data/lib/striuct/subclassable/safety.rb +72 -0
- data/lib/striuct/subclassable/yaml.rb +14 -0
- data/lib/striuct/version.rb +2 -2
- data/lib/striuct.rb +3 -2
- data/test/test_striuct.rb +649 -20
- metadata +55 -24
- data/lib/striuct/core.rb +0 -56
- data/lib/striuct/import.rb +0 -95
- data/lib/striuct/subclass.rb +0 -262
- data/lib/striuct/subclass_eigen.rb +0 -428
- data/test/test_helper_import.rb +0 -4
- data/test/test_striuct_import.rb +0 -42
@@ -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
|