Module: Musa::REPL::CustomizableDSLContext

Defined in:
lib/musa-dsl/repl/repl.rb

Overview

Mixin for DSL contexts that can be bound to a REPL.

This module provides the interface required for a DSL context to work with the REPL server. Classes that include this module can execute REPL-sent code in their own context, making their DSL methods available to live coding clients.

Requirements

Classes that include this module must implement the #binder method, which should return a Ruby Binding object representing the execution context.

Integration with DynamicProxy

Typically used with Musa::Extension::DynamicProxy::DynamicProxy:

class MyDSL
  include CustomizableDSLContext

  def initialize
    @repl = REPL.new(Musa::Extension::DynamicProxy::DynamicProxy.new(self))
  end

  protected def binder
    @__binder ||= binding
  end

  # DSL methods available in REPL:
  def play(note)
    # ...
  end
end

Execution Context

Code sent via REPL is evaluated in the binding returned by #binder, giving it access to:

  • Instance variables of the DSL context
  • All DSL methods (public and private)
  • Local variables captured in the binding

A live coding environment built on it (a reading: it starts a listening server in its constructor):

class LiveCodingEnvironment
  include Musa::REPL::CustomizableDSLContext

  def initialize
    @sequencer = Musa::Sequencer::Sequencer.new(4, 24)
    @repl = REPL.new(Musa::Extension::DynamicProxy::DynamicProxy.new(self))
  end

  protected def binder
    @__binder ||= binding
  end

  # DSL methods accessible from REPL:
  def at(position, &block)
    @sequencer.at(position, &block)
  end
end

And what the editor then sends, which executes in that instance's context:

at(1) { play C4 }
at(4) { play D4 }

Instance Method Summary collapse

Instance Method Details

#execute(source_block, file, line) ⇒ Object

Executes source code in the DSL context.

Called by the REPL to evaluate received code blocks. Delegates to Binding#eval with the binding provided by #binder.

Parameters

  • source_block: Ruby code as string
  • file: Filename for error reporting (typically '(repl)')
  • line: Starting line number for error reporting

Error Handling

Exceptions raised during evaluation propagate to the caller (REPL), which formats them and sends them to the client.

How the REPL calls it (a reading: context is the bound DSL context):

context.execute("sequencer.at(1) { puts 'tick' }", "(repl)", 1)

Parameters:

  • source_block (String)

    Ruby code to execute

  • file (String)

    filename for backtrace (usually '(repl)')

  • line (Integer)

    starting line number for backtrace

Returns:

  • (Object)

    result of evaluating the source code

Raises:

  • (Exception)

    any exception raised by the executed code

See Also:



760
761
762
# File 'lib/musa-dsl/repl/repl.rb', line 760

def execute(source_block, file, line)
  binder.eval source_block, file, line
end