Problems with Ruby/Gosu relative file referencing - ruby

So I'm making a game with Ruby/Gosu and the lines to load all the images look like this:
#image_name = Gosu::Image.new(self, 'C:\Users\Carlos\Desktop\gamefolder\assets\bg.jpg', false)
I want to refer to them based on their location relative to the referring file. The file which includes the above line is in C:\Users\Carlos\Desktop\gamefolder\, so I would think I could just change the above to '\assets\bg.jpg' or 'assets\bg.jpg', but this doesn't work.
The specific error is "Could not load image assets/bg.jpg using either GDI+ or FreeImage: Unknown Error (Runtime Error)."

If you want to get the current directory (of your execution context, not necessarily the file you're 'in'), just use Dir.pwd. Output this to console to check that your current directory is actually gamefolder.
To get the current directory of your actual ruby file (relative to Dir.pwd), use __FILE__, e.g.
File.dirname(__FILE__)
Pass that to File.expand_path to get a fully-qualified path. You can do a little sanity check by making sure File.exists?("#{File.expand_path File.dirname __FILE__}/assets/bg.jpg") returns true.
(Try File.expand_path('assets/bg.jpg')...that might be all you need here.)

Related

Unable to load/require file from Lua running from Atom in Windows

I'm trying to use Atom to run a Lua script. However, when I try to load files via the require() command, it always says it's unable to locate them. The files are all in the same folder. For example, to load utils.lua I have tried
require 'utils'
require 'utils.lua'
require 'D:\Users\Mike\Dropbox\Lua Modeling\utils.lua'
require 'D:\\Users\\Mike\\Dropbox\\Lua Modeling\\utils.lua'
require 'D:/Users/Mike/Dropbox/Lua Modeling/utils.lua'
I get errors like
Lua: D:\Users\Mike\Dropbox\Lua Modeling\main.lua:12: module 'D:\Users\Mike\Dropbox\Lua Modeling\utils.lua' not found:
no field package.preload['D:\Users\Mike\Dropbox\Lua Modeling\utils.lua']
no file '.\D:\Users\Mike\Dropbox\Lua Modeling\utils\lua.lua'
no file 'D:\Program Files (x86)\Lua\5.1\lua\D:\Users\Mike\Dropbox\Lua Modeling\utils\lua.lua'
no file 'D:\Program Files (x86)\Lua\5.1\lua\D:\Users\Mike\Dropbox\Lua Modeling\utils\lua\init.lua'
no file 'D:\Program Files (x86)\Lua\5.1\D:\Users\Mike\Dropbox\Lua Modeling\utils\lua.lua'
The messages says on the first line that 'D:\Users\Mike\Dropbox\Lua Modeling\utils.lua' was not found, even though that is the full path of the file. What am I doing wrong?
Thanks.
The short answer
You should be able to load utils.lua by using the following code:
require("utils")
And by starting your program from the directory that utils.lua is in:
cd "D:\Users\Mike\Dropbox\Lua Modeling"
lua main.lua
The long answer
To understand what is going wrong here, it is helpful to know a little bit about how require works. The first thing that require does is to search for the module in the module path. From Programming in Lua chapter 8.1:
The path used by require is a little different from typical paths. Most programs use paths as a list of directories wherein to search for a given file. However, ANSI C (the abstract platform where Lua runs) does not have the concept of directories. Therefore, the path used by require is a list of patterns, each of them specifying an alternative way to transform a virtual file name (the argument to require) into a real file name. More specifically, each component in the path is a file name containing optional interrogation marks. For each component, require replaces each ? by the virtual file name and checks whether there is a file with that name; if not, it goes to the next component. The components in a path are separated by semicolons (a character seldom used for file names in most operating systems). For instance, if the path is
?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua
then the call require"lili" will try to open the following files:
lili
lili.lua
c:\windows\lili
/usr/local/lua/lili/lili.lua
Judging from your error message, your Lua path seems to be the following:
.\?.lua;D:\Program Files (x86)\Lua\5.1\lua\?.lua;D:\Program Files (x86)\Lua\5.1\lua\?\init.lua;D:\Program Files (x86)\Lua\5.1\?.lua
To make that easier to read, here are each the patterns separated by line breaks:
.\?.lua
D:\Program Files (x86)\Lua\5.1\lua\?.lua
D:\Program Files (x86)\Lua\5.1\lua\?\init.lua
D:\Program Files (x86)\Lua\5.1\?.lua
From this list you can see that when calling require
Lua fills in the .lua extension for you
Lua fills in the rest of the file path for you
In other words, you should just specify the module name, like this:
require("utils")
Now, Lua also needs to know where the utils.lua file is. The easiest way is to run your program from the D:\Users\Mike\Dropbox\Lua Modeling folder. This means that when you run require("utils"), Lua will expand the first pattern .\?.lua into .\utils.lua, and when it checks that path it will find the utils.lua file in the current directory.
In other words, running your program like this should work:
cd "D:\Users\Mike\Dropbox\Lua Modeling"
lua main.lua
An alternative
If you can't (or don't want to) change your working directory to run the program, you can use the LUA_PATH environment variable to add new patterns to the path that require uses to search for modules.
set LUA_PATH=D:\Users\Mike\Dropbox\Lua Modeling\?.lua;%LUA_PATH%;
lua "D:\Users\Mike\Dropbox\Lua Modeling\main.lua"
There is a slight trick to this. If the LUA_PATH environment variable already exists, then this will add your project's folder to the start of it. If LUA_PATH doesn't exist, this will add ;; to the end, which Lua fills in with the default path.

How can I specify the file location to write and read from in Ruby?

So, I have a function that creates an object specifying user data. Then, using the Ruby YAML gem and some code, I put the object to a YAML file and save it. This saves the YAML file to the location where the Ruby script was run from. How can I tell it to save to a certain file directory? (A simplified version of) my code is this
print "Please tell me your name: "
$name=gets.chomp
$name.capitalize!
print "Please type in a four-digit PIN number: "
$pin=gets.chomp
I also have a function that enforces that the pin be a four-digit integer, but that is not important.
Then, I add this to an object
new_user=Hash.new (false)
new_user["name"]=$name
new_user["pin"]=$pin
and then add it to a YAML file and save it. If the YAML file doesn't exist, one is created. It creates it in the same file directory as the script is run in. Is there a way to change the save location?
The script fo save the object to a YAML file is this.
def put_to_yaml (new_user)
File.write("#{new_user["name"]}.yaml", new_user.to_yaml)
end
put_to_yaml(new_user)
Ultimately, the question is this: How can I change the save location of the file? And when I load it again, how can i tell it where to get the file from?
Thanks for any help
Currently when you use File.write it takes your current working directory, and appends the file name to that location. Try:
puts Dir.pwd # Will print the location you ran ruby script from.
You can specify the absolute path if you want to write it in a specific location everytime:
File.write("/home/chameleon/different_location/#{new_user["name"]}.yaml")
Or you can specify a relative path to your current working directory:
# write one level above your current working directory
File.write("../#{new_user["name"]}.yaml", new_user.to_yaml)
You can also specify relative to your current executing ruby file:
file_path = File.expand_path(File.dirname(__FILE__))
absolute_path = File.join(file_path, file_name)
File.write(absolute_path, new_user.to_yaml)
You are supplying a partial pathname (a mere file name), so we read and write from the current directory. Thus you have two choices:
Supply a full absolute pathname (personally, I like to use the Pathname class for this); or
Change the current directory first (with Dir.chdir)

Why load "file.rb" works even though "." is not in the load path?

I have created a project in /Projects/test that have the following files:
/Projects/test/first.rb
/Projects/test/second.rb
In first.rb, I do:
load 'second.rb'
And it gets loaded correctly. However, if I open the console and I type $:, I don't see the current directory "." in the load path. How does Ruby know where to load that 'second.rb' from?
See the documentation of Kernel#load clearly :
Loads and executes the Ruby program in the file filename. If the filename does not resolve to an absolute path, the file is searched for in the library directories listed in $:. If the optional wrap parameter is true, the loaded script will be executed under an anonymous module, protecting the calling program’s global namespace. In no circumstance will any local variables in the loaded file be propagated to the loading environment.
In case load 'second.rb' - second.rb has been internally resolved to the absolute path /Projects/test/second.rb,as your requiring file in the directory is same as required file directory. Nothing has been searched to the directories listed in$: for your case.
Just remember another way always
- The load method looks first in the current directory for files
Contrary to the currently accepted answer, the argument 'second.rb' does not resolve to an absolute path. If that were what was meant, you would also be able to require 'second.rb', since require has exactly the same wording about absolute paths.
I think what's happening here is just that the phrasing in the documentation for load is not clear at all about what the actual steps are. When it says "Loads and executes the Ruby program in the file filename," it means that literally — it treats the argument as a file name and attempts to load it as a Ruby program. If isn't an absolute path†, then Ruby goes through $LOAD_PATH and looks for it in those places. If that doesn't turn anything up, then it just goes ahead and tries to open it just as you passed it in. That's the logic that MRI actually follows.
† The actual check that Ruby does is essentially "Does the path start with '/', '~' or './'?".

Requiring file outside of load path in Ruby

I have a gem that I have written that has a number of handlers, each of which has their own ruby file in the gem. I need to add the ability to specify a file on the command line that will be loaded in the same manner as these other handlers. The file will typically not be in the default load path of the gem.
I'm not sure the best way to do this. I could take the filename, and then add the containing directory to the load path and then load the file. I could have the user specify a directory containing handlers to be read instead of specifying the file, or I'm sure there are a better way to do it that I haven't yet thought of.
This was fixed using require_relative and expanding the file path using Dir.pwd:
req_path = File.expand_path(arg, Dir.pwd)
require_relative req_path

How do I load files from a specific relative path in Ruby?

I'm making a gem for internal use. In it, I load some YAML from another directory:
# in <project_root>/bin/magicwand
MagicWand::Configuration::Initializer.new(...)
# in <project_root>/lib/magicwand/configuration/initializer.rb
root_yaml = YAML.load_file(
File.expand_path("../../../../data/#{RootFileName}", __FILE__))
# in <project_root>/data/root.yaml
---
apple: 100
banana: 200
coconut: 300
I'd rather not depend on the location of data/root.yaml relative to initializer.rb. Instead, I'd rather get a reference to <project_root> and depend on the relative path from there, which seems like a smarter move.
First, is that the best way to go about this? Second, if so, how do I do that? I checked out the various File methods, but I don't think there's anything like that. I'm using Ruby 1.9.
Right now, I create a special constant and depend on that instead:
# in lib/magicwand/magicwand.rb
module MagicWand
# Project root directory.
ROOT = File.expand_path("../..", __FILE__)
end
but I'm not sure I like that approach either.
If there's a main file you always run you can use that file as a reference point. The relative path (between the current directory and) of that file will be in $0, so to get the relative path to data/root.yaml (assuming that is the relative path between the main file and root.yaml) you do
path_to_root_yaml = File.dirname($0) + '/data/root.yaml'

Resources