I'm writing a game engine with JRuby, and something goes wrong when I use a global variable. I have only these scripts:
main.rb:
$CLASSPATH << "src.rb"
require 'modules'
require 'SceneMenu'
require 'SceneMap'
$game.setScene(SceneMenu.new)
modules.rb:
$game = Java::MyNamespace::Game::getInstance
module MyGame
def self.cache
return $game.cache # << ERROR OCCURS HERE
end
end
SceneMenu.rb:
class SceneMenu
def initialize
#count = 0
end
def update
if #count == 100
$game.setScene(SceneMap.new)
end
#count += 1
end
end
SceneMap.rb:
class SceneMap
def initialize
#logoTexture = MyGame::cache.load("mylogo.png")
end
end
My problem is that when I launch the game, it always is fine, but when my #count reaches 100, and SceneMap is created, an error occurs saying:
undefined method 'cache' for nil:NilClass
while I have called $game.setScene( ... ) just before.
I do not modify my $game variable at all, so I don't know what happens.
Does someone have an idea of what is going on?
Maybe try changing the code to:
$game = Java::MyNamespace::Game::getInstance
module MyGame
def cache
return $game.cache
end
end
I have finally fixed my problem by writing:
module MyGame
def self.game
return Java::MyNamespace::Game::getInstance
end
end
$game = MyGame::game
Related
Given a set of class definitions:
class Application
def self.open_current
return Current.new()
end
end
class Current
def get_row(row)
Row.new(row)
end
end
class Row
def get_col(row)
#...
end
end
Design a Proxy class which will:
Create Proxy<<Class>> versions of each class which are extendable via
class ProxyApplication
def myMethod()
#...
end
end
#...
Wrap all return values of all methods in each class such that a proxied class is always used instead of a standard class. I.E.
app = Proxy.new(Application) #app == ProxyApplication
current = app.open_current #current == #<ProxyCurrent>
Ultimately, the definition of Proxy must be dynamic rather than static definitions.
I've been working on this problem for about 6 hours now. I've got the following code. This includes 3 sections:
Initial class setup
Proxy class definition
Testing proxy class
Currently I've got to the point where pApplication=Proxy.new(Application) returns #<Proxy> and pApplication.open_current returns #<ProxyCurrent> which seems kind of on the correct line. However currently it errors when delegate.rb tries to call test() with 2,3 arguments instead of 0...
But my question is, realistically am I going about this correctly? Is using SimpleDelegator the easiest way to do this? One current problem is I'm basically having to add new functionality to the existing SimpleDelegator. I've also looked at using Forwardable, but having to delegate methods manually is not where I want to go with this project, if possible.
Any ideas?
Due to numerous limitations with the initial idea of packing all the calls into a single class, I redesigned it a bit, but it works in exactly the same way.
def proxy__enwrap(obj)
isClass = obj.is_a?(Class)
oldClass = isClass ? obj : obj.class
sNewClass = "Proxy#{oldClass.to_s}"
code = <<-EOF
class #{sNewClass}
include InstanceProxy
def self.__cinit__(obj)
##__cobj__ = obj
end
def self.__cget__
##__cobj__
end
def self.method_missing(m,*args,&block)
if ##__cobj__.respond_to? m
retVal = ##__cobj__.public_send(m,*args,*block)
return proxy__enwrap(retVal)
else
puts "ERROR " + m.to_s + "(" + args.to_s + ") + block?"
#Throw error
end
end
end
#{sNewClass}.__cinit__(#{oldClass.to_s})
if isClass
return #{sNewClass}
else
return #{sNewClass}.new(obj)
end
EOF
::Kernel.eval(code)
end
module InstanceProxy
def method_missing(m,*args,&block)
retVal = #__obj__.__send__(m,*args,&block)
return proxy__enwrap(retVal)
end
def initialize(obj)
#__obj__ = obj
end
end
XXApplication = Application
::Object.const_set "Application", proxy__enwrap(Application)
Currently the only issue is that the object doesn't wrap correctly around yielded objects... I'm not sure if that's even possible though.
Edit:
I've improved the system to also wrap objects passed in as blocks:
def proxy__enwrap(obj)
isClass = obj.is_a?(Class)
oldClass = isClass ? obj : obj.class
sNewClass = "Proxy#{oldClass.to_s}"
code = <<-EOF
class #{sNewClass}
include InstanceProxy
def self.__cinit__(obj)
##__cobj__ = obj
end
def self.__cget__
##__cobj__
end
def self.to_ary
#fix for puts (puts calls to_ary. see: https://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary)
[self.to_s]
end
def self.method_missing(m,*args,&block)
#Wrap block arguments:
newBlock = Proc.new {}
if block_given?
newBlock = Proc.new do |*args|
args = args.map {|arg| proxy__enwrap(arg)}
block.call(*args)
end
end
#Call delegated functions. Raise error if object doesn't respond to method.
#Return wrapped value
if ##__cobj__.respond_to? m
retVal = ##__cobj__.public_send(m,*args,*block)
return proxy__enwrap(retVal)
else
raise ArgumentError.new("Method '\#\{m.to_s}' doesn't exist.")
end
end
end
#{sNewClass}.__cinit__(#{oldClass.to_s})
if isClass
return #{sNewClass}
else
return #{sNewClass}.new(obj)
end
EOF
::Kernel.eval(code)
end
module InstanceProxy
def method_missing(m,*args,&block)
#Wrap block arguments:
newBlock = Proc.new {}
if block_given?
newBlock = Proc.new do |*args|
args = args.map {|arg| proxy__enwrap(arg)}
block.call(*args)
end
end
#Call delegated functions. Raise error if object doesn't respond to method.
#Return wrapped value
if #__obj__.respond_to? m
retVal = #__obj__.__send__(m,*args,&newBlock)
return proxy__enwrap(retVal)
else
raise ArgumentError.new("Method '#{m.to_s}' doesn't exist.")
end
end
def initialize(obj)
#__obj__ = obj
end
def to_ary
#fix for puts (puts calls to_ary. see: https://stackoverflow.com/questions/8960685/ruby-why-does-puts-call-to-ary)
[self.to_s]
end
end
#
XXApplication = Application
#Silence warnings of overwriting constant
original_verbosity = $VERBOSE
$VERBOSE = nil
::Object.const_set "Application", proxy__enwrap(Application)
$VERBOSE = original_verbosity
Working in Ruby, I'm getting an error saying
'add': undefined local variable or method 'food' for #<FoodDB:...
This is the code I'm trying to run
require_relative 'FoodDB.rb'
class Manager
def initialize
food = FoodDB.new
self.create_foodDB(food)
end
def create_foodDB(food)
counter = 1
word = []
file = File.new("FoodDB.txt","r")
while (line = file.gets)
food.addFood(line)
counter = counter + 1
end
file.close
end
end
manager = Manager.new
input_stream = $stdin
input_stream.each_line do |line|
line = line.chomp
if line == "quit"
input_stream.close
end
end
This is FoodDB.rb's code
class FoodDB
def initialize
food = []
end
def addFood(str)
food.push(str)
end
end
I'm not sure what's the problem since it seems like I'm definitely calling the correct method from the FoodDB class. All help is appreciated, thank you!
You need to change food in the FoodDB class to an instance variable:
class FoodDB
def initialize
#food = []
end
def addFood(str)
#food.push(str)
end
end
An instance variable will be available throughout all methods of an instance, while the food variable you used was local to its lexical scope, i.e. only available within the initialize method.
I'm trying to make a small game where you go from room to room but when I try to return the value for the next room instead of being the string I intended I get something that looks like this:
#<Roseroom:0x007fe40984c778>
instead of
"skullroom"
This happens whether I use a $global variable or try to return "a string"
Perhaps I'm going about this completely wrong, so if you have any suggestions that would be appreciated as well.
Here is my code, the problem is with class Roseroom not being about to send "skullroom" back to the map class (which is the runner).
$next_room = ''
class Engine
def initialize(stage)
#stage = stage
puts "succesfully initialized game"
#map = Map.new(#stage)
end
end
class Map
def initialize(start)
#start = start
#rooms = {"roseroom" => method(:enterRose),
"skullroom" => method(:enterSkull)
}
runner(#rooms, #start)
end
def runner(map, start)
$next_room = start
while true
room = map[$next_room]
puts $next_room
$next_room = room.call()
#method(:enterSkull).call() #This work if I call it directly
end
end
def enterRose()
#roseroom = Roseroom.new
end
def enterSkull()
#skullroom = Skullroom.new
end
end
class Roseroom
def initialize
puts "succesfully initialized roseroom"
#$next_room = "skullroom"
return "skullroom"
end
def exit
end
end
class Skullroom
def initialize
puts "succesfully initialized skullroom"
Process.exit(1)
end
end
game = Engine.new("roseroom")
I have it here on codepad if that helps:
http://codepad.org/AlpkRIGb
Thanks!
There is nothing in Roseroom class that would return "skullroom"... you may be under the impression that because the last line in initialize is return "skullroom" you would then see "skullroom" returned on a a Roseroom.new but that's not what happens... doing Roseroom.new will always return a new Roseroom object.
you'd be better off defining a next_room method within Roseroom that returns "skullroom"
class Roseroom
def next_room
return "skullroom"
end
Then when you do...
def enterRose
i_am_here = Roseroom.new
i_am_here.next_room
end
Hope this helps.
So, I know there is a simple error, but I just can't seem to spot it. I'm using Modules/Mixins for the first time and any help would be much appreciated. I keep getting this error:
undefined method `this_is' for Value:Module (NoMethodError)
But it looks like the method is there...Here are is my module and classes...
module Value
def this_is
puts "#{self.players_hand} is the players hand"
end
end
require './value.rb'
class Player
include Value
attr_accessor :players_hand
def initialize
#players_hand = 0
end
def value_is
Value.this_is
end
end
require './player.rb'
class Game
def initialize
#player = Player.new
end
def start
puts #player.players_hand
puts #player.value_is
end
end
game = Game.new
game.start
When you include Value inside of the Player class, you are making the Value module's methods a part of the Player class, so the this_is method is not namespaced. Knowing that, we need to change this method:
def value_is
Value.this_is
end
To:
def value_is
this_is
end
I'm trying to learn ruby more in depth before I move on to rails dev, but I'm having some issues learning classes. I can't seem to understand why the following doesn't work.
#point.rb
class Point
attr_accessor :x, :y
def initialize(p = [0,0])
#x = p[0]
#y = p[1]
end
end
#shape.rb
require_relative 'point.rb'
class Shape
attr_accessor :points
def initialize *the_points
for p in the_points
#points.append Point.new(p)
end
end
end
s = Shape.new([3,2])
puts s.points
When I call the function I get a no method error for NilClass, which I'm assuming is referring to #point.append.
First, try this:
def initialize *the_points
#points = []
for p in the_points
#points << Point.new(p)
end
end
You get NilClass error because #points instance variable is Nil, and NilClass, which does not have append() method.
Better than creating an array and populating it in a loop would be to initialize it like so:
class Shape
attr_accessor :points
def initialize *the_points
#points = the_points.map{ |p| Point.new(p) }
end
end
If you had warnings on (ruby -w or $VERBOSE = true), it'd warn you that #points didn't exist.
See some other debugging tips in How do I debug Ruby scripts?
You need to initialize #points to be a new array. It starts off as nil.
def initialize *the_points
#points = [];
for p in the_points
#points.append Point.new(p)
end
end