Upgrade to Pro — share decks privately, control downloads, hide ads and more …

API for docs

API for docs

RubyKaigi 2025, Matsuyama, Ehime

Soutaro Matsumoto

April 18, 2025
Tweet

More Decks by Soutaro Matsumoto

Other Decks in Programming

Transcript

  1. Soutaro Matsumoto • Ruby committer working for RBS/ Steep •

    Working at Timee • Started writing a series of articles for ιϑτ΢ΣΞσβΠϯ New
  2. Soutaro Matsumoto • Ruby committer working for RBS/ Steep •

    Working at Timee • Started writing a series of articles for ιϑτ΢ΣΞσβΠϯ New
  3. Steep & RBS updates • RBS 3.4 (RubyKaigi 2024) →

    3.9 • Steep 1.6 (RubyKaigi 2024) → 1.10
  4. Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 steep:ignore

    annotation steep-1.7 Better project organization steep-1.9
  5. Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation

    annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9
  6. Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation

    annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork
  7. Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation

    annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork Receiver type narrowing steep-1.10
  8. Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation

    annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork Receiver type narrowing steep-1.10
  9. Generics with default types rbs-3.6 resolve-type-names magic comment rbs-3.9 Deprecation

    annotation rbs-3.9, steep-1.10 steep:ignore annotation steep-1.7 Better project organization steep-1.9 Memory footprint improvement steep-1.9 $ steep langserver --refork Receiver type narrowing steep-1.10
  10. Inline RBS declaration • Not yet... 🙇 • Working for

    RBS 4.0/Steep 2.0 with the feature • They will support inline RBS declaration directly, without rbs-inline gem
  11. Documentation helper in Steep • Steep helps reading docs associated

    to the Ruby program components -- classes/modules/methods/interfaces/constants • Hover • Completion • Signature Help
  12. This is API • These features are implemented on the

    top of API that looks up docs with classes/modules/methods RBS fi les Internal data structure API Language Server
  13. What is RDoc? ## # Creates a new shape described

    by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end The syntax to annotate Ruby code
  14. What is RDoc? ## # Creates a new shape described

    by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end The syntax to annotate Ruby code The generated HTML fi les
  15. What is RDoc? ## # Creates a new shape described

    by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end The syntax to annotate Ruby code The generated HTML fi les The internal structure
  16. ## # Creates a new shape described by a +polyline+.

    # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end Input Internal structure Output RBS fi les
  17. ## # Creates a new shape described by a +polyline+.

    # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end Input Internal structure Output RBS fi les
  18. RBS/Steep Implementation 1. The AST 2. The parser 3. The

    environment 4. The type checker 5. Displaying the docs RBS RBS RBS Steep Steep
  19. The environment • Environment stores all of the RBS declarations

    • Definition is the data structure that has methods and variables of a class/module
  20. The environment • Environment stores all of the RBS declarations

    • Definition is the data structure that has methods and variables of a class/module
  21. The environment • Environment stores all of the RBS declarations

    • Definition is the data structure that has methods and variables of a class/module
  22. The environment • Environment stores all of the RBS declarations

    • Definition is the data structure that has methods and variables of a class/module
  23. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  24. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  25. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  26. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  27. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  28. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  29. Type checker • The type checker identi fi es the

    type of each Ruby node • It also detects which method overload is called by a send node s = String.new() s.encoding
  30. Displaying the docs { "method": "document/hover", "id": 1, "params": {

    "textDocument": { uri: "file://..." }, "position": { "line": 10, "character": 20 } } } Language server { "id": 1, "result": { "contents": "## 📚 String#encoding\n\nReturns the encoding" } } 1. Find the Ruby node associated at the position 2. Fetch the docs for the node 3. Format the docs for LSP
  31. Index • Introducing an index would solve the problem •

    RBS docs are registered to the index • The language server pulls the docs from the index using identi fi ers • The index may be reused after server restart Index Language server Query the docs by identi fi ers
  32. Overload identi fi er • With line number of the

    overload? • Foo#foo@a.rbs:4 • Foo#foo@b.rbs:4
  33. Overload identi fi er • With line number of the

    overload? • Foo#foo@a.rbs:4 • Foo#foo@b.rbs:4
  34. Overload identi fi er • With line number of the

    overload? • Foo#foo@a.rbs:4 • Foo#foo@b.rbs:4
  35. Overload identi fi er • The line number may change

    after comment update 😫 • Foo#foo@a.rbs:4 • Foo#foo@b.rbs:4
  36. Overload identi fi er • The line number may change

    after comment update 😫 • Foo#foo@a.rbs:4 • Foo#foo@b.rbs:4
  37. Overload identi fi er • The line number may change

    after comment update 😫 • Foo#foo@a.rbs:4 • Foo#foo@b.rbs:4
  38. Overload identi fi er • With the index of the

    overload? • Foo#foo@0 • Foo#foo@1 • Overloads added with ... comes fi rst
  39. Overload identi fi er • With the index of the

    overload? • Foo#foo@0 • Foo#foo@1 • Overloads added with ... comes fi rst
  40. Overload identi fi er • With the index of the

    overload? • Foo#foo@0 • Foo#foo@1 • Overloads added with ... comes fi rst
  41. Overload identi fi er • The fi le loading order

    is unspeci fi ed • Foo#foo@0 • Foo#foo@1 • Foo#foo@2 • (Foo#foo@2 always points to String case)
  42. Overload identi fi er • The fi le loading order

    is unspeci fi ed • Foo#foo@0 • Foo#foo@1 • Foo#foo@2 • (Foo#foo@2 always points to String case)
  43. Overload identi fi er • The fi le loading order

    is unspeci fi ed • Foo#foo@0 • Foo#foo@1 • Foo#foo@2 • (Foo#foo@2 always points to String case)
  44. JVM method descriptor • JVM method name contains parameter types

    and return type hello(Ljava/lang/String;I)Ljava/lang/String; String hello(String s, int i)
  45. Method name normalization • Let's call it MethodType#normalize • Implementation

    agnostic • Stable after restarts (String name, id: ::Integer, email: String?) -> void (String, email: String?, id: Integer) -> void
  46. Method name normalization • Let's call it MethodType#normalize • Implementation

    agnostic • Stable after restarts (String name, id: ::Integer, email: String?) -> void (String, email: String?, id: Integer) -> void Drop parameter names
  47. Method name normalization • Let's call it MethodType#normalize • Implementation

    agnostic • Stable after restarts (String name, id: ::Integer, email: String?) -> void (String, email: String?, id: Integer) -> void Drop parameter names Sort keyword args
  48. Can it be universal? • Making the index from other

    gems would be great idea • RDoc/YARD makes the index with their docs • Steep/ruby-lsp can use the index for their documentation features ## # Creates a new shape described by a +polyline+. # # If the +polyline+ does not end at the same point it started at the # first pointed is copied and placed at the end of the line. # # An ArgumentError is raised if the line crosses itself, but shapes may # be concave. def initialize polyline # ... end Input Universal index Output RBS fi les
  49. Index content • Discussed the key of the index; assume

    we have a solution • How can we de fi ne the content of the index? • A data structure that can be shared with RBS/Steep, RDoc, YARD, which keeps the contents of all of them? • How about go-to-de fi nition?
  50. Summary • The documentation needs APIs because it's used by

    IDE/editors to help programming • Steep already has implementation, but it is tightly coupled with type checker and causing problems • I plan to implement a doc system API (index) • The index may help other tools too (but I'm not sure if it's a good idea)