Rake and current directory - ruby

How do I get the directory where the rakefile.rb is located?
I want to use this as my root directory to locate everything off.

use __FILE__ to get the file name then you can get the directory from there:
in test.rb
puts __FILE__
output:
/users/foo/test.rb
__FILE__ resolves to the full path of the file it is in.
Use this to get the dir name:
File.dirname(__FILE__)

You can get it by calling application.original_dir method. In task you can achieve application object using application method on task object.

Why not just use Dir.pwd
?

As of Ruby 2 you can use __dir__ instead of File.dirname(__FILE__) to get the directory that contains the current script.

If this is a RoR app your Rakefile.rb should be in your RAILS_ROOT directory. So in any script you can specify file location like
config.load_paths += %W( #{RAILS_ROOT}/extras )

Related

Reading files elsewhere in directory w/ Ruby

I've got a project structure as follows:
info.config (just a JSON file w/ prefs+creds)
main.rb
tasks/
test.rb
In both main.rb (at the root of the project), and test.rb (under the tasks folder), I want to be able to read and parse the info.config file. I've figured out how to do that in main.rb with the following:
JSON.parse(File.read('info.config'))
Of course, that doesn't work in test.rb.
Question: How can I read the file from a test.rb even though it's one level deeper in the hierarchy?
Appreciate any guidance I can get! Thanks!
Use relative path:
path = File.join(
File.dirname(File.dirname(File.absolute_path(__FILE__))),
'info.config'
)
JSON.parse(File.read(path))
File.dirname(File.absolute_path(__FILE__)) will give you the directory where test.rb resides. -> (1)
File.dirname(File.dirname(File.absolute_path(__FILE__))) will give you parent directory of (1).
Reference: File::absolute_path, File::dirname
UPDATE
Using File::expand_path is more readable.
path = File.expand_path('../../info.config', __FILE__)
JSON.parse(File.read(path))
What I usually do is:
Create file called environment or similar in your project root. This file has only one purpose - to extend load path:
require 'pathname'
ROOT_PATH = Pathname.new(File.dirname(__FILE__))
$:.unshift ROOT_PATH
Require this file at the beginning of your code. From now on every time you call require, you can use relative_path to you root directory, without worrying where file you are requiring it from is located.
When using File, you can simple do:
File.open(ROOT_PATH.join 'task', 'test.rb')
You can do as below using File::expand_path :
path = File.expand_path("info.config","#{File.dirname(__FILE__)}/..")
JSON.parse(File.read(path))
File.dirname(__FILE__) will give you the path as "root_path_of_your_projet/tasks/".
"#{File.dirname(__FILE__)}/.." will give you the path as "root_path_of_your_projet/". .. means go one level up from the current directory.
File.expand_path("info.config","root_path_of_your_projet/") will give you the actual path to the file as "root_path_of_your_projet/info.config".
You can also use __dir__ instead of File.dirname(__FILE__).
__dir__ : Returns the canonicalized absolute path of the directory of the file from which this method is called.
Hope that explanation helps.

require_relative from present working dir

I built a ruby gem with a binary. I use like this:
myruby "param"
It is a helper for building integration, and needs a setting for each project. I have settings in settings.rb for several projects. Is it possible to require a .rb file based on the present working dir? When I run:
/home/usr/admin/sources/myproject1/ $ myruby start
I want it to require the settings from:
/home/usr/admin/sources/myproject1/settings.rb
How could I do this if it's possible? I tried:
require_relative '#{Dir.pwd}/settings.rb'
which did not work.
File.expand_path('../', __FILE__)
gives you the path to the current directory. Thus if you have a file in bin/foo and you want to require something in lib/foo/settings.rb simply use
require File.join(File.expand_path('../../'), __FILE__), 'lib/foo/settings.rb')
Note the double ../ because the first is required to strip out from __FILE__ the current filename.
If the file is in /home/usr/admin/sources/myproject1/bin/foo
File.expand_path('../', __FILE__)
# => /home/usr/admin/sources/myproject1/bin
File.expand_path('../../', __FILE__)
# => /home/usr/admin/sources/myproject1
File.join(File.expand_path('../../', __FILE__), 'lib/foo/settings.rb')
# => /home/usr/admin/sources/myproject1/lib/foo/settings.rb
If you want to include the file with a relative path from the working directory, use
require File.join(Dir.pwd, 'settings.rb')
However, I don't think it's a good idea to hard-code a path in this way. You may probably want to pass the settings as argument to the command line.
It doesn't really make sense to create a gem that depends on a path of a file hard-coded on your machine.
File.expand_path(File.dirname(__FILE__)) will return the directory relative to the file this command is called from.
The difference between require and require_relative is that require_relative loads files from directory relative to the file where it is written. While require searches for files in directories from $LOAD_PATH if given a relative path or can load files from absolute path, which can be created with File.expand_path

Ruby - FileUtils copy_file Permission denied on Windows

I'm making gem that copy files from /template directory (inside the gem) into the current directory of the console.
Here's what it looks like:
require "fileutils"
# Get the console's current directory
destination_dir = Dir.pwd
# Home directory of my gem, looks like C:/Ruby193/lib/ruby/gems/1.9.1/gems/my_gem-1.0.0
home_dir = File.expand_path( "..", File.dirname(__FILE__) )
# Template directory, looks like C:/Ruby193/lib/ruby/gems/1.9.1/gems/my_gem-1.0.0/template
template_dir = File.join( home_dir, "template" )
FileUtils.copy_file( template_dir, destination_dir )
And I got this error:
C:/Ruby193/lib/ruby/1.9.1/fileutils.rb:1370:in `initialize': Permission denied -
C:/Ruby193/lib/ruby/gems/1.9.1/gems/my_gem-1.0.0/template (Errno::
EACCES)
I have checked that the directory does exists by running Dir[template_dir].
Any solution? Thanks
UPDATE to answer comments below
#Babai
I added this line before copy_file, but still doesn't work. Am I doing it right?
FileUtils.chmod(0777, template_dir)
#mudasobwa
Here's the result of the code
# puts "#{template_dir} \n #{destination_dir}"
C:/Ruby193/lib/ruby/gems/1.9.1/gems/my_gem-1.0.0/template
C:/Users/myname/Documents/Test
My bad. My template directory contains another folders. So I need to use cp_r instead of copy_file
FileUtils.cp_r( template_dir, destination_dir )

Ruby: How to find path relative to where class was instantiated?

I am creating a gem that is a Rack application, so I assume my application is going to be instantiated in a config.ru file. I expect certain paths to be relative to this config.ru file. So how can I get and set the path when the app is initialized?
For example:
Hidden away in my gem:
class MyApp
def initialize
#base_path = get_the_base_path_here
end
def call(env)
html = render_view(#base_path + '/views/index.erb')
end
end
User of the gem's config.ru:
require 'my_app'
run MyApp.new
...and their views directory:
/views
index.erb
Update:
One way to achieve this is to pass in the base path as an argument, but I would like to find a way to achieve this without passing it as an argument.
require 'my_app'
run MyApp.new(File.dirname(__FILE__))
Absolute Path of Current File
In general, you can simply use File.expand_path(__FILE__) to find the absolute path of the current file, which you can then store a variable or global if you like. For example:
$file_path = File.expand_path(__FILE__)
Absolute Path of Current Program
File.expand_path($0) is similar, but returns the program that was called. The distinction is sometimes subtle, but can be useful from time to time.
Creating an Absolute Path to a File in the Same Base Directory
If you want to use the directory name of the location of the current file to address another file, you can use File#join. For example:
File.join File.dirname(File.expand_path(__FILE__)), '.X11-unix'
=> "/tmp/.X11-unix"
Probably not the best way but you can find config.ru with:
$:.find{|path| File.exists? "#{path}/config.ru"}

Can a Ruby script tell what directory it’s in?

Inspired by "Getting the source directory of a Bash script from within", what's the Ruby way to do this?
For newer versions of Ruby, try:
__dir__
For older versions of Ruby (< 2.0), the script being run can be found using:
File.dirname(__FILE__) - relative path; or
File.expand_path(File.dirname(__FILE__)) - the absolute path.
Note: Using __dir__ will return the script path even after a call to Dir.chdir; whereas, using the older syntax may not return the path to the script.
Use __dir__
As of Ruby 2.0, __dir__ is the simplest way to get this. It
Returns the canonicalized absolute path of the directory of the file
from which this method is called.
See the __dir__ documentation, and "Why is __FILE__ uppercase and __dir__ lowercase?".
use __dir__
File.dirname(__FILE__) is not a proper way to get directory where script is stored.
At start working directory and directory with script file is the same, but it may change.
For example:
Dir.chdir('..') do
puts __dir__
puts File.expand_path(File.dirname(__FILE__))
end
for script file stored in /Desktop/tmp running it will give output
/home/mateusz/Desktop/tmp
/home/mateusz/Desktop
ENV["PWD"] seems the simplest way for me under Linux. I don't know of an OS-agnostic way.

Resources