Skip to content

Commit

Permalink
Add refactor to write RBS
Browse files Browse the repository at this point in the history
  • Loading branch information
stevegeek committed Nov 2, 2023
1 parent 928f8aa commit efa7add
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
17 changes: 17 additions & 0 deletions examples/ex2_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# example from https://blog.kiprosh.com/type-checking-in-ruby-3-using-rbs/
# basic_math.rb

class BasicMath
def initialize(num1, num2)
@num1 = num1
@num2 = num2
end

def first_less_than_second?
@num1 < @num2
end

def add
@num1 + @num2
end
end
7 changes: 7 additions & 0 deletions examples/ex2_write_rbs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
refactor: ruby/write_rbs
input_file_paths:
- examples/ex2_input.rb
# We need to add context here as our class doesnt actually give any context.
context_text: "Assume that the inputs can be any numeric type."
# By default this refactor writes to `sig/...` but here we just put the result in `examples/...`
output_file_path: examples/outputs/ex2_input.rbs
62 changes: 62 additions & 0 deletions lib/ai_refactor/refactors/ruby/write_rbs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
You are an expert Ruby senior software developer.

You will be writing the type signatures for the Ruby code below, in RBS format.

RBS is a language to describe the structure of Ruby programs. You can write down the definition of a class or module: methods defined in the class, instance variables and their types, and inheritance/mix-in relations. It also allows declaring constants and global variables.

The following is a small example of RBS for a chat app.

```
module ChatApp
VERSION: String
class User
attr_reader login: String
attr_reader email: String
def initialize: (login: String, email: String) -> void
end
class Bot
attr_reader name: String
attr_reader email: String
attr_reader owner: User
def initialize: (name: String, owner: User) -> void
end
class Message
attr_reader id: String
attr_reader string: String
attr_reader from: User | Bot # `|` means union types: `#from` can be `User` or `Bot`
attr_reader reply_to: Message? # `?` means optional type: `#reply_to` can be `nil`
def initialize: (from: User | Bot, string: String) -> void
def reply: (from: User | Bot, string: String) -> Message
end
class Channel
attr_reader name: String
attr_reader messages: Array[Message]
attr_reader users: Array[User]
attr_reader bots: Array[Bot]
def initialize: (name: String) -> void
def each_member: () { (User | Bot) -> void } -> void # `{` and `}` means block.
| () -> Enumerator[User | Bot, void] # Method can be overloaded.
end
end
```

Do not include comments in your RBS code.

__{{context}}__

__{{prompt_header}}__

The input file is: __{{input_file_path}}__
The output file path is: __{{output_file_path}}__

__{{prompt_footer}}__
33 changes: 33 additions & 0 deletions lib/ai_refactor/refactors/ruby/write_rbs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# frozen_string_literal: true

module AIRefactor
module Refactors
module Ruby
class WriteRbs < BaseRefactor
def run
logger.verbose "Write some RBS for #{input_file}..."
logger.verbose "Write output to #{output_file_path}..." if output_file_path

begin
output_content = process!(strip_ticks: true)
rescue => e
logger.error "Failed to process #{input_file}: #{e.message}"
return false
end

return false unless output_content

output_file_path ? true : output_content
end

def self.description
"User supplied prompt to write RBS for some Ruby"
end

def default_output_path
File.join("sig", input_file.gsub(/\.rb$/, ".rbs"))
end
end
end
end
end

0 comments on commit efa7add

Please sign in to comment.