ai_refactor 0.5.2 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +30 -0
- data/Gemfile +1 -1
- data/README.md +11 -4
- data/Steepfile +27 -0
- data/ai_refactor.gemspec +1 -1
- data/commands/quickdraw/0.1.0/convert_minitest.yml +194 -0
- data/examples/ex1_convert_a_rspec_test_to_minitest.yml +2 -1
- data/examples/ex2_input.rb +17 -0
- data/examples/ex2_write_rbs.yml +7 -0
- data/exe/ai_refactor +11 -11
- data/lib/ai_refactor/cli.rb +3 -0
- data/lib/ai_refactor/commands.rb +41 -0
- data/lib/ai_refactor/file_processor.rb +1 -1
- data/lib/ai_refactor/prompt.rb +1 -1
- data/lib/ai_refactor/refactors/base_refactor.rb +37 -13
- data/lib/ai_refactor/refactors/custom.rb +2 -1
- data/lib/ai_refactor/refactors/ruby/refactor_ruby.md +0 -2
- data/lib/ai_refactor/refactors/ruby/write_rbs.md +118 -0
- data/lib/ai_refactor/refactors/ruby/write_rbs.rb +50 -0
- data/lib/ai_refactor/refactors/ruby/write_ruby.md +0 -2
- data/lib/ai_refactor/run_configuration.rb +23 -2
- data/lib/ai_refactor/test_runners/steep_runner.rb +27 -0
- data/lib/ai_refactor/test_runners/test_run_result.rb +1 -1
- data/lib/ai_refactor/version.rb +1 -1
- metadata +13 -7
- data/Gemfile.lock +0 -244
- data/examples/.gitignore +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca299458e2af2bc7ba495ce6473e1e6b1824e679893815616a209697178aefbd
|
4
|
+
data.tar.gz: b13da64462ef3f5572a9afebb0020ecdb5adc538b92e7c80b3b6bbd756473f9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5714f5535a9a6436beba5a6b33a79a0eb02c095f4ca93a5cdfd794fc231cdcab6341a87565fc8c9f32ef24e1edf35957d5268b48f259c2046f867d722520760a
|
7
|
+
data.tar.gz: d986828235c4f26ba78a443ca267455be12d2b9647b672f7cb8a4f4ce53eed5f02c426f626531a9d567058ad8f3e4a34f0c43072529820ca803719542ea0c9e0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,35 @@
|
|
1
1
|
# AI Refactor Changelog
|
2
2
|
|
3
|
+
|
4
|
+
## [0.5.4] - 2024-02-07
|
5
|
+
|
6
|
+
### Added
|
7
|
+
- Support for built-in command YML files to make it easy to add new refactors
|
8
|
+
- Support for specifying context files from gems with `context_file_paths_from_gems:` key in command templates
|
9
|
+
- Command to convert Minitest tests to Quickdraw tests
|
10
|
+
|
11
|
+
### Changes
|
12
|
+
- Default openAI model is now `gpt-4-turbo-preview`
|
13
|
+
|
14
|
+
## [0.5.3] - 2024-02-06
|
15
|
+
|
16
|
+
### Added
|
17
|
+
- Add runner to run steep on inputs after generating RBS
|
18
|
+
- Add refactor to write RBS
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
- Removed dependency on `dotenv` gems
|
22
|
+
- Update openai dependency
|
23
|
+
- Improve prompt handling to allow having custom text prompts from commands that can append to build in prompt templates
|
24
|
+
- Custom refactor should allow prompt to come from prompt text option
|
25
|
+
|
26
|
+
## [0.5.2] - 2023-09-21
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
- Removed `puts`
|
32
|
+
|
3
33
|
## [0.5.1] - 2023-09-21
|
4
34
|
|
5
35
|
### Added
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -49,8 +49,7 @@ And find the file `examples/ex1_input_test.rb` has been created. Note the proces
|
|
49
49
|
|
50
50
|
If you see an error, then try to run it again, or use a different GPT model.
|
51
51
|
|
52
|
-
|
53
|
-
## Available refactors
|
52
|
+
## Available refactors & commands
|
54
53
|
|
55
54
|
Write your own prompt:
|
56
55
|
|
@@ -107,6 +106,14 @@ For example, if the input file is `app/stuff/my_thing.rb` the output will be wri
|
|
107
106
|
This refactor can benefit from being passed related files as context, for example, if the class under test inherits from another class,
|
108
107
|
then context can be used to provide the parent class.
|
109
108
|
|
109
|
+
### `quickdraw/0.1.0/convert_minitest`
|
110
|
+
|
111
|
+
Convert Minitest or Test::Unit test suite files to [Quickdraw](https://github.com/joeldrapper/quickdraw) test suite files.
|
112
|
+
|
113
|
+
Files, by default, are output to the same directory as the input file but with .test.rb extension (and _test removed).
|
114
|
+
|
115
|
+
Note: Quickdraw is still missing some features, so some minitest methods are not converted, for example, Quickdraw does not support setup/teardown just yet.
|
116
|
+
|
110
117
|
## Installation
|
111
118
|
|
112
119
|
Install the gem and add to the application's Gemfile by executing:
|
@@ -134,7 +141,7 @@ Where REFACTOR_TYPE_OR_COMMAND_FILE is either the path to a command YML file, or
|
|
134
141
|
-p, --prompt PROMPT_FILE Specify path to a text file that contains the ChatGPT 'system' prompt.
|
135
142
|
-f, --diffs Request AI generate diffs of changes rather than writing out the whole file.
|
136
143
|
-C, --continue [MAX_MESSAGES] If ChatGPT stops generating due to the maximum token count being reached, continue to generate more messages, until a stop condition or MAX_MESSAGES. MAX_MESSAGES defaults to 3
|
137
|
-
-m, --model MODEL_NAME Specify a ChatGPT model to use (default gpt-4).
|
144
|
+
-m, --model MODEL_NAME Specify a ChatGPT model to use (default gpt-4-turbo-preview).
|
138
145
|
--temperature TEMP Specify the temperature parameter for ChatGPT (default 0.7).
|
139
146
|
--max-tokens MAX_TOKENS Specify the max number of tokens of output ChatGPT can generate. Max will depend on the size of the prompt (default 1500)
|
140
147
|
-t, --timeout SECONDS Specify the max wait time for ChatGPT response.
|
@@ -180,7 +187,7 @@ context_text: |
|
|
180
187
|
Some extra info to prepend to the prompt
|
181
188
|
diff: true/false (default false)
|
182
189
|
ai_max_attempts: max times to generate more if AI does not complete generating (default 3)
|
183
|
-
ai_model: ChatGPT model name (default gpt-4)
|
190
|
+
ai_model: ChatGPT model name (default gpt-4-turbo-preview)
|
184
191
|
ai_temperature: ChatGPT temperature (default 0.7)
|
185
192
|
ai_max_tokens: ChatGPT max tokens (default 1500)
|
186
193
|
ai_timeout: ChatGPT timeout (default 60)
|
data/Steepfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# D = Steep::Diagnostic
|
2
|
+
#
|
3
|
+
# target :lib do
|
4
|
+
# signature "sig"
|
5
|
+
#
|
6
|
+
# check "lib" # Directory name
|
7
|
+
# check "Gemfile" # File name
|
8
|
+
# check "app/models/**/*.rb" # Glob
|
9
|
+
# # ignore "lib/templates/*.rb"
|
10
|
+
#
|
11
|
+
# # library "pathname" # Standard libraries
|
12
|
+
# # library "strong_json" # Gems
|
13
|
+
#
|
14
|
+
# # configure_code_diagnostics(D::Ruby.default) # `default` diagnostics setting (applies by default)
|
15
|
+
# # configure_code_diagnostics(D::Ruby.strict) # `strict` diagnostics setting
|
16
|
+
# # configure_code_diagnostics(D::Ruby.lenient) # `lenient` diagnostics setting
|
17
|
+
# # configure_code_diagnostics(D::Ruby.silent) # `silent` diagnostics setting
|
18
|
+
# # configure_code_diagnostics do |hash| # You can setup everything yourself
|
19
|
+
# # hash[D::Ruby::NoMethod] = :information
|
20
|
+
# # end
|
21
|
+
# end
|
22
|
+
|
23
|
+
# A steep target to check our example
|
24
|
+
target :examples do
|
25
|
+
signature "examples/outputs"
|
26
|
+
check "examples/ex2_input.rb"
|
27
|
+
end
|
data/ai_refactor.gemspec
CHANGED
@@ -31,6 +31,6 @@ Gem::Specification.new do |spec|
|
|
31
31
|
# Uncomment to register a new dependency of your gem
|
32
32
|
spec.add_dependency "colorize", "< 2.0"
|
33
33
|
spec.add_dependency "open3", "< 2.0"
|
34
|
-
spec.add_dependency "ruby-openai", ">= 3.4.0", "<
|
34
|
+
spec.add_dependency "ruby-openai", ">= 3.4.0", "< 6.0"
|
35
35
|
spec.add_dependency "zeitwerk", "~> 2.6"
|
36
36
|
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# Convert Minitest or Test::Unit test suite files to Quickdraw test suite files.
|
2
|
+
#
|
3
|
+
# Files are output to the same directory as the input file but with .test.rb extension (and _test removed).
|
4
|
+
# Quickdraw is still missing some features, so some minitest methods are not converted. Also
|
5
|
+
# Quickdraw does not support setup/teardown just yet.
|
6
|
+
|
7
|
+
refactor: ruby/refactor_ruby
|
8
|
+
description: Convert Minitest or Test::Unit test suite files to Quickdraw test suite files.
|
9
|
+
output_template_path: "[DIR]/[NAME|_test|].test[EXT]"
|
10
|
+
context_file_paths_from_gems:
|
11
|
+
quickdraw:
|
12
|
+
- "lib/quickdraw/matchers/boolean.rb"
|
13
|
+
- "lib/quickdraw/matchers/case_equality.rb"
|
14
|
+
- "lib/quickdraw/matchers/change.rb"
|
15
|
+
- "lib/quickdraw/matchers/equality.rb"
|
16
|
+
- "lib/quickdraw/matchers/include.rb"
|
17
|
+
- "lib/quickdraw/matchers/predicate.rb"
|
18
|
+
- "lib/quickdraw/matchers/respond_to.rb"
|
19
|
+
- "lib/quickdraw/matchers/to_be_a.rb"
|
20
|
+
- "lib/quickdraw/matchers/to_have_attributes.rb"
|
21
|
+
prompt: |
|
22
|
+
You are an expert Ruby senior software developer. You convert minitest or Test::Unit test suite files to Quickdraw test suite files.
|
23
|
+
|
24
|
+
Quickdraw is a new test framework for Ruby:
|
25
|
+
|
26
|
+
- Spec-like DSL, but with just five methods: `describe`, `test` and `expect`, `assert`, `refute`. No `context`, `let`, `subject`, `to`, `it`, `is_expected` or `specify`, and you’ll never need to guess whether the next symbol should be a space, a colon, a dot or an underscore.
|
27
|
+
- No chaining on matchers. Rather than chain, the matcher can yield if it wants to allow for more complex matching.
|
28
|
+
- Auto-loaded configuration, so you never need to `require "test_helper"`.
|
29
|
+
- Scoped execution, so you can define methods and constants at the top level without worrying about collisions.
|
30
|
+
- You can define your own matchers, which can be scoped to a specific type of object and they can be overloaded for different types.
|
31
|
+
- Designed to take advantage of all your CPU cores — by default it runs one process per CPU core and two threads per process.
|
32
|
+
- Optional test names — sometimes the code is so clear, you don’t need names.
|
33
|
+
- Make as many expectations as you want in a test. You’ll get a dot for each one to make you feel good about youtself.
|
34
|
+
|
35
|
+
> [!TIP]
|
36
|
+
> Your test files are executed in an anonymous class, so you can define methods and constants at the top level without worrying about collisions. If you’re testing something that references `Class#name`, you may have to define those classes as fixtures somewhere else.
|
37
|
+
|
38
|
+
### `.test`
|
39
|
+
Use the `test` method to define a test. The description is optional — sometimes you don’t need it.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
test { assert true }
|
43
|
+
```
|
44
|
+
|
45
|
+
You can pass `skip: true` to skip the test. Skipped tests are still run; they pass if they fail and fail they pass.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
test(skip: true) { assert false }
|
49
|
+
```
|
50
|
+
|
51
|
+
### `.describe`
|
52
|
+
You can optionally wrap tests in any number of `describe` blocks, which can take a description as a string or module/class.
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
describe Thing do
|
56
|
+
# your Thing tests here
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
### `#assert`
|
61
|
+
`assert` takes a value and passes if it’s truthy.
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
test "something" do
|
65
|
+
assert true
|
66
|
+
end
|
67
|
+
```
|
68
|
+
|
69
|
+
You can pass a custom failure message as a block. Using blocks for the failure messages means we don’t waste time constructing them unless the test fails. You don’t need to worry about expensive failure messages slowing down your tests.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
test "something" do
|
73
|
+
assert(false) { "This is a custom failure message" }
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
### `#refute`
|
78
|
+
`refute` is just like `assert`, but it passes if the value is falsy.
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
test "something" do
|
82
|
+
refute false
|
83
|
+
end
|
84
|
+
```
|
85
|
+
|
86
|
+
### `expect` matchers
|
87
|
+
`expect` takes either a value or a block and returns an expectation object, which you can call matchers on.
|
88
|
+
|
89
|
+
#### `==` and `!=`
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
test "equality" do
|
93
|
+
expect(Thing.foo) == "foo"
|
94
|
+
expect(Thing.bar) != "foo"
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
#### `to_raise`
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
test "raises" do
|
102
|
+
expect { Thing.bar! }.to_raise(ArgumentError) do |error|
|
103
|
+
expect(error.message) == "Foo bar"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
```
|
107
|
+
|
108
|
+
#### `to_receive`
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
test "mocks and spies" do
|
112
|
+
expect(Thing).to_receive(:foo) do |a, b, c|
|
113
|
+
# The block receives arguments and can make assertions about them.
|
114
|
+
expect(a) == 1
|
115
|
+
expect(b) != 1
|
116
|
+
assert(c)
|
117
|
+
|
118
|
+
# Either return a mock response or call the original via `@super`
|
119
|
+
@super.call
|
120
|
+
end
|
121
|
+
|
122
|
+
Thing.foo(1, 2, 3)
|
123
|
+
end
|
124
|
+
```
|
125
|
+
|
126
|
+
### Mappings of minitest assertions/expectations to quickdraw
|
127
|
+
|
128
|
+
The minitest test class (which inherits from Test::Unit or Minitest::Test) should be removed from the output, as the
|
129
|
+
quickdraw test class is anonymous and implicit.
|
130
|
+
eg
|
131
|
+
```ruby
|
132
|
+
class MyTest < Minitest::Test
|
133
|
+
def test_something
|
134
|
+
assert true
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
becomes
|
139
|
+
```ruby
|
140
|
+
test "something" do
|
141
|
+
assert true
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
`should` in Test::Unit is the same as `describe` in Quickdraw.
|
146
|
+
|
147
|
+
minitest "assert" and "refute" methods are mapped to quickdraw `assert` and `refute` methods.
|
148
|
+
|
149
|
+
minitest "expect" methods are mapped to quickdraw `expect` methods.
|
150
|
+
|
151
|
+
below are the mappings of minitest methods to quickdraw methods:
|
152
|
+
|
153
|
+
`_(x).must_be`, `expect(x).must_be :==, 0` or `assert_operator x, :==, 0` becomes `expect(x) == 0`
|
154
|
+
`_(x).must_be`, `expect(x).must_be :>, 0` or `assert_operator x, :>, 0` becomes `assert(x > 0)`
|
155
|
+
`_(x).must_be`, `expect(x).must_be :empty?` `expect(x).must_be_empty` `assert_empty` becomes `assert(x.empty?)`
|
156
|
+
`_(x).must_equal`, `expect(x).must_equal b` or `assert_equal b, x` becomes `expect(x) == b`
|
157
|
+
`_(x).must_be_close_to`, `expect(x).must_be_close_to 2.99999`, `assert_in_epsilon` or `assert_in_delta` becomes `raise "Not implemented in Quickdraw yet"`
|
158
|
+
`_(x).must_be_same_as`, `expect(x).must_be_same_as b` and `assert_same` becomes `expect(x).to_equal(b)`
|
159
|
+
`_(x).must_include`, `expect(x).must_include needle`, `assert_includes x, needle` becomes `expect(x).to_include(needle)`
|
160
|
+
`_(x).must_be_kind_of`, `expect(x).must_be_kind_of Enumerable` or `assert_kind_of Enumerable, x` becomes `assert(x.kind_of? Enumerable)`
|
161
|
+
`_(x).must_be_instance_of`, `expect(x).must_be_instance_of Array` or `assert_instance_of Array, x` becomes `assert(x.instance_of? Array)`
|
162
|
+
`_(x).must_be_nil`, `expect(x).must_be_nil` or `assert_nil` becomes `assert(x == nil)`
|
163
|
+
`_(x).must_match`, `expect(x).must_match /regex/` , `assert_match x, /regex/` becomes `assert(/regex/ === x)`
|
164
|
+
`_(x).must_respond_to`, `expect(x).must_respond_to msg` or `assert_respond_to x, msg` becomes `expect(x).to_respond_to(msg)`
|
165
|
+
`_(x).wont_respond_to`, `expect(x).wont_respond_to msg` or `refute_respond_to x, msg` becomes `expect(x).not_to_respond_to(msg)`
|
166
|
+
`proc { "no stdout or stderr" }.must_output` or `assert_output {}`, proc { "no stdout or stderr" }.must_be_silent` or `assert_silent {}` becomes `raise "Not implemented in Quickdraw yet"`
|
167
|
+
`proc { ... }.must_raise exception` or `assert_raises(exp) {}` becomes `expect {}.to_raise(exp)`
|
168
|
+
`proc { ... }.must_throw sym` or `assert_throws(sym) {}` becomes `raise "Not implemented in Quickdraw yet"`
|
169
|
+
|
170
|
+
note: there are also `refute_*` methods in minitest, which are mapped to either a `refute(...)` or a #not_to* methods in quickdraw.
|
171
|
+
|
172
|
+
Converting `MiniTest::Spec` to `Quickdraw` as follows (like converting from Spec syntax to Test syntax):
|
173
|
+
|
174
|
+
`subject {}` becomes
|
175
|
+
```ruby
|
176
|
+
def subject
|
177
|
+
@subject ||= Thing.new
|
178
|
+
end
|
179
|
+
```
|
180
|
+
|
181
|
+
`let(:x) { 1 }` becomes
|
182
|
+
```ruby
|
183
|
+
def x
|
184
|
+
@x ||= 1
|
185
|
+
end
|
186
|
+
```
|
187
|
+
|
188
|
+
If any modules are included in the minitest class, then take the contents of the module and add it to the output but remove the wrapping `module`
|
189
|
+
Also remove the `include Module` statement from the output.
|
190
|
+
Also remove the def self.included(base) method from the output.
|
191
|
+
|
192
|
+
Only show me the test file code. Do NOT provide any other description of your work. Always enclose the output code in triple backticks (```).
|
193
|
+
|
194
|
+
The minitest test to convert is as follows:
|
@@ -2,6 +2,7 @@ refactor: rails/minitest/rspec_to_minitest
|
|
2
2
|
input_file_paths:
|
3
3
|
- examples/ex1_input_spec.rb
|
4
4
|
# We need to add context here as otherwise to tell the AI to require our local test_helper.rb file so that we can run the tests after
|
5
|
-
context_text: "In the output test use `require_relative` to include 'test_helper'."
|
5
|
+
context_text: "In the output test use `require_relative '../test_helper'` to include 'test_helper'."
|
6
6
|
# By default, ai_refactor runs "bundle exec rails test" but this isn't going to work here as we are not actually in a Rails app context in the examples
|
7
7
|
minitest_run_command: ruby __FILE__
|
8
|
+
output_file_path: examples/outputs/ex1_input_test.rb
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# example from https://blog.kiprosh.com/type-checking-in-ruby-3-using-rbs/
|
2
|
+
# basic_math.rb
|
3
|
+
|
4
|
+
class BasicMath
|
5
|
+
def initialize(num1, num2)
|
6
|
+
@num1 = num1
|
7
|
+
@num2 = num2
|
8
|
+
end
|
9
|
+
|
10
|
+
def first_less_than_second?
|
11
|
+
@num1 < @num2
|
12
|
+
end
|
13
|
+
|
14
|
+
def add
|
15
|
+
@num1 + @num2
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
refactor: ruby/write_rbs
|
2
|
+
input_file_paths:
|
3
|
+
- examples/ex2_input.rb
|
4
|
+
# We need to add context here as our class doesnt actually give any context.
|
5
|
+
context_text: "Assume that the inputs can be any numeric type."
|
6
|
+
# By default this refactor writes to `sig/...` but here we just put the result in `examples/...`
|
7
|
+
output_file_path: examples/outputs/ex2_input.rbs
|
data/exe/ai_refactor
CHANGED
@@ -6,10 +6,9 @@ require "openai"
|
|
6
6
|
require "shellwords"
|
7
7
|
require_relative "../lib/ai_refactor"
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
refactors_descriptions = AIRefactor::Refactors.descriptions
|
9
|
+
supported_refactors = AIRefactor::Refactors.all.merge(AIRefactor::Commands.all)
|
10
|
+
supported_refactors_names = supported_refactors.keys
|
11
|
+
refactors_descriptions = AIRefactor::Refactors.descriptions.merge(AIRefactor::Commands.descriptions)
|
13
12
|
|
14
13
|
arguments = ARGV.dup
|
15
14
|
|
@@ -54,7 +53,7 @@ option_parser = OptionParser.new do |parser|
|
|
54
53
|
run_config.ai_max_attempts = c
|
55
54
|
end
|
56
55
|
|
57
|
-
parser.on("-m", "--model MODEL_NAME", String, "Specify a ChatGPT model to use (default gpt-4).") do |m|
|
56
|
+
parser.on("-m", "--model MODEL_NAME", String, "Specify a ChatGPT model to use (default gpt-4-turbo-preview).") do |m|
|
58
57
|
run_config.ai_model = m
|
59
58
|
end
|
60
59
|
|
@@ -139,10 +138,9 @@ if arguments.empty? || arguments.all? { |arg| arg.start_with?("-") && !(arg == "
|
|
139
138
|
# For each option that is required but not provided, prompt for it
|
140
139
|
# Put the option in arguments to parse with option_parser
|
141
140
|
interactive_log.info "Interactive mode started. You can use tab to autocomplete:"
|
142
|
-
predefined_commands = AIRefactor::Refactors.names
|
143
141
|
|
144
|
-
interactive_log.info "Available refactors: #{
|
145
|
-
command = AIRefactor::Cli.request_input_with_autocomplete("Enter refactor name: ",
|
142
|
+
interactive_log.info "Available refactors: #{supported_refactors_names.join(", ")}\n"
|
143
|
+
command = AIRefactor::Cli.request_input_with_autocomplete("Enter refactor name: ", supported_refactors_names)
|
146
144
|
exit_with_option_error("No refactor name provided.", option_parser) if command.nil? || command.empty?
|
147
145
|
initial = [command]
|
148
146
|
|
@@ -182,10 +180,12 @@ logger = AIRefactor::Logger.new(verbose: run_config.verbose, debug: run_config.d
|
|
182
180
|
logger.info "Also loaded options from '.ai_refactor' file..." if options_from_config_file&.size&.positive?
|
183
181
|
|
184
182
|
command_or_file = arguments.shift
|
185
|
-
|
186
|
-
|
183
|
+
is_built_in_command = AIRefactor::Commands.supported?(command_or_file)
|
184
|
+
if is_built_in_command || AIRefactor::CommandFileParser.command_file?(command_or_file)
|
185
|
+
logger.info "Loading #{is_built_in_command ? "built-in" : "custom"} refactor command file '#{command_or_file}'..."
|
187
186
|
begin
|
188
|
-
|
187
|
+
command_file_path = is_built_in_command ? Commands.get(command_name).path : command_or_file
|
188
|
+
run_config.set!(AIRefactor::CommandFileParser.new(command_file_path).parse)
|
189
189
|
rescue => e
|
190
190
|
exit_with_option_error(e.message, option_parser, logger)
|
191
191
|
end
|
data/lib/ai_refactor/cli.rb
CHANGED
@@ -85,6 +85,9 @@ module AIRefactor
|
|
85
85
|
|
86
86
|
logger.info "AI Refactor #{expanded_inputs.size} files(s)/dir(s) '#{expanded_inputs}' with #{refactorer.refactor_name} refactor\n"
|
87
87
|
logger.info "====================\n"
|
88
|
+
if configuration.description
|
89
|
+
logger.info "Description: #{configuration.description}\n"
|
90
|
+
end
|
88
91
|
|
89
92
|
return_values = expanded_inputs.map do |file|
|
90
93
|
logger.info "Processing #{file}..."
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AIRefactor
|
4
|
+
module Commands
|
5
|
+
# TODO: support command_line_options
|
6
|
+
BuiltInCommand = Data.define(:name, :description, :path, :command_line_options, :config)
|
7
|
+
|
8
|
+
def get(name)
|
9
|
+
all[name]
|
10
|
+
end
|
11
|
+
module_function :get
|
12
|
+
|
13
|
+
def names
|
14
|
+
all.keys
|
15
|
+
end
|
16
|
+
module_function :names
|
17
|
+
|
18
|
+
def descriptions
|
19
|
+
names.map { |n| "\"#{n}\"" }.zip(all.values.map(&:description)).to_h
|
20
|
+
end
|
21
|
+
module_function :descriptions
|
22
|
+
|
23
|
+
def supported?(name)
|
24
|
+
names.include?(name)
|
25
|
+
end
|
26
|
+
module_function :supported?
|
27
|
+
|
28
|
+
def all
|
29
|
+
@all ||= begin
|
30
|
+
commands = Dir.glob(File.join(__dir__, "../../commands", "**/*.yml")).map do |path|
|
31
|
+
path_to_commands = File.join(__dir__, "../../commands/")
|
32
|
+
name = File.join(File.dirname(path.gsub(path_to_commands, "")), File.basename(path, ".yml")).to_sym
|
33
|
+
config = YAML.safe_load_file(path, permitted_classes: [Symbol], symbolize_names: true, aliases: true)
|
34
|
+
BuiltInCommand.new(name: name, path: path, description: config[:description], config: config, command_line_options: [])
|
35
|
+
end
|
36
|
+
commands.map { |c| [c.name, c] }.to_h
|
37
|
+
end
|
38
|
+
end
|
39
|
+
module_function :all
|
40
|
+
end
|
41
|
+
end
|
@@ -62,7 +62,7 @@ module AIRefactor
|
|
62
62
|
|
63
63
|
response = @ai_client.chat(
|
64
64
|
parameters: {
|
65
|
-
model: options[:ai_model] || "gpt-4",
|
65
|
+
model: options[:ai_model] || "gpt-4-turbo-preview",
|
66
66
|
messages: messages,
|
67
67
|
temperature: options[:ai_temperature] || 0.7,
|
68
68
|
max_tokens: options[:ai_max_tokens] || 1500
|
data/lib/ai_refactor/prompt.rb
CHANGED
@@ -39,7 +39,7 @@ module AIRefactor
|
|
39
39
|
|
40
40
|
def file_processor
|
41
41
|
context = ::AIRefactor::Context.new(files: options[:context_file_paths], text: options[:context_text], logger: logger)
|
42
|
-
prompt = ::AIRefactor::Prompt.new(input_content: input_content, input_path: input_file, output_file_path: output_file_path, prompt: prompt_input, context: context, logger: logger, options: options)
|
42
|
+
prompt = ::AIRefactor::Prompt.new(input_content: input_content, input_path: input_file, output_file_path: output_file_path, prompt: prompt_input, context: context, logger: logger, prompt_footer: prompt_footer, options: options)
|
43
43
|
AIRefactor::FileProcessor.new(prompt: prompt, ai_client: ai_client, output_path: output_file_path, logger: logger, options: options)
|
44
44
|
end
|
45
45
|
|
@@ -102,22 +102,46 @@ module AIRefactor
|
|
102
102
|
false
|
103
103
|
end
|
104
104
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
def prompt_template_for_refactor
|
106
|
+
location = Module.const_source_location(::AIRefactor::Refactors::BaseRefactor.name)
|
107
|
+
File.join(File.dirname(location.first), "#{refactor_name}.md")
|
108
|
+
end
|
109
|
+
|
110
|
+
def prompt_template_for_refactor?
|
111
|
+
File.exist?(prompt_template_for_refactor)
|
112
|
+
end
|
113
|
+
|
114
|
+
def user_provided_prompt_template?
|
115
|
+
options[:prompt_file_path]&.length&.positive?
|
116
|
+
end
|
109
117
|
|
110
|
-
|
111
|
-
|
118
|
+
def prompt_from_file?
|
119
|
+
user_provided_prompt_template? || prompt_template_for_refactor?
|
120
|
+
end
|
121
|
+
|
122
|
+
def user_provided_prompt?
|
123
|
+
options[:prompt]&.length&.positive?
|
124
|
+
end
|
125
|
+
|
126
|
+
def prompt_input
|
127
|
+
if user_provided_prompt_template?
|
128
|
+
file = options[:prompt_file_path]
|
129
|
+
raise "No prompt file '#{file}' found. Check prompt_file_path is valid" unless File.exist?(file)
|
130
|
+
File.read(file)
|
112
131
|
else
|
113
|
-
|
114
|
-
File.
|
115
|
-
|
116
|
-
|
117
|
-
|
132
|
+
file = prompt_template_for_refactor
|
133
|
+
if File.exist?(file)
|
134
|
+
File.read(file)
|
135
|
+
elsif user_provided_prompt?
|
136
|
+
options[:prompt]
|
137
|
+
else
|
138
|
+
raise "No prompt was provided. Please provide one with the --prompt option or with a command file."
|
139
|
+
end
|
118
140
|
end
|
141
|
+
end
|
119
142
|
|
120
|
-
|
143
|
+
def prompt_footer
|
144
|
+
options[:prompt] if user_provided_prompt? && prompt_from_file?
|
121
145
|
end
|
122
146
|
|
123
147
|
def output_file_path
|
@@ -4,7 +4,7 @@ module AIRefactor
|
|
4
4
|
module Refactors
|
5
5
|
class Custom < BaseRefactor
|
6
6
|
def run
|
7
|
-
logger.verbose "Custom refactor to #{input_file}... (using user supplied prompt #{prompt_file_path})"
|
7
|
+
logger.verbose "Custom refactor to #{input_file}... (using user supplied prompt #{prompt_file_path || "from options"})"
|
8
8
|
logger.verbose "Write output to #{output_file_path}..." if output_file_path
|
9
9
|
|
10
10
|
begin
|
@@ -26,6 +26,7 @@ module AIRefactor
|
|
26
26
|
private
|
27
27
|
|
28
28
|
def prompt_file_path
|
29
|
+
return if options[:prompt]&.length&.positive?
|
29
30
|
specified_prompt_path = options[:prompt_file_path]
|
30
31
|
if specified_prompt_path&.length&.positive?
|
31
32
|
if File.exist?(specified_prompt_path)
|
@@ -0,0 +1,118 @@
|
|
1
|
+
You are an expert Ruby senior software developer.
|
2
|
+
|
3
|
+
You will be writing the type signatures for the Ruby code below, in RBS format.
|
4
|
+
|
5
|
+
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.
|
6
|
+
|
7
|
+
The following is a small example of RBS for a chat app.
|
8
|
+
|
9
|
+
Given the Ruby
|
10
|
+
```ruby
|
11
|
+
module ChatApp
|
12
|
+
VERSION = "1.0.0"
|
13
|
+
class User
|
14
|
+
attr_reader :login, :email
|
15
|
+
|
16
|
+
def initialize(login:, email:); end
|
17
|
+
|
18
|
+
def my_method(String arg1, Integer arg2); end
|
19
|
+
end
|
20
|
+
|
21
|
+
class Bot
|
22
|
+
attr_reader :name
|
23
|
+
attr_reader :email
|
24
|
+
attr_reader :owner
|
25
|
+
|
26
|
+
def initialize(name:, owner:); end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Message
|
30
|
+
attr_reader :id, :string, :from, :reply_to
|
31
|
+
|
32
|
+
def initialize(from:, string:); end
|
33
|
+
|
34
|
+
def reply(from:, string:)
|
35
|
+
Message.new(from, string)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class Channel
|
40
|
+
attr_reader :name, :messages, :users, :bots
|
41
|
+
|
42
|
+
def initialize(name)
|
43
|
+
@name = name
|
44
|
+
@messages = []
|
45
|
+
@users = []
|
46
|
+
@bots = []
|
47
|
+
end
|
48
|
+
|
49
|
+
def each_member(&block)
|
50
|
+
members = users + bots
|
51
|
+
block? ? members.each(&block) : members.each
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
```
|
56
|
+
|
57
|
+
We can write the RBS as follows:
|
58
|
+
```
|
59
|
+
module ChatApp
|
60
|
+
VERSION: String
|
61
|
+
|
62
|
+
class User
|
63
|
+
attr_reader login: String
|
64
|
+
attr_reader email: String
|
65
|
+
|
66
|
+
# If a method takes keyword arguments then use `key: Type` syntax.
|
67
|
+
def initialize: (login: String, email: String) -> void
|
68
|
+
|
69
|
+
# If a method takes positional arguments then put the type before the argument name.
|
70
|
+
def my_method: (String arg1, Integer arg2) -> String
|
71
|
+
end
|
72
|
+
|
73
|
+
class Bot
|
74
|
+
attr_reader name: String
|
75
|
+
attr_reader email: String
|
76
|
+
attr_reader owner: User
|
77
|
+
|
78
|
+
def initialize: (name: String, owner: User) -> void
|
79
|
+
end
|
80
|
+
|
81
|
+
class Message
|
82
|
+
attr_reader id: String
|
83
|
+
attr_reader string: String
|
84
|
+
attr_reader from: User | Bot # `|` means union types: `#from` can be `User` or `Bot`
|
85
|
+
attr_reader reply_to: Message? # `?` means optional type: `#reply_to` can be `nil`
|
86
|
+
|
87
|
+
def initialize: (from: User | Bot, string: String) -> void
|
88
|
+
|
89
|
+
def reply: (from: User | Bot, string: String) -> Message
|
90
|
+
end
|
91
|
+
|
92
|
+
class Channel
|
93
|
+
attr_reader name: String
|
94
|
+
attr_reader messages: Array[Message]
|
95
|
+
attr_reader users: Array[User]
|
96
|
+
attr_reader bots: Array[Bot]
|
97
|
+
|
98
|
+
def initialize: (String name) -> void
|
99
|
+
|
100
|
+
def each_member: () { (User | Bot) -> void } -> void # `{` and `}` means block.
|
101
|
+
| () -> Enumerator[User | Bot, void] # Method can be overloaded.
|
102
|
+
end
|
103
|
+
end
|
104
|
+
```
|
105
|
+
|
106
|
+
Note, when writing the RBS for a class method, eg one in a `class << self` block, use `def self.method` in the
|
107
|
+
type definition.
|
108
|
+
|
109
|
+
Do not include comments in your RBS code or start the file with 'rbs' or '.rbs'.
|
110
|
+
|
111
|
+
__{{context}}__
|
112
|
+
|
113
|
+
__{{prompt_header}}__
|
114
|
+
|
115
|
+
The input file is: __{{input_file_path}}__
|
116
|
+
The output file path is: __{{output_file_path}}__
|
117
|
+
|
118
|
+
__{{prompt_footer}}__
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AIRefactor
|
4
|
+
module Refactors
|
5
|
+
module Ruby
|
6
|
+
class WriteRbs < BaseRefactor
|
7
|
+
def run
|
8
|
+
logger.verbose "Write some RBS for #{input_file}..."
|
9
|
+
logger.verbose "Write output to #{output_file_path}..." if output_file_path
|
10
|
+
|
11
|
+
begin
|
12
|
+
output_content = process!(strip_ticks: true)
|
13
|
+
rescue => e
|
14
|
+
logger.error "Failed to process #{input_file}: #{e.message}"
|
15
|
+
return false
|
16
|
+
end
|
17
|
+
|
18
|
+
return false unless output_content
|
19
|
+
|
20
|
+
if output_file_path
|
21
|
+
steep_runner = AIRefactor::TestRunners::SteepRunner.new(input_file, command_template: options.minitest_run_command)
|
22
|
+
|
23
|
+
logger.verbose "Run steep against generated RBS file #{output_file_path} (`#{steep_runner.command}`)..."
|
24
|
+
test_run = steep_runner.run
|
25
|
+
|
26
|
+
if test_run.failed?
|
27
|
+
logger.warn "#{input_file} was translated to #{output_file_path} but the resulting RBS fails to pass a steep check..."
|
28
|
+
logger.error "Failed to run test, exited with status #{test_run.exitstatus}. Stdout: #{test_run.stdout}\n\nStderr: #{test_run.stderr}\n\n"
|
29
|
+
logger.error "New RBS failed!", bold: true
|
30
|
+
self.failed_message = "Generated RBS file failed to pass checks"
|
31
|
+
return false
|
32
|
+
end
|
33
|
+
|
34
|
+
logger.verbose "\nNew RBS file passed checks"
|
35
|
+
end
|
36
|
+
|
37
|
+
output_file_path ? true : output_content
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.description
|
41
|
+
"User supplied prompt to write RBS for some Ruby"
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_output_path
|
45
|
+
File.join("sig", input_file.gsub(/\.rb$/, ".rbs"))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -8,10 +8,12 @@ module AIRefactor
|
|
8
8
|
end
|
9
9
|
|
10
10
|
attr_reader :refactor,
|
11
|
+
:description,
|
11
12
|
:input_file_paths,
|
12
13
|
:output_file_path,
|
13
14
|
:output_template_path,
|
14
15
|
:context_file_paths,
|
16
|
+
:context_file_paths_from_gems,
|
15
17
|
:context_text,
|
16
18
|
:review_prompt,
|
17
19
|
:prompt,
|
@@ -33,7 +35,7 @@ module AIRefactor
|
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
|
-
attr_writer :refactor
|
38
|
+
attr_writer :refactor, :description
|
37
39
|
|
38
40
|
# @deprecated
|
39
41
|
def [](key)
|
@@ -56,6 +58,25 @@ module AIRefactor
|
|
56
58
|
@context_file_paths.concat(paths)
|
57
59
|
end
|
58
60
|
|
61
|
+
# A hash is passed in, where the keys are gem names that should be in the bundle and the path is a path inside the gem
|
62
|
+
# install location. We resolve the absolute path of each and then add to @context_file_paths
|
63
|
+
def context_file_paths_from_gems=(paths)
|
64
|
+
@context_file_paths ||= []
|
65
|
+
@context_file_paths_from_gems ||= {}
|
66
|
+
@context_file_paths_from_gems.merge!(paths)
|
67
|
+
|
68
|
+
paths.each do |gem_name, paths|
|
69
|
+
paths = [paths] unless paths.is_a?(Array)
|
70
|
+
paths.each do |path|
|
71
|
+
gem_spec = Gem::Specification.find_by_name(gem_name.to_s)
|
72
|
+
raise "Gem #{gem_name} not found" unless gem_spec
|
73
|
+
gem_path = gem_spec.gem_dir
|
74
|
+
full_path = File.join(gem_path, path)
|
75
|
+
@context_file_paths << full_path
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
59
80
|
def context_text=(text)
|
60
81
|
@context_text ||= ""
|
61
82
|
@context_text += text
|
@@ -81,7 +102,7 @@ module AIRefactor
|
|
81
102
|
end
|
82
103
|
|
83
104
|
def ai_model=(value)
|
84
|
-
@ai_model = value || "gpt-4"
|
105
|
+
@ai_model = value || "gpt-4-turbo-preview"
|
85
106
|
end
|
86
107
|
|
87
108
|
def ai_temperature=(value)
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "open3"
|
4
|
+
|
5
|
+
module AIRefactor
|
6
|
+
module TestRunners
|
7
|
+
class SteepRunner
|
8
|
+
def initialize(file_path, command_template: "bundle exec steep __FILE__")
|
9
|
+
@file_path = file_path
|
10
|
+
@command_template = command_template
|
11
|
+
end
|
12
|
+
|
13
|
+
def command
|
14
|
+
@command_template.gsub("__FILE__", @file_path)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
stdout, stderr, status = Open3.capture3(command)
|
19
|
+
# TODO: parse output
|
20
|
+
# look initally for Cannot find a configuration at Steepfile
|
21
|
+
#
|
22
|
+
# _matched, runs, _assertions, failures, errors, skips = stdout.match(/(\d+) runs, (\d+) assertions, (\d+) failures, (\d+) errors, (\d+) skips/).to_a
|
23
|
+
TestRunResult.new(stdout, stderr, status) # , runs, failures, skips, errors)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -5,7 +5,7 @@ module AIRefactor
|
|
5
5
|
class TestRunResult
|
6
6
|
attr_reader :stdout, :stderr, :example_count, :failure_count, :pending_count
|
7
7
|
|
8
|
-
def initialize(stdout, stderr, status, example_count, failure_count, pending_count, errored)
|
8
|
+
def initialize(stdout, stderr, status, example_count = 0, failure_count = 0, pending_count = 0, errored = 0)
|
9
9
|
@stdout = stdout
|
10
10
|
@stderr = stderr
|
11
11
|
@status = status
|
data/lib/ai_refactor/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ai_refactor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Ierodiaconou
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-02-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -47,7 +47,7 @@ dependencies:
|
|
47
47
|
version: 3.4.0
|
48
48
|
- - "<"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
50
|
+
version: '6.0'
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -57,7 +57,7 @@ dependencies:
|
|
57
57
|
version: 3.4.0
|
58
58
|
- - "<"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
60
|
+
version: '6.0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: zeitwerk
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,20 +84,23 @@ files:
|
|
84
84
|
- ".standard.yml"
|
85
85
|
- CHANGELOG.md
|
86
86
|
- Gemfile
|
87
|
-
- Gemfile.lock
|
88
87
|
- LICENSE.txt
|
89
88
|
- README.md
|
90
89
|
- Rakefile
|
90
|
+
- Steepfile
|
91
91
|
- ai_refactor.gemspec
|
92
|
-
-
|
92
|
+
- commands/quickdraw/0.1.0/convert_minitest.yml
|
93
93
|
- examples/ex1_convert_a_rspec_test_to_minitest.yml
|
94
94
|
- examples/ex1_input_spec.rb
|
95
|
+
- examples/ex2_input.rb
|
96
|
+
- examples/ex2_write_rbs.yml
|
95
97
|
- examples/rails_helper.rb
|
96
98
|
- examples/test_helper.rb
|
97
99
|
- exe/ai_refactor
|
98
100
|
- lib/ai_refactor.rb
|
99
101
|
- lib/ai_refactor/cli.rb
|
100
102
|
- lib/ai_refactor/command_file_parser.rb
|
103
|
+
- lib/ai_refactor/commands.rb
|
101
104
|
- lib/ai_refactor/context.rb
|
102
105
|
- lib/ai_refactor/file_processor.rb
|
103
106
|
- lib/ai_refactor/logger.rb
|
@@ -117,12 +120,15 @@ files:
|
|
117
120
|
- lib/ai_refactor/refactors/rspec/minitest_to_rspec.rb
|
118
121
|
- lib/ai_refactor/refactors/ruby/refactor_ruby.md
|
119
122
|
- lib/ai_refactor/refactors/ruby/refactor_ruby.rb
|
123
|
+
- lib/ai_refactor/refactors/ruby/write_rbs.md
|
124
|
+
- lib/ai_refactor/refactors/ruby/write_rbs.rb
|
120
125
|
- lib/ai_refactor/refactors/ruby/write_ruby.md
|
121
126
|
- lib/ai_refactor/refactors/ruby/write_ruby.rb
|
122
127
|
- lib/ai_refactor/run_configuration.rb
|
123
128
|
- lib/ai_refactor/templated_path.rb
|
124
129
|
- lib/ai_refactor/test_runners/minitest_runner.rb
|
125
130
|
- lib/ai_refactor/test_runners/rspec_runner.rb
|
131
|
+
- lib/ai_refactor/test_runners/steep_runner.rb
|
126
132
|
- lib/ai_refactor/test_runners/test_run_diff_report.rb
|
127
133
|
- lib/ai_refactor/test_runners/test_run_result.rb
|
128
134
|
- lib/ai_refactor/version.rb
|
@@ -147,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
153
|
- !ruby/object:Gem::Version
|
148
154
|
version: '0'
|
149
155
|
requirements: []
|
150
|
-
rubygems_version: 3.4.
|
156
|
+
rubygems_version: 3.4.20
|
151
157
|
signing_key:
|
152
158
|
specification_version: 4
|
153
159
|
summary: Use AI to convert a Rails RSpec test suite to minitest.
|
data/Gemfile.lock
DELETED
@@ -1,244 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
ai_refactor (0.5.2)
|
5
|
-
colorize (< 2.0)
|
6
|
-
open3 (< 2.0)
|
7
|
-
ruby-openai (>= 3.4.0, < 5.0)
|
8
|
-
zeitwerk (~> 2.6)
|
9
|
-
|
10
|
-
GEM
|
11
|
-
remote: https://rubygems.org/
|
12
|
-
specs:
|
13
|
-
actioncable (7.0.8)
|
14
|
-
actionpack (= 7.0.8)
|
15
|
-
activesupport (= 7.0.8)
|
16
|
-
nio4r (~> 2.0)
|
17
|
-
websocket-driver (>= 0.6.1)
|
18
|
-
actionmailbox (7.0.8)
|
19
|
-
actionpack (= 7.0.8)
|
20
|
-
activejob (= 7.0.8)
|
21
|
-
activerecord (= 7.0.8)
|
22
|
-
activestorage (= 7.0.8)
|
23
|
-
activesupport (= 7.0.8)
|
24
|
-
mail (>= 2.7.1)
|
25
|
-
net-imap
|
26
|
-
net-pop
|
27
|
-
net-smtp
|
28
|
-
actionmailer (7.0.8)
|
29
|
-
actionpack (= 7.0.8)
|
30
|
-
actionview (= 7.0.8)
|
31
|
-
activejob (= 7.0.8)
|
32
|
-
activesupport (= 7.0.8)
|
33
|
-
mail (~> 2.5, >= 2.5.4)
|
34
|
-
net-imap
|
35
|
-
net-pop
|
36
|
-
net-smtp
|
37
|
-
rails-dom-testing (~> 2.0)
|
38
|
-
actionpack (7.0.8)
|
39
|
-
actionview (= 7.0.8)
|
40
|
-
activesupport (= 7.0.8)
|
41
|
-
rack (~> 2.0, >= 2.2.4)
|
42
|
-
rack-test (>= 0.6.3)
|
43
|
-
rails-dom-testing (~> 2.0)
|
44
|
-
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
45
|
-
actiontext (7.0.8)
|
46
|
-
actionpack (= 7.0.8)
|
47
|
-
activerecord (= 7.0.8)
|
48
|
-
activestorage (= 7.0.8)
|
49
|
-
activesupport (= 7.0.8)
|
50
|
-
globalid (>= 0.6.0)
|
51
|
-
nokogiri (>= 1.8.5)
|
52
|
-
actionview (7.0.8)
|
53
|
-
activesupport (= 7.0.8)
|
54
|
-
builder (~> 3.1)
|
55
|
-
erubi (~> 1.4)
|
56
|
-
rails-dom-testing (~> 2.0)
|
57
|
-
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
58
|
-
activejob (7.0.8)
|
59
|
-
activesupport (= 7.0.8)
|
60
|
-
globalid (>= 0.3.6)
|
61
|
-
activemodel (7.0.8)
|
62
|
-
activesupport (= 7.0.8)
|
63
|
-
activerecord (7.0.8)
|
64
|
-
activemodel (= 7.0.8)
|
65
|
-
activesupport (= 7.0.8)
|
66
|
-
activestorage (7.0.8)
|
67
|
-
actionpack (= 7.0.8)
|
68
|
-
activejob (= 7.0.8)
|
69
|
-
activerecord (= 7.0.8)
|
70
|
-
activesupport (= 7.0.8)
|
71
|
-
marcel (~> 1.0)
|
72
|
-
mini_mime (>= 1.1.0)
|
73
|
-
activesupport (7.0.8)
|
74
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
75
|
-
i18n (>= 1.6, < 2)
|
76
|
-
minitest (>= 5.1)
|
77
|
-
tzinfo (~> 2.0)
|
78
|
-
ast (2.4.2)
|
79
|
-
builder (3.2.4)
|
80
|
-
colorize (0.8.1)
|
81
|
-
concurrent-ruby (1.2.2)
|
82
|
-
crass (1.0.6)
|
83
|
-
date (3.3.3)
|
84
|
-
diff-lcs (1.5.0)
|
85
|
-
dotenv (2.8.1)
|
86
|
-
erubi (1.12.0)
|
87
|
-
faraday (2.7.4)
|
88
|
-
faraday-net_http (>= 2.0, < 3.1)
|
89
|
-
ruby2_keywords (>= 0.0.4)
|
90
|
-
faraday-multipart (1.0.4)
|
91
|
-
multipart-post (~> 2)
|
92
|
-
faraday-net_http (3.0.2)
|
93
|
-
globalid (1.2.1)
|
94
|
-
activesupport (>= 6.1)
|
95
|
-
i18n (1.14.1)
|
96
|
-
concurrent-ruby (~> 1.0)
|
97
|
-
json (2.6.3)
|
98
|
-
language_server-protocol (3.17.0.3)
|
99
|
-
lint_roller (1.0.0)
|
100
|
-
loofah (2.21.3)
|
101
|
-
crass (~> 1.0.2)
|
102
|
-
nokogiri (>= 1.12.0)
|
103
|
-
mail (2.8.1)
|
104
|
-
mini_mime (>= 0.1.1)
|
105
|
-
net-imap
|
106
|
-
net-pop
|
107
|
-
net-smtp
|
108
|
-
marcel (1.0.2)
|
109
|
-
method_source (1.0.0)
|
110
|
-
mini_mime (1.1.5)
|
111
|
-
minitest (5.18.0)
|
112
|
-
multipart-post (2.3.0)
|
113
|
-
net-imap (0.3.7)
|
114
|
-
date
|
115
|
-
net-protocol
|
116
|
-
net-pop (0.1.2)
|
117
|
-
net-protocol
|
118
|
-
net-protocol (0.2.1)
|
119
|
-
timeout
|
120
|
-
net-smtp (0.3.3)
|
121
|
-
net-protocol
|
122
|
-
nio4r (2.5.9)
|
123
|
-
nokogiri (1.15.4-arm64-darwin)
|
124
|
-
racc (~> 1.4)
|
125
|
-
open3 (0.1.2)
|
126
|
-
parallel (1.23.0)
|
127
|
-
parser (3.2.2.1)
|
128
|
-
ast (~> 2.4.1)
|
129
|
-
racc (1.7.1)
|
130
|
-
rack (2.2.8)
|
131
|
-
rack-test (2.1.0)
|
132
|
-
rack (>= 1.3)
|
133
|
-
rails (7.0.8)
|
134
|
-
actioncable (= 7.0.8)
|
135
|
-
actionmailbox (= 7.0.8)
|
136
|
-
actionmailer (= 7.0.8)
|
137
|
-
actionpack (= 7.0.8)
|
138
|
-
actiontext (= 7.0.8)
|
139
|
-
actionview (= 7.0.8)
|
140
|
-
activejob (= 7.0.8)
|
141
|
-
activemodel (= 7.0.8)
|
142
|
-
activerecord (= 7.0.8)
|
143
|
-
activestorage (= 7.0.8)
|
144
|
-
activesupport (= 7.0.8)
|
145
|
-
bundler (>= 1.15.0)
|
146
|
-
railties (= 7.0.8)
|
147
|
-
rails-dom-testing (2.2.0)
|
148
|
-
activesupport (>= 5.0.0)
|
149
|
-
minitest
|
150
|
-
nokogiri (>= 1.6)
|
151
|
-
rails-html-sanitizer (1.6.0)
|
152
|
-
loofah (~> 2.21)
|
153
|
-
nokogiri (~> 1.14)
|
154
|
-
railties (7.0.8)
|
155
|
-
actionpack (= 7.0.8)
|
156
|
-
activesupport (= 7.0.8)
|
157
|
-
method_source
|
158
|
-
rake (>= 12.2)
|
159
|
-
thor (~> 1.0)
|
160
|
-
zeitwerk (~> 2.5)
|
161
|
-
rainbow (3.1.1)
|
162
|
-
rake (13.0.6)
|
163
|
-
regexp_parser (2.8.0)
|
164
|
-
rexml (3.2.5)
|
165
|
-
rspec (3.12.0)
|
166
|
-
rspec-core (~> 3.12.0)
|
167
|
-
rspec-expectations (~> 3.12.0)
|
168
|
-
rspec-mocks (~> 3.12.0)
|
169
|
-
rspec-core (3.12.2)
|
170
|
-
rspec-support (~> 3.12.0)
|
171
|
-
rspec-expectations (3.12.3)
|
172
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
173
|
-
rspec-support (~> 3.12.0)
|
174
|
-
rspec-mocks (3.12.6)
|
175
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
176
|
-
rspec-support (~> 3.12.0)
|
177
|
-
rspec-rails (6.0.3)
|
178
|
-
actionpack (>= 6.1)
|
179
|
-
activesupport (>= 6.1)
|
180
|
-
railties (>= 6.1)
|
181
|
-
rspec-core (~> 3.12)
|
182
|
-
rspec-expectations (~> 3.12)
|
183
|
-
rspec-mocks (~> 3.12)
|
184
|
-
rspec-support (~> 3.12)
|
185
|
-
rspec-support (3.12.1)
|
186
|
-
rubocop (1.50.2)
|
187
|
-
json (~> 2.3)
|
188
|
-
parallel (~> 1.10)
|
189
|
-
parser (>= 3.2.0.0)
|
190
|
-
rainbow (>= 2.2.2, < 4.0)
|
191
|
-
regexp_parser (>= 1.8, < 3.0)
|
192
|
-
rexml (>= 3.2.5, < 4.0)
|
193
|
-
rubocop-ast (>= 1.28.0, < 2.0)
|
194
|
-
ruby-progressbar (~> 1.7)
|
195
|
-
unicode-display_width (>= 2.4.0, < 3.0)
|
196
|
-
rubocop-ast (1.28.1)
|
197
|
-
parser (>= 3.2.1.0)
|
198
|
-
rubocop-performance (1.16.0)
|
199
|
-
rubocop (>= 1.7.0, < 2.0)
|
200
|
-
rubocop-ast (>= 0.4.0)
|
201
|
-
ruby-openai (4.1.0)
|
202
|
-
faraday (>= 1)
|
203
|
-
faraday-multipart (>= 1)
|
204
|
-
ruby-progressbar (1.13.0)
|
205
|
-
ruby2_keywords (0.0.5)
|
206
|
-
shoulda-matchers (5.3.0)
|
207
|
-
activesupport (>= 5.2.0)
|
208
|
-
standard (1.28.2)
|
209
|
-
language_server-protocol (~> 3.17.0.2)
|
210
|
-
lint_roller (~> 1.0)
|
211
|
-
rubocop (~> 1.50.2)
|
212
|
-
standard-custom (~> 1.0.0)
|
213
|
-
standard-performance (~> 1.0.1)
|
214
|
-
standard-custom (1.0.0)
|
215
|
-
lint_roller (~> 1.0)
|
216
|
-
standard-performance (1.0.1)
|
217
|
-
lint_roller (~> 1.0)
|
218
|
-
rubocop-performance (~> 1.16.0)
|
219
|
-
thor (1.2.2)
|
220
|
-
timeout (0.4.0)
|
221
|
-
tzinfo (2.0.6)
|
222
|
-
concurrent-ruby (~> 1.0)
|
223
|
-
unicode-display_width (2.4.2)
|
224
|
-
websocket-driver (0.7.6)
|
225
|
-
websocket-extensions (>= 0.1.0)
|
226
|
-
websocket-extensions (0.1.5)
|
227
|
-
zeitwerk (2.6.8)
|
228
|
-
|
229
|
-
PLATFORMS
|
230
|
-
arm64-darwin-22
|
231
|
-
|
232
|
-
DEPENDENCIES
|
233
|
-
ai_refactor!
|
234
|
-
dotenv
|
235
|
-
minitest (~> 5.0)
|
236
|
-
rails
|
237
|
-
rake (~> 13.0)
|
238
|
-
rspec
|
239
|
-
rspec-rails
|
240
|
-
shoulda-matchers
|
241
|
-
standard (~> 1.3)
|
242
|
-
|
243
|
-
BUNDLED WITH
|
244
|
-
2.4.10
|
data/examples/.gitignore
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
ex1_input_test.rb
|