How can I "require" code from another .rb file like in PHP? - ruby

Coming to Ruby from a PHP background, I'm used to being able to use require, require_once, include, or include_once which all have a similar effect, but the key being they continue to process code in the same scope where the include / require command was invoked.
Example:
sub.php
<?php
echo $foo;
main.php
<?php
$foo = 1234;
include('sub.php'); // outputs '1234'
When I first started using Ruby I tried to include / require / require_relative / load other .rb files, and after becoming a little frustrated with not having it work how I would expect it to I decided that there were better ways to go about breaking up large files and that Ruby didn't need to behave in the same way PHP did.
However, occasionally I feel that for testing purposes it would be nice to to load code from another .rb file in the way PHP does - in the same scope with access to all the same variables - without having to use class / instance variables or constants. Is this possible? Maybe somehow using a proc / binding / or eval command?
Again, I'm not advocating that this should be used during development - but I am curious if it is possible - and if so, how?

Yes, this is possible, although certainly not something I'd recommend doing. This works:
includer.rb:
puts var
include.rb:
var = "Hello!"
eval(File.read("include.rb"), binding)
Running this (Ruby 2.2.1, Ruby 1.9.3) will print Hello!. It works simply: eval takes an optional binding with which to evaluate the code it is passed, and Kernel#binding returns the current binding.

To have code run in same binding, you could simply eval the file contents as follows:
example.rb
class Example
def self.called_by_include
"value for bar"
end
def foo
puts "Called foo"
end
eval( File.read( 'included.rb' ) )
end
Example.new.bar
included.rb
BAR_CONSTANT = called_by_include
def bar
puts BAR_CONSTANT
end
Running ruby example.rb produces output
value for bar
The important thing is the eval( File.read( 'included.rb' ) ) code, which if you really wanted you could define as a class method on Object, to allow arbitrary source to be included with a convenience function*. The use of constants, class variables etc just shows influences working in both directions between the two pieces of source code.
It would be bad practice to use this in any production code. Ruby gives you much better tools for meta-programming, such as ability to use mix-ins, re-open classes, define methods from blocks etc.
* Something like this
class Object
def self.include_source filename
eval( File.read( filename ) )
end
end
And the line in example.rb would become just
include_source 'included.rb'
Again I have to repeat this is not such a great idea . . .

To import external .rb file in your code, I'm not sure but I think it have to be a gem.
Use require followed by the name of the gem you want to import.
Example
require 'foobar'
# do some stuff
Or you can use load to import entire rb file
load 'foobar.rb'
# do some stuff
Good luck and sorry for my english

Related

Is it possible to explicitly include sub-modules or classes in Ruby?

I want to be able to statically analyze my code. That is, to know from the plain text of the file where every function and variable comes from. IDEs and text editor plugins work better when they can trace the origin of every symbol as well.
So for example, if I have application code like this:
#...
Y.some_method()
#...
Then I want to see Y in an include/import/require/extend/def statement somewhere on the page.
In other languages I use, one can explicitly choose which sub-parts of a namespace to bring in to the current context.
Python:
from X import Y
Haskell:
import X (Y)
Elixir:
alias X.Y, as: Y
And while it's possible to import all contained names in Python, the "wildcard import" is frowned upon:
from X import *
". . . they make it unclear which names are present in the namespace, confusing both readers and many automated tools."
In Ruby, it seems that this fully implicit "wildcard" way is the only way to bring in a contained name:
include X
This makes Y available, but is there some way to make this explicit? The docs for Ruby include don't show any options.
What I'd really like to do in Ruby is something like one of these:
from X include Y
include X::Y as Y
The best I've come up with so far is:
require 'x/y' ; Y = X::Y
Here's a crazy hack in the answer to another question which would enable this.
Try this. But I agree with #tadman that you should consider doing it in the Ruby way.
Object.define_singleton_method(:include) do |*mths, from: nil|
mod = from || mths.first
mod = mod.dup
if from
all_mths = mod.instance_methods
(all_mths - mths).each { |mth| mod.send :undef_method, mth }
end
super(mod)
end
module Foobar
def foo
puts :foo
end
def bar
puts :bar
end
end
class Abc
include Foobar
end
Abc.new.foo # => 'foo'
Abc.new.bar # => 'foo'
class AbcWithoutBar
include :foo, from: Foobar
end
AbcWithoutBar.new.foo # => 'foo'
AbcWithoutBar.new.bar # => NoMethodError
Ruby always executes the code that you require
And since there is no partial execution of a file there cannot be partial require.
When you require a feature Ruby locates the corresponding file using the load paths in $: and then double checks against the list of loaded files in $" and if the file has not yet been loaded executes the file.
Ruby is a dynamic language, the best way to reason about its source code is halting a running program rather than statically. In fact even class and def are not declarations but just method calls that are executed at runtime. Consider for example this contrived example
class Surprise < [Array, Hash, Fixnum, Object].sample
end
If you want to know where a method or class has been defined best use pry. You can require pry and then use binding.pry to stop anywhere in your source code and spelunk around to inspect objects and source code. Two of the most useful commands are ls and $
ls prints all methods of an object or class
$ prints the file location and source code of a method

Is there a way to force a required file to be reloaded in Ruby?

Yes, I know I can just use load instead of require. But that is not a good solution for my use case:
When the app boots, it requires a config file. Each environment has its own config. The config sets constants.
When the app boots, only one environment is required. However, during testing, it loads config files multiple times to make sure there are no syntax errors.
In the testing environment, the same config file may be loaded more than once. But I don't want to change the require to load because every time the a spec runs, it reloads the config. This should be done via require, because if the config has already been loaded, it raises already initialized constant warnings.
The cleanest solution I can see is to manually reset the require flag for the config file after any config spec.
Is there a way to do that in Ruby?
Edit: adding code.
When the app boots it calls the init file:
init.rb:
require "./config/environments/#{ ENV[ 'RACK_ENV' ]}.rb"
config/environments/test.rb:
APP_SETTING = :foo
config/environments/production.rb:
APP_SETTING = :bar
spec/models/config.rb: # It's not a model spec...
describe 'Config' do
specify do
load './config/environments/test.rb'
end
specify do
load './config/environments/production.rb'
end
Yes it can be done. You must know the path to the files that you want to reload. There is a special variable $LOADED_FEATURES which stores what has been loaded, and is used by require to decide whether to load a file when it is requested again.
Here I am assuming that the files you want to re-require all have the unique path /myapp/config/ in their name. But hopefully you can see that this would work for any rule about the path name you can code.
$LOADED_FEATURES.reject! { |path| path =~ /\/myapp\/config\// }
And that's it . . .
Some caveats:
require does not store or follow any kind of dependency tree, to know what it "should" have loaded. So you need to ensure the full chain of requires starting with the require command you run in the spec to re-load the config, and including everything you need to be loaded, is covered by the removed paths.
This will not unload class definitions or constants, but simply re-load the files. In fact that is literally what require does, it just calls load internally. So all the warning messages about re-defining constants will also need to be handled by un-defining the constants you expect to see defined in the files.
There is probably a design of your config and specs that avoids the need to do this.
if you really want to do this, here's one approach that doesn't leak into your test process. Fork a process for every config file you want to test, communicate the status back to the test process via IO.pipe and fail/succeed the test based on the result.
You can go as crazy as you want with the stuff you send down the pipe...
Here's some quick and dirty example to show you what I mean.
a config
# foo.rb
FOO = "from foo"
another config
# bar.rb
FOO = "from bar"
some faulty config
# witherror.rb
asdf
and your "test"
# yourtest.rb
def load_config(writer, config_file)
fork do
begin
require_relative config_file
writer.write "success: #{FOO}\n"
rescue
writer.write "fail: #{$!.message}\n"
end
writer.close
exit # maybe this is even enough to NOT make it run your other tests...
end
end
rd, writer = IO.pipe
load_config(writer, "foo.rb")
load_config(writer, "bar.rb")
load_config(writer, "witherror.rb")
writer.close
puts rd.read
puts rd.read
puts rd.read
puts FOO
The output is:
success: from foo
success: from bar
fail: undefined local variable or method `asdf' for main:Object
yourtest.rb:24:in `<main>': uninitialized constant FOO (NameError)
as you can see, the FOO constant doesn't leak into your test process etc.
Of course you're only through half way because there's more to it like, making sure only one process runs the test etc.
Frankly, I don't think this is a good idea, no matter what approach you chose because you'll open a can of worms and imho there's no really clean way to do this.

Stub require statement in rspec?

I have to maintain a Ruby script, which requires some libs I don't have locally and which won't work in my environment. Nevertheless I want to spec some methods in this script so that I can change them easily.
Is there an option to stub some of the require statements in the script I want to test so that it can be loaded by rspec and the spec can be executed within my environment?
Example (old_script.rb):
require "incompatible_lib"
class Script
def some_other_stuff
...
end
def add(a,b)
a+b
end
end
How can I write a test to check the add function without splitting the "old_Script.rb" file and without providing the incompatible_lib I don't have?
Instead of stubbing require which is "inherited" from Kernel, you could do this:
Create a dummy incompatible_lib.rb file somewhere that is not in your $LOAD_PATH. I.e., if this is a Ruby application (not Rails), don't put it in lib/ nor spec/.
You can do this a number of ways, but I'll tell you one method: in your spec file which tests Script, modify $LOAD_PATH to include the parent directory of your dummy incompatible_lib.rb.
Ordering is very important -- next you will include script.rb (the file which defines Script).
This will get you around the issue and allow you test test the add method.
Once you've successfully tested Script, I would highly recommend refactoring it so that you don't have to do this technique, which is a hack, IMHO.
Thanks, I also thought about the option of adding the files, but finally hacked the require itself within the test case:
module Kernel
alias :old_require :require
def require(path)
old_require(path) unless LIBS_TO_SKIP.include?(path)
end
end
I know that this is an ugly hack but as this is legacy code executed on a modified ruby compiler I can't easily get these libs running and it's sufficient to let me test my modifications...

Is there a "main" method in Ruby like in C?

I'm new to Ruby, so apologies if this sounds really silly.
I can't seem to figure out how to write a "main" code and have methods in the same file (similar to C). I end up with a "main" file which loads a seperate file that has all the methods. I appreciate any guidance on this.
I spotted the following SO post but I don't understand it:
Should I define a main method in my ruby scripts?
While it's not a big deal, it's just easier being able to see all the relevant code in the same file. Thank you.
[-EDIT-]
Thanks to everyone who responded - turns out you just need to define all the methods above the code. An example is below:
def callTest1
puts "in test 1"
end
def callTest2
puts "in test 2"
end
callTest1
callTest2
I think this makes sense as Ruby needs to know all methods beforehand. This is unlike C where there is a header file which clearly list the available functions and therefore, can define them beneath the main() function
Again, thanks to everyone who responded.
#Hauleth's answer is correct: there is no main method or structure in Ruby. I just want to provide a slightly different view here along with some explanation.
When you execute ruby somefile.rb, Ruby executes all of the code in somefile.rb. So if you have a very small project and want it to be self-contained in a single file, there's absolutely nothing wrong with doing something like this:
# somefile.rb
class MyClass
def say_hello
puts "Hello World"
end
end
def another_hello
puts "Hello World (from a method)"
end
c = MyClass.new
c.say_hello
another_hello
It's not that the first two blocks aren't executed, it's just that you don't see the effects until you actually use the corresponding class/method.
The if __FILE__ == $0 bit is just a way to block off code that you only want to run if this file is being run directly from the command line. __FILE__
is the name of the current file, $0 is the command that was executed by the shell (though it's smart enough to drop the ruby), so comparing the two tells you precisely that: is this the file that was executed from the command line? This is sometimes done by coders who want to define a class/module in a file and also provide a command-line utility that uses it. IMHO that's not very good project structure, but just like anything there are use cases where doing it makes perfect sense.
If you want to be able to execute your code directly, you can add a shebang line
#!/usr/bin/env ruby
# rest of somefile.rb
and make it executable with chmod +x somefile.rb (optionally rename it without the .rb extension). This doesn't really change your situation. The if __FILE__ == $0 still works and still probably isn't necessary.
Edit
As #steenslag correctly points out, the top-level scope in Ruby is an Object called main. It has slightly funky behavior, though:
irb
>> self
=> main
>> self.class
=> Object
>> main
NameError: undefined local variable or method `main' for main:Object
from (irb):8
Don't worry about this until you start to dig much deeper into the language. If you do want to learn lots more about this kind of stuff, Metaprogramming Ruby is a great read :)
No there isn't such structure. Of course you can define main function but it won't be called until you do so. Ruby execute line by line so if you want to print 'Hello World' you simply write:
puts 'Hello World'
The question that you mentioned is about using one file as module and executable, so if you write
if __FILE__ == $0
# your code
end
It will be called only if you run this file. If you only require it in other file then this code will never run. But IMHO it's bad idea, better option is using RubyGems and there add executables.
Actually there is a main, but it is not a method; it's the top-level object that is the initial execution context of a Ruby program.
class Foo
p self
end
#=> Foo
p self
#=> main
def foo
p self
end
foo
#=> main
There is no magic main function in Ruby. See http://en.wikipedia.org/wiki/Main_function#Ruby
If you wish to run Ruby scripts like C compiled files, do the following:
#!/usr/bin/env ruby
puts "Hello"
and then chmod a+x file_name.rb. Everything that is below the first line will be run, as if it was contents of main in C. Of course class and function definitions won't give you any results until they are instantiated/invoked (although the code inside class definitions is actually evaluated, so you could get some output but this is not expected in normal circumstances).
Another way to write main() method is:
class HelloWorld
def initialize(name)
#name = name
end
def sayHello()
print "Hello ##name!"
end
end
def main()
helloWorld = HelloWorld.new("Alice")
helloWorld.sayHello
end
main

Is there a shorter way to require a file in the same directory in ruby?

Is there a shorter way to require a file located in the same directory (as the script being executed)?
require File.expand_path(File.dirname(__FILE__) + '/some_other_script')
I read that require "my_script" and require "./my_script" will actually load the script twice (ruby will not recognize that it is actually the same script), and this is the reason why File.expand_path is recommended: if it is used every time the script is required, then it will only be loaded once.
It seems weird to me that a concise language like Ruby does not seem to have a shorter solution. For example, python simply has this:
import .some_other_module_in_the_same_directory
I guess I could monkey-patch require... but that's just evil! ;-)
Since ruby 1.9 you can use require_relative.
Check the latest doc for require_relative or another version of the Core API.
Just require filename.
Yes, it will import it twice if you specify it as filename and ./filename, so don't do that. You're not specifying the .rb, so don't specify the path. I usually put the bulk of my application logic into a file in lib, and then have a script in bin that looks something like this:
#!/usr/bin/env ruby
$: << File.join(File.dirname(__FILE__), "/../lib")
require 'app.rb'
App.new.run(ARGV)
Another advantage is that I find it easier to do unit testing if the loading the application logic doesn't automatically start executing it.
The above will work even when you're running the script from some other directory.
However, inside the same directory the shorter forms you refer to work as expected and at least for ruby 1.9 won't result in a double-require.
testa.rb
puts "start test A"
require 'testb'
require './testb'
puts "finish test A"
testb.rb
puts "start test B"
puts "finish test B"
running 'ruby testa.rb' will result in:
start test A
start test B
finish test B
finish test A
However, the longer form will work even from another directory (eg. ruby somedir/script.rb)
Put this in a standard library directory (somewhere that's already in your default loadpath $:):
# push-loadpath.rb
if caller.first
$: << File.expand_path(File.dirname(caller.first))
end
Then, this should work
% ls /path/to/
bin.rb lib1.rb lib2.rb #...
% cat /path/to/bin.rb
load 'push-loadpath.rb'
require 'lib1'
require 'lib2'
#...
caller gives you access to the current callstack, and tells you what file and where, so push-loadpath.rb uses that to add the file that load'd it to the loadpath.
Note that you should load the file, rather than require it, so the body can be invoked multiple times (once for each time you want to alter the loadpath).
Alternately, you could wrap the body in a method,
# push-loadpath.rb
def push_loadpath
$: << File.expand_path(File.dirname(caller.first))
end
This would allow you to require it, and use it this way:
% ls /path/to/
bin.rb lib1.rb lib2.rb #...
% cat /path/to/bin.rb
require 'push-loadpath'
push_loadpath
require 'lib1'
require 'lib2'
#...

Resources