Class: Vangrail::Rail

Inherits:
Object
  • Object
show all
Defined in:
lib/vangrail/rail.rb

Overview

The whole rail protocol: a name, the sides it applies to, and call.

class ShoutRail < Vangrail::Rail
def call(text, _context)
  return pass if text == text.downcase

  modify(text.downcase, reason: 'lowered')
end
end

Deliberately not a DSL. A rail is an object with one method, so a Ruby application can write one in five lines, test it without a network, and put it in the same ordered list as the model-backed ones.

Constant Summary collapse

SIDES =

Three sides, not two. :context is text the application retrieved and is about to put in a prompt: a wiki page, a search result, a file. It is the side an attacker usually reaches without touching the application at all, and a stack that checks only what the user typed and what the model answered never looks at it.

%i[input context output].freeze
DEFAULT_SIDES =

What a rail gets by default. Context is opt-in per rail, because a rail written to judge a question is rarely the right one to judge a document.

%i[input output].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name: nil, sides: DEFAULT_SIDES) ⇒ Rail

Returns a new instance of Rail.

Raises:

  • (ArgumentError)


33
34
35
36
37
38
# File 'lib/vangrail/rail.rb', line 33

def initialize(name: nil, sides: DEFAULT_SIDES)
  @name = (name || default_name).to_s
  @sides = Array(sides).map(&:to_sym)
  unknown = @sides - SIDES
  raise ArgumentError, "unknown side(s): #{unknown.join(', ')}" unless unknown.empty?
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



31
32
33
# File 'lib/vangrail/rail.rb', line 31

def name
  @name
end

#sidesObject (readonly)

Returns the value of attribute sides.



31
32
33
# File 'lib/vangrail/rail.rb', line 31

def sides
  @sides
end

Instance Method Details

#applies_to?(side) ⇒ Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/vangrail/rail.rb', line 40

def applies_to?(side)
  sides.include?(side.to_sym)
end

#call(_text, _context) ⇒ Object

Returns a Result. context is a hash the engine threads through: :side, :user_input, :passages, :history, plus anything a caller adds.

Raises:

  • (NotImplementedError)


46
47
48
# File 'lib/vangrail/rail.rb', line 46

def call(_text, _context)
  raise NotImplementedError, "#{self.class} must implement #call"
end

#offline?Boolean

Does this rail need the network. Used to report a posture and to let a caller build a model-free engine on purpose.

Returns:

  • (Boolean)


52
53
54
# File 'lib/vangrail/rail.rb', line 52

def offline?
  false
end

#placeholder?Boolean

A rail that stands in for one that could not be built, rather than a rail that ran. The engine prefers the reason from something that actually ran when both are uncertain, because "the endpoint refused the connection" is more actionable than "no endpoint was resolved".

Returns:

  • (Boolean)


60
61
62
# File 'lib/vangrail/rail.rb', line 60

def placeholder?
  false
end

#to_sObject



64
65
66
# File 'lib/vangrail/rail.rb', line 64

def to_s
  name
end