Module: Rigor::Source::Literals

Defined in:
lib/rigor/source/literals.rb,
sig/rigor/source.rbs

Overview

Extracts literal Symbol/String values from Prism call arguments.

The "is this argument a literal :sym or "str", and if so what Symbol does it name?" question recurs across the analyzer (sig-gen observation, attr-accessor generation, synthetic-method scanning) and across nearly every DSL plugin (state :draft, has_one_attached :avatar, validate_presence_of(:name), …). This module is the one place that answers it, so the node.unescaped.to_sym if SymbolNode || StringNode shape is written once rather than copied per call site.

#unescaped (not #value) is used deliberately so an interpolation- free "foo" / :foo round-trips to :foo consistently for both node kinds.

The surface is a small grid over two axes — which node kinds are accepted (SymbolNode only, or SymbolNode/StringNode) and what the caller wants back (the interned Symbol, or the raw String name). The SymbolNode-only forms (Literals.symbol / Literals.symbol_name) exist so a DSL that distinguishes state :draft from state "draft" keeps that distinction instead of silently widening to accept the string literal.

accepts → Symbol → String
:sym only Literals.symbol Literals.symbol_name
:sym or "str" Literals.symbol_or_string Literals.symbol_or_string_name

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.symbol(node) ⇒ Symbol?

The Symbol a literal Prism::SymbolNode names, or nil for any other node (including a Prism::StringNode and nil). Stricter than symbol_or_string: a DSL that accepts only :draft and not "draft" keeps that distinction by reaching for this rather than the Symbol-or-String form.

Parameters:

  • node (Prism::Node, nil)

Returns:

  • (Symbol, nil)


62
63
64
65
66
# File 'lib/rigor/source/literals.rb', line 62

def symbol(node)
  return nil unless node.is_a?(Prism::SymbolNode)

  node.unescaped.to_sym
end

.symbol_arg(call_node, index) ⇒ Symbol?

The literal Symbol/String at positional index, or nil when the call has no argument list, the index is out of range, or the argument there is not a literal Symbol/String.

Parameters:

  • call_node (Prism::CallNode, nil)
  • index (Integer)

Returns:

  • (Symbol, nil)


110
111
112
113
114
115
# File 'lib/rigor/source/literals.rb', line 110

def symbol_arg(call_node, index)
  args = call_node&.arguments&.arguments
  return nil if args.nil?

  symbol_or_string(args[index])
end

.symbol_arguments(call_node) ⇒ Array<Symbol>

Every literal Symbol/String positional argument of a call, in source order. Non-literal arguments are dropped. Returns [] when the call has no argument list.

Parameters:

  • call_node (Prism::CallNode, nil)

Returns:

  • (Array<Symbol>)


85
86
87
88
89
90
# File 'lib/rigor/source/literals.rb', line 85

def symbol_arguments(call_node)
  args = call_node&.arguments&.arguments
  return [] if args.nil?

  args.filter_map { |arg| symbol_or_string(arg) }
end

.symbol_name(node) ⇒ String?

The String a literal Prism::SymbolNode names, or nil for any other node (including a Prism::StringNode and nil). The String-returning sibling of symbol — SymbolNode-only, but the caller wants the raw name rather than the interned Symbol.

Parameters:

  • node (Prism::Node, nil)

Returns:

  • (String, nil)


74
75
76
77
78
# File 'lib/rigor/source/literals.rb', line 74

def symbol_name(node)
  return nil unless node.is_a?(Prism::SymbolNode)

  node.unescaped
end

.symbol_named?(node, name) ⇒ Boolean

Whether a node is a literal Prism::SymbolNode that names name. The key-comparison counterpart to symbol_name — for callers that need a predicate rather than an extraction (hash-key matching in keyword or assoc argument positions, e.g. el.is_a?(AssocNode) && symbol_named?(el.key, "required")). Uses #unescaped (not #value) for round-trip consistency.

Parameters:

  • node (Prism::Node, nil)
  • name (String)

Returns:

  • (Boolean)


100
101
102
# File 'lib/rigor/source/literals.rb', line 100

def symbol_named?(node, name)
  node.is_a?(Prism::SymbolNode) && node.unescaped == name
end

.symbol_or_string(node) ⇒ Symbol?

The Symbol a literal Prism::SymbolNode / Prism::StringNode names, or nil for any other node (including nil).

Parameters:

  • node (Prism::Node, nil)

Returns:

  • (Symbol, nil)


37
38
39
40
41
# File 'lib/rigor/source/literals.rb', line 37

def symbol_or_string(node)
  return nil unless node.is_a?(Prism::SymbolNode) || node.is_a?(Prism::StringNode)

  node.unescaped.to_sym
end

.symbol_or_string_name(node) ⇒ String?

The String a literal Prism::SymbolNode / Prism::StringNode names, or nil for any other node (including nil). The String-returning sibling of symbol_or_string — for callers that key on the raw name rather than the interned Symbol (route helpers, factory names, filter targets). #unescaped round-trips an interpolation-free :foo / "foo" to "foo" for both kinds.

Parameters:

  • node (Prism::Node, nil)

Returns:

  • (String, nil)


50
51
52
53
54
# File 'lib/rigor/source/literals.rb', line 50

def symbol_or_string_name(node)
  return nil unless node.is_a?(Prism::SymbolNode) || node.is_a?(Prism::StringNode)

  node.unescaped
end

Instance Method Details

#self?.symbolSymbol?

Parameters:

  • node (Object, nil)

Returns:

  • (Symbol, nil)


17
# File 'sig/rigor/source.rbs', line 17

def self?.symbol: (untyped? node) -> Symbol?

#self?.symbol_argSymbol?

Parameters:

  • call_node (Object, nil)
  • index (Integer)

Returns:

  • (Symbol, nil)


21
# File 'sig/rigor/source.rbs', line 21

def self?.symbol_arg: (untyped? call_node, Integer index) -> Symbol?

#self?.symbol_argumentsArray[Symbol]

Parameters:

  • call_node (Object, nil)

Returns:

  • (Array[Symbol])


20
# File 'sig/rigor/source.rbs', line 20

def self?.symbol_arguments: (untyped? call_node) -> Array[Symbol]

#self?.symbol_nameString?

Parameters:

  • node (Object, nil)

Returns:

  • (String, nil)


18
# File 'sig/rigor/source.rbs', line 18

def self?.symbol_name: (untyped? node) -> String?

#self?.symbol_named?Boolean

Parameters:

  • node (Object, nil)
  • name (String)

Returns:

  • (Boolean)


19
# File 'sig/rigor/source.rbs', line 19

def self?.symbol_named?: (untyped? node, String name) -> bool

#self?.symbol_or_stringSymbol?

Parameters:

  • node (Object, nil)

Returns:

  • (Symbol, nil)


15
# File 'sig/rigor/source.rbs', line 15

def self?.symbol_or_string: (untyped? node) -> Symbol?

#self?.symbol_or_string_nameString?

Parameters:

  • node (Object, nil)

Returns:

  • (String, nil)


16
# File 'sig/rigor/source.rbs', line 16

def self?.symbol_or_string_name: (untyped? node) -> String?