Class: Riffer::Params::Param

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

Overview

Riffer::Params::Param represents a single parameter definition.

Handles type validation and JSON Schema generation for individual parameters.

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. The inverse of TYPE_MAPPINGS, collapsing the three boolean spellings onto Riffer::Params::Boolean. Used by from_json_schema.

{
  "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



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

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)

: untyped



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

def default
  @default
end

#descriptionObject (readonly)

: String?



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

def description
  @description
end

#enumObject (readonly)

: Array?



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

def enum
  @enum
end

#item_typeObject (readonly)

: Module?



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

def item_type
  @item_type
end

#nameObject (readonly)

: Hash[String, Module]



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

def name
  @name
end

#nested_paramsObject (readonly)

: Riffer::Params?



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

def nested_params
  @nested_params
end

#requiredObject (readonly)

: bool



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

def required
  @required
end

#typeObject (readonly)

: Module



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

def type
  @type
end

Class Method Details

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

– Reconstructs a Param from a single JSON Schema property.

name

the parameter name (Symbol).

schema

the property’s JSON Schema (Symbol-keyed).

required

whether the property appeared in the parent’s required list.

Raises Riffer::ArgumentError on a type outside the Params-expressible subset.

– : (Symbol, Hash[Symbol, untyped], required: bool) -> Riffer::Params::Param



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/riffer/params/param.rb', line 55

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 is true, optional parameters are made nullable (["type", "null"]) so that strict mode providers can distinguish “absent” from “present” without rejecting the schema.

Optional parameters with an enum use anyOf to separate the enum constraint from the null type, since providers like Anthropic reject {"type": ["string", "null"], "enum": [...]}.

In non-strict mode a default is emitted when set (a standard JSON Schema keyword), making the schema a lossless source for Riffer::Params.from_json_schema. Strict mode omits it, since strict providers reject the keyword.

– : (?strict: bool) -> Hash[Symbol, untyped]



155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/riffer/params/param.rb', line 155

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



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

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:



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

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