Skip to content

Commit 0565f7e

Browse files
committed
Reorganize schema_builders and utilities
1 parent 91358ba commit 0565f7e

File tree

2 files changed

+82
-79
lines changed

2 files changed

+82
-79
lines changed

lib/ruby_llm/schema/dsl/schema_builders.rb

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ def object_schema(description: nil, of: nil, &block)
5757
# If the block returned a Schema class or instance, convert it to inline schema
5858
elsif schema_class?(result) && sub_schema.properties.empty?
5959
schema_class_to_inline_schema(result).merge(description ? {description: description} : {})
60+
# Block didn't return reference or schema, so we build an inline object schema
6061
else
6162
{
6263
type: "object",
@@ -89,6 +90,87 @@ def any_of_schema(description: nil, &block)
8990
anyOf: schemas
9091
}.compact
9192
end
93+
94+
private
95+
96+
def determine_array_items(of, &)
97+
return collect_schemas_from_block(&).first if block_given?
98+
return send("#{of}_schema") if primitive_type?(of)
99+
return reference(of) if of.is_a?(Symbol)
100+
return schema_class_to_inline_schema(of) if schema_class?(of)
101+
102+
raise InvalidArrayTypeError, "Invalid array type: #{of.inspect}. Must be a primitive type (:string, :number, etc.), a symbol reference, a Schema class, or a Schema instance."
103+
end
104+
105+
def determine_object_reference(of, description = nil)
106+
result = case of
107+
when Symbol
108+
reference(of)
109+
when Class
110+
if schema_class?(of)
111+
schema_class_to_inline_schema(of)
112+
else
113+
raise InvalidObjectTypeError, "Invalid object type: #{of.inspect}. Class must inherit from RubyLLM::Schema."
114+
end
115+
else
116+
if schema_class?(of)
117+
schema_class_to_inline_schema(of)
118+
else
119+
raise InvalidObjectTypeError, "Invalid object type: #{of.inspect}. Must be a symbol reference, a Schema class, or a Schema instance."
120+
end
121+
end
122+
123+
description ? result.merge(description: description) : result
124+
end
125+
126+
def collect_schemas_from_block(&block)
127+
schemas = []
128+
schema_builder = self
129+
130+
context = Object.new
131+
132+
# Dynamically create methods for all schema builders
133+
schema_builder.methods.grep(/_schema$/).each do |schema_method|
134+
type_name = schema_method.to_s.sub(/_schema$/, "")
135+
136+
context.define_singleton_method(type_name) do |name = nil, **options, &blk|
137+
schemas << schema_builder.send(schema_method, **options, &blk)
138+
end
139+
end
140+
141+
# Allow Schema classes to be accessed in the context
142+
context.define_singleton_method(:const_missing) do |name|
143+
const_get(name) if const_defined?(name)
144+
end
145+
146+
context.instance_eval(&block)
147+
schemas
148+
end
149+
150+
def schema_class_to_inline_schema(schema_class_or_instance)
151+
# Handle both Schema classes and Schema instances
152+
schema_class = if schema_class_or_instance.is_a?(Class)
153+
schema_class_or_instance
154+
else
155+
schema_class_or_instance.class
156+
end
157+
158+
# Directly convert schema class to inline object schema
159+
{
160+
type: "object",
161+
properties: schema_class.properties,
162+
required: schema_class.required_properties,
163+
additionalProperties: schema_class.additional_properties
164+
}.tap do |schema|
165+
# For instances, prefer instance description over class description
166+
description = if schema_class_or_instance.is_a?(Class)
167+
schema_class.description
168+
else
169+
schema_class_or_instance.instance_variable_get(:@description) || schema_class.description
170+
end
171+
schema[:description] = description if description
172+
end
173+
end
92174
end
93175
end
94176
end

lib/ruby_llm/schema/dsl/utilities.rb

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -32,92 +32,13 @@ def add_property(name, definition, required:)
3232
required_properties << name.to_sym if required
3333
end
3434

35-
def determine_array_items(of, &)
36-
return collect_schemas_from_block(&).first if block_given?
37-
return send("#{of}_schema") if primitive_type?(of)
38-
return reference(of) if of.is_a?(Symbol)
39-
return schema_class_to_inline_schema(of) if schema_class?(of)
40-
41-
raise InvalidArrayTypeError, "Invalid array type: #{of.inspect}. Must be a primitive type (:string, :number, etc.), a symbol reference, a Schema class, or a Schema instance."
42-
end
43-
44-
def determine_object_reference(of, description = nil)
45-
result = case of
46-
when Symbol
47-
reference(of)
48-
when Class
49-
if schema_class?(of)
50-
schema_class_to_inline_schema(of)
51-
else
52-
raise InvalidObjectTypeError, "Invalid object type: #{of.inspect}. Class must inherit from RubyLLM::Schema."
53-
end
54-
else
55-
if schema_class?(of)
56-
schema_class_to_inline_schema(of)
57-
else
58-
raise InvalidObjectTypeError, "Invalid object type: #{of.inspect}. Must be a symbol reference, a Schema class, or a Schema instance."
59-
end
60-
end
61-
62-
description ? result.merge(description: description) : result
63-
end
64-
65-
def collect_schemas_from_block(&block)
66-
schemas = []
67-
schema_builder = self
68-
69-
context = Object.new
70-
71-
# Dynamically create methods for all schema builders
72-
schema_builder.methods.grep(/_schema$/).each do |schema_method|
73-
type_name = schema_method.to_s.sub(/_schema$/, "")
74-
75-
context.define_singleton_method(type_name) do |name = nil, **options, &blk|
76-
schemas << schema_builder.send(schema_method, **options, &blk)
77-
end
78-
end
79-
80-
# Allow Schema classes to be accessed in the context
81-
context.define_singleton_method(:const_missing) do |name|
82-
const_get(name) if const_defined?(name)
83-
end
84-
85-
context.instance_eval(&block)
86-
schemas
87-
end
88-
8935
def primitive_type?(type)
9036
type.is_a?(Symbol) && PRIMITIVE_TYPES.include?(type)
9137
end
9238

9339
def schema_class?(type)
9440
(type.is_a?(Class) && type < Schema) || type.is_a?(Schema)
9541
end
96-
97-
def schema_class_to_inline_schema(schema_class_or_instance)
98-
# Handle both Schema classes and Schema instances
99-
schema_class = if schema_class_or_instance.is_a?(Class)
100-
schema_class_or_instance
101-
else
102-
schema_class_or_instance.class
103-
end
104-
105-
# Directly convert schema class to inline object schema
106-
{
107-
type: "object",
108-
properties: schema_class.properties,
109-
required: schema_class.required_properties,
110-
additionalProperties: schema_class.additional_properties
111-
}.tap do |schema|
112-
# For instances, prefer instance description over class description
113-
description = if schema_class_or_instance.is_a?(Class)
114-
schema_class.description
115-
else
116-
schema_class_or_instance.instance_variable_get(:@description) || schema_class.description
117-
end
118-
schema[:description] = description if description
119-
end
120-
end
12142
end
12243
end
12344
end

0 commit comments

Comments
 (0)