Keeping variables across requires?

I’m making a Befunge interpreter in Ruby - I like to keep my brain
active. I want to be able to switch between different sets of rules, so
as well as my base program befunge.rb, I’ve got a file called
befunge-93.rb that contains the Befunge-93 specification. Like so:

befunge.rb

instructions = {}
require ‘befunge-93’

befunge-93.rb

instructions = {}
instructions["+"] = lambda { |a, b| stack.push a+b }
instructions["-"] = lambda { |a, b| stack.push b-a }
more instructions, snipped.

I do the ‘instructions = {}’ line twice, as it curls up and dies without
it. But after I’ve included the instructions file, instructions is still
{}. This hints at the fact that it’s not letting me use the instructions
variable across the file.

Is there any way to do this? I could do something like:
File.open(“befunge-93.rb”).each { |instruction| eval(instruction }

But it that’s a valid solution, then I’m Tony Blair.

On Dec 5, 2007, at 12:30 PM, Peter B. wrote:


without
it. But after I’ve included the instructions file, instructions is
still
{}. This hints at the fact that it’s not letting me use the
instructions
variable across the file.

Is there any way to do this?

You really have two variables ‘instructions’, each local to file in
which it appears. You could use the following trick with a global
variable:

#! /usr/bin/env ruby -w $instructions = {} instructions = $instructions require "xtest" p instructions instructions = $instructions instructions["+"] = lambda { |a, b| stack.push a+b } instructions["-"] = lambda { |a, b| stack.push b-a }

Regards, Morton

Ah, thanks. With Ruby I’m used to not having to do global/local things;
I didn’t know you could create global ones with $. But now I have
another problem: The functions I created with lambda {} are now
returning -1 as their arity.

My new code:

befunge.rb

elsif $instructions.include? operator
arguments = []
$instructions[operator].arity.times {arguments.push stack.pop}
$instructions[operator].call( *arguments )
else

befunge-93.rb (just a sample)

$instructions = {}
$instructions["!"] = lambda { |a| stack.push !a}
$instructions["`"] = lambda { |a, b| stack.push b>a ? 1 : 0 }
$instructions[">"] = lambda { xvel = 1; yvel = 0 }

On Dec 5, 2007 5:13 PM, Peter B. [email protected] wrote:

Ah, thanks. With Ruby I’m used to not having to do global/local things;
I didn’t know you could create global ones with $. But now I have
another problem: The functions I created with lambda {} are now
returning -1 as their arity.

AFAIK, that’s a quirk in 1.8. Blocks with no arguments return -1 when
you
ask them for their arity. That behavior was redefined in 1.9, and they
now
return 0. You can also, currently, pass arguments to those blocks
without
any indication that they’ll be ignored.

1.8.6:

irb(main):001:0> lambda {}.arity
=> -1
irb(main):002:0> lambda {}.call 1
=> nil

1.9.0 (2007-11-28 patchlevel 0):

irb(main):001:0> lambda {}.arity
=> 0
irb(main):002:0> lambda {}.call 1
ArgumentError: wrong number of arguments (1 for 0)

-Vitor.

Ah, the program was that I didn’t make all the other variables global as
well. So it ran, but didn’t like it.

Also, if there is any way to include the file without playing around
with any global malarky, that would be brilliant.

On Dec 5, 1:13 pm, Peter B. [email protected] wrote:

arguments = []

$instructions[“>”] = lambda { xvel = 1; yvel = 0 }


Posted viahttp://www.ruby-forum.com/.

Global state is usually unnecessary. It looks like your code would fit
naturally into a layout similar to this…

==befunge-93.rb==
require ‘singleton’

class Befunge93
include Singleton
attr_accessor :instructions, :stack
def initialize
@stack = []
@instructions = {}
@instructions[“!”] = lambda { | a |
@stack.push(!a)
}
@instructions[“`”] = lambda { | a, b |
@stack.push(b>a ? 1 : 0)
}
@instructions[“>”] = lambda {
xvel = 1
yvel = 0
}
end
end

==befunge.rb==
require ‘befunge-93’

b = Befunge93.instance

#…
elsif b.instructions.include?(operator)
arguments = []
b.instructions[operator].arity.times {
arguments.push(b.stack.pop)
}
b.instructions[operator].call(*arguments)
else
#…

Regards,
Jordan