class Keisan::Context

Attributes

allow_blocks[R]
allow_multiline[R]
allow_random[R]
allow_recursive[R]
function_registry[R]
variable_registry[R]

Public Class Methods

new(parent: nil, random: nil, allow_recursive: false, allow_multiline: true, allow_blocks: true, allow_random: true, shadowed: []) click to toggle source
# File lib/keisan/context.rb, line 10
def initialize(parent: nil,
               random: nil,
               allow_recursive: false,
               allow_multiline: true,
               allow_blocks: true,
               allow_random: true,
               shadowed: [])
  @parent = parent
  @function_registry = Functions::Registry.new(parent: @parent&.function_registry)
  @variable_registry = Variables::Registry.new(parent: @parent&.variable_registry, shadowed: shadowed)
  @random            = random
  @allow_recursive   = allow_recursive
  @allow_multiline   = allow_multiline
  @allow_blocks      = allow_blocks
  @allow_random      = allow_random
end

Public Instance Methods

allow_recursive!() click to toggle source
# File lib/keisan/context.rb, line 27
def allow_recursive!
  @allow_recursive = true
end
freeze() click to toggle source
Calls superclass method
# File lib/keisan/context.rb, line 31
def freeze
  super
  @function_registry.freeze
  @variable_registry.freeze
end
function(name) click to toggle source
# File lib/keisan/context.rb, line 96
def function(name)
  @function_registry[name.to_s]
end
function_is_modifiable?(name) click to toggle source
# File lib/keisan/context.rb, line 104
def function_is_modifiable?(name)
  @function_registry.modifiable?(name)
end
has_function?(name) click to toggle source
# File lib/keisan/context.rb, line 100
def has_function?(name)
  @function_registry.has?(name)
end
has_variable?(name) click to toggle source
# File lib/keisan/context.rb, line 80
def has_variable?(name)
  @variable_registry.has?(name)
end
random() click to toggle source
# File lib/keisan/context.rb, line 116
def random
  raise Keisan::Exceptions::InvalidExpression.new("Context does not permit expressions with randomness") unless allow_random
  @random ||= @parent&.random || Random.new
end
register_function!(name, function, local: false) click to toggle source
# File lib/keisan/context.rb, line 108
def register_function!(name, function, local: false)
  if transient? || !local && @parent&.function_is_modifiable?(name)
    @parent.register_function!(name, function, local: local)
  else
    @function_registry.register!(name.to_s, function)
  end
end
register_variable!(name, value, local: false) click to toggle source
# File lib/keisan/context.rb, line 88
def register_variable!(name, value, local: false)
  if !@variable_registry.shadowed.member?(name) && (transient? || !local && @parent&.variable_is_modifiable?(name))
    @parent.register_variable!(name, value, local: local)
  else
    @variable_registry.register!(name, value)
  end
end
set_random(random) click to toggle source
# File lib/keisan/context.rb, line 121
def set_random(random)
  raise Keisan::Exceptions::InvalidExpression.new("Context does not permit expressions with randomness") unless allow_random
  @random = random
end
spawn_child(definitions: {}, shadowed: [], transient: nil) click to toggle source

A transient context does not persist variables and functions in this context, but rather store them one level higher in the parent context. When evaluating a string, the entire operation is done in a transient context that is unique from the calculators current context, but such that variable/function definitions can be persisted in the calculator.

# File lib/keisan/context.rb, line 42
def spawn_child(definitions: {}, shadowed: [], transient: nil)
  child = pure_child(shadowed: shadowed)

  definitions.each do |name, value|
    case value
    when Proc
      child.register_function!(name, value)
    when Functions::ProcFunction
      child.register_function!(name, value.function_proc)
    else
      child.register_variable!(name, value)
    end
  end

  if transient.nil? && self.transient? || transient == true
    child.set_transient!
  end
  child
end
transient?() click to toggle source
# File lib/keisan/context.rb, line 72
def transient?
  !!@transient
end
transient_definitions() click to toggle source
# File lib/keisan/context.rb, line 62
def transient_definitions
  return {} unless @transient
  parent_definitions = @parent.nil? ? {} : @parent.transient_definitions
  parent_definitions.merge(
    @variable_registry.locals
  ).merge(
    @function_registry.locals
  )
end
variable(name) click to toggle source
# File lib/keisan/context.rb, line 76
def variable(name)
  @variable_registry[name.to_s]
end
variable_is_modifiable?(name) click to toggle source
# File lib/keisan/context.rb, line 84
def variable_is_modifiable?(name)
  @variable_registry.modifiable?(name)
end

Protected Instance Methods

pure_child(shadowed: []) click to toggle source
# File lib/keisan/context.rb, line 132
def pure_child(shadowed: [])
  self.class.new(
    parent: self,
    shadowed: shadowed,
    allow_recursive: allow_recursive,
    allow_multiline: allow_multiline,
    allow_blocks: allow_blocks
  )
end
set_transient!() click to toggle source
# File lib/keisan/context.rb, line 128
def set_transient!
  @transient = true
end