rbs_goose 0.1.1 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +9 -2
  3. data/.ruby-version +1 -1
  4. data/Gemfile +20 -13
  5. data/Gemfile.lock +69 -38
  6. data/README-ja.md +88 -0
  7. data/README.md +25 -22
  8. data/Rakefile +53 -8
  9. data/Steepfile +1 -3
  10. data/evaluations/01_rbs_goose/claude_haiku.log +1494 -0
  11. data/evaluations/01_rbs_goose/claude_opus.log +1439 -0
  12. data/evaluations/01_rbs_goose/claude_sonnet.log +1437 -0
  13. data/evaluations/01_rbs_goose/gpt-3-5-turbo.log +1241 -0
  14. data/evaluations/01_rbs_goose/gpt-4-turbo.log +1304 -0
  15. data/examples/fix_errors/Steepfile +6 -0
  16. data/examples/fix_errors/error_messages.txt +26 -0
  17. data/{lib/rbs_goose/examples/rbs_samples → examples/fix_errors}/refined/sig/email.rbs +1 -1
  18. data/{lib/rbs_goose/examples/rbs_samples → examples/fix_errors}/refined/sig/person.rbs +2 -2
  19. data/{lib/rbs_goose/examples/rbs_samples → examples/fix_errors}/refined/sig/phone.rbs +1 -1
  20. data/examples/fix_errors/sig/email.rbs +11 -0
  21. data/examples/fix_errors/sig/person.rbs +15 -0
  22. data/examples/fix_errors/sig/phone.rbs +15 -0
  23. data/examples/rbs_samples/lib/email.rb +16 -0
  24. data/examples/rbs_samples/lib/person.rb +23 -0
  25. data/examples/rbs_samples/lib/phone.rb +22 -0
  26. data/examples/rbs_samples/refined/sig/email.rbs +11 -0
  27. data/examples/rbs_samples/refined/sig/person.rbs +15 -0
  28. data/examples/rbs_samples/refined/sig/phone.rbs +15 -0
  29. data/examples/rbs_syntax/Steepfile +6 -0
  30. data/examples/rbs_syntax/lib/a.rb +53 -0
  31. data/examples/rbs_syntax/lib/list.rb +9 -0
  32. data/examples/rbs_syntax/lib/main.rb +17 -0
  33. data/examples/rbs_syntax/refined/sig/a.rbs +47 -0
  34. data/examples/rbs_syntax/refined/sig/list.rbs +7 -0
  35. data/examples/rbs_syntax/refined/sig/main.rbs +26 -0
  36. data/examples/rbs_syntax/sig/a.rbs +47 -0
  37. data/examples/rbs_syntax/sig/list.rbs +7 -0
  38. data/examples/rbs_syntax/sig/main.rbs +26 -0
  39. data/lib/rbs_goose/configuration.rb +93 -23
  40. data/lib/rbs_goose/io/example.rb +2 -2
  41. data/lib/rbs_goose/io/example_group.rb +16 -7
  42. data/lib/rbs_goose/io/target_group.rb +1 -1
  43. data/lib/rbs_goose/io/typed_ruby.rb +3 -3
  44. data/lib/rbs_goose/orthoses/fix_error.rb +26 -0
  45. data/lib/rbs_goose/orthoses/infer.rb +26 -0
  46. data/lib/rbs_goose/orthoses.rb +9 -0
  47. data/lib/rbs_goose/templates/base.rb +77 -0
  48. data/lib/rbs_goose/templates/fix_error_template.rb +43 -0
  49. data/lib/rbs_goose/templates/infer_template.rb +30 -0
  50. data/lib/rbs_goose/templates.rb +3 -1
  51. data/lib/rbs_goose/type_inferrer.rb +85 -2
  52. data/lib/rbs_goose/version.rb +1 -1
  53. data/lib/rbs_goose.rb +24 -4
  54. data/rbs_collection.lock.yaml +63 -47
  55. data/renovate.json +5 -0
  56. data/sig/rbs_goose/configuration.rbs +20 -12
  57. data/sig/rbs_goose/io/example.rbs +7 -7
  58. data/sig/rbs_goose/io/example_group.rbs +9 -7
  59. data/sig/rbs_goose/io/file.rbs +10 -10
  60. data/sig/rbs_goose/io/target_group.rbs +2 -2
  61. data/sig/rbs_goose/io/typed_ruby.rbs +7 -7
  62. data/sig/rbs_goose/io.rbs +1 -1
  63. data/sig/rbs_goose/orthoses/fix_error.rbs +11 -0
  64. data/sig/rbs_goose/orthoses/infer.rbs +11 -0
  65. data/sig/rbs_goose/orthoses.rbs +2 -0
  66. data/sig/rbs_goose/templates/base.rbs +18 -0
  67. data/sig/rbs_goose/templates/fix_error_template.rbs +6 -0
  68. data/sig/rbs_goose/templates/infer_template.rbs +6 -0
  69. data/sig/rbs_goose/templates.rbs +1 -1
  70. data/sig/rbs_goose/type_inferrer.rbs +9 -1
  71. data/sig/rbs_goose.rbs +18 -9
  72. metadata +137 -21
  73. data/README-EN-US.md +0 -85
  74. data/lib/rbs_goose/templates/default_template.rb +0 -49
  75. data/sig/rbs_goose/templates/default_template.rbs +0 -10
  76. /data/{lib/rbs_goose/examples/rbs_samples → examples/fix_errors}/lib/email.rb +0 -0
  77. /data/{lib/rbs_goose/examples/rbs_samples → examples/fix_errors}/lib/person.rb +0 -0
  78. /data/{lib/rbs_goose/examples/rbs_samples → examples/fix_errors}/lib/phone.rb +0 -0
  79. /data/{lib/rbs_goose/examples → examples}/rbs_samples/Steepfile +0 -0
  80. /data/{lib/rbs_goose/examples → examples}/rbs_samples/sig/email.rbs +0 -0
  81. /data/{lib/rbs_goose/examples → examples}/rbs_samples/sig/person.rbs +0 -0
  82. /data/{lib/rbs_goose/examples → examples}/rbs_samples/sig/phone.rbs +0 -0
@@ -0,0 +1,1494 @@
1
+ I, [2024-05-08T16:13:56.349456 #66706] INFO -- : [RbsGoose::Orthoses::Infer]#call start
2
+ I, [2024-05-08T16:13:56.349490 #66706] INFO -- : [Orthoses::CreateFileByName]#call start
3
+ I, [2024-05-08T16:13:56.350712 #66706] INFO -- : [Orthoses::Filter]#call start
4
+ I, [2024-05-08T16:13:56.350720 #66706] INFO -- : [Orthoses::Mixin]#call start
5
+ I, [2024-05-08T16:13:56.350730 #66706] INFO -- : [Orthoses::RBSPrototypeRB]#call start
6
+ I, [2024-05-08T16:13:56.350734 #66706] INFO -- : [Orthoses::Store]#call start
7
+ I, [2024-05-08T16:13:56.350737 #66706] INFO -- : [loader].call start
8
+ I, [2024-05-08T16:13:56.350741 #66706] INFO -- : [loader].call end
9
+ I, [2024-05-08T16:13:56.350746 #66706] INFO -- : [Orthoses::Store]#call end
10
+ I, [2024-05-08T16:13:56.933059 #66706] INFO -- : [Orthoses::RBSPrototypeRB]#call end
11
+ I, [2024-05-08T16:13:57.496997 #66706] INFO -- : [Orthoses::Mixin]#call end
12
+ I, [2024-05-08T16:13:57.497042 #66706] INFO -- : [Orthoses::Filter]#call end
13
+ I, [2024-05-08T16:13:57.498780 #66706] INFO -- : Generate file to sig/rbs_goose.rbs
14
+ I, [2024-05-08T16:13:57.499234 #66706] INFO -- : Generate file to sig/rbs_goose/configuration.rbs
15
+ I, [2024-05-08T16:13:57.499396 #66706] INFO -- : Generate file to sig/rbs_goose/io.rbs
16
+ I, [2024-05-08T16:13:57.499586 #66706] INFO -- : Generate file to sig/rbs_goose/io/example.rbs
17
+ I, [2024-05-08T16:13:57.499782 #66706] INFO -- : Generate file to sig/rbs_goose/io/example_group.rbs
18
+ I, [2024-05-08T16:13:57.499990 #66706] INFO -- : Generate file to sig/rbs_goose/io/file.rbs
19
+ I, [2024-05-08T16:13:57.500108 #66706] INFO -- : Generate file to sig/rbs_goose/io/target_group.rbs
20
+ I, [2024-05-08T16:13:57.500271 #66706] INFO -- : Generate file to sig/rbs_goose/io/typed_ruby.rbs
21
+ I, [2024-05-08T16:13:57.500381 #66706] INFO -- : Generate file to sig/rbs_goose/orthoses.rbs
22
+ I, [2024-05-08T16:13:57.500585 #66706] INFO -- : Generate file to sig/rbs_goose/orthoses/fix_error.rbs
23
+ I, [2024-05-08T16:13:57.500736 #66706] INFO -- : Generate file to sig/rbs_goose/orthoses/infer.rbs
24
+ I, [2024-05-08T16:13:57.500832 #66706] INFO -- : Generate file to sig/rbs_goose/templates.rbs
25
+ I, [2024-05-08T16:13:57.501075 #66706] INFO -- : Generate file to sig/rbs_goose/templates/base.rbs
26
+ I, [2024-05-08T16:13:57.501213 #66706] INFO -- : Generate file to sig/rbs_goose/templates/fix_error_template.rbs
27
+ I, [2024-05-08T16:13:57.501358 #66706] INFO -- : Generate file to sig/rbs_goose/templates/infer_template.rbs
28
+ I, [2024-05-08T16:13:57.501549 #66706] INFO -- : Generate file to sig/rbs_goose/type_inferrer.rbs
29
+ I, [2024-05-08T16:13:57.501660 #66706] INFO -- : Generate file to sig/rbs_goose/error.rbs
30
+ I, [2024-05-08T16:13:57.501698 #66706] INFO -- : [Orthoses::CreateFileByName]#call end
31
+ Run RbsGoose.(Code Directory: lib, Signature Directory: sig)
32
+ !!!!!!!! Prompt !!!!!!!!
33
+
34
+ role: user
35
+ content:
36
+ Act as Ruby type inferrer.
37
+ When ruby source codes and RBS type signatures are given, refine each RBS type signatures. Each file should be split in markdown code format.
38
+ Use class names, variable names, etc., to infer type.
39
+
40
+
41
+ ========Input========
42
+ ```ruby:lib/email.rb
43
+ class Email
44
+ # @dynamic address
45
+ attr_reader :address
46
+
47
+ def initialize(address:)
48
+ @address = address
49
+ end
50
+
51
+ def ==(other)
52
+ other.is_a?(self.class) && other.address == address
53
+ end
54
+
55
+ def hash
56
+ self.class.hash ^ address.hash
57
+ end
58
+ end
59
+ ```
60
+
61
+ ```rbs:sig/email.rbs
62
+ class Email
63
+ @address: untyped
64
+
65
+ attr_reader address: untyped
66
+
67
+ def initialize: (address: untyped) -> void
68
+
69
+ def ==: (untyped other) -> untyped
70
+
71
+ def hash: () -> untyped
72
+ end
73
+ ```
74
+
75
+ ```ruby:lib/person.rb
76
+ class Person
77
+ # @dynamic name, contacts
78
+ attr_reader :name
79
+ attr_reader :contacts
80
+
81
+ def initialize(name:)
82
+ @name = name
83
+ @contacts = []
84
+ end
85
+
86
+ def name=(name)
87
+ @name = name
88
+ end
89
+
90
+ def guess_country()
91
+ contacts.map do |contact|
92
+ case contact
93
+ when Phone
94
+ contact.country
95
+ end
96
+ end.compact.first
97
+ end
98
+ end
99
+ ```
100
+
101
+ ```rbs:sig/person.rbs
102
+ class Person
103
+ @name: untyped
104
+
105
+ @contacts: untyped
106
+
107
+ attr_reader name: untyped
108
+
109
+ attr_reader contacts: untyped
110
+
111
+ def initialize: (name: untyped) -> void
112
+
113
+ def name=: (untyped name) -> void
114
+
115
+ def guess_country: () -> untyped
116
+ end
117
+ ```
118
+
119
+ ```ruby:lib/phone.rb
120
+ class Phone
121
+ # @dynamic country, number
122
+ attr_reader :country, :number
123
+
124
+ def initialize(country:, number:)
125
+ @country = country
126
+ @number = number
127
+ end
128
+
129
+ def ==(other)
130
+ if other.is_a?(Phone)
131
+ # @type var other: Phone
132
+ other.country == country && other.number == number
133
+ else
134
+ false
135
+ end
136
+ end
137
+
138
+ def hash
139
+ self.class.hash ^ country.hash ^ number.hash
140
+ end
141
+ end
142
+ ```
143
+
144
+ ```rbs:sig/phone.rbs
145
+ class Phone
146
+ @country: untyped
147
+
148
+ @number: untyped
149
+
150
+ attr_reader country: untyped
151
+
152
+ attr_reader number: untyped
153
+
154
+ def initialize: (country: untyped, number: untyped) -> void
155
+
156
+ def ==: (untyped other) -> (untyped | nil)
157
+
158
+ def hash: () -> untyped
159
+ end
160
+ ```
161
+
162
+
163
+ ========Output========
164
+ ```rbs:sig/email.rbs
165
+ class Email
166
+ @address: String
167
+
168
+ attr_reader address: String
169
+
170
+ def initialize: (address: String) -> void
171
+
172
+ def ==: (Object other) -> bool
173
+
174
+ def hash: () -> Integer
175
+ end
176
+ ```
177
+
178
+ ```rbs:sig/person.rbs
179
+ class Person
180
+ @name: String
181
+
182
+ @contacts: Array[(Email | Phone)]
183
+
184
+ attr_reader name: String
185
+
186
+ attr_reader contacts: Array[(Email | Phone)]
187
+
188
+ def initialize: (name: String) -> void
189
+
190
+ def name=: (String name) -> void
191
+
192
+ def guess_country: () -> (String | nil)
193
+ end
194
+ ```
195
+
196
+ ```rbs:sig/phone.rbs
197
+ class Phone
198
+ @country: String
199
+
200
+ @number: String
201
+
202
+ attr_reader country: String
203
+
204
+ attr_reader number: String
205
+
206
+ def initialize: (country: String, number: String) -> void
207
+
208
+ def ==: (Object other) -> (bool | nil)
209
+
210
+ def hash: () -> Integer
211
+ end
212
+ ```
213
+
214
+
215
+ ========Input========
216
+ ```ruby:lib/rbs_goose/configuration.rb
217
+ # frozen_string_literal: true
218
+
219
+ require 'langchain'
220
+
221
+ require 'forwardable'
222
+
223
+ module RbsGoose
224
+ class Configuration
225
+ extend Forwardable
226
+
227
+ LLMConfig = Struct.new(:client, :mode, keyword_init: true)
228
+
229
+ TemplateConfig = Struct.new(:instruction, :example_groups, :template_class, keyword_init: true) do
230
+ def build_template
231
+ template_class.new(instruction:, example_groups:)
232
+ end
233
+ end
234
+
235
+ def initialize(&)
236
+ self.infer_template = default_infer_template
237
+ self.fix_error_template = default_fix_error_template
238
+ instance_eval(&) if block_given?
239
+ end
240
+
241
+ attr_accessor :llm, :infer_template, :fix_error_template
242
+
243
+ def use_open_ai( # rubocop:disable Metrics/MethodLength
244
+ open_ai_access_token, model_name: 'gpt-3.5-turbo-1106', mode: :chat,
245
+ llm_options: {}, default_options: {}
246
+ )
247
+ @llm = LLMConfig.new(
248
+ client: ::Langchain::LLM::OpenAI.new(
249
+ api_key: open_ai_access_token,
250
+ llm_options: { request_timeout: 600 }.merge(llm_options),
251
+ default_options: {
252
+ completion_model_name: model_name,
253
+ chat_completion_model_name: model_name
254
+ }.merge(default_options)
255
+ ),
256
+ mode:
257
+ )
258
+ end
259
+
260
+ def use_anthropic(access_token, model_name: 'claude-3-haiku-20240307', mode: :chat, default_options: {}) # rubocop:disable Metrics/MethodLength
261
+ @llm = LLMConfig.new(
262
+ client: ::Langchain::LLM::Anthropic.new(
263
+ api_key: access_token,
264
+ default_options: {
265
+ completion_model_name: model_name,
266
+ chat_completion_model_name: model_name,
267
+ max_tokens_to_sample: 4096
268
+ }.merge(default_options)
269
+ ),
270
+ mode:
271
+ )
272
+ end
273
+
274
+ def use_ollama(url: 'http://localhost:11434', model_name: 'codegemma', mode: :complete, default_options: {}) # rubocop:disable Metrics/MethodLength
275
+ @llm = LLMConfig.new(
276
+ client: ::Langchain::LLM::Ollama.new(
277
+ url:,
278
+ default_options: {
279
+ temperature: 0.0,
280
+ completion_model_name: model_name,
281
+ chat_completion_model_name: model_name
282
+ }.merge(default_options)
283
+ ),
284
+ mode:
285
+ )
286
+ end
287
+
288
+ def_delegator :llm, :client, :llm_client
289
+ def_delegator :llm, :mode, :llm_mode
290
+ def_delegator :infer_template, :instruction, :infer_instruction
291
+ def_delegator :infer_template, :example_groups, :infer_example_groups
292
+
293
+ private
294
+
295
+ def default_infer_template
296
+ TemplateConfig.new(
297
+ instruction: default_infer_instruction,
298
+ example_groups: default_infer_example_groups,
299
+ template_class: Templates::InferTemplate
300
+ )
301
+ end
302
+
303
+ def default_fix_error_template
304
+ TemplateConfig.new(
305
+ instruction: default_fix_error_instruction,
306
+ example_groups: default_fix_error_example_groups,
307
+ template_class: Templates::FixErrorTemplate
308
+ )
309
+ end
310
+
311
+ def default_infer_instruction
312
+ <<~INSTRUCTION
313
+ Act as Ruby type inferrer.
314
+ When ruby source codes and RBS type signatures are given, refine each RBS type signatures. Each file should be split in markdown code format.
315
+ Use class names, variable names, etc., to infer type.
316
+ INSTRUCTION
317
+ end
318
+
319
+ def default_infer_example_groups
320
+ [RbsGoose::IO::ExampleGroup.default_examples[:rbs_samples]]
321
+ end
322
+
323
+ def default_fix_error_instruction
324
+ <<~INSTRUCTION
325
+ You are a highly skilled programmer.
326
+ Based on the following Ruby code, the RBS code that is a type definition, and the type checking error messages for them, modify the RBS code and output it.
327
+ All RBS files should be output, regardless of whether they have been modified or not.
328
+ INSTRUCTION
329
+ end
330
+
331
+ def default_fix_error_example_groups
332
+ [RbsGoose::IO::ExampleGroup.default_examples[:fix_errors]]
333
+ end
334
+ end
335
+ end
336
+ ```
337
+
338
+ ```rbs:sig/rbs_goose/configuration.rbs
339
+ class RbsGoose::Configuration
340
+ @llm: untyped
341
+ extend Forwardable
342
+ LLMConfig: untyped
343
+ TemplateConfig: untyped
344
+ def initialize: () ?{ () -> untyped } -> void
345
+ attr_accessor llm: untyped
346
+ attr_accessor infer_template: untyped
347
+ attr_accessor fix_error_template: untyped
348
+ def use_open_ai: (untyped open_ai_access_token, ?model_name: ::String, ?mode: ::Symbol, ?llm_options: ::Hash[untyped, untyped], ?default_options: ::Hash[untyped, untyped]) -> untyped
349
+ def use_anthropic: (untyped access_token, ?model_name: ::String, ?mode: ::Symbol, ?default_options: ::Hash[untyped, untyped]) -> untyped
350
+ def use_ollama: (?url: ::String, ?model_name: ::String, ?mode: ::Symbol, ?default_options: ::Hash[untyped, untyped]) -> untyped
351
+ private def default_infer_template: () -> untyped
352
+ private def default_fix_error_template: () -> untyped
353
+ private def default_infer_instruction: () -> "Act as Ruby type inferrer.\nWhen ruby source codes and RBS type signatures are given, refine each RBS type signatures. Each file should be split in markdown code format.\nUse class names, variable names, etc., to infer type.\n"
354
+ private def default_infer_example_groups: () -> ::Array[untyped]
355
+ private def default_fix_error_instruction: () -> "You are a highly skilled programmer.\nBased on the following Ruby code, the RBS code that is a type definition, and the type checking error messages for them, modify the RBS code and output it.\nAll RBS files should be output, regardless of whether they have been modified or not.\n"
356
+ private def default_fix_error_example_groups: () -> ::Array[untyped]
357
+ end
358
+ ```
359
+
360
+ ```ruby:lib/rbs_goose/io/example.rb
361
+ # frozen_string_literal: true
362
+
363
+ module RbsGoose
364
+ module IO
365
+ class Example
366
+ class << self
367
+ def from_path(ruby_path:, rbs_path:, refined_rbs_dir:, base_path:)
368
+ Example.new(
369
+ typed_ruby: TypedRuby.from_path(ruby_path:, rbs_path:, base_path:),
370
+ refined_rbs: File.new(path: rbs_path, base_path: ::File.join(base_path, refined_rbs_dir))
371
+ )
372
+ end
373
+ end
374
+
375
+ def initialize(typed_ruby:, refined_rbs:)
376
+ @typed_ruby = typed_ruby
377
+ @refined_rbs = refined_rbs
378
+ end
379
+
380
+ def to_h
381
+ { typed_ruby:, refined_rbs: }
382
+ end
383
+
384
+ attr_reader :typed_ruby, :refined_rbs
385
+ end
386
+ end
387
+ end
388
+ ```
389
+
390
+ ```rbs:sig/rbs_goose/io/example.rbs
391
+ class RbsGoose::IO::Example
392
+ @typed_ruby: untyped
393
+ @refined_rbs: untyped
394
+ def self.from_path: (ruby_path: untyped, rbs_path: untyped, refined_rbs_dir: untyped, base_path: untyped) -> untyped
395
+ def initialize: (typed_ruby: untyped, refined_rbs: untyped) -> void
396
+ def to_h: () -> { typed_ruby: untyped, refined_rbs: untyped }
397
+ attr_reader typed_ruby: untyped
398
+ attr_reader refined_rbs: untyped
399
+ end
400
+ ```
401
+
402
+ ```ruby:lib/rbs_goose/io/example_group.rb
403
+ # frozen_string_literal: true
404
+
405
+ module RbsGoose
406
+ module IO
407
+ class ExampleGroup < Array
408
+ attr_accessor :error_messages
409
+
410
+ class << self
411
+ def load_from(base_path, code_dir: 'lib', sig_dir: 'sig', refined_dir: 'refined')
412
+ new.tap do |group|
413
+ Dir.glob('**/*.rb', base: ::File.join(base_path, code_dir)).each do |path|
414
+ group << load_example(base_path, code_dir, path, refined_dir, sig_dir)
415
+ end
416
+ # Read error messages if exists
417
+ error_path = ::File.join(base_path, 'error_messages.txt')
418
+ group.error_messages = ::File.read(error_path).strip if ::File.exist?(error_path)
419
+ end
420
+ end
421
+
422
+ def default_examples
423
+ example_dir = ::File.join(__dir__.to_s, '../../../examples')
424
+ @default_examples ||= Dir.glob('*', base: example_dir).to_h do |dir|
425
+ [dir.to_sym, load_from(::File.join(example_dir, dir))]
426
+ end
427
+ end
428
+
429
+ private
430
+
431
+ def load_example(base_path, code_dir, path, refined_dir, sig_dir)
432
+ Example.from_path(
433
+ ruby_path: ::File.join(code_dir, path),
434
+ rbs_path: to_rbs_path(path, sig_dir),
435
+ refined_rbs_dir: refined_dir,
436
+ base_path:
437
+ )
438
+ end
439
+
440
+ def to_rbs_path(path, sig_dir)
441
+ ::File.join(sig_dir, "#{path}s")
442
+ end
443
+ end
444
+
445
+ def to_target_group
446
+ TargetGroup.new.tap do |g|
447
+ each { g << _1.typed_ruby }
448
+ end
449
+ end
450
+
451
+ def to_refined_rbs_list
452
+ map(&:refined_rbs)
453
+ end
454
+ end
455
+ end
456
+ end
457
+ ```
458
+
459
+ ```rbs:sig/rbs_goose/io/example_group.rbs
460
+ class RbsGoose::IO::ExampleGroup < ::Array[untyped]
461
+ self.@default_examples: untyped
462
+ attr_accessor error_messages: untyped
463
+ def self.load_from: (untyped base_path, ?code_dir: ::String, ?sig_dir: ::String, ?refined_dir: ::String) -> untyped
464
+ def self.default_examples: () -> untyped
465
+ private def self.load_example: (untyped base_path, untyped code_dir, untyped path, untyped refined_dir, untyped sig_dir) -> untyped
466
+ private def self.to_rbs_path: (untyped path, untyped sig_dir) -> untyped
467
+ def to_target_group: () -> untyped
468
+ def to_refined_rbs_list: () -> untyped
469
+ end
470
+ ```
471
+
472
+ ```ruby:lib/rbs_goose/io/file.rb
473
+ # frozen_string_literal: true
474
+
475
+ module RbsGoose
476
+ module IO
477
+ class File
478
+ MARKDOWN_REGEXP = /\A```(?<type>ruby|rbs):(?<path>.+)\n(?<content>[\s\S]+)```\Z/
479
+
480
+ class << self
481
+ def from_markdown(markdown)
482
+ parsed = markdown.match(MARKDOWN_REGEXP)
483
+ raise ArgumentError, "Ruby or RBS Markdown parsing failed.\n#{markdown}" unless parsed
484
+
485
+ new(path: parsed[:path].to_s, content: parsed[:content].to_s)
486
+ end
487
+ end
488
+
489
+ def initialize(path:, content: nil, base_path: nil)
490
+ @path = path
491
+ @base_path = base_path
492
+ @content = content&.strip
493
+ load_content if @content.nil?
494
+ end
495
+
496
+ def load_content
497
+ @content = ::File.read(absolute_path).strip
498
+ end
499
+
500
+ def absolute_path
501
+ base_path ? ::File.join(base_path, path) : path
502
+ end
503
+
504
+ def type
505
+ @type ||= case path
506
+ in /\.rb\z/
507
+ :ruby
508
+ in /\.rbs\z/
509
+ :rbs
510
+ else
511
+ raise ArgumentError, "Unknown file type: #{path}"
512
+ end
513
+ end
514
+
515
+ def to_s
516
+ "```#{type}:#{path}\n#{content}\n```\n"
517
+ end
518
+
519
+ def content=(content)
520
+ @content = content.strip
521
+ end
522
+
523
+ def write
524
+ ::File.write(path, content)
525
+ end
526
+
527
+ def ==(other)
528
+ self.class == other.class &&
529
+ @path == other.path &&
530
+ @content == other.content
531
+ end
532
+
533
+ attr_reader :path, :content, :base_path
534
+ end
535
+ end
536
+ end
537
+ ```
538
+
539
+ ```rbs:sig/rbs_goose/io/file.rbs
540
+ class RbsGoose::IO::File
541
+ @path: untyped
542
+ @base_path: untyped
543
+ @content: untyped
544
+ @type: untyped
545
+ MARKDOWN_REGEXP: ::Regexp
546
+ def self.from_markdown: (untyped markdown) -> untyped
547
+ def initialize: (path: untyped, ?content: untyped?, ?base_path: untyped?) -> void
548
+ def load_content: () -> untyped
549
+ def absolute_path: () -> untyped
550
+ def type: () -> untyped
551
+ def to_s: () -> ::String
552
+ def content=: (untyped content) -> untyped
553
+ def write: () -> untyped
554
+ def ==: (untyped other) -> untyped
555
+ attr_reader path: untyped
556
+ attr_reader content: untyped
557
+ attr_reader base_path: untyped
558
+ end
559
+ ```
560
+
561
+ ```ruby:lib/rbs_goose/io/target_group.rb
562
+ # frozen_string_literal: true
563
+
564
+ module RbsGoose
565
+ module IO
566
+ class TargetGroup < Array
567
+ class << self
568
+ def load_from(base_path, code_dir: 'lib', sig_dir: 'sig')
569
+ new.tap do |group|
570
+ Dir.glob('**/*.rb', base: ::File.join(base_path, code_dir)).each do |path|
571
+ group << TypedRuby.from_path(
572
+ ruby_path: ::File.join(code_dir, path),
573
+ rbs_path: ::File.join(sig_dir, "#{path}s"),
574
+ base_path:
575
+ )
576
+ end
577
+ end
578
+ end
579
+ end
580
+ end
581
+ end
582
+ end
583
+ ```
584
+
585
+ ```rbs:sig/rbs_goose/io/target_group.rbs
586
+ class RbsGoose::IO::TargetGroup < ::Array[untyped]
587
+ def self.load_from: (untyped base_path, ?code_dir: ::String, ?sig_dir: ::String) -> untyped
588
+ end
589
+ ```
590
+
591
+ ```ruby:lib/rbs_goose/io/typed_ruby.rb
592
+ # frozen_string_literal: true
593
+
594
+ module RbsGoose
595
+ module IO
596
+ class TypedRuby
597
+ class << self
598
+ def from_path(ruby_path:, rbs_path:, base_path:)
599
+ ruby = File.new(path: ruby_path, base_path:)
600
+ rbs = begin
601
+ File.new(path: rbs_path, base_path:)
602
+ rescue StandardError
603
+ nil
604
+ end
605
+ new(ruby:, rbs:)
606
+ end
607
+ end
608
+
609
+ def initialize(ruby:, rbs:)
610
+ raise ArgumentError, 'ruby must have ".rb" extension' unless ruby.type == :ruby
611
+ raise ArgumentError, 'rbs must have ".rbs" extension' if !rbs.nil? && rbs.type != :rbs
612
+
613
+ @ruby = ruby
614
+ @rbs = rbs
615
+ end
616
+
617
+ def to_s
618
+ rbs.nil? ? ruby.to_s : "#{ruby}\n#{rbs}"
619
+ end
620
+
621
+ attr_reader :ruby, :rbs
622
+ end
623
+ end
624
+ end
625
+ ```
626
+
627
+ ```rbs:sig/rbs_goose/io/typed_ruby.rbs
628
+ class RbsGoose::IO::TypedRuby
629
+ @ruby: untyped
630
+ @rbs: untyped
631
+ def self.from_path: (ruby_path: untyped, rbs_path: untyped, base_path: untyped) -> untyped
632
+ def initialize: (ruby: untyped, rbs: untyped) -> void
633
+ def to_s: () -> (untyped | ::String)
634
+ attr_reader ruby: untyped
635
+ attr_reader rbs: untyped
636
+ end
637
+ ```
638
+
639
+ ```ruby:lib/rbs_goose/io.rb
640
+ # frozen_string_literal: true
641
+
642
+ require_relative 'io/example'
643
+ require_relative 'io/example_group'
644
+ require_relative 'io/file'
645
+ require_relative 'io/target_group'
646
+ require_relative 'io/typed_ruby'
647
+
648
+ module RbsGoose
649
+ module IO
650
+ end
651
+ end
652
+ ```
653
+
654
+ ```rbs:sig/rbs_goose/io.rbs
655
+ module RbsGoose::IO
656
+ end
657
+ ```
658
+
659
+ ```ruby:lib/rbs_goose/orthoses/fix_error.rb
660
+ # frozen_string_literal: true
661
+
662
+ require 'orthoses/outputable'
663
+
664
+ module RbsGoose
665
+ module Orthoses
666
+ # Call RbsGoose::TypeInferrer to fix steep type errors.
667
+ # use TbsGoose::Orthoses::FixError, code_dir: 'lib', sig_dir: 'sig' do |config|
668
+ # config.use_open_ai('open_ai_access_token')
669
+ # end
670
+ class FixError
671
+ def initialize(loader, code_dir: 'lib', sig_dir: 'sig', &)
672
+ @loader = loader
673
+ @code_dir = code_dir
674
+ @sig_dir = sig_dir
675
+ RbsGoose.configure(&) if block_given?
676
+ end
677
+
678
+ def call
679
+ @loader.call.tap do
680
+ RbsGoose.fix_error(code_dir: @code_dir, sig_dir: @sig_dir)
681
+ end
682
+ end
683
+ end
684
+ end
685
+ end
686
+ ```
687
+
688
+ ```rbs:sig/rbs_goose/orthoses/fix_error.rbs
689
+ # Call RbsGoose::TypeInferrer to fix steep type errors.
690
+ # use TbsGoose::Orthoses::FixError, code_dir: 'lib', sig_dir: 'sig' do |config|
691
+ # config.use_open_ai('open_ai_access_token')
692
+ # end
693
+ class RbsGoose::Orthoses::FixError
694
+ @loader: untyped
695
+ @code_dir: untyped
696
+ @sig_dir: untyped
697
+ def initialize: (untyped loader, ?code_dir: ::String, ?sig_dir: ::String) ?{ () -> untyped } -> void
698
+ def call: () -> untyped
699
+ end
700
+ ```
701
+
702
+ ```ruby:lib/rbs_goose/orthoses/infer.rb
703
+ # frozen_string_literal: true
704
+
705
+ require 'orthoses/outputable'
706
+
707
+ module RbsGoose
708
+ module Orthoses
709
+ # Call RbsGoose::TypeInferrer to infer RBS type signatures.
710
+ # use TbsGoose::Orthoses::Infer, code_dir: 'lib', sig_dir: 'sig' do |config|
711
+ # config.use_open_ai('open_ai_access_token')
712
+ # end
713
+ class Infer
714
+ def initialize(loader, code_dir: 'lib', sig_dir: 'sig', &)
715
+ @loader = loader
716
+ @code_dir = code_dir
717
+ @sig_dir = sig_dir
718
+ RbsGoose.configure(&) if block_given?
719
+ end
720
+
721
+ def call
722
+ @loader.call.tap do
723
+ RbsGoose.run(code_dir: @code_dir, sig_dir: @sig_dir)
724
+ end
725
+ end
726
+ end
727
+ end
728
+ end
729
+ ```
730
+
731
+ ```rbs:sig/rbs_goose/orthoses/infer.rbs
732
+ # Call RbsGoose::TypeInferrer to infer RBS type signatures.
733
+ # use TbsGoose::Orthoses::Infer, code_dir: 'lib', sig_dir: 'sig' do |config|
734
+ # config.use_open_ai('open_ai_access_token')
735
+ # end
736
+ class RbsGoose::Orthoses::Infer
737
+ @loader: untyped
738
+ @code_dir: untyped
739
+ @sig_dir: untyped
740
+ def initialize: (untyped loader, ?code_dir: ::String, ?sig_dir: ::String) ?{ () -> untyped } -> void
741
+ def call: () -> untyped
742
+ end
743
+ ```
744
+
745
+ ```ruby:lib/rbs_goose/orthoses.rb
746
+ # frozen_string_literal: true
747
+
748
+ require_relative 'orthoses/fix_error'
749
+ require_relative 'orthoses/infer'
750
+
751
+ module RbsGoose
752
+ module Orthoses
753
+ end
754
+ end
755
+ ```
756
+
757
+ ```rbs:sig/rbs_goose/orthoses.rbs
758
+ module RbsGoose::Orthoses
759
+ end
760
+ ```
761
+
762
+ ```ruby:lib/rbs_goose/templates/base.rb
763
+ # frozen_string_literal: true
764
+
765
+ require 'langchain'
766
+
767
+ module RbsGoose
768
+ module Templates
769
+ class Base
770
+ def initialize(instruction:, example_groups:)
771
+ @instruction = instruction
772
+ @example_groups = example_groups
773
+ end
774
+
775
+ def format(**args)
776
+ Langchain::Prompt::FewShotPromptTemplate.new(
777
+ prefix:,
778
+ suffix:,
779
+ example_prompt:,
780
+ examples: example_groups.map { transform_example_group(_1) },
781
+ input_variables:
782
+ ).format(**format_args(args)).strip
783
+ end
784
+
785
+ def format_system_prompt
786
+ prefix.strip
787
+ end
788
+
789
+ def format_user_prompt(**args)
790
+ Langchain::Prompt::FewShotPromptTemplate.new(
791
+ prefix: '',
792
+ suffix:,
793
+ example_prompt:,
794
+ examples: example_groups.map { transform_example_group(_1) },
795
+ input_variables:
796
+ ).format(**format_args(args)).strip
797
+ end
798
+
799
+ def parse_result(result)
800
+ result.scan(/```.+?```/m).map { IO::File.from_markdown(_1) }
801
+ end
802
+
803
+ private
804
+
805
+ def input_template_string
806
+ raise NotImplementedError
807
+ end
808
+
809
+ def input_variables
810
+ raise NotImplementedError
811
+ end
812
+
813
+ def transform_example_group(example_group)
814
+ raise NotImplementedError
815
+ end
816
+
817
+ def format_args(args)
818
+ raise NotImplementedError
819
+ end
820
+
821
+ def prefix
822
+ instruction
823
+ end
824
+
825
+ def suffix
826
+ "#{input_template_string}\n"
827
+ end
828
+
829
+ def example_prompt
830
+ Langchain::Prompt::PromptTemplate.new(
831
+ template: "#{input_template_string}\n{refined_rbs_list}",
832
+ input_variables: input_variables + ['refined_rbs_list']
833
+ )
834
+ end
835
+
836
+ attr_reader :instruction, :example_groups
837
+ end
838
+ end
839
+ end
840
+ ```
841
+
842
+ ```rbs:sig/rbs_goose/templates/base.rbs
843
+ class RbsGoose::Templates::Base
844
+ @instruction: untyped
845
+ @example_groups: untyped
846
+ def initialize: (instruction: untyped, example_groups: untyped) -> void
847
+ def format: (**untyped args) -> untyped
848
+ def format_system_prompt: () -> untyped
849
+ def format_user_prompt: (**untyped args) -> untyped
850
+ def parse_result: (untyped result) -> untyped
851
+ private def input_template_string: () -> untyped
852
+ private def input_variables: () -> untyped
853
+ private def transform_example_group: (untyped example_group) -> untyped
854
+ private def format_args: (untyped args) -> untyped
855
+ private def prefix: () -> untyped
856
+ private def suffix: () -> ::String
857
+ private def example_prompt: () -> untyped
858
+ private attr_reader instruction: untyped
859
+ private attr_reader example_groups: untyped
860
+ end
861
+ ```
862
+
863
+ ```ruby:lib/rbs_goose/templates/fix_error_template.rb
864
+ # frozen_string_literal: true
865
+
866
+ require 'langchain'
867
+
868
+ module RbsGoose
869
+ module Templates
870
+ class FixErrorTemplate < Base
871
+ private
872
+
873
+ def input_variables
874
+ %w[typed_ruby_list error_messages]
875
+ end
876
+
877
+ def input_template_string
878
+ <<~TEMPLATE.strip
879
+ ========Input========
880
+ {typed_ruby_list}
881
+
882
+ ========Errors========
883
+ {error_messages}
884
+
885
+
886
+ ========Output========
887
+ TEMPLATE
888
+ end
889
+
890
+ def format_args(args)
891
+ {
892
+ typed_ruby_list: args[:typed_ruby_list].join("\n"),
893
+ error_messages: args[:error_messages]
894
+ }
895
+ end
896
+
897
+ def transform_example_group(example_group)
898
+ {
899
+ typed_ruby_list: example_group.map(&:typed_ruby).join("\n"),
900
+ error_messages: example_group.error_messages,
901
+ refined_rbs_list: example_group.map(&:refined_rbs).join("\n")
902
+ }
903
+ end
904
+ end
905
+ end
906
+ end
907
+ ```
908
+
909
+ ```rbs:sig/rbs_goose/templates/fix_error_template.rbs
910
+ class RbsGoose::Templates::FixErrorTemplate < ::RbsGoose::Templates::Base
911
+ private def input_variables: () -> ::Array["typed_ruby_list" | "error_messages"]
912
+ private def input_template_string: () -> untyped
913
+ private def format_args: (untyped args) -> { typed_ruby_list: untyped, error_messages: untyped }
914
+ private def transform_example_group: (untyped example_group) -> { typed_ruby_list: untyped, error_messages: untyped, refined_rbs_list: untyped }
915
+ end
916
+ ```
917
+
918
+ ```ruby:lib/rbs_goose/templates/infer_template.rb
919
+ # frozen_string_literal: true
920
+
921
+ require 'langchain'
922
+
923
+ module RbsGoose
924
+ module Templates
925
+ class InferTemplate < Base
926
+ private
927
+
928
+ def input_variables
929
+ %w[typed_ruby_list]
930
+ end
931
+
932
+ def input_template_string
933
+ "========Input========\n{typed_ruby_list}\n\n========Output========"
934
+ end
935
+
936
+ def format_args(args)
937
+ { typed_ruby_list: args[:typed_ruby_list].join("\n") }
938
+ end
939
+
940
+ def transform_example_group(example_group)
941
+ {
942
+ typed_ruby_list: example_group.map(&:typed_ruby).join("\n"),
943
+ refined_rbs_list: example_group.map(&:refined_rbs).join("\n")
944
+ }
945
+ end
946
+ end
947
+ end
948
+ end
949
+ ```
950
+
951
+ ```rbs:sig/rbs_goose/templates/infer_template.rbs
952
+ class RbsGoose::Templates::InferTemplate < ::RbsGoose::Templates::Base
953
+ private def input_variables: () -> ::Array["typed_ruby_list"]
954
+ private def input_template_string: () -> "========Input========\n{typed_ruby_list}\n\n========Output========"
955
+ private def format_args: (untyped args) -> { typed_ruby_list: untyped }
956
+ private def transform_example_group: (untyped example_group) -> { typed_ruby_list: untyped, refined_rbs_list: untyped }
957
+ end
958
+ ```
959
+
960
+ ```ruby:lib/rbs_goose/templates.rb
961
+ # frozen_string_literal: true
962
+
963
+ require_relative 'templates/base'
964
+ require_relative 'templates/fix_error_template'
965
+ require_relative 'templates/infer_template'
966
+
967
+ module RbsGoose
968
+ module Templates
969
+ end
970
+ end
971
+ ```
972
+
973
+ ```rbs:sig/rbs_goose/templates.rbs
974
+ module RbsGoose::Templates
975
+ end
976
+ ```
977
+
978
+ ```ruby:lib/rbs_goose/type_inferrer.rb
979
+ # frozen_string_literal: true
980
+
981
+ require 'steep'
982
+ require 'steep/cli'
983
+ require 'benchmark'
984
+
985
+ require_relative 'templates'
986
+
987
+ module RbsGoose
988
+ class TypeInferrer
989
+ def infer(target_group)
990
+ call_llm(RbsGoose.infer_template, { typed_ruby_list: target_group })
991
+ end
992
+
993
+ def fix_error(target_group)
994
+ error_messages = steep_check
995
+ call_llm(RbsGoose.fix_error_template, { typed_ruby_list: target_group, error_messages: })
996
+ end
997
+
998
+ private
999
+
1000
+ def call_llm(template, format_args)
1001
+ result =
1002
+ case RbsGoose.llm_mode.to_sym
1003
+ when :complete
1004
+ call_llm_complete(format_args, template)
1005
+ when :chat
1006
+ call_llm_chat(format_args, template)
1007
+ else
1008
+ raise "Invalid LLM mode: #{RbsGoose.llm_mode}"
1009
+ end
1010
+ template.parse_result(result)
1011
+ end
1012
+
1013
+ def call_llm_complete(format_args, template)
1014
+ prompt = template.format(**format_args)
1015
+ llm_debug(prompt) do
1016
+ RbsGoose.llm.complete(prompt:)
1017
+ end.completion
1018
+ end
1019
+
1020
+ def call_llm_chat(format_args, template)
1021
+ messages = [
1022
+ { role: 'user', content: template.format(**format_args) }
1023
+ ]
1024
+ llm_debug(messages.map { "role: #{_1[:role]}\ncontent:\n#{_1[:content]}" }.join("\n")) do
1025
+ RbsGoose.llm.chat(messages:)
1026
+ end.chat_completion
1027
+ end
1028
+
1029
+ def llm_debug(prompt)
1030
+ return yield if ENV['DEBUG'].nil?
1031
+
1032
+ puts "!!!!!!!! Prompt !!!!!!!!\n\n#{prompt}\n\n"
1033
+ result = nil
1034
+ sec = Benchmark.realtime do
1035
+ result = yield
1036
+ end
1037
+ puts "!!!!!!!! Stats !!!!!!!!\n\n spend: #{sec}[s]\n prompt_tokens: #{result.prompt_tokens}\n completion_tokens: #{result.completion_tokens}\n"
1038
+ puts "!!!!!!!! Result !!!!!!!!\n\n#{result.chat_completion}\n\n"
1039
+ result
1040
+ end
1041
+
1042
+ def steep_check
1043
+ stdin, stdout, stderr = io_stubs
1044
+ disable_rainbow do
1045
+ steep_cli = Steep::CLI.new(stdout:, stdin:, stderr:, argv: [])
1046
+ steep_cli.process_check
1047
+ end
1048
+ stdout.string
1049
+ end
1050
+
1051
+ def io_stubs
1052
+ [StringIO.new(''), StringIO.new(+'', 'w+'), StringIO.new(+'', 'w+')]
1053
+ end
1054
+
1055
+ def disable_rainbow
1056
+ rainbow_enabled = Rainbow.enabled
1057
+ Rainbow.enabled = false
1058
+ yield
1059
+ Rainbow.enabled = rainbow_enabled
1060
+ end
1061
+ end
1062
+ end
1063
+ ```
1064
+
1065
+ ```rbs:sig/rbs_goose/type_inferrer.rbs
1066
+ class RbsGoose::TypeInferrer
1067
+ def infer: (untyped target_group) -> untyped
1068
+ def fix_error: (untyped target_group) -> untyped
1069
+ private def call_llm: (untyped template, untyped format_args) -> untyped
1070
+ private def call_llm_complete: (untyped format_args, untyped template) -> untyped
1071
+ private def call_llm_chat: (untyped format_args, untyped template) -> untyped
1072
+ private def llm_debug: (untyped prompt) { () -> untyped } -> untyped
1073
+ private def steep_check: () -> untyped
1074
+ private def io_stubs: () -> ::Array[untyped]
1075
+ private def disable_rainbow: () { () -> untyped } -> untyped
1076
+ end
1077
+ ```
1078
+
1079
+ ```ruby:lib/rbs_goose/version.rb
1080
+ # frozen_string_literal: true
1081
+
1082
+ module RbsGoose
1083
+ VERSION = '0.1.1'
1084
+ end
1085
+ ```
1086
+
1087
+ ```ruby:lib/rbs_goose.rb
1088
+ # frozen_string_literal: true
1089
+
1090
+ require_relative 'rbs_goose/configuration'
1091
+ require_relative 'rbs_goose/io'
1092
+ require_relative 'rbs_goose/orthoses'
1093
+ require_relative 'rbs_goose/type_inferrer'
1094
+ require_relative 'rbs_goose/version'
1095
+
1096
+ require 'forwardable'
1097
+
1098
+ module RbsGoose
1099
+ class Error < StandardError; end
1100
+
1101
+ class << self
1102
+ extend Forwardable
1103
+
1104
+ def configure(&)
1105
+ @configuration = Configuration.new(&)
1106
+ end
1107
+
1108
+ def reset_configuration
1109
+ @configuration = nil
1110
+ end
1111
+
1112
+ def run(code_dir: 'lib', sig_dir: 'sig', base_path: ::Dir.pwd)
1113
+ puts "Run RbsGoose.(Code Directory: #{code_dir}, Signature Directory: #{sig_dir})"
1114
+ target_group = RbsGoose::IO::TargetGroup.load_from(base_path, code_dir:, sig_dir:)
1115
+ RbsGoose::TypeInferrer.new.infer(target_group).each do |refined_rbs|
1116
+ puts "write refined rbs to #{refined_rbs.path}\n"
1117
+ refined_rbs.write
1118
+ puts "done.\n\n"
1119
+ end
1120
+ end
1121
+
1122
+ def fix_error(code_dir: 'lib', sig_dir: 'sig', base_path: ::Dir.pwd)
1123
+ puts "Run FixError.(Code Directory: #{code_dir}, Signature Directory: #{sig_dir})"
1124
+ target_group = RbsGoose::IO::TargetGroup.load_from(base_path, code_dir:, sig_dir:)
1125
+ RbsGoose::TypeInferrer.new.fix_error(target_group).each do |refined_rbs|
1126
+ puts "write refined rbs to #{refined_rbs.path}\n"
1127
+ refined_rbs.write
1128
+ puts "done.\n\n"
1129
+ end
1130
+ end
1131
+
1132
+ def infer_template
1133
+ configuration.infer_template.build_template
1134
+ end
1135
+
1136
+ def fix_error_template
1137
+ configuration.fix_error_template.build_template
1138
+ end
1139
+
1140
+ attr_reader :configuration
1141
+
1142
+ def_delegators :configuration, :infer_instruction, :infer_example_groups, :llm_mode
1143
+ def_delegator :configuration, :llm_client, :llm
1144
+ end
1145
+ end
1146
+ ```
1147
+
1148
+ ```rbs:sig/rbs_goose.rbs
1149
+ module RbsGoose
1150
+ VERSION: "0.1.1"
1151
+
1152
+ self.@configuration: untyped
1153
+
1154
+ extend Forwardable
1155
+
1156
+ def self.configure: () { () -> untyped } -> untyped
1157
+
1158
+ def self.reset_configuration: () -> untyped
1159
+
1160
+ def self.run: (?code_dir: ::String, ?sig_dir: ::String, ?base_path: untyped) -> untyped
1161
+
1162
+ def self.fix_error: (?code_dir: ::String, ?sig_dir: ::String, ?base_path: untyped) -> untyped
1163
+
1164
+ def self.infer_template: () -> untyped
1165
+
1166
+ def self.fix_error_template: () -> untyped
1167
+
1168
+ attr_reader self.configuration: untyped
1169
+ end
1170
+ ```
1171
+
1172
+
1173
+ ========Output========
1174
+
1175
+ !!!!!!!! Stats !!!!!!!!
1176
+
1177
+ spend: 27.408822000026703[s]
1178
+ prompt_tokens: 10035
1179
+ completion_tokens: 3333
1180
+ !!!!!!!! Result !!!!!!!!
1181
+
1182
+ Here are the refined RBS type signatures based on the provided Ruby source codes:
1183
+
1184
+ ```rbs:sig/email.rbs
1185
+ class Email
1186
+ @address: String
1187
+
1188
+ attr_reader address: String
1189
+
1190
+ def initialize: (address: String) -> void
1191
+
1192
+ def ==: (Object other) -> bool
1193
+
1194
+ def hash: () -> Integer
1195
+ end
1196
+ ```
1197
+
1198
+ ```rbs:sig/person.rbs
1199
+ class Person
1200
+ @name: String
1201
+ @contacts: Array[Email | Phone]
1202
+
1203
+ attr_reader name: String
1204
+ attr_reader contacts: Array[Email | Phone]
1205
+
1206
+ def initialize: (name: String) -> void
1207
+
1208
+ def name=: (String name) -> void
1209
+
1210
+ def guess_country: () -> (String | nil)
1211
+ end
1212
+ ```
1213
+
1214
+ ```rbs:sig/phone.rbs
1215
+ class Phone
1216
+ @country: String
1217
+ @number: String
1218
+
1219
+ attr_reader country: String
1220
+ attr_reader number: String
1221
+
1222
+ def initialize: (country: String, number: String) -> void
1223
+
1224
+ def ==: (Object other) -> (bool | nil)
1225
+
1226
+ def hash: () -> Integer
1227
+ end
1228
+ ```
1229
+
1230
+ ```rbs:sig/rbs_goose/configuration.rbs
1231
+ class RbsGoose::Configuration
1232
+ @llm: LLMConfig
1233
+ extend Forwardable
1234
+ LLMConfig: Struct.new(:client, :mode, keyword_init: true)
1235
+ TemplateConfig: Struct.new(:instruction, :example_groups, :template_class, keyword_init: true)
1236
+ def initialize: () ?{ () -> untyped } -> void
1237
+ attr_accessor llm: LLMConfig
1238
+ attr_accessor infer_template: TemplateConfig
1239
+ attr_accessor fix_error_template: TemplateConfig
1240
+ def use_open_ai: (String open_ai_access_token, ?model_name: String, ?mode: Symbol, ?llm_options: Hash[untyped, untyped], ?default_options: Hash[untyped, untyped]) -> LLMConfig
1241
+ def use_anthropic: (String access_token, ?model_name: String, ?mode: Symbol, ?default_options: Hash[untyped, untyped]) -> LLMConfig
1242
+ def use_ollama: (?url: String, ?model_name: String, ?mode: Symbol, ?default_options: Hash[untyped, untyped]) -> LLMConfig
1243
+ private def default_infer_template: () -> TemplateConfig
1244
+ private def default_fix_error_template: () -> TemplateConfig
1245
+ private def default_infer_instruction: () -> "Act as Ruby type inferrer.\nWhen ruby source codes and RBS type signatures are given, refine each RBS type signatures. Each file should be split in markdown code format.\nUse class names, variable names, etc., to infer type.\n"
1246
+ private def default_infer_example_groups: () -> Array[untyped]
1247
+ private def default_fix_error_instruction: () -> "You are a highly skilled programmer.\nBased on the following Ruby code, the RBS code that is a type definition, and the type checking error messages for them, modify the RBS code and output it.\nAll RBS files should be output, regardless of whether they have been modified or not.\n"
1248
+ private def default_fix_error_example_groups: () -> Array[untyped]
1249
+ end
1250
+ ```
1251
+
1252
+ ```rbs:sig/rbs_goose/io/example.rbs
1253
+ class RbsGoose::IO::Example
1254
+ @typed_ruby: TypedRuby
1255
+ @refined_rbs: IO::File
1256
+ def self.from_path: (ruby_path: untyped, rbs_path: untyped, refined_rbs_dir: untyped, base_path: untyped) -> RbsGoose::IO::Example
1257
+ def initialize: (typed_ruby: TypedRuby, refined_rbs: IO::File) -> void
1258
+ def to_h: () -> { typed_ruby: TypedRuby, refined_rbs: IO::File }
1259
+ attr_reader typed_ruby: TypedRuby
1260
+ attr_reader refined_rbs: IO::File
1261
+ end
1262
+ ```
1263
+
1264
+ ```rbs:sig/rbs_goose/io/example_group.rbs
1265
+ class RbsGoose::IO::ExampleGroup < Array[RbsGoose::IO::Example]
1266
+ @default_examples: Hash[Symbol, RbsGoose::IO::ExampleGroup]
1267
+ attr_accessor error_messages: String
1268
+ def self.load_from: (String base_path, ?code_dir: String, ?sig_dir: String, ?refined_dir: String) -> RbsGoose::IO::ExampleGroup
1269
+ def self.default_examples: () -> Hash[Symbol, RbsGoose::IO::ExampleGroup]
1270
+ private def self.load_example: (String base_path, String code_dir, String path, String refined_dir, String sig_dir) -> RbsGoose::IO::Example
1271
+ private def self.to_rbs_path: (String path, String sig_dir) -> String
1272
+ def to_target_group: () -> RbsGoose::IO::TargetGroup
1273
+ def to_refined_rbs_list: () -> Array[RbsGoose::IO::File]
1274
+ end
1275
+ ```
1276
+
1277
+ ```rbs:sig/rbs_goose/io/file.rbs
1278
+ class RbsGoose::IO::File
1279
+ @path: String
1280
+ @base_path: String
1281
+ @content: String
1282
+ @type: Symbol
1283
+ MARKDOWN_REGEXP: Regexp
1284
+ def self.from_markdown: (String markdown) -> RbsGoose::IO::File
1285
+ def initialize: (path: String, ?content: String?, ?base_path: String?) -> void
1286
+ def load_content: () -> void
1287
+ def absolute_path: () -> String
1288
+ def type: () -> Symbol
1289
+ def to_s: () -> String
1290
+ def content=: (String content) -> String
1291
+ def write: () -> void
1292
+ def ==: (Object other) -> bool
1293
+ attr_reader path: String
1294
+ attr_reader content: String
1295
+ attr_reader base_path: String
1296
+ end
1297
+ ```
1298
+
1299
+ ```rbs:sig/rbs_goose/io/target_group.rbs
1300
+ class RbsGoose::IO::TargetGroup < Array[RbsGoose::IO::TypedRuby]
1301
+ def self.load_from: (String base_path, ?code_dir: String, ?sig_dir: String) -> RbsGoose::IO::TargetGroup
1302
+ end
1303
+ ```
1304
+
1305
+ ```rbs:sig/rbs_goose/io/typed_ruby.rbs
1306
+ class RbsGoose::IO::TypedRuby
1307
+ @ruby: RbsGoose::IO::File
1308
+ @rbs: RbsGoose::IO::File
1309
+ def self.from_path: (ruby_path: String, rbs_path: String, base_path: String) -> RbsGoose::IO::TypedRuby
1310
+ def initialize: (ruby: RbsGoose::IO::File, rbs: RbsGoose::IO::File) -> void
1311
+ def to_s: () -> (String | nil)
1312
+ attr_reader ruby: RbsGoose::IO::File
1313
+ attr_reader rbs: RbsGoose::IO::File
1314
+ end
1315
+ ```
1316
+
1317
+ ```rbs:sig/rbs_goose/io.rbs
1318
+ module RbsGoose::IO
1319
+ end
1320
+ ```
1321
+
1322
+ ```rbs:sig/rbs_goose/orthoses/fix_error.rbs
1323
+ # Call RbsGoose::TypeInferrer to fix steep type errors.
1324
+ # use TbsGoose::Orthoses::FixError, code_dir: 'lib', sig_dir: 'sig' do |config|
1325
+ # config.use_open_ai('open_ai_access_token')
1326
+ # end
1327
+ class RbsGoose::Orthoses::FixError
1328
+ @loader: untyped
1329
+ @code_dir: String
1330
+ @sig_dir: String
1331
+ def initialize: (untyped loader, ?code_dir: String, ?sig_dir: String) ?{ () -> untyped } -> void
1332
+ def call: () -> untyped
1333
+ end
1334
+ ```
1335
+
1336
+ ```rbs:sig/rbs_goose/orthoses/infer.rbs
1337
+ # Call RbsGoose::TypeInferrer to infer RBS type signatures.
1338
+ # use TbsGoose::Orthoses::Infer, code_dir: 'lib', sig_dir: 'sig' do |config|
1339
+ # config.use_open_ai('open_ai_access_token')
1340
+ # end
1341
+ class RbsGoose::Orthoses::Infer
1342
+ @loader: untyped
1343
+ @code_dir: String
1344
+ @sig_dir: String
1345
+ def initialize: (untyped loader, ?code_dir: String, ?sig_dir: String) ?{ () -> untyped } -> void
1346
+ def call: () -> untyped
1347
+ end
1348
+ ```
1349
+
1350
+ ```rbs:sig/rbs_goose/orthoses.rbs
1351
+ module RbsGoose::Orthoses
1352
+ end
1353
+ ```
1354
+
1355
+ ```rbs:sig/rbs_goose/templates/base.rbs
1356
+ class RbsGoose::Templates::Base
1357
+ @instruction: untyped
1358
+ @example_groups: untyped
1359
+ def initialize: (instruction: untyped, example_groups: untyped) -> void
1360
+ def format: (**untyped args) -> untyped
1361
+ def format_system_prompt: () -> untyped
1362
+ def format_user_prompt: (**untyped args) -> untyped
1363
+ def parse_result: (untyped result) -> Array[RbsGoose::IO::File]
1364
+ private def input_template_string: () -> untyped
1365
+ private def input_variables: () -> untyped
1366
+ private def transform_example_group: (untyped example_group) -> untyped
1367
+ private def format_args: (untyped args) -> untyped
1368
+ private def prefix: () -> untyped
1369
+ private def suffix: () -> String
1370
+ private def example_prompt: () -> untyped
1371
+ private attr_reader instruction: untyped
1372
+ private attr_reader example_groups: untyped
1373
+ end
1374
+ ```
1375
+
1376
+ ```rbs:sig/rbs_goose/templates/fix_error_template.rbs
1377
+ class RbsGoose::Templates::FixErrorTemplate < RbsGoose::Templates::Base
1378
+ private def input_variables: () -> Array["typed_ruby_list" | "error_messages"]
1379
+ private def input_template_string: () -> untyped
1380
+ private def format_args: (untyped args) -> { typed_ruby_list: untyped, error_messages: untyped }
1381
+ private def transform_example_group: (untyped example_group) -> { typed_ruby_list: untyped, error_messages: untyped, refined_rbs_list: untyped }
1382
+ end
1383
+ ```
1384
+
1385
+ ```rbs:sig/rbs_goose/templates/infer_template.rbs
1386
+ class RbsGoose::Templates::InferTemplate < RbsGoose::Templates::Base
1387
+ private def input_variables: () -> Array["typed_ruby_list"]
1388
+ private def input_template_string: () -> "========Input========\n{typed_ruby_list}\n\n========Output========"
1389
+ private def format_args: (untyped args) -> { typed_ruby_list: untyped }
1390
+ private def transform_example_group: (untyped example_group) -> { typed_ruby_list: untyped, refined_rbs_list: untyped }
1391
+ end
1392
+ ```
1393
+
1394
+ ```rbs:sig/rbs_goose/templates.rbs
1395
+ module RbsGoose::Templates
1396
+ end
1397
+ ```
1398
+
1399
+ ```rbs:sig/rbs_goose/type_inferrer.rbs
1400
+ class RbsGoose::TypeInferrer
1401
+ def infer: (untyped target_group) -> Array[RbsGoose::IO::File]
1402
+ def fix_error: (untyped target_group) -> Array[RbsGoose::IO::File]
1403
+ private def call_llm: (untyped template, untyped format_args) -> untyped
1404
+ private def call_llm_complete: (untyped format_args, untyped template) -> untyped
1405
+ private def call_llm_chat: (untyped format_args, untyped template) -> untyped
1406
+ private def llm_debug: (untyped prompt) { () -> untyped } -> untyped
1407
+ private def steep_check: () -> untyped
1408
+ private def io_stubs: () -> Array[untyped]
1409
+ private def disable_rainbow: () { () -> untyped } -> untyped
1410
+ end
1411
+ ```
1412
+
1413
+ ```rbs:sig/rbs_goose.rbs
1414
+ module RbsGoose
1415
+ VERSION: "0.1.1"
1416
+
1417
+ self.@configuration: RbsGoose::Configuration
1418
+
1419
+ extend Forwardable
1420
+
1421
+ def self.configure: () { () -> untyped } -> RbsGoose::Configuration
1422
+
1423
+ def self.reset_configuration: () -> void
1424
+
1425
+ def self.run: (?code_dir: String, ?sig_dir: String, ?base_path: String) -> void
1426
+
1427
+ def self.fix_error: (?code_dir: String, ?sig_dir: String, ?base_path: String) -> void
1428
+
1429
+ def self.infer_template: () -> RbsGoose::Templates::Base
1430
+
1431
+ def self.fix_error_template: () -> RbsGoose::Templates::Base
1432
+
1433
+ attr_reader self.configuration: RbsGoose::Configuration
1434
+ end
1435
+ ```
1436
+
1437
+ write refined rbs to sig/email.rbs
1438
+ done.
1439
+
1440
+ write refined rbs to sig/person.rbs
1441
+ done.
1442
+
1443
+ write refined rbs to sig/phone.rbs
1444
+ done.
1445
+
1446
+ write refined rbs to sig/rbs_goose/configuration.rbs
1447
+ done.
1448
+
1449
+ write refined rbs to sig/rbs_goose/io/example.rbs
1450
+ done.
1451
+
1452
+ write refined rbs to sig/rbs_goose/io/example_group.rbs
1453
+ done.
1454
+
1455
+ write refined rbs to sig/rbs_goose/io/file.rbs
1456
+ done.
1457
+
1458
+ write refined rbs to sig/rbs_goose/io/target_group.rbs
1459
+ done.
1460
+
1461
+ write refined rbs to sig/rbs_goose/io/typed_ruby.rbs
1462
+ done.
1463
+
1464
+ write refined rbs to sig/rbs_goose/io.rbs
1465
+ done.
1466
+
1467
+ write refined rbs to sig/rbs_goose/orthoses/fix_error.rbs
1468
+ done.
1469
+
1470
+ write refined rbs to sig/rbs_goose/orthoses/infer.rbs
1471
+ done.
1472
+
1473
+ write refined rbs to sig/rbs_goose/orthoses.rbs
1474
+ done.
1475
+
1476
+ write refined rbs to sig/rbs_goose/templates/base.rbs
1477
+ done.
1478
+
1479
+ write refined rbs to sig/rbs_goose/templates/fix_error_template.rbs
1480
+ done.
1481
+
1482
+ write refined rbs to sig/rbs_goose/templates/infer_template.rbs
1483
+ done.
1484
+
1485
+ write refined rbs to sig/rbs_goose/templates.rbs
1486
+ done.
1487
+
1488
+ write refined rbs to sig/rbs_goose/type_inferrer.rbs
1489
+ done.
1490
+
1491
+ write refined rbs to sig/rbs_goose.rbs
1492
+ done.
1493
+
1494
+ I, [2024-05-08T16:14:24.920159 #66706] INFO -- : [RbsGoose::Orthoses::Infer]#call end