Module: TCOMethod

Defined in:
lib/tco_method.rb,
lib/tco_method/mixin.rb,
lib/tco_method/version.rb,
lib/tco_method/method_info.rb,
lib/tco_method/block_with_tco.rb,
lib/tco_method/block_extractor.rb,
lib/tco_method/method_reevaluator.rb,
lib/tco_method/ambiguous_source_error.rb

Overview

The namespace for the TCOMethod gem. Home to private API methods employed by the Mixin module to provide tail call optimized behavior to extending Classes and Modules.

Defined Under Namespace

Modules: Mixin Classes: AmbiguousSourceError, BlockExtractor, BlockWithTCO, MethodInfo, MethodReevaluator

Constant Summary collapse

ISEQ_OPTIONS =

Options that must be provided to RubyVM::InstructionSequence in order to compile code with tail call optimization enabled. Beyond simply enabling the ‘tailcall optimization` option, the `trace_instruction` option must also be disabled because the RubyVM doesn’t currently support ‘set_trace_func` for code that is compiled with tail call optimization.

{
  tailcall_optimization: true,
  trace_instruction: false,
}.freeze
VERSION =

The version of the TCOMethod gem.

"0.2.0"

Class Method Summary collapse

Class Method Details

.tco_eval(code, file = nil, path = nil, line = nil) ⇒ Object

Provides a mechanism for evaluating Strings of code with tail call optimization enabled.

Parameters:

  • code (String)

    The code to evaluate with tail call optimization enabled.

Returns:

  • (Object)

    Returns the value of the final expression of the provided code String.

Raises:

  • (ArgumentError)

    if the provided code argument is not a String.



28
29
30
31
# File 'lib/tco_method.rb', line 28

def self.tco_eval(code, file = nil, path = nil, line = nil)
  raise ArgumentError, "Invalid code string!" unless code.is_a?(String)
  RubyVM::InstructionSequence.new(code, file, path, line, ISEQ_OPTIONS).eval
end

.with_tco(&block) ⇒ Object

Allows for executing a block of code with tail call optimization enabled.

All code that is evaluated in the block will be evaluated with tail call optimization enabled, however here be dragons, so be warned of a few things:

  1. Though it may not be obvious, any call to ‘require`, `load`, or similar

methods from within the block will be evaluated by another part of the VM and will not be tail call optimized. This applies for ‘tco_eval` as well.

  1. The block will be evaluated with a different binding than the binding it

was defined in. That means that references to variables or other binding context will result in method errors. For example:

some_variable = "Hello, World!"
womp_womp = TCOMethod.with_tco { some_variable }
# => NameError: Undefined local variable or method 'some_variable'
  1. Though this approach is some what nicer than working with strings of

code, it comes with the tradeoff that it relies on the the ‘method_source` gem to do the work of finding the source of the block. There are situations where `method_source` can’t accurately determine the source location of a block. That said, if you don’t format your code like a maniac, you should be fine.

Parameters:

  • block (Proc)

    The proc to evaluate with tail call optimization enabled.

Returns:

  • (Object)

    Returns whatever the result of evaluating the given block.

Raises:

  • (ArgumentError)


60
61
62
63
# File 'lib/tco_method.rb', line 60

def self.with_tco(&block)
  raise ArgumentError, "Block required" unless block_given?
  BlockWithTCO.new(&block).result
end