structure 4.0.0 → 4.1.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/rbs.rb +42 -22
- data/lib/structure/version.rb +1 -1
- data/lib/structure.rb +16 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74f52e94d4ffd40ad55e291a4ab72c108af572be936ee2d1571fef47699af2cb
|
4
|
+
data.tar.gz: d2ef8dee35e2ea236237d1c34c68bc6877039145553f7e1b16729ea84e3778c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0c4192ddde552c7cd4a583aca9bdad31aeb64dc039680e965944696ee7648cc9a423017ab8cea5546c708ae72b7920c21fb2c96e74442932f24a3a85faa6b81
|
7
|
+
data.tar.gz: 03d4ea5fda959cd3bcd60b79a323b8dbfaeb5792c22b809179b7f84f76aab36845e7dbcd2f30567cf7922eea9995997cfb730cd69e8dd726cebded2bd076f540
|
data/lib/structure/rbs.rb
CHANGED
@@ -4,6 +4,10 @@ require "fileutils"
|
|
4
4
|
require "pathname"
|
5
5
|
|
6
6
|
module Structure
|
7
|
+
# Generates RBS type signatures for Structure classes
|
8
|
+
#
|
9
|
+
# Note: Custom methods defined in Structure blocks are not included and must be manually added to RBS files. This is
|
10
|
+
# consistent with how Ruby's RBS tooling handles Data classes.
|
7
11
|
module RBS
|
8
12
|
class << self
|
9
13
|
def emit(klass)
|
@@ -63,50 +67,66 @@ module Structure
|
|
63
67
|
[attr, rbs_type != "untyped" ? "#{rbs_type}?" : rbs_type]
|
64
68
|
end.to_h
|
65
69
|
|
66
|
-
#
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
70
|
+
# Sort keyword params: required first, then optional (with ? prefix)
|
71
|
+
# Within each group, maintain declaration order
|
72
|
+
required_params = required.map { |attr| "#{attr}: #{rbs_types[attr]}" }
|
73
|
+
optional_params = (attributes - required).map { |attr| "?#{attr}: #{rbs_types[attr]}" }
|
74
|
+
keyword_params = (required_params + optional_params).join(", ")
|
71
75
|
positional_params = attributes.map { |attr| rbs_types[attr] }.join(", ")
|
72
76
|
|
73
|
-
lines << " def self.new: (#{keyword_params}) -> #{class_name}"
|
74
|
-
lines << " | (#{positional_params}) -> #{class_name}"
|
75
|
-
lines << ""
|
76
|
-
|
77
77
|
needs_parse_data = types.any? do |_attr, type|
|
78
78
|
type == :self || type == [:self]
|
79
79
|
end
|
80
80
|
|
81
|
+
# Generate type alias first if needed (RBS::Sorter puts types at top)
|
81
82
|
if needs_parse_data
|
82
|
-
lines << " type parse_data = {"
|
83
|
-
attributes.each do |attr|
|
83
|
+
lines << " type parse_data = { " + attributes.map { |attr|
|
84
84
|
type = types.fetch(attr, nil)
|
85
85
|
parse_type = parse_data_type(type, class_name)
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
86
|
+
"?#{attr}: #{parse_type}"
|
87
|
+
}.join(", ") + " }"
|
88
|
+
end
|
89
|
+
|
90
|
+
lines << " def self.new: (#{keyword_params}) -> #{class_name}"
|
91
|
+
lines << " | (#{positional_params}) -> #{class_name}"
|
92
|
+
lines << ""
|
93
|
+
lines << " def self.[]: (#{keyword_params}) -> #{class_name}"
|
94
|
+
lines << " | (#{positional_params}) -> #{class_name}"
|
95
|
+
lines << ""
|
96
|
+
|
97
|
+
# Generate members tuple type
|
98
|
+
members_tuple = attributes.map { |attr| ":#{attr}" }.join(", ")
|
99
|
+
lines << " def self.members: () -> [ #{members_tuple} ]"
|
100
|
+
lines << ""
|
101
|
+
|
102
|
+
# Generate parse method signatures
|
103
|
+
if needs_parse_data
|
91
104
|
lines << " def self.parse: (?parse_data data) -> #{class_name}"
|
92
105
|
lines << " | (?Hash[String, untyped] data) -> #{class_name}"
|
93
106
|
else
|
94
|
-
#
|
95
|
-
lines << " def self.parse: (?
|
107
|
+
# Remove optional parentheses to match RBS::Sorter style
|
108
|
+
lines << " def self.parse: (?Hash[String | Symbol, untyped], **untyped) -> #{class_name}"
|
96
109
|
end
|
97
110
|
lines << ""
|
98
111
|
|
99
|
-
|
112
|
+
# Sort attr_reader lines alphabetically (RBS::Sorter does this)
|
113
|
+
attributes.sort.each do |attr|
|
100
114
|
lines << " attr_reader #{attr}: #{rbs_types[attr]}"
|
101
115
|
end
|
102
|
-
lines << ""
|
103
116
|
|
104
|
-
|
105
|
-
|
117
|
+
# Add boolean predicates
|
118
|
+
boolean_predicates = types.sort.select { |attr, type| type == :boolean && !attr.to_s.end_with?("?") }
|
119
|
+
unless boolean_predicates.empty?
|
120
|
+
lines << ""
|
121
|
+
boolean_predicates.each do |attr, _type|
|
106
122
|
lines << " def #{attr}?: () -> bool"
|
107
123
|
end
|
108
124
|
end
|
109
125
|
|
126
|
+
# Instance members method comes after attr_readers and predicates
|
127
|
+
lines << " def members: () -> [ #{members_tuple} ]"
|
128
|
+
lines << ""
|
129
|
+
|
110
130
|
hash_type = attributes.map { |attr| "#{attr}: #{rbs_types[attr]}" }.join(", ")
|
111
131
|
lines << " def to_h: () -> { #{hash_type} }"
|
112
132
|
end
|
data/lib/structure/version.rb
CHANGED
data/lib/structure.rb
CHANGED
@@ -26,6 +26,22 @@ module Structure
|
|
26
26
|
# @type var klass: untyped
|
27
27
|
klass = Data.define(*builder.attributes)
|
28
28
|
|
29
|
+
# Enable custom method definitions by evaluating block on the class
|
30
|
+
if block
|
31
|
+
# Provide temporary dummy DSL methods to prevent NoMethodError during class_eval
|
32
|
+
klass.define_singleton_method(:attribute) { |*args, **kwargs, &blk| }
|
33
|
+
klass.define_singleton_method(:attribute?) { |*args, **kwargs, &blk| }
|
34
|
+
klass.define_singleton_method(:after_parse) { |&blk| }
|
35
|
+
|
36
|
+
# Evaluate block in class context for method definitions
|
37
|
+
klass.class_eval(&block)
|
38
|
+
|
39
|
+
# Remove temporary DSL methods
|
40
|
+
klass.singleton_class.send(:remove_method, :attribute)
|
41
|
+
klass.singleton_class.send(:remove_method, :attribute?)
|
42
|
+
klass.singleton_class.send(:remove_method, :after_parse)
|
43
|
+
end
|
44
|
+
|
29
45
|
# Override initialize to make optional attributes truly optional
|
30
46
|
optional_attrs = builder.optional
|
31
47
|
unless optional_attrs.empty?
|