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

API for docs

API for docs

RubyKaigi 2025, Matsuyama, Ehime

Avatar for Soutaro Matsumoto

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)