passing arguaments to a system call in Rails, but not plain ruby program - ruby

Ubuntu 12.04
Sinatra 1.3.3
Why does passing an argument to a ruby system call (%x[] or ``) give me a 'not found' error in my sinatra app? The same code works fine in a normal ruby script running from the same directory.
I have a file test.rb like this
output = %x["ls"]
p output
When I run it with "ruby test.rb" I get the contents of the current directory in the console, as expected.
If I modify the program to give an argument to the system call like so:
output = %x["ls sub_dir/"]
p output
I get the contents of sub_dir, which sits in the current directory, as expected.
So far so good.
Now if I make a Sintra app with a post method:
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
post "/" do
output = x["ls"]
return output
end
The response to a Post call to "/" returns the contents of the current directory, which includes 'sub_dir', as expected.
If I try to add the argument to the system call to the sinatra app like so:
require 'rubygems'
require 'bundler/setup'
require 'sinatra'
post "/" do
output = x["ls sub_dir/"]
return output
end
the response is nil and there is an error in the console:
sh: 1: ls sub_dir/: not found
Why does adding a parameter to a system call in my sinatra app cause it to crash, when the same code called from a plain ruby script, run from the same location works perfectly.
By the way, the 'ls' example shown here is not the command I really need to run, so please don't explain a different way to get this information. I have an executable file that takes a file name as a parameter that I need to run, which behaves exactly the same way.
Thanks in advance!

If you want to specify a path in relation to the application, you could use something like this:
post "/" do
path = File.join(File.dirname(__FILE__), "sub_dir")
%x[ls #{path}]
end
However, if you want to list the contents of a directory, why not do it in Ruby?

I rewrote the sinatra app in another file in the same directory.
Everything works as expected.
I did not find the reason and I deleted the original file so that I won't lose anymore time trying to figure it out.

Related

How do some files not execute when required in irb?

If I have file.rb:
puts "Hello, World"
then in irb type:
require "./file.rb"
the output will be Hello, World.
Why then, if I have a sinatra file, e.g.
require "sinatra"
get "/" do
return "Hi"
end
and require that, there is no output?
Clarification
What executing the sinatra file via ruby sinatra_app.rb it will start a rack server, and not stop until CTRL+C is pressed. Why does it not do that when required in irb, but it does do that when it is explicitly run with ruby sinatra_app.rb?
Because the script doesn't output anything. There is nothing in the script you showed that would generate any sort of output, there are no calls to print, puts, or p, no writes to any file, nothing.
The first script prints something when required, because it prints something, the second prints nothing when required because, well, it prints nothing. Remove the call to puts from the first script and it won't print anything either. Add a call to puts to the second script and it will print something.
Workaround is require sinatra before requiring file.
Root file:
require "sinatra"
require "/tmp/ddd.rb"
Required file:
get "/" do
return "Hi"
end
I guess it's somehow related to Sinatra startup process. They put get method in default namespace, without namespacing it to separate module.

Error reading local file in Sinatra

I'm trying to write a Sinatra app that reads in a list from a file, and then spits back a random item from that list.
I'm having trouble figuring out the path to the file to read it, though. Sinatra says 'no such file or directory' when I try to load an item in my browser:
Errno::ENOENT at /wod
No such file or directory - http://localhost:4567/listing.txt
Here is the code:
require 'sinatra'
#list
get /item
puts read_list[rand(#list.size)]
end
def read_list
File.open('listing.txt', 'r').readlines
end
I have the file in /public, which the Sinatra README says is the default location for hosting static files. Furthermore, if I put it in /public I can navigate to localhost:4567/listing.txt and read the file in the browser.
A couple things I noticed:
get /item
isn't correct, it should be:
get '/item' do
If you start your code inside the same directory the Ruby code is in, the current working-directory will be ".", which is where Ruby will look when trying to:
File.open('listing.txt', 'r').readlines
Ruby will actually use './listing.txt' as the path. That's OK if you manually launch the code from the root directory of the application, but that doesn't work well if you try to launch it from anywhere else.
It's better to be explicit about the location of the file when you're actually trying to load something for use with a web server. Instead of relying on chance, there are a couple things you can do to help make it more bullet-proof. Consider this:
def read_list
running_dir = File.dirname(__FILE__)
running_dir = Dir.pwd if (running_dir == '.')
File.open(running_dir + '/public/listing.txt', 'r').readlines
end
File.dirname gets the path information from __FILE__, which is the absolute path and name of the current file running. If the application was started from the same directory as the file, that will be ., which isn't what we want. In that case, we want the absolute path of the current working-directory, which Dir.pwd returns. Then we can append that to the path of the file you want, from the root of the application.
You'll need to do File.read('public/listing.txt', 'r') to get what you want here.
File.open isn't part of Sinatra and doesn't know to look in a specific place for static files, so it just looks in the current working directory.

Require a ruby file in a ruby file

I want to require a file called config.rb in a different ruby file called basics.rb. I'm using Sinatra as my web framework. I'm sure there's a way to do this, I just can't find anything in the docs.
Hopefully it would look something like
post '/' do
require 'config.rb'
// logic
end
If config.rb is in your load path, you can require it at the top of your basics.rb file with require 'config'. If it is not in your load path, you'll need something like require '/path/to/your/config'.
The code you've posted will require the file. But only when someone POSTs to '/'.
Also, it's normal to omit the .rb extension when requiring ruby files. But you can include it if you like.
You can view your load path by inspecting the global variable $LOAD_PATH. From the command line ruby -e 'puts $LOAD_PATH' will print it for your version of ruby. You can also add directories to your load path.

Ruby 'require' error: cannot load such file

I've one file, main.rb with the following content:
require "tokenizer.rb"
The tokenizer.rb file is in the same directory and its content is:
class Tokenizer
def self.tokenize(string)
return string.split(" ")
end
end
If i try to run main.rb I get the following error:
C:\Documents and Settings\my\src\folder>ruby main.rb
C:/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- tokenizer.rb (LoadError)
from C:/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require '
from main.rb:1:in `<main>'
I just noticed that if I use load instead of require everything works fine. What may the problem be here?
I just tried and it works with require "./tokenizer".
Just do this:
require_relative 'tokenizer'
If you put this in a Ruby file that is in the same directory as tokenizer.rb, it will work fine no matter what your current working directory (CWD) is.
Explanation of why this is the best way
The other answers claim you should use require './tokenizer', but that is the wrong answer, because it will only work if you run your Ruby process in the same directory that tokenizer.rb is in. Pretty much the only reason to consider using require like that would be if you need to support Ruby 1.8, which doesn't have require_relative.
The require './tokenizer' answer might work for you today, but it unnecessarily limits the ways in which you can run your Ruby code. Tomorrow, if you want to move your files to a different directory, or just want to start your Ruby process from a different directory, you'll have to rethink all of those require statements.
Using require to access files that are on the load path is a fine thing and Ruby gems do it all the time. But you shouldn't start the argument to require with a . unless you are doing something very special and know what you are doing.
When you write code that makes assumptions about its environment, you should think carefully about what assumptions to make. In this case, there are up to three different ways to require the tokenizer file, and each makes a different assumption:
require_relative 'path/to/tokenizer': Assumes that the relative path between the two Ruby source files will stay the same.
require 'path/to/tokenizer': Assumes that path/to/tokenizer is inside one of the directories on the load path ($LOAD_PATH). This generally requires extra setup, since you have to add something to the load path.
require './path/to/tokenizer': Assumes that the relative path from the Ruby process's current working directory to tokenizer.rb is going to stay the same.
I think that for most people and most situations, the assumptions made in options #1 and #2 are more likely to hold true over time.
Ruby 1.9 has removed the current directory from the load path, and so you will need to do a relative require on this file, as David Grayson says:
require_relative 'tokenizer'
There's no need to suffix it with .rb, as Ruby's smart enough to know that's what you mean anyway.
require loads a file from the $LOAD_PATH. If you want to require a file relative to the currently executing file instead of from the $LOAD_PATH, use require_relative.
I would recommend,
load './tokenizer.rb'
Given, that you know the file is in the same working directory.
If you're trying to require it relative to the file, you can use
require_relative 'tokenizer'
I hope this helps.
Another nice little method is to include the current directory in your load path with
$:.unshift('.')
You could push it onto the $: ($LOAD_PATH) array but unshift will force it to load your current working directory before the rest of the load path.
Once you've added your current directory in your load path you don't need to keep specifying
require './tokenizer'
and can just go back to using
require 'tokenizer'
This will work nicely if it is in a gem lib directory and this is the tokenizer.rb
require_relative 'tokenizer/main'
For those who are absolutely sure their relative path is correct, my problem was that my files did not have the .rb extension! (Even though I used RubyMine to create the files and selected that they were Ruby files on creation.)
Double check the file extensions on your file!
What about including the current directory in the search path?
ruby -I. main.rb
I used jruby-1.7.4 to compile my ruby code.
require 'roman-numerals.rb'
is the code which threw the below error.
LoadError: no such file to load -- roman-numerals
require at org/jruby/RubyKernel.java:1054
require at /Users/amanoharan/.rvm/rubies/jruby-1.7.4/lib/ruby/shared/rubygems/custom_require.rb:36
(root) at /Users/amanoharan/Documents/Aptana Studio 3 Workspace/RubyApplication/RubyApplication1/Ruby2.rb:2
I removed rb from require and gave
require 'roman-numerals'
It worked fine.
The problem is that require does not load from the current directory. This is what I thought, too but then I found this thread. For example I tried the following code:
irb> f = File.new('blabla.rb')
=> #<File:blabla.rb>
irb> f.read
=> "class Tokenizer\n def self.tokenize(string)\n return string.split(
\" \")\n end\nend\n"
irb> require f
LoadError: cannot load such file -- blabla.rb
from D:/dev/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `req
uire'
from D:/dev/Ruby193/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `req
uire'
from (irb):24
from D:/dev/Ruby193/bin/irb:12:in `<main>'
As it can be seen it read the file ok, but I could not require it (the path was not recognized). and here goes code that works:
irb f = File.new('D://blabla.rb')
=> #<File:D://blabla.rb>
irb f.read
=> "class Tokenizer\n def self.tokenize(string)\n return string.split(
\" \")\n end\nend\n"
irb> require f
=> true
As you can see if you specify the full path the file loads correctly.
First :
$ sudo gem install colored2
And,you should input your password
Then :
$ sudo gem update --system
Appear
Updating rubygems-update
ERROR: While executing gem ... (OpenSSL::SSL::SSLError)
hostname "gems.ruby-china.org" does not match the server certificate
Then:
$ rvm -v
$ rvm get head
Last
What language do you want to use?? [ Swift / ObjC ]
ObjC
Would you like to include a demo application with your library? [ Yes / No ]
Yes
Which testing frameworks will you use? [ Specta / Kiwi / None ]
None
Would you like to do view based testing? [ Yes / No ]
No
What is your class prefix?
XMG
Running pod install on your new library.
you need to give the path.
Atleast you should give the path from the current directory. It will work for sure.
./filename

Rails irb default directory

I'm trying to include a source code file when I run irb but irb is unable to find it.
For example, say I am in the following directory in terminal:
/dan/rubyapp/
Assume I have a file named "firstapp.rb" in /dan/rubyapp/
I startup irb and from the irb prompt I type
> require "firstapp.rb"
but the file can't be found. If I type "Dir.pwd" it shows as
/dan/rubyapp/
The only way I can get "require" to work is if I include the full path like so
> require "/dan/rubyapp/firstapp.rb"
Is that the only way I can get this to work? All the tutorials I see online simply do "require file_name" so I assumed it would work.
here is the output from $: at irb
ruby-1.9.2-p0 > $:
=> ["/Users/Daniel/.rvm/gems/ruby-1.9.2-p0/gems/wirble-0.1.3/bin",
"/Users/Daniel/.rvm/gems/ruby-1.9.2-p0/gems/wirble-0.1.3/lib",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/site_ruby/1.9.1",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/site_ruby/1.9.1/x86_64-darwin10.4.0",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/site_ruby",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/vendor_ruby/1.9.1",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/vendor_ruby/1.9.1/x86_64-darwin10.4.0",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/vendor_ruby",
"/Users/Daniel/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1",
"/Users/Daniel/.rvm/rubies/ruby-
1.9.2-p0/lib/ruby/1.9.1/x86_64-darwin10.4.0"]
The problem is that the current working directory is no longer in your path (as of Ruby 1.9.2). There are a few different ways around the problem.
1) In a ruby file itself, you can use the method require_relative instead of require. This will load a file relative to the loaction of the file containing the require_relative method:
http://extensions.rubyforge.org/rdoc/classes/Kernel.html
require_relative 'firstapp.rb'
This, however, will not work in irb.
2) Your other option is to include the current path in your argument to the require method. This will work in irb or in a ruby file. For instance:
require './firstapp.rb'
The reason this was implemented in ruby was to avoid inadvertently requiring the wrong file if there are different files with the same name in different directories in the path (similar to how *nix does not include the current directory "." in its path)
A couple of things to try:
1) Drop the .rb from the end of your require so you have:
require 'firstapp'
You don't normally add the .rb to a require (only to a load) - have a look here for more details:
http://www.fromjavatoruby.com/2008/10/require-vs-load.html
2) Failing that, make sure the current directory is on your load path - in irb execute:
p $:
and it will print out your ruby load path - check for an entry for "." (mine is the last entry)

Resources