Skip to content

Commit 9d8c2d6

Browse files
chore: clean up whitespace and add install generator tests
- Removed unnecessary whitespace in railtie.rb for cleaner code. - Added comprehensive tests for the RubyLLM::InstallGenerator to ensure migration and model templates are correctly defined and structured. - Deleted outdated template files spec to streamline test organization. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 5eeedf9 commit 9d8c2d6

File tree

3 files changed

+267
-200
lines changed

3 files changed

+267
-200
lines changed

lib/ruby_llm/railtie.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ class Railtie < Rails::Railtie
88
include RubyLLM::ActiveRecord::ActsAs
99
end
1010
end
11-
11+
1212
# Include rake tasks if applicable
1313
rake_tasks do
1414
# Task definitions go here if needed
1515
end
16-
16+
1717
# Register generators
1818
generators do
1919
require 'generators/ruby_llm/install_generator'
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require 'fileutils'
5+
require 'generators/ruby_llm/install_generator'
6+
7+
RSpec.describe RubyLLM::InstallGenerator, type: :generator do
8+
# Use the actual template directory
9+
let(:template_dir) { '/Users/kieranklaassen/rails/ruby_llm/lib/generators/ruby_llm/install/templates' }
10+
let(:generator_file) { '/Users/kieranklaassen/rails/ruby_llm/lib/generators/ruby_llm/install_generator.rb' }
11+
12+
describe 'migration templates' do
13+
let(:expected_migration_files) do
14+
[
15+
'create_chats_migration.rb.tt',
16+
'create_messages_migration.rb.tt',
17+
'create_tool_calls_migration.rb.tt'
18+
]
19+
end
20+
21+
it 'has all required migration template files' do
22+
expected_migration_files.each do |file|
23+
expect(File.exist?(File.join(template_dir, file))).to be(true)
24+
end
25+
end
26+
27+
describe 'chats migration' do
28+
let(:chat_migration) { File.read(File.join(template_dir, 'create_chats_migration.rb.tt')) }
29+
30+
it 'defines chats table' do
31+
expect(chat_migration).to include('create_table :chats')
32+
end
33+
34+
it 'includes model_id field' do
35+
expect(chat_migration).to include('t.string :model_id')
36+
end
37+
end
38+
39+
describe 'messages migration' do
40+
let(:message_migration) { File.read(File.join(template_dir, 'create_messages_migration.rb.tt')) }
41+
42+
it 'defines messages table' do
43+
expect(message_migration).to include('create_table :messages')
44+
end
45+
46+
it 'includes chat reference' do
47+
expect(message_migration).to include('t.references :chat')
48+
end
49+
50+
it 'includes role field' do
51+
expect(message_migration).to include('t.string :role')
52+
end
53+
54+
it 'includes content field' do
55+
expect(message_migration).to include('t.text :content')
56+
end
57+
end
58+
59+
describe 'tool_calls migration' do
60+
let(:tool_call_migration) { File.read(File.join(template_dir, 'create_tool_calls_migration.rb.tt')) }
61+
62+
it 'defines tool_calls table' do
63+
expect(tool_call_migration).to include('create_table :tool_calls')
64+
end
65+
66+
it 'includes tool_call_id field' do
67+
expect(tool_call_migration).to include('t.string :tool_call_id')
68+
end
69+
70+
it 'includes name field' do
71+
expect(tool_call_migration).to include('t.string :name')
72+
end
73+
end
74+
end
75+
76+
describe 'JSON handling in migrations' do
77+
let(:tool_call_migration) { File.read(File.join(template_dir, 'create_tool_calls_migration.rb.tt')) }
78+
79+
describe 'PostgreSQL support' do
80+
it 'includes postgresql condition check' do
81+
expect(tool_call_migration).to include('if postgresql?')
82+
end
83+
84+
it 'uses jsonb type' do
85+
expect(tool_call_migration).to include('t.jsonb :arguments')
86+
end
87+
end
88+
89+
describe 'other databases support' do
90+
it 'includes else condition' do
91+
expect(tool_call_migration).to include('else')
92+
end
93+
94+
it 'uses json type' do
95+
expect(tool_call_migration).to include('t.json :arguments')
96+
end
97+
end
98+
end
99+
100+
describe 'model templates' do
101+
let(:expected_model_files) do
102+
[
103+
'chat_model.rb.tt',
104+
'message_model.rb.tt',
105+
'tool_call_model.rb.tt'
106+
]
107+
end
108+
109+
it 'has all required model template files' do
110+
expected_model_files.each do |file|
111+
expect(File.exist?(File.join(template_dir, file))).to be(true)
112+
end
113+
end
114+
115+
it 'declares acts_as_chat in chat model' do
116+
chat_content = File.read(File.join(template_dir, 'chat_model.rb.tt'))
117+
expect(chat_content).to include('acts_as_chat')
118+
end
119+
120+
it 'declares acts_as_message in message model' do
121+
message_content = File.read(File.join(template_dir, 'message_model.rb.tt'))
122+
expect(message_content).to include('acts_as_message')
123+
end
124+
125+
it 'declares acts_as_tool_call in tool call model' do
126+
tool_call_content = File.read(File.join(template_dir, 'tool_call_model.rb.tt'))
127+
expect(tool_call_content).to include('acts_as_tool_call')
128+
end
129+
end
130+
131+
describe 'initializer template' do
132+
let(:initializer_content) { File.read(File.join(template_dir, 'initializer.rb.tt')) }
133+
134+
it 'has initializer template file' do
135+
expect(File.exist?(File.join(template_dir, 'initializer.rb.tt'))).to be(true)
136+
end
137+
138+
it 'includes RubyLLM configuration block' do
139+
expect(initializer_content).to include('RubyLLM.configure do |config|')
140+
end
141+
142+
it 'configures OpenAI API key' do
143+
expect(initializer_content).to include('config.openai_api_key')
144+
end
145+
146+
it 'configures Anthropic API key' do
147+
expect(initializer_content).to include('config.anthropic_api_key')
148+
end
149+
end
150+
151+
describe 'README template' do
152+
let(:readme_content) { File.read(File.join(template_dir, 'README.md')) }
153+
154+
it 'has README template file' do
155+
expect(File.exist?(File.join(template_dir, 'README.md'))).to be(true)
156+
end
157+
158+
it 'includes welcome message' do
159+
expect(readme_content).to include('RubyLLM Rails Setup Complete')
160+
end
161+
162+
it 'includes setup information' do
163+
expect(readme_content).to include('Run migrations')
164+
end
165+
166+
it 'includes migration instructions' do
167+
expect(readme_content).to include('rails db:migrate')
168+
end
169+
170+
it 'includes API configuration instructions' do
171+
expect(readme_content).to include('Set your API keys')
172+
end
173+
174+
it 'includes usage examples' do
175+
expect(readme_content).to include('Start using RubyLLM in your code')
176+
end
177+
178+
it 'includes streaming response information' do
179+
expect(readme_content).to include('For streaming responses')
180+
end
181+
end
182+
183+
describe 'generator structure' do
184+
let(:generator_content) { File.read(generator_file) }
185+
186+
it 'has generator file' do
187+
expect(File.exist?(generator_file)).to be(true)
188+
end
189+
190+
it 'inherits from Rails::Generators::Base' do
191+
expect(generator_content).to include('class InstallGenerator < Rails::Generators::Base')
192+
end
193+
194+
it 'includes Rails::Generators::Migration' do
195+
expect(generator_content).to include('include Rails::Generators::Migration')
196+
end
197+
end
198+
199+
describe 'generator methods' do
200+
let(:generator_content) { File.read(generator_file) }
201+
202+
it 'defines create_migration_files method' do
203+
expect(generator_content).to include('def create_migration_files')
204+
end
205+
206+
it 'defines create_model_files method' do
207+
expect(generator_content).to include('def create_model_files')
208+
end
209+
210+
it 'defines create_initializer method' do
211+
expect(generator_content).to include('def create_initializer')
212+
end
213+
214+
it 'defines show_readme method' do
215+
expect(generator_content).to include('def show_readme')
216+
end
217+
end
218+
219+
describe 'migration sequence' do
220+
let(:generator_content) { File.read(generator_file) }
221+
let(:migrations_order) do
222+
{
223+
chats: generator_content.index('create_chats.rb'),
224+
tool_calls: generator_content.index('create_tool_calls.rb'),
225+
messages: generator_content.index('create_messages.rb')
226+
}
227+
end
228+
229+
it 'orders chats before tool_calls' do
230+
expect(migrations_order[:chats]).to be < migrations_order[:tool_calls]
231+
end
232+
233+
it 'orders tool_calls before messages' do
234+
expect(migrations_order[:tool_calls]).to be < migrations_order[:messages]
235+
end
236+
237+
it 'initializes timestamp from current time' do
238+
expect(generator_content).to include('@migration_number = Time.now.utc.strftime')
239+
end
240+
241+
it 'increments timestamp for sequential migrations' do
242+
expect(generator_content).to include('@migration_number = (@migration_number.to_i + 1).to_s')
243+
end
244+
end
245+
246+
describe 'database detection' do
247+
let(:generator_content) { File.read(generator_file) }
248+
249+
it 'defines postgresql? method' do
250+
expect(generator_content).to include('def postgresql?')
251+
end
252+
253+
it 'detects PostgreSQL adapter' do
254+
expect(generator_content).to include('ActiveRecord::Base.connection.adapter_name.downcase.include?')
255+
end
256+
257+
it 'includes rescue block for error handling' do
258+
expect(generator_content).to include('rescue')
259+
end
260+
261+
it 'returns false on error' do
262+
expect(generator_content).to include('false')
263+
end
264+
end
265+
end

0 commit comments

Comments
 (0)