@@ -21,50 +21,88 @@ class << self
21
21
def new ( opts = Options . new , **properties )
22
22
properties . each_key do |prop |
23
23
if method_defined? ( prop )
24
- $stdout . puts OVERRIDING_NATIVE_METHOD_MSG % [ prop . inspect , caller ( 3 ) . first ]
24
+ warn OVERRIDING_NATIVE_METHOD_MSG % [ prop . inspect , caller ( 3 ) . first ]
25
25
end
26
26
end
27
27
28
- super ( * properties . keys , keyword_init : true ) . tap do | klass |
29
- klass . class . instance_eval do
30
- include TypeChecking
31
- attr_reader :options
32
- end
28
+ klass = if opts [ :class_name ]
29
+ super ( opts [ :class_name ] , * properties . keys , keyword_init : opts [ :keyword_init ] )
30
+ else
31
+ super ( * properties . keys , keyword_init : opts [ :keyword_init ] )
32
+ end
33
33
34
- klass . instance_eval do
35
- @options = { types : properties , options : opts }
34
+ klass . class . instance_eval do
35
+ include TypeChecking
36
+ attr_reader :options
37
+ end
36
38
37
- define_method :[]= do |key , val |
38
- prop = properties [ key ]
39
- unless val_is_type? val , prop
40
- raise "Unexpected type #{ val . class } for #{ key . inspect } (expected #{ prop } )"
41
- end
39
+ klass . instance_eval do
40
+ @options = { types : properties , options : opts }
42
41
43
- super key , val
42
+ define_method :[]= do |key , val |
43
+ if key . is_a? ( Integer )
44
+ if key . negative?
45
+ raise IndexError , "offset #{ key } too small for struct(size:#{ members . size } )"
46
+ elsif key >= members . size
47
+ raise IndexError , "offset #{ key } too large for struct(size:#{ members . size } )"
48
+ end
49
+ key = self . members [ key ]
50
+ end
51
+ unless properties . key? ( key )
52
+ raise NameError , "no member '#{ key } ' in struct"
53
+ end
54
+ prop = properties [ key ]
55
+ unless val_is_type? val , prop
56
+ raise TypeError , "unexpected type #{ val . class } for #{ key . inspect } (expected #{ prop } )"
44
57
end
45
58
46
- properties . each_key do |k |
47
- define_method :"#{ k } =" do |val |
48
- self [ k ] = val
49
- end
59
+ super key , val
60
+ end
61
+
62
+ properties . each_key do |k |
63
+ define_method :"#{ k } =" do |val |
64
+ self [ k ] = val
50
65
end
51
66
end
52
67
end
68
+
69
+ klass
53
70
end
54
71
end
55
72
56
- def initialize ( **attrs )
73
+ def initialize ( *positional_attrs , * *attrs )
57
74
opts = self . __class__ . options
75
+ if opts [ :options ] [ :keyword_init ] == true && !positional_attrs . empty?
76
+ raise ArgumentError , "wrong number of arguments (given #{ positional_attrs . size } , expected 0)"
77
+ elsif ( opts [ :options ] [ :keyword_init ] == false && !attrs . empty? ) ||
78
+ ( opts [ :options ] [ :keyword_init ] != true && !positional_attrs . empty? )
79
+ positional_attrs << attrs unless attrs . empty?
80
+ attrs = positional_attrs . zip ( self . members ) . to_h ( &:reverse )
81
+ end
82
+
83
+ if attrs . size > members . size
84
+ raise ArgumentError , "struct size differs"
85
+ end
86
+
58
87
vals = opts [ :types ] . to_h do |prop , expected_type |
59
88
value = attrs . fetch ( prop , opts [ :options ] [ :default ] )
60
89
unless val_is_type? value , expected_type
61
- raise "Unexpected type #{ value . class } for #{ prop . inspect } (expected #{ expected_type } )"
90
+ raise TypeError , "unexpected type #{ value . class } for #{ prop . inspect } (expected #{ expected_type } )"
62
91
end
63
92
[ prop , value ]
64
93
end
65
94
66
- super **vals
95
+ if opts [ :options ] [ :keyword_init ] == true
96
+ super **vals
97
+ else
98
+ super *vals . values
99
+ end
67
100
end
68
101
69
- Options = TypedStruct . new ( { default : nil } , default : Rbs ( "untyped" ) )
102
+ Options = TypedStruct . new (
103
+ { default : nil } ,
104
+ default : Rbs ( "untyped" ) ,
105
+ keyword_init : Rbs ( "bool?" ) ,
106
+ class_name : Rbs ( "String? | Symbol?" )
107
+ )
70
108
end
0 commit comments