Last active
August 3, 2023 20:15
-
-
Save dhnaranjo/0fcd50eca2c57010421df370f96acbc8 to your computer and use it in GitHub Desktop.
A cute AI-powered junior engineer to maybe do something useful.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Required gems: | |
# - asimov | |
# - fast_ignore | |
class RoboJunior | |
def get_to_work | |
puts(changes) | |
Changer.new.change_stuff(changes) | |
end | |
def changes | |
@changes ||= Asker.new.chat(Teller.new.content) | |
end | |
# If you wanna paste it into the web interface. | |
def changes_to_clipboard | |
IO.popen("pbcopy", "w") { |f| f << teller.content } | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Asker | |
def chat(content) | |
response = request(content) | |
reply(response) | |
end | |
private | |
def request(content) | |
client.chat.create_completions( | |
model: model, | |
messages: [ | |
{role: "user", content: content} | |
] | |
) | |
end | |
def reply(response) | |
response["choices"].first.dig("message", "content") | |
end | |
def model | |
"gpt-3.5-turbo" | |
end | |
def client | |
@openai_client ||= Asimov::Client.new( | |
api_key: ENV["OPENAI_API_KEY"], | |
request_options: { | |
timeout: 300 | |
} | |
) | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Changer | |
def change_stuff(changes) | |
changes | |
.split("----") | |
.compact_blank | |
.map(&:strip) | |
.map { |change| write_change(change) } | |
end | |
def write_change(change) | |
relative_path = change.lines[0].strip | |
file_path = File.join(repo_root, relative_path) | |
content = change.lines[1..].join | |
FileUtils.mkdir_p(File.dirname(file_path)) | |
File.write(file_path, content) | |
rescue => e | |
puts(e) | |
puts(e.message) | |
binding.break | |
end | |
def repo_root | |
Rails.root | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Teller | |
INCLUDE_RULES = <<~INCLUDE_FILES | |
app/models/**/*.rb | |
test/models/**/*_test.rb | |
Gemfile | |
INCLUDE_FILES | |
def content | |
instructions + files_string | |
end | |
def files_string | |
files_contents.join("\n") | |
end | |
def instructions | |
<<~INSTRUCTIONS | |
I want you to act as a full stack developer working in Ruby on Rails verson 7.0 and Ruby 3.2. | |
I will provide a codebase with a number of TODOs for you to complete. | |
#{todo_completion} | |
#{model_creation} | |
#{test_creation} | |
#{general_guidelines} | |
#{reply_formatting} | |
INSTRUCTIONS | |
end | |
def reply_formatting | |
<<~REPLY_FORMATTING | |
When replying to this message, please format your response as follows: | |
- Include any files you created or modified | |
- Do not include any files you did not create or modify | |
- Prepend each file with `----` on a line by itself | |
- Prepend each file with the file path on a line by itself | |
- Do not include any other text in your response | |
REPLY_FORMATTING | |
end | |
def general_guidelines | |
<<~GENERAL_GUIDELINES | |
Also, please follow these general guidelines: | |
- Do not use any gems that are not already in the codebase | |
- Do not make any changes to the codebase that are not required to complete a TODO | |
GENERAL_GUIDELINES | |
end | |
def todo_completion | |
<<~TODO_COMPLETION | |
When completing a TODO you must: | |
- Complete the TODO | |
- Write a test to ensure the TODO is completed | |
- Remove the completed TODO from the codebase | |
TODO_COMPLETION | |
end | |
def model_creation | |
<<~MODEL_CREATION | |
When creating a model you must: | |
- Create a migration | |
- Create a model | |
- Create a factory | |
- Create a test | |
- All attributes should be required unless specified as optional | |
- All associations should be defined with `inverse_of: :<association>` | |
- All has_many associations should be defined with `dependent: :destroy` | |
- Only one model should be created per TODO | |
MODEL_CREATION | |
end | |
def test_creation | |
<<~TEST_CREATION | |
When creating a test you must: | |
- Use FactoryBot to create test data | |
- Use Faker to generate test data | |
- Use MiniTest assertions | |
- Use Shoulda Matchers to test validations and associations | |
TEST_CREATION | |
end | |
def files_contents | |
non_ignored_file_paths.map { |file_path| prepare_file(file_path) } | |
end | |
def prepare_file(file_path) | |
contents = File.read(file_path) | |
relative_path = file_path.relative_path_from(repo_root) | |
<<~FILE | |
---- | |
#{relative_path} | |
#{contents} | |
FILE | |
end | |
def non_ignored_file_paths | |
FastIgnore | |
.new(include_rules: INCLUDE_RULES) | |
.map { Pathname(_1) } | |
end | |
def repo_root | |
Rails.root | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment