Class: Riffer::Params::Param

Inherits:
Object
  • Object
show all
Defined in:
lib/riffer/params/param.rb

Overview

A single parameter definition, handling type validation and JSON Schema generation.

Constant Summary collapse

TYPE_MAPPINGS =

Maps Ruby types to JSON Schema type strings

{
  String => "string",
  Integer => "integer",
  Float => "number",
  Riffer::Params::Boolean => "boolean",
  TrueClass => "boolean",
  FalseClass => "boolean",
  Array => "array",
  Hash => "object"
}.freeze
PRIMITIVE_TYPES =

Primitive types allowed for the of: keyword on Array params

(TYPE_MAPPINGS.keys - [Array, Hash]).freeze
JSON_TYPE_MAPPINGS =

Maps JSON Schema type strings back to Ruby types (inverse of TYPE_MAPPINGS), collapsing the three boolean spellings onto Riffer::Params::Boolean.

{
  "string" => String,
  "integer" => Integer,
  "number" => Float,
  "boolean" => Riffer::Params::Boolean,
  "array" => Array,
  "object" => Hash
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, type:, required:, description: nil, enum: nil, default: nil, item_type: nil, nested_params: nil) ⇒ Param

– : (name: Symbol, type: Module, required: bool, ?description: String?, ?enum: Array?, ?default: untyped, ?item_type: Module?, ?nested_params: Riffer::Params?) -> void



104
105
106
107
108
109
110
111
112
113
# File 'lib/riffer/params/param.rb', line 104

def initialize(name:, type:, required:, description: nil, enum: nil, default: nil, item_type: nil, nested_params: nil)
  @name = name.to_sym
  @type = type
  @required = required
  @description = description
  @enum = enum
  @default = default
  @item_type = item_type
  @nested_params = nested_params
end

Instance Attribute Details

#defaultObject (readonly)

The default value, if any.



49
50
51
# File 'lib/riffer/params/param.rb', line 49

def default
  @default
end

#descriptionObject (readonly)

The parameter description, if any.



43
44
45
# File 'lib/riffer/params/param.rb', line 43

def description
  @description
end

#enumObject (readonly)

Allowed values, if constrained.



46
47
48
# File 'lib/riffer/params/param.rb', line 46

def enum
  @enum
end

#item_typeObject (readonly)

Element type for a typed array (of:).



52
53
54
# File 'lib/riffer/params/param.rb', line 52

def item_type
  @item_type
end

#nameObject (readonly)

The parameter name.



34
35
36
# File 'lib/riffer/params/param.rb', line 34

def name
  @name
end

#nested_paramsObject (readonly)

Nested Params for object / array-of-object types.



55
56
57
# File 'lib/riffer/params/param.rb', line 55

def nested_params
  @nested_params
end

#requiredObject (readonly)

Whether the parameter is required.



40
41
42
# File 'lib/riffer/params/param.rb', line 40

def required
  @required
end

#typeObject (readonly)

The Ruby type.



37
38
39
# File 'lib/riffer/params/param.rb', line 37

def type
  @type
end

Class Method Details

.from_json_schema(name, schema, required:) ⇒ Object

Reconstructs a Param from a single JSON Schema property. Raises Riffer::ArgumentError on a type outside the Params-expressible subset. – : (Symbol, Hash[Symbol, untyped], required: bool) -> Riffer::Params::Param



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/riffer/params/param.rb', line 61

def self.from_json_schema(name, schema, required:)
  ruby_type = json_type_to_ruby(schema[:type])
  item_type, nested = resolve_nesting(ruby_type, schema)

  new(
    name: name,
    type: ruby_type,
    required: required,
    description: schema[:description],
    enum: schema[:enum],
    default: schema[:default],
    item_type: item_type,
    nested_params: nested
  )
end

Instance Method Details

#to_json_schema(strict: false) ⇒ Object

Converts this parameter to JSON Schema format. When strict, optional params are made nullable (["type", "null"]) so strict providers distinguish absent from present; optional params with an enum use anyOf instead, since providers like Anthropic reject {"type": ["string", "null"], "enum": [...]}. – : (?strict: bool) -> Hash[Symbol, untyped]



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/riffer/params/param.rb', line 144

def to_json_schema(strict: false)
  nullable = strict && !required

  if nullable && enum
    schema = {anyOf: [{type: type_name, enum: enum}, {type: "null"}]} #: Hash[Symbol, untyped]
    schema[:description] = description if description
    return schema
  end

  type = type_name
  type = [type, "null"] if nullable

  schema = {type: type} #: Hash[Symbol, untyped]
  schema[:description] = description if description
  schema[:enum] = enum if enum
  # Strict providers reject the +default+ keyword; emit it only in
  # non-strict mode, where it makes the schema a lossless round-trip
  # source for +from_json_schema+.
  schema[:default] = default unless strict || default.nil?

  if self.type == Array && nested_params
    schema[:items] = nested_params.to_json_schema(strict: strict)
  elsif self.type == Array && item_type
    schema[:items] = {type: TYPE_MAPPINGS[item_type]}
  elsif self.type == Hash && nested_params
    schema.merge!(nested_params.to_json_schema(strict: strict))
  end

  schema
end

#type_nameObject

Returns the JSON Schema type name for this parameter.

– : () -> String



133
134
135
# File 'lib/riffer/params/param.rb', line 133

def type_name
  TYPE_MAPPINGS[type] || type.to_s.downcase
end

#valid_type?(value) ⇒ Boolean

Validates that a value matches the expected type.

– : (untyped) -> bool

Returns:



119
120
121
122
123
124
125
126
127
# File 'lib/riffer/params/param.rb', line 119

def valid_type?(value)
  return true if value.nil? && !required

  if type == Riffer::Params::Boolean || type == TrueClass || type == FalseClass
    value == true || value == false
  else
    value.is_a?(type)
  end
end