`no implicit conversion of nil into String` wih ruby2d - ruby

So for practice with ruby, I am creating a library on top of ruby2d, but one problem.
I keep getting an error, I think setting up a window, here is the full error:
C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/ruby2d-0.11.3/lib/ruby2d/window.rb:476:in `exist?': no implicit conversion of nil into String (TypeError)
from C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/ruby2d-0.11.3/lib/ruby2d/window.rb:476:in `add_controller_mappings'
from C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/ruby2d-0.11.3/lib/ruby2d/window.rb:629:in `ext_show'
from C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/ruby2d-0.11.3/lib/ruby2d/window.rb:629:in `show'
from C:/Users/Admin/Desktop/RubyProjects/RSGE/rsge_window.rb:19:in `mainloop'
from c:/Users/Admin/Desktop/RubyProjects/test.rb:4:in `<main>'
it shows that something is wrong in ruby2d (a graphics library for ruby)
here is the code for my test file that uses my library
require './RSGE/rsge'
root = Window.new(800, 800)
root.mainloop
and here is my window class:
require 'ruby2d'
require_relative 'rsge_colors'
class Window
def initialize (w, h)
#width = w.to_i
#height = h.to_i
#title = 'Blank Window'
#background = $WHITE
end
def config
set width: #width, height: #height
set background: #background
set title: #title
end
def mainloop
show
end
end
if your wondering what rsge_colors is, here it is
$RED = 'red'
$GREEN = 'green'
$BLUE = 'blue'
$ORANGE = 'orange'
$PURPLE = 'purple'
$YELLOW = 'yellow'
$WHITE = 'white'
$BLACK = 'black'
Why am I getting this error, and how can I fix it?
Thank you for any help you can give me!

Defining class Window looks like you're overriding Ruby2D::Window class.
I've never used this library, but looking the code for some of the games in the showcase, and also the "Get started" section, it looks like the dsl must be used in the root level of your ruby file.
In your case, it should be something like:
require 'ruby2d'
require_relative 'rsge_colors'
set width: 800, height: 800
set background: $WHITE
set title: 'Blank Window'
show
Probably there must be a way to encapsulate the code into classes or modules, but if you're just learning to use the gem, probably would be better to start with the basic stuff then move to refactor these type of things.

Related

Program not running

I have been trying to execute the following code using the command prompt. However, when I try to run it I get the following
C:>circle
C:>
Basically, nothing happens. However, I cannot figure out why this is happening as I am still new to Gosu and Ruby in general. Any help would be much appreciated.
require "rubygems"
require "gosu"
class Circle
attr_reader :columns, :rows
def initialize(radius)
#columns = #rows = radius * 2
img = Gosu::Image.new(Circle.new(50))
img.draw(200, 200, ZOrder::TOP, 0.5, 1.0, Gosu::Color::RED)
clear, solid = 0x00.chr, 0xff.chr
lower_half = (0...radius).map do |y|
x = Math.sqrt(radius ** 2 - y ** 2).round
right_half = "#{solid * x}#{clear * (radius - x)}"
right_half.reverse + right_half
end.join
alpha_channel = lower_half.reverse + lower_half
# Expand alpha bytes into RGBA color values.
#blob = alpha_channel.gsub(/./) { |alpha| solid * 3 + alpha }
end
def to_blob
#blob
end
end
There are 2 problems:
You are running file with class definition. What you need to run if you want to look at that blob is is Circle.new(10).to_blob - where 10 is radius. You can place it in separate file and require class.rb.
initialize method will be run during Circle.new()call. And you have Circle.new called in your class:
img = Gosu::Image.new(Circle.new(50))
So it will lead to infinite recursion and will cause SystemStackError. AFAIK, there is no built-in empty image constructor in gosu (maybe I am wrong).

Ruby + Tk's canvas and shapes are bugging out

I'm running Windows + Ruby2.3 and was messing with the tk library. I'm trying to get it to draw a grid of rectangles of different colors, but whenever I try to add a shape to the canvas my script crashes. Here's a stripped down version of the code:
require 'tk'
require 'tkextlib/tile'
root = TkRoot.new
content = Tk::Tile::Frame.new(root)
canvas = TkCanvas.new(content)
line = TkcLine.new( canvas, 0, 0, 10, 10, :fill => 'red' )
Tk.mainloop
However, when I run it I get the following error + backtrace:
C:/Ruby23/lib/ruby/2.3.0/tk/itemconfig.rb:115:in `hash_kv': wrong argument type nil (expected Array) (TypeError)
from C:/Ruby23/lib/ruby/2.3.0/tk/itemconfig.rb:115:in `itemconfig_hash_kv'
from C:/Ruby23/lib/ruby/2.3.0/tk/canvas.rb:722:in `_parse_create_args'
from C:/Ruby23/lib/ruby/2.3.0/tk/canvas.rb:735:in `create'
from C:/Ruby23/lib/ruby/2.3.0/tk/canvas.rb:758:in `create_self'
from C:/Ruby23/lib/ruby/2.3.0/tk/canvas.rb:751:in `initialize'
from C:/nopathforyou.rb:9:in `new'
from C:/nopathforyou.rb:9:in `<main>'
Anyone know what to do about this? Thanks in advance.
I've experienced the same bug, and I finally solve this issue by adding the code below:
module TkItemConfigOptkeys
def itemconfig_hash_kv(id, keys, enc_mode = [], conf = [])
hash_kv(__conv_item_keyonly_opts(id, keys), enc_mode, conf)
end
end
It should be after the 'require' statements, say, your code should be like:
require 'tk'
require 'tkextlib/tile'
module TkItemConfigOptkeys
def itemconfig_hash_kv(id, keys, enc_mode = [], conf = [])
hash_kv(__conv_item_keyonly_opts(id, keys), enc_mode, conf)
end
end
root = TkRoot.new
content = Tk::Tile::Frame.new(root)
canvas = TkCanvas.new(content)
line = TkcLine.new( canvas, 0, 0, 10, 10, :fill => 'red' )
Tk.mainloop
After adding that, my code works like a charm.
Ruby/Tk has fixed this bug in this commit.
So you can just update your tk library, as an alternative.

Cannot print a text with Gosu in Ruby

Im sitting here with what I think is a very simple bug I just can not figure out.. Im trying to learn how to make games with Gosu gem with Ruby, but have hit a speed bump. Here is my code.
require "gosu"
class Hello < Gosu::Window
def initialize width = 800, height = 600, fullscreen = false
super
self.caption = "Ruby Practise"
#image = Gosu::Image.from_text self. "My text to print".
Gosu.default_font_name.
100
end
def button_down id
close if id == Gosu::KbEscape
end
def update
end
def draw
#image.draw 0, 0, 0
end
end
Hello.new.show
There is something wrong but I do not know what. I have spent at least 1 hour on it.. It complains on the String, here is the output from terminal.
hello.rb:8: syntax error, unexpected tSTRING_BEG
#image = Gosu::Image.from_text self. "My text to print".
^
hello.rb:10: syntax error, unexpected tINTEGER
I do not what I am doing wrong, do some one know? It is probably something really simple..
Use commas to separate function arguments, not dots:
#image = Gosu::Image.from_text self, "My text to print",
Gosu.default_font_name,
100

Ruby TkButton won't run proc

I have a ruby program that uses the TK gui package and I am having trouble with TkButton, specifically the command part. I am trying to run a method that's in the same class when the button is clicked. My code is below. I'm very new to Ruby but not programming in general. When the button is clicked in the gui I get an Application error that says "Error: NameError: unknown option..." where it identifies the method call in the button as the error cause. Can someone explain what I'm doing wrong? I'm using RubyMine to develop.
Code:
require 'tk'
require 'test/unit'
require_relative 'calc'
require_relative 'calcTest'
class CalcUIK
def test_add
calc = Calc.new
expected = Calc.add tk6.get().to_i,tk6.get().to_i
tk8['textvariable'] = 'Result: ' + expected
end
hello = TkRoot.new do
title "Hello World"
# the min size of window
minsize(400,400)
end
tk1 = TkLabel.new(hello) do
text 'Super Calculator'
foreground 'red'
pack { padx 15; pady 15; side 'left'}
end
tk5 = TkLabel.new(hello) do
text 'Enter two numbers to math'
foreground 'blue'
pack { padx 15; pady 15; side 'left'}
end
tk6 = TkEntry.new(hello) do
foreground 'blue'
pack { padx 15; pady 15; side 'left'}
end
tk7 = TkEntry.new(hello) do
foreground 'blue'
pack { padx 15; pady 15; side 'left'}
end
tk8 = TkLabel.new(hello) do
textvariable
foreground 'blue'
pack { padx 15; pady 15; side 'left'}
end
tk2 = TkButton.new(hello){
text 'Add'
command (proc {self.test_add})
pack('padx'=>'20')
pack('side'=>'left')
}
end
Tk.mainloop
PS I know that this code is kind of dumb but it is just a dummy program to set some more important things up. The issue I need to resolve is why the button click is not executing the test_add method. Thanks.
You've defined an instance method on your class called test_add, but in the context in which your "Add" button is defined, self refers to the class CalcUIK. Edit - now that I think about it, I think since self occurs within a block given to TkButton.new, self refers to the new instance of TkButton, which is trying to receive the test_add method, but doesn't recognize it as a valid option. Define the proc as proc { CalcUIK.new.test_add } to generate a new instance that will run the method.
I would also recommend moving all of the TkRoot, TkButton, etc. calls either outside the class entirely, or move them into an initialize method on CalcUIK. Right now, they are run as the class is evaluated, but it's very unusual to have code that is unrelated to the class executed within the context of the class definition.

Ruby setter idiom

I'm working on a Chart class and it has a margin parameter, that holds :top, :bottom, :right and :left values. My first option was to make margin a setter and set values like this:
# Sets :left and :right margins and doesn't alter :top and :bottom
chart.margins = {:left => 10, :right => 15}
It's nice, because it is clearly a setter, but, after some thought, I think it could be confusing too: the user might think that margins contains only :left and :right values, what is not right. Another option is eliminate = and make it an ordinary method:
chart.margins(:left => 10, :right => 15)
With this syntax, it's easy to figure out what is happening, but it is not a standard setter and conflicts with margins getter. And there's still another option:
chart.margins(:left, 10)
chart.margins(:right, 15)
I don't know what to think about this. For me, it is obvious the method is a setter, but this time I cannot set multiple values with just one call and there's the problem with getter again. I'm relatively new to Ruby and I haven't got used to all the idioms yet. So, what do you think guys? Which is the best option?
You could also make a Margin class to enjoy the following clear syntax:
class Margin
attr_accessor :left, :right, :top, :bottom
...
end
class Chart
attr_accessor :margins
...
end
chart.margins.left = 10
puts chart.margins.right
Not so sure if this is the kind of syntax that you would like to make available (sorry if not : )
#!/usr/bin/ruby
class Margins < Struct.new(:top, :bottom, :left, :right)
end
class Chart
attr_reader :margins
def initialize()
#margins = Margins.new(0,0,0,0)
end
def margins=(hash)
[:top, :bottom, :left, :right].each do |dir|
if (hash[dir])
#margins[dir] = hash[dir]
end
end
end
end
c = Chart.new
c.margins.left = 10
c.margins={:top=>12,:bottom=>13}
puts c.margins.left
# 10
puts c.inspect;
# #<Chart:0xb7caaf8c #margins=#<struct Margins top=12, bottom=13, left=10, right=0>>
# However c.margins.foo = 12 would give you an error
In addition to paradigmatic's answer, you could add a method to the Margins class to support:
chart.margins.set :left => 10, :right => 15
You could extend the margins= method to treat a numeric argument:
chart.margins = 20
as sugar for:
chart.margins = Margins.new(20, 20, 20, 20)
I don't think creating a class for Margin is an overkill. You can always expose its values as a hash using to_hash or something similar.
Also, if you like, you can make it work in DSL-style:
chart.margins do |m|
m.left 10
m.right 20
m.vertical 5 # sets both top and bottom margin
end
But I guess I would choose paradigmatic's approach anyway...
You could also stick with what you had first and use the normal hash syntax.
margins["left"] = 10 #to set just one without changing the others

Resources