Module: Kumi::Frontends::Ruby

Defined in:
lib/kumi/frontends/ruby.rb

Class Method Summary collapse

Class Method Details

.load(path:, inputs: {}) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/kumi/frontends/ruby.rb', line 10

def load(path:, inputs: {})
  src = File.read(path)

  begin
    [parse(src, path), inputs]
  rescue StandardError => e
    # Render the same `file:line: message` + code-frame the text frontend
    # produces. Located errors (SyntaxError/SemanticError) carry a Location;
    # anything else degrades to a clean `file: message` with no frame.
    raise StandardError, SourceFrame.render(e, src: src, file_label: path)
  end
end

.parse(src, path) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/kumi/frontends/ruby.rb', line 23

def parse(src, path)
  mod = Module.new
  mod.extend(Kumi::Schema)
  begin
    mod.module_eval(src, path)
  rescue NameError => e
    raise translate_uppercase_reference(e, path) || e
  end

  # Extract just the syntax tree AST (same as Text frontend)
  if mod.const_defined?(:GoldenSchema)
    golden = mod.const_get(:GoldenSchema)
    golden.build if golden.respond_to?(:build)
    golden.__syntax_tree__
  elsif mod.__syntax_tree__
    mod.__syntax_tree__
  else
    raise "No schema AST found. Make sure the .rb file calls 'schema do...end'"
  end
end

.translate_uppercase_reference(error, path) ⇒ Object

A bare reference to a declaration whose name starts with an uppercase letter (e.g. ‘let :W` then `W`) is read by Ruby as a constant, not a method, so the DSL’s method_missing never sees it and Ruby raises a raw ‘uninitialized constant …::W`. The text frontend accepts such names, so this is a Ruby-only limitation — turn it into a clear, located error instead of leaking Ruby’s anonymous-module constant message.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/kumi/frontends/ruby.rb', line 50

def translate_uppercase_reference(error, path)
  const = error.name
  return nil unless const&.to_s&.match?(/\A[A-Z]/)
  return nil unless error.message.include?("uninitialized constant")

  frame = error.backtrace_locations&.find { |f| f.path == path }
  location = frame && Kumi::Syntax::Location.new(file: frame.path, line: frame.lineno, column: 0)

  Kumi::Core::Errors::SyntaxError.new(
    "`#{const}` looks like a reference to a declaration, but names starting " \
    "with an uppercase letter can't be referenced bare in the Ruby DSL " \
    "(Ruby reads them as constants). Use `ref(:#{const})`, or rename the " \
    "declaration to start with a lowercase letter.",
    location
  )
end