Keeping variables across requires?

P

Peter Bunyan

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.
 
M

Morton Goldberg

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?


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

<code test.rb>
#! /usr/bin/env ruby -w
$instructions = {}
instructions = $instructions
require "xtest"
p instructions
</code>

<code xtest.rb>
instructions = $instructions
instructions["+"] = lambda { |a, b| stack.push a+b }
instructions["-"] = lambda { |a, b| stack.push b-a }
</code>

Regards, Morton
 
P

Peter Bunyan

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
 
V

Vitor Peres

Note: parts of this message were removed by the gateway to make it a legal Usenet post.

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.
 
M

MonkeeSage

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 }

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
 
P

Peter Bunyan

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,273
Messages
2,571,364
Members
48,050
Latest member
Carson62C3

Latest Threads

Top