decode 0.24.3 → 0.24.4

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/bake/decode/rbs.rb +1 -1
  4. data/context/coverage.md +1 -1
  5. data/context/getting-started.md +1 -1
  6. data/context/ruby-documentation.md +3 -3
  7. data/context/types.md +127 -0
  8. data/lib/decode/comment/attribute.rb +4 -1
  9. data/lib/decode/comment/constant.rb +47 -0
  10. data/lib/decode/comment/node.rb +32 -12
  11. data/lib/decode/comment/option.rb +1 -1
  12. data/lib/decode/comment/parameter.rb +5 -1
  13. data/lib/decode/comment/rbs.rb +8 -8
  14. data/lib/decode/comment/tag.rb +13 -1
  15. data/lib/decode/comment/tags.rb +16 -5
  16. data/lib/decode/comment/text.rb +1 -0
  17. data/lib/decode/comment/yields.rb +5 -1
  18. data/lib/decode/definition.rb +33 -31
  19. data/lib/decode/documentation.rb +10 -5
  20. data/lib/decode/index.rb +12 -7
  21. data/lib/decode/language/generic.rb +10 -1
  22. data/lib/decode/language/reference.rb +7 -4
  23. data/lib/decode/language/ruby/class.rb +2 -2
  24. data/lib/decode/language/ruby/code.rb +21 -3
  25. data/lib/decode/language/ruby/definition.rb +15 -3
  26. data/lib/decode/language/ruby/generic.rb +2 -1
  27. data/lib/decode/language/ruby/parser.rb +132 -91
  28. data/lib/decode/language/ruby/reference.rb +4 -1
  29. data/lib/decode/language/ruby/segment.rb +2 -2
  30. data/lib/decode/languages.rb +29 -8
  31. data/lib/decode/location.rb +12 -1
  32. data/lib/decode/rbs/class.rb +91 -14
  33. data/lib/decode/rbs/generator.rb +67 -11
  34. data/lib/decode/rbs/method.rb +394 -68
  35. data/lib/decode/rbs/module.rb +81 -5
  36. data/lib/decode/rbs/type.rb +51 -0
  37. data/lib/decode/rbs/wrapper.rb +10 -3
  38. data/lib/decode/scope.rb +2 -2
  39. data/lib/decode/segment.rb +3 -2
  40. data/lib/decode/source.rb +5 -14
  41. data/lib/decode/syntax/rewriter.rb +4 -1
  42. data/lib/decode/trie.rb +29 -21
  43. data/lib/decode/version.rb +2 -1
  44. data/readme.md +6 -0
  45. data/releases.md +6 -0
  46. data/sig/decode.rbs +501 -113
  47. data.tar.gz.sig +0 -0
  48. metadata +4 -1
  49. metadata.gz.sig +0 -0
@@ -19,15 +19,15 @@ module Decode
19
19
  end
20
20
 
21
21
  # Extract generic type parameters from the class definition.
22
- # @returns [Array] The generic type parameters for this class.
22
+ # @returns [Array[Symbol]] The generic type parameters for this class.
23
23
  def generics
24
24
  @generics ||= extract_generics
25
25
  end
26
26
 
27
27
  # Convert the class definition to RBS AST
28
- def to_rbs_ast(method_definitions = [], index = nil)
28
+ def to_rbs_ast(method_definitions = [], constant_definitions = [], attribute_definitions = [], index = nil)
29
29
  name = simple_name_to_rbs(@definition.name)
30
- comment = extract_comment(@definition)
30
+ comment = self.comment
31
31
 
32
32
  # Extract generics from RBS tags
33
33
  type_params = generics.map do |generic|
@@ -39,24 +39,30 @@ module Decode
39
39
  )
40
40
  end
41
41
 
42
- # Build method definitions
42
+ # Build method definitions:
43
43
  methods = method_definitions.map{|method_def| Method.new(method_def).to_rbs_ast(index)}.compact
44
44
 
45
- # Extract super class if present
45
+ # Build constant definitions:
46
+ constants = constant_definitions.map{|const_def| build_constant_rbs(const_def)}.compact
47
+
48
+ # Build attribute definitions and infer instance variable types:
49
+ attributes, instance_variables = build_attributes_rbs(attribute_definitions)
50
+
51
+ # Extract super class if present:
46
52
  super_class = if @definition.super_class
47
53
  ::RBS::AST::Declarations::Class::Super.new(
48
- name: qualified_name_to_rbs(@definition.super_class),
49
- args: [],
50
- location: nil
51
- )
54
+ name: qualified_name_to_rbs(@definition.super_class),
55
+ args: [],
56
+ location: nil
57
+ )
52
58
  end
53
59
 
54
- # Create the class declaration with generics
60
+ # Create the class declaration with generics:
55
61
  ::RBS::AST::Declarations::Class.new(
56
62
  name: name,
57
63
  type_params: type_params,
58
64
  super_class: super_class,
59
- members: methods,
65
+ members: constants + attributes + instance_variables + methods,
60
66
  annotations: [],
61
67
  location: nil,
62
68
  comment: comment
@@ -69,18 +75,89 @@ module Decode
69
75
  tags.select(&:generic?).map(&:generic_parameter)
70
76
  end
71
77
 
72
- # Convert a simple name to RBS TypeName (not qualified)
78
+ # Build a constant RBS declaration.
79
+ def build_constant_rbs(constant_definition)
80
+ # Look for @constant tags in the constant's documentation:
81
+ documentation = constant_definition.documentation
82
+ constant_tags = documentation&.filter(Decode::Comment::Constant)&.to_a
83
+
84
+ if constant_tags&.any?
85
+ type_string = constant_tags.first.type.strip
86
+ type = ::Decode::RBS::Type.parse(type_string)
87
+
88
+ ::RBS::AST::Declarations::Constant.new(
89
+ name: constant_definition.name.to_sym,
90
+ type: type,
91
+ location: nil,
92
+ comment: nil
93
+ )
94
+ end
95
+ end
96
+
97
+ # Convert a simple name to RBS TypeName (not qualified).
73
98
  def simple_name_to_rbs(name)
74
99
  ::RBS::TypeName.new(name: name.to_sym, namespace: ::RBS::Namespace.empty)
75
100
  end
76
101
 
102
+ # Build attribute RBS declarations and infer instance variable types.
103
+ # @parameter attribute_definitions [Array] Array of Attribute definition objects
104
+ # @returns [Array] A tuple of [attribute_declarations, instance_variable_declarations]
105
+ def build_attributes_rbs(attribute_definitions)
106
+ attributes = []
107
+ instance_variables = []
108
+
109
+ # Create a mapping from attribute names to their types:
110
+ attribute_types = {}
111
+
112
+ attribute_definitions.each do |attr_def|
113
+ # Extract @attribute type annotation from documentation:
114
+ documentation = attr_def.documentation
115
+ attribute_tags = documentation&.filter(Decode::Comment::Attribute)&.to_a
116
+
117
+ if attribute_tags&.any?
118
+ type_string = attribute_tags.first.type.strip
119
+ type = ::Decode::RBS::Type.parse(type_string)
120
+
121
+ attribute_types[attr_def.name] = type
122
+
123
+ # Generate attr_reader RBS declaration:
124
+ attributes << ::RBS::AST::Members::AttrReader.new(
125
+ name: attr_def.name.to_sym,
126
+ type: type,
127
+ ivar_name: :"@#{attr_def.name}",
128
+ kind: :instance,
129
+ annotations: [],
130
+ location: nil,
131
+ comment: nil
132
+ )
133
+
134
+ # Generate instance variable declaration:
135
+ instance_variables << ::RBS::AST::Members::InstanceVariable.new(
136
+ name: :"@#{attr_def.name}",
137
+ type: type,
138
+ location: nil,
139
+ comment: nil
140
+ )
141
+ end
142
+ end
143
+
144
+ [attributes, instance_variables]
145
+ end
146
+
77
147
  # Convert a qualified name to RBS TypeName
78
148
  def qualified_name_to_rbs(qualified_name)
79
149
  parts = qualified_name.split("::")
80
150
  name = parts.pop
81
- namespace = ::RBS::Namespace.new(path: parts.map(&:to_sym), absolute: true)
82
151
 
83
- ::RBS::TypeName.new(name: name.to_sym, namespace: namespace)
152
+ # For simple names (no ::), create relative references within current namespace:
153
+ if parts.empty?
154
+ ::RBS::TypeName.new(name: name.to_sym, namespace: ::RBS::Namespace.empty)
155
+ else
156
+ # For qualified names within the same root namespace, use relative references.
157
+ # This handles cases like `Comment::Node`, `Language::Generic` within `Decode` module.
158
+ namespace = ::RBS::Namespace.new(path: parts.map(&:to_sym), absolute: false)
159
+ ::RBS::TypeName.new(name: name.to_sym, namespace: namespace)
160
+ end
84
161
  end
85
162
 
86
163
  end
@@ -14,19 +14,30 @@ module Decode
14
14
  class Generator
15
15
  # Initialize a new RBS generator.
16
16
  # Sets up the RBS environment for type resolution.
17
- def initialize
17
+ # @parameter include_private [bool] Whether to include private methods in RBS output.
18
+ def initialize(include_private: false)
18
19
  # Set up RBS environment for type resolution
19
20
  @loader = ::RBS::EnvironmentLoader.new()
20
21
  @environment = ::RBS::Environment.from_loader(@loader).resolve_type_names
22
+ @include_private = include_private
21
23
  end
22
24
 
25
+ # @attribute [::RBS::EnvironmentLoader] The RBS environment loader.
26
+ attr :loader
27
+
28
+ # @attribute [::RBS::Environment] The resolved RBS environment.
29
+ attr :environment
30
+
31
+ # @attribute [bool] Whether to include private methods.
32
+ attr :include_private
33
+
23
34
  # Generate RBS declarations for the given index.
24
35
  # @parameter index [Decode::Index] The index containing definitions to generate RBS for.
25
36
  # @parameter output [IO] The output stream to write to.
26
37
  def generate(index, output: $stdout)
27
38
  # Build nested RBS AST structure using a hash for proper ||= behavior
28
- declarations = {}
29
- roots = {}
39
+ declarations = {} #: Hash[Array[Symbol], untyped]
40
+ roots = {} #: Hash[Array[Symbol], untyped]
30
41
 
31
42
  # Efficiently traverse the trie to find containers and their methods
32
43
  index.trie.traverse do |lexical_path, node, descend|
@@ -58,8 +69,10 @@ module Decode
58
69
  private
59
70
 
60
71
  # Build nested RBS declarations preserving the parent hierarchy.
61
- # @returns [::RBS::AST::Declarations::Class | ::RBS::AST::Declarations::Module] If the definition has no parent, returns the declaration.
62
- # @returns [Nil] If the definition has a parent, adds to parent's members.
72
+ # @parameter definition [Definition] The definition to build RBS for.
73
+ # @parameter declarations [Hash] The declarations hash to store results.
74
+ # @parameter index [Index] The index containing all definitions.
75
+ # @returns [untyped?] If the definition has no parent, returns the declaration, otherwise nil.
63
76
  def build_nested_declaration(definition, declarations, index)
64
77
  # Create the declaration for this definition using ||= to avoid duplicates
65
78
  qualified_name = definition.qualified_name
@@ -81,22 +94,65 @@ module Decode
81
94
  end
82
95
  end
83
96
 
84
- # Convert a definition to RBS AST
97
+ # Convert a definition to RBS AST.
98
+ # @parameter definition [Definition] The definition to convert.
99
+ # @parameter index [Index] The index containing all definitions.
100
+ # @returns [untyped] The RBS AST declaration.
85
101
  def definition_to_rbs(definition, index)
102
+ methods = get_methods_for_definition(definition, index)
103
+ constants = get_constants_for_definition(definition, index)
104
+ attributes = get_attributes_for_definition(definition, index)
105
+
86
106
  case definition
87
107
  when Decode::Language::Ruby::Class
88
- Class.new(definition).to_rbs_ast(get_methods_for_definition(definition, index), index)
108
+ Class.new(definition).to_rbs_ast(methods, constants, attributes, index)
89
109
  when Decode::Language::Ruby::Module
90
- Module.new(definition).to_rbs_ast(get_methods_for_definition(definition, index), index)
110
+ Module.new(definition).to_rbs_ast(methods, constants, attributes, index)
91
111
  end
92
112
  end
93
113
 
94
- # Get methods for a given definition efficiently using trie lookup
114
+ # Get methods for a given definition efficiently using trie lookup.
115
+ # @parameter definition [Definition] The definition to get methods for.
116
+ # @parameter index [Index] The index containing all definitions.
117
+ # @returns [Array] Array of method definitions.
95
118
  def get_methods_for_definition(definition, index)
96
119
  # Use the trie to efficiently find methods for this definition
97
120
  if node = index.trie.lookup(definition.full_path)
98
121
  node.children.flat_map do |name, child|
99
- child.values.select{|symbol| symbol.is_a?(Decode::Language::Ruby::Method) && symbol.public?}
122
+ child.values.select do |symbol|
123
+ symbol.is_a?(Decode::Language::Ruby::Method) &&
124
+ (symbol.public? || symbol.protected? || (@include_private && symbol.private?))
125
+ end
126
+ end
127
+ else
128
+ []
129
+ end
130
+ end
131
+
132
+ # Get constants for a given definition efficiently using trie lookup.
133
+ # @parameter definition [Definition] The definition to get constants for.
134
+ # @parameter index [Index] The index containing all definitions.
135
+ # @returns [Array] Array of constant definitions.
136
+ def get_constants_for_definition(definition, index)
137
+ # Use the trie to efficiently find constants for this definition
138
+ if node = index.trie.lookup(definition.full_path)
139
+ node.children.flat_map do |name, child|
140
+ child.values.select{|symbol| symbol.is_a?(Decode::Language::Ruby::Constant)}
141
+ end
142
+ else
143
+ []
144
+ end
145
+ end
146
+
147
+ # Get attributes for a given definition efficiently using trie lookup.
148
+ # @parameter definition [Definition] The definition to get attributes for.
149
+ # @parameter index [Index] The index containing all definitions.
150
+ # @returns [Array] Array of attribute definitions.
151
+ def get_attributes_for_definition(definition, index)
152
+ # Use the trie to efficiently find attributes for this definition
153
+ if node = index.trie.lookup(definition.full_path)
154
+ node.children.flat_map do |name, child|
155
+ child.values.select{|symbol| symbol.is_a?(Decode::Language::Ruby::Attribute)}
100
156
  end
101
157
  else
102
158
  []
@@ -104,4 +160,4 @@ module Decode
104
160
  end
105
161
  end
106
162
  end
107
- end
163
+ end