structure 3.3.0 → 3.5.0
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.
- checksums.yaml +4 -4
- data/lib/structure/builder.rb +12 -12
- data/lib/structure/rbs.rb +161 -0
- data/lib/structure/types.rb +72 -65
- data/lib/structure/version.rb +1 -1
- data/lib/structure.rb +74 -56
- data/sig/structure/builder.rbs +21 -0
- data/sig/structure/rbs.rbs +10 -0
- data/sig/structure/types.rbs +16 -0
- data/sig/structure/version.rbs +3 -0
- data/sig/structure.rbs +12 -0
- metadata +7 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69015a521f4a1a35438cd69d0d195e8f0fa276156d64371c8a6437030b14caf0
|
4
|
+
data.tar.gz: d4e5c263a7c92ae2bfbdbe5213b933c55ea1a8f0c9a8d6583302f8c032bb69a9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e8ace0197fb9b9cd4811cc1eb7774fe98eff67df140400b567a0a636b9bdabcf2e7858586a7b13f96fbc95e101e2eef74518d9940b1f7c4dab168fec119fb3e
|
7
|
+
data.tar.gz: 9d7fa653f6b4aeb60b10bfca4a940677bee89c6803a8e50d893e9dc0ce687306691bbb6f92f4af0a59c89245c3583e8b6d64f477d27b44b71f0f1b7fc359bb26
|
data/lib/structure/builder.rb
CHANGED
@@ -33,16 +33,13 @@ module Structure
|
|
33
33
|
# Money.new(value["amount"], value["currency"])
|
34
34
|
# end
|
35
35
|
def attribute(name, type = nil, from: nil, default: nil, &block)
|
36
|
-
|
37
|
-
|
38
|
-
@defaults[name] = default unless default.nil?
|
36
|
+
mappings[name] = from || name.to_s
|
37
|
+
defaults[name] = default unless default.nil?
|
39
38
|
|
40
39
|
if type && block
|
41
40
|
raise ArgumentError, "Cannot specify both type and block for :#{name}"
|
42
|
-
|
43
|
-
|
44
|
-
elsif type
|
45
|
-
@types[name] = Types.coerce(type)
|
41
|
+
else
|
42
|
+
types[name] = type || block
|
46
43
|
end
|
47
44
|
end
|
48
45
|
|
@@ -63,13 +60,16 @@ module Structure
|
|
63
60
|
@mappings.keys
|
64
61
|
end
|
65
62
|
|
63
|
+
def coercions
|
64
|
+
@types.transform_values { |type| Types.coerce(type) }
|
65
|
+
end
|
66
|
+
|
66
67
|
def predicate_methods
|
67
|
-
@types.filter_map do |name,
|
68
|
-
if
|
69
|
-
|
70
|
-
[predicate_name.to_sym, name]
|
68
|
+
@types.filter_map do |name, type|
|
69
|
+
if type == :boolean
|
70
|
+
["#{name}?".to_sym, name] unless name.to_s.end_with?("?")
|
71
71
|
end
|
72
|
-
end.to_h
|
72
|
+
end.compact.to_h
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
require "pathname"
|
5
|
+
|
6
|
+
module Structure
|
7
|
+
module RBS
|
8
|
+
class << self
|
9
|
+
def emit(klass)
|
10
|
+
return unless klass < Data
|
11
|
+
|
12
|
+
class_name = klass.name
|
13
|
+
return unless class_name
|
14
|
+
|
15
|
+
# @type var meta: Hash[Symbol, untyped]
|
16
|
+
meta = klass.respond_to?(:__structure_meta__) ? klass.__structure_meta__ : {}
|
17
|
+
|
18
|
+
emit_rbs_content(
|
19
|
+
class_name: class_name,
|
20
|
+
attributes: meta.fetch(:attributes, klass.members),
|
21
|
+
types: meta.fetch(:types, {}), # steep:ignore
|
22
|
+
has_structure_modules: meta.any?,
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
def write(klass, dir: "sig")
|
27
|
+
rbs_content = emit(klass)
|
28
|
+
return unless rbs_content
|
29
|
+
|
30
|
+
# User::Address -> user/address.rbs
|
31
|
+
path_segments = klass.name.split("::").map(&:downcase)
|
32
|
+
filename = "#{path_segments.pop}.rbs"
|
33
|
+
|
34
|
+
# full path
|
35
|
+
dir_path = Pathname.new(dir)
|
36
|
+
dir_path = dir_path.join(*path_segments) unless path_segments.empty?
|
37
|
+
FileUtils.mkdir_p(dir_path)
|
38
|
+
|
39
|
+
file_path = dir_path.join(filename).to_s
|
40
|
+
File.write(file_path, rbs_content)
|
41
|
+
|
42
|
+
file_path
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def emit_rbs_content(class_name:, attributes:, types:, has_structure_modules:)
|
48
|
+
# @type var lines: Array[String]
|
49
|
+
lines = []
|
50
|
+
lines << "class #{class_name} < Data"
|
51
|
+
|
52
|
+
unless attributes.empty?
|
53
|
+
# map types to rbs
|
54
|
+
rbs_types = attributes.map do |attr|
|
55
|
+
type = types.fetch(attr, nil)
|
56
|
+
rbs_type = map_type_to_rbs(type, class_name)
|
57
|
+
|
58
|
+
[attr, rbs_type != "untyped" ? "#{rbs_type}?" : rbs_type]
|
59
|
+
end.to_h
|
60
|
+
|
61
|
+
keyword_params = attributes.map { |attr| "#{attr}: #{rbs_types[attr]}" }.join(", ")
|
62
|
+
positional_params = attributes.map { |attr| rbs_types[attr] }.join(", ")
|
63
|
+
|
64
|
+
lines << " def self.new: (#{keyword_params}) -> instance"
|
65
|
+
lines << " | (#{positional_params}) -> instance"
|
66
|
+
lines << ""
|
67
|
+
|
68
|
+
needs_parse_data = types.any? do |_attr, type|
|
69
|
+
type == :self || type == [:self] || (type.is_a?(Array) && type.first == :array)
|
70
|
+
end
|
71
|
+
|
72
|
+
if needs_parse_data
|
73
|
+
lines << " type parse_data = {"
|
74
|
+
attributes.each do |attr|
|
75
|
+
type = types.fetch(attr, nil)
|
76
|
+
parse_type = parse_data_type(type, class_name)
|
77
|
+
lines << " ?#{attr}: #{parse_type},"
|
78
|
+
end
|
79
|
+
lines[-1] = lines[-1].chomp(",")
|
80
|
+
lines << " }"
|
81
|
+
lines << ""
|
82
|
+
lines << " def self.parse: (?parse_data data) -> instance"
|
83
|
+
lines << " | (?Hash[String, untyped] data) -> instance"
|
84
|
+
else
|
85
|
+
# For structures without special types, just use Hash
|
86
|
+
lines << " def self.parse: (?(Hash[String | Symbol, untyped]), **untyped) -> instance"
|
87
|
+
end
|
88
|
+
lines << ""
|
89
|
+
|
90
|
+
attributes.each do |attr|
|
91
|
+
lines << " attr_reader #{attr}: #{rbs_types[attr]}"
|
92
|
+
end
|
93
|
+
lines << ""
|
94
|
+
|
95
|
+
types.each do |attr, type|
|
96
|
+
if type == :boolean && !attr.to_s.end_with?("?")
|
97
|
+
lines << " def #{attr}?: () -> bool"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
hash_type = attributes.map { |attr| "#{attr}: #{rbs_types[attr]}" }.join(", ")
|
102
|
+
lines << " def to_h: () -> { #{hash_type} }"
|
103
|
+
end
|
104
|
+
|
105
|
+
lines << "end"
|
106
|
+
lines.join("\n")
|
107
|
+
end
|
108
|
+
|
109
|
+
def parse_data_type(type, class_name)
|
110
|
+
case type
|
111
|
+
when [:self]
|
112
|
+
"Array[#{class_name} | parse_data]"
|
113
|
+
when Array
|
114
|
+
if type.first == :array && type.last == :self
|
115
|
+
"Array[#{class_name} | parse_data]"
|
116
|
+
elsif type.first == :array
|
117
|
+
# For [:array, SomeType] format, use Array[untyped] since we coerce
|
118
|
+
"Array[untyped]"
|
119
|
+
elsif type.size == 1 && type.first == :self
|
120
|
+
# [:self] is handled above, this shouldn't happen
|
121
|
+
"Array[#{class_name} | parse_data]"
|
122
|
+
elsif type.size == 1
|
123
|
+
# Regular array type like [String], [Integer], etc.
|
124
|
+
# Use Array[untyped] since we coerce values
|
125
|
+
"Array[untyped]"
|
126
|
+
else
|
127
|
+
"untyped"
|
128
|
+
end
|
129
|
+
when :self
|
130
|
+
"#{class_name} | parse_data"
|
131
|
+
else
|
132
|
+
"untyped"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def map_type_to_rbs(type, class_name)
|
137
|
+
case type
|
138
|
+
when Class
|
139
|
+
type.name || "untyped"
|
140
|
+
when :boolean
|
141
|
+
"bool"
|
142
|
+
when :self
|
143
|
+
class_name || "untyped"
|
144
|
+
when Array
|
145
|
+
if type.size == 2 && type.first == :array
|
146
|
+
element_type = map_type_to_rbs(type.last, class_name)
|
147
|
+
"Array[#{element_type}]"
|
148
|
+
elsif type.size == 1
|
149
|
+
# Single element array means array of that type
|
150
|
+
element_type = map_type_to_rbs(type.first, class_name)
|
151
|
+
"Array[#{element_type}]"
|
152
|
+
else
|
153
|
+
"untyped"
|
154
|
+
end
|
155
|
+
else
|
156
|
+
"untyped"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
data/lib/structure/types.rb
CHANGED
@@ -3,81 +3,88 @@
|
|
3
3
|
module Structure
|
4
4
|
# Type coercion methods for converting values to specific types
|
5
5
|
module Types
|
6
|
-
|
6
|
+
class << self
|
7
|
+
# Rails-style boolean truthy values
|
8
|
+
# Reference: https://api.rubyonrails.org/classes/ActiveModel/Type/Boolean.html
|
9
|
+
BOOLEAN_TRUTHY = [true, 1, "1", "t", "T", "true", "TRUE", "on", "ON"].freeze
|
10
|
+
private_constant :BOOLEAN_TRUTHY
|
7
11
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
boolean
|
37
|
-
when :self
|
38
|
-
self_referential
|
39
|
-
when Array
|
40
|
-
if type.length == 1
|
41
|
-
array(type.first)
|
42
|
-
else
|
43
|
-
type
|
44
|
-
end
|
45
|
-
else
|
46
|
-
# Handle Class, Module, and any other types
|
47
|
-
if type.respond_to?(:parse)
|
48
|
-
parseable(type)
|
49
|
-
elsif type.respond_to?(:name) && type.name && Kernel.respond_to?(type.name)
|
50
|
-
kernel(type)
|
12
|
+
# Main factory method for creating type coercers
|
13
|
+
#
|
14
|
+
# @param type [Class, Symbol, Array] Type specification
|
15
|
+
# @return [Proc, Object] Coercion proc or the type itself if no coercion available
|
16
|
+
#
|
17
|
+
# @example Boolean type
|
18
|
+
# coerce(:boolean) # => boolean proc
|
19
|
+
#
|
20
|
+
# @example Kernel types
|
21
|
+
# coerce(Integer) # => proc that calls Kernel.Integer
|
22
|
+
#
|
23
|
+
# @example Parseable types
|
24
|
+
# coerce(Date) # => proc that calls Date.parse
|
25
|
+
#
|
26
|
+
# @example Array types
|
27
|
+
# coerce([String]) # => proc that coerces array elements to String
|
28
|
+
def coerce(type)
|
29
|
+
case type
|
30
|
+
when :boolean
|
31
|
+
boolean
|
32
|
+
when :self
|
33
|
+
self_referential
|
34
|
+
when Array
|
35
|
+
if type.length == 1
|
36
|
+
array(type.first)
|
37
|
+
else
|
38
|
+
type
|
39
|
+
end
|
51
40
|
else
|
52
|
-
type
|
41
|
+
if type.respond_to?(:parse)
|
42
|
+
parseable(type)
|
43
|
+
elsif type.respond_to?(:name) && type.name && Kernel.respond_to?(type.name)
|
44
|
+
kernel(type)
|
45
|
+
else
|
46
|
+
type
|
47
|
+
end
|
53
48
|
end
|
54
49
|
end
|
55
|
-
end
|
56
50
|
|
57
|
-
|
51
|
+
private
|
58
52
|
|
59
|
-
|
60
|
-
|
61
|
-
|
53
|
+
def boolean
|
54
|
+
@boolean ||= ->(val) { BOOLEAN_TRUTHY.include?(val) }
|
55
|
+
end
|
62
56
|
|
63
|
-
|
64
|
-
|
65
|
-
|
57
|
+
def self_referential
|
58
|
+
proc { |val| parse(val) }
|
59
|
+
end
|
66
60
|
|
67
|
-
|
68
|
-
|
69
|
-
|
61
|
+
def kernel(type)
|
62
|
+
->(val) { Kernel.send(type.name, val) }
|
63
|
+
end
|
70
64
|
|
71
|
-
|
72
|
-
|
73
|
-
|
65
|
+
def parseable(type)
|
66
|
+
->(val) { type.parse(val) }
|
67
|
+
end
|
74
68
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
69
|
+
def array(element_type)
|
70
|
+
if element_type == :self
|
71
|
+
proc do |value|
|
72
|
+
unless value.respond_to?(:map)
|
73
|
+
raise TypeError, "can't convert #{value.class} into Array"
|
74
|
+
end
|
75
|
+
|
76
|
+
value.map { |element| parse(element) }
|
77
|
+
end
|
78
|
+
else
|
79
|
+
element_coercer = coerce(element_type)
|
80
|
+
lambda do |value|
|
81
|
+
unless value.respond_to?(:map)
|
82
|
+
raise TypeError, "can't convert #{value.class} into Array"
|
83
|
+
end
|
84
|
+
|
85
|
+
value.map { |element| element_coercer.call(element) }
|
86
|
+
end
|
87
|
+
end
|
81
88
|
end
|
82
89
|
end
|
83
90
|
end
|
data/lib/structure/version.rb
CHANGED
data/lib/structure.rb
CHANGED
@@ -23,78 +23,96 @@ module Structure
|
|
23
23
|
builder = Builder.new
|
24
24
|
builder.instance_eval(&block) if block
|
25
25
|
|
26
|
-
|
26
|
+
# @type var klass: untyped
|
27
|
+
klass = Data.define(*builder.attributes)
|
27
28
|
|
28
|
-
#
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
# capture metadata and attach to class
|
30
|
+
meta = {
|
31
|
+
attributes: builder.attributes.freeze,
|
32
|
+
types: builder.types.freeze,
|
33
|
+
defaults: builder.defaults.freeze,
|
34
|
+
}.freeze
|
35
|
+
klass.instance_variable_set(:@__structure_meta__, meta)
|
36
|
+
klass.singleton_class.attr_reader(:__structure_meta__)
|
34
37
|
|
35
|
-
#
|
38
|
+
# capture locals for method generation
|
36
39
|
mappings = builder.mappings
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
40
|
+
coercions = builder.coercions
|
41
|
+
predicates = builder.predicate_methods
|
42
|
+
after = builder.after_parse_callback
|
43
|
+
|
44
|
+
# Define predicate methods
|
45
|
+
predicates.each do |pred, attr|
|
46
|
+
klass.define_method(pred) { public_send(attr) }
|
47
|
+
end
|
48
|
+
|
49
|
+
# recursive to_h
|
50
|
+
klass.define_method(:to_h) do
|
51
|
+
# @type var h: Hash[Symbol, untyped]
|
52
|
+
h = {}
|
53
|
+
klass.members.each do |m|
|
54
|
+
v = public_send(m)
|
55
|
+
h[m] =
|
56
|
+
case v
|
57
|
+
when Array then v.map { |x| x.respond_to?(:to_h) && x ? x.to_h : x }
|
58
|
+
when ->(x) { x.respond_to?(:to_h) && x } then v.to_h
|
59
|
+
else v
|
60
|
+
end
|
57
61
|
end
|
58
|
-
|
62
|
+
h
|
59
63
|
end
|
60
64
|
|
61
|
-
|
62
|
-
|
63
|
-
|
65
|
+
# parse accepts JSON-ish hashes + kwargs override
|
66
|
+
klass.define_singleton_method(:parse) do |data = {}, **kwargs|
|
67
|
+
return data if data.is_a?(self)
|
68
|
+
|
69
|
+
unless data.respond_to?(:merge!)
|
70
|
+
raise TypeError, "can't convert #{data.class} into #{self}"
|
71
|
+
end
|
72
|
+
|
73
|
+
# @type var kwargs: Hash[Symbol, untyped]
|
64
74
|
string_kwargs = kwargs.transform_keys(&:to_s)
|
65
|
-
data
|
75
|
+
data.merge!(string_kwargs)
|
76
|
+
# @type self: singleton(Data) & _StructuredDataClass
|
77
|
+
# @type var final: Hash[Symbol, untyped]
|
78
|
+
final = {}
|
66
79
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
data[source_key]
|
72
|
-
elsif data.key?(source_key.to_sym)
|
73
|
-
data[source_key.to_sym]
|
74
|
-
elsif defaults.key?(attr)
|
75
|
-
defaults[attr]
|
76
|
-
end
|
80
|
+
# TODO: `__structure_meta__` exists but seems not to return the types it defines, so going untyped for now
|
81
|
+
#
|
82
|
+
# @type var meta: untyped
|
83
|
+
meta = __structure_meta__
|
77
84
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
attributes = meta.fetch(:attributes)
|
86
|
+
defaults = meta.fetch(:defaults)
|
87
|
+
|
88
|
+
attributes.each do |attr|
|
89
|
+
source = mappings[attr] || attr.to_s
|
90
|
+
value =
|
91
|
+
if data.key?(source) then data[source]
|
92
|
+
elsif data.key?(source.to_sym) then data[source.to_sym]
|
93
|
+
elsif defaults.key?(attr) then defaults[attr]
|
86
94
|
end
|
95
|
+
|
96
|
+
coercion = coercions[attr]
|
97
|
+
if coercion && !value.nil?
|
98
|
+
# self-referential types need class context to call parse
|
99
|
+
value =
|
100
|
+
if coercion.is_a?(Proc) && !coercion.lambda?
|
101
|
+
instance_exec(value, &coercion) # steep:ignore
|
102
|
+
else
|
103
|
+
coercion.call(value)
|
104
|
+
end
|
87
105
|
end
|
88
106
|
|
89
|
-
|
107
|
+
final[attr] = value
|
90
108
|
end
|
91
109
|
|
92
|
-
|
93
|
-
|
94
|
-
|
110
|
+
obj = new(**final)
|
111
|
+
after&.call(obj)
|
112
|
+
obj
|
95
113
|
end
|
96
114
|
|
97
|
-
|
115
|
+
klass
|
98
116
|
end
|
99
117
|
end
|
100
118
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Structure
|
2
|
+
class Builder
|
3
|
+
@mappings: Hash[Symbol, String]
|
4
|
+
@types: Hash[Symbol, untyped]
|
5
|
+
@defaults: Hash[Symbol, untyped]
|
6
|
+
@after_parse_callback: Proc?
|
7
|
+
|
8
|
+
def attribute: (Symbol name, untyped type, ?from: String?, ?default: untyped) ?{ (untyped) -> untyped } -> void
|
9
|
+
| (Symbol name, ?from: String, ?default: untyped) ?{ (untyped) -> untyped } -> void
|
10
|
+
|
11
|
+
def after_parse: () { (Data) -> void } -> void
|
12
|
+
|
13
|
+
def attributes: () -> Array[Symbol]
|
14
|
+
def mappings: () -> Hash[Symbol, String]
|
15
|
+
def types: () -> Hash[Symbol, untyped]
|
16
|
+
def defaults: () -> Hash[Symbol, untyped]
|
17
|
+
def coercions: () -> Hash[Symbol, Proc]
|
18
|
+
def predicate_methods: () -> Hash[Symbol, Symbol]
|
19
|
+
def after_parse_callback: () -> (Proc | nil)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Structure
|
2
|
+
module RBS
|
3
|
+
def self.emit: (untyped klass) -> String?
|
4
|
+
def self.write: (untyped klass, ?dir: String) -> String?
|
5
|
+
|
6
|
+
private def self.emit_rbs_content: (class_name: String, attributes: Array[Symbol], types: Hash[Symbol, untyped], has_structure_modules: bool) -> String
|
7
|
+
private def self.parse_data_type: (untyped type, String class_name) -> String
|
8
|
+
private def self.map_type_to_rbs: (untyped type, String class_name) -> String
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Structure
|
2
|
+
module Types
|
3
|
+
BOOLEAN_TRUTHY: Array[untyped]
|
4
|
+
|
5
|
+
self.@boolean: Proc
|
6
|
+
|
7
|
+
def self.coerce: (untyped type) -> untyped
|
8
|
+
|
9
|
+
private def self.boolean: () -> Proc
|
10
|
+
private def self.self_referential: () -> Proc
|
11
|
+
private def self.array: (untyped type) -> Proc
|
12
|
+
private def self.parseable: (untyped type) -> Proc
|
13
|
+
private def self.kernel: (Class type) -> Proc
|
14
|
+
private def self.parse: (untyped val) -> untyped
|
15
|
+
end
|
16
|
+
end
|
data/sig/structure.rbs
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Structure
|
2
|
+
interface _StructuredDataClass
|
3
|
+
def __structure_meta__: () -> {
|
4
|
+
attributes: Array[Symbol],
|
5
|
+
types: Hash[Symbol, untyped],
|
6
|
+
defaults: Hash[Symbol, untyped]
|
7
|
+
}
|
8
|
+
def parse: (?Hash[String | Symbol, untyped] data, **untyped kwargs) -> instance
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.new: () ?{ (Structure::Builder) [self: Structure::Builder] -> void } -> untyped
|
12
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: structure
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hakan Ensari
|
@@ -17,8 +17,14 @@ extra_rdoc_files: []
|
|
17
17
|
files:
|
18
18
|
- lib/structure.rb
|
19
19
|
- lib/structure/builder.rb
|
20
|
+
- lib/structure/rbs.rb
|
20
21
|
- lib/structure/types.rb
|
21
22
|
- lib/structure/version.rb
|
23
|
+
- sig/structure.rbs
|
24
|
+
- sig/structure/builder.rbs
|
25
|
+
- sig/structure/rbs.rbs
|
26
|
+
- sig/structure/types.rbs
|
27
|
+
- sig/structure/version.rbs
|
22
28
|
licenses:
|
23
29
|
- MIT
|
24
30
|
metadata:
|