how can I know which Ruby executable was used in ruby script? - ruby

there are two Ruby environments on a system, normal ruby and Chef embedded ruby. I want to know, in a ruby script, which ruby executable is used to invoke the script itself. How can get that?

Recommended Solutions
Use the poorly-documented RbConfig module, if available:
RbConfig.ruby
#=> "/Users/foo/.rubies/ruby-2.7.0/bin/ruby"
Alternatively, you can use the easier-to-find Gem module from the standard library to do the same thing:
Gem.ruby
#=> "/Users/foo/.rubies/ruby-2.7.0/bin/ruby"
Other Approaches
The RbConfig and Gem modules are your best bet, but there may be times when you need to get at the version or path information another way. Here are some different approaches.
Get the Version
You can return the version of the executing Ruby as a String with:
RUBY_VERSION
#=> "2.7.0"
Get the Path
Ruby is usually installed to bin/ruby in the RUBY_ROOT. You can return the expected path to the running Ruby binary (and verify it actually exists, if necessary) as follows:
ENV["RUBY_ROOT"] + "/bin/ruby"
#=> "/Users/foo/.rubies/ruby-2.7.0/bin/ruby"
File.exist? ENV["RUBY_ROOT"] + "/bin/ruby"
#=> true
Alternatively, you can use Kernel#` to find the first Ruby in your PATH as follows:
`which ruby`.chomp
=> "/Users/foo/.rubies/ruby-2.7.0/bin/ruby"
There are certainly edge cases where either approach can be misleading, though. For example, Ruby may have been built in a non-standard way, or you may have invoked Ruby with a fully-qualified path rather than calling the first binary in PATH. That makes "roll your own" lookups less reliable, but if your environment is missing the RbConfig or Gem modules for some reason, this might be a reasonable alternative for you.

Related

get specification of executed gem from within

I have build a gem and want it to print its version.
I cant use Gem::Specification.find_by_name('mygem').version
because there are several versions of it installed.
Lets just say my program has just a single src file /bin/myruby containing this:
#!/usr/bin/env ruby
mygem_version = ???
puts "This is my gems version: #{mygem_version}"
A common convention is to create a lib/<your_gem_name>/version.rb that defines a YourGemName::VERSION constant. Then, you can refer to that constant in your gemspec, which is Ruby code that gets evaluated when the gem is built.
Read http://timelessrepo.com/making-ruby-gems for a guide that uses this approach.
If you're using Bundler (think rails), try
Bundler.definition.specs
else, make sure your gem has a VERSION constant you can ask these things
This worked for me and always returned the correct version.
#!/usr/bin/env ruby
puts "This is my gems version: #{Gem.loaded_specs['mygem'].version}"

how do you start ruby 1.9 without rubygems

I want my app to not be able to use any installed gems. Is there a ruby 1.9 startup parameter or way of doing this programmatically?
ruby --disable-gems
is the MRI (1.9) commandline parameter. "It prevents the addition of gem installation directories to the default load path". (The Ruby Programming Language, p. 391)
Edit 25-10-2012: Ruby core had the same idea as #rogerdpack in the comments and added the more verbose ruby --help parameter. Ruby revision!
Looking at the rubygems configuration file, I would attempt to hack out gempath or gemhome to see if you can override (instead of just append to) defaults.
If, for example, setting gempath to be empty, or to point to /dev/null, prevents using system gems, then that would be the way to go.
The main advantage to this, as I see it, is that your anti-rubygems config file can be passed to ruby 1.9 as a startup parameter (so not coded in), well documented, and checked into your repository.
All of this is, of course, disregarding that rubygems is part of ruby 1.9's standard library - so ruby may choke and die if it can't have access to its gems, depending on how much of ruby's base install requires gem functionality. YMMV.

Can I determine which paths RubyGems added to the load path to make my command line app work?

In a gemspec, I can specify the require_paths, which represent paths I want to be able to require from at runtime. These get put into the $LOAD_PATH by RubyGems.
My question is: is there a way I can determine what these paths are at runtime? Can I examine elements of $LOAD_PATH and know which ones were added just for my gem?
Update: Ultimately, I would like to dynamically load ruby files from inside the gem, e.g.
load_from 'foo/bar'
And have that find $MY_GEMS_LIB_DIR/foo/bar/*.rb. I can certainly go through the entire $LOAD_PATH looking for foo/bar, but I'd rather restrict it just to the gem.
I don't know if I understood your needing (my english is bad :-/ ); anyway, if the problem is to determine the directories that will be loaded when you require a gem you can use Gem::Specification.lib_dirs_glob:
Gem::Specification.find_by_name('irbtools').lib_dirs_glob
#=> "/home/my_user/.rvm/gems/ruby-1.9.3-p125/gems/irbtools-1.2.2/lib"
Gem::Specification.find_by_name('xyz').lib_dirs_glob
# raises a Gem::LoadError
So a possible implementation of load_from could be:
def load_from(gem_name, path)
path_to_load = File.join(Gem::Specification.find_by_name(gem_name).lib_dirs_glob, path)
Dir.glob(path_to_load).each(&method(:load))
end
Trying to load Thor::CoreExt :
Thor::CoreExt #=> NameError: uninitialized constant Thor
load_from 'thor', 'thor/core_ext/*.rb'
Thor::CoreExt #=> Thor::CoreExt
This works on my machine with ruby 1.9.3 and gem 1.8.21 .
If I understand you correctly, this should do (Ruby 1.9.3):
before = $LOAD_PATH.dup
require 'the_gem'
added_paths = $LOAD_PATH - before
Of course, this will include the paths added by the dependencies.
You can use the $: global in irb. There is also the gem which command which gives you a library path, but I'm not sure if that includes exactly what you want.
Looks like Gem.find_files may help you.

Detecting ruby binary compilation layout in runtime

Quite often Ruby installed with RVM (the 'most popular tool to install Ruby') produces a binary not capable of SSL operations (like connecting via HTTPS). It's a known issue with a known workaround.
If you're trying to use SSL with such Ruby binary it results in exception LoadError: cannot load such file -- openssl.
Question: is there any way I can tell which libs Ruby binary was built against and thus detect if it is capable of SSL or not at runtime? Other than trying to actually use SSL and catching the exception?
Unless you want to do the same work that require does, I think the easiest is to try to require openssl and rescue the LoadError in case it's not present on the system to detect its availability.
It seems to be an idiom commonly used.
If you wanted something that detects afterwards if it was loaded or not would
ruby -ropenssl -e 'p defined? OpenSSL' # => "constant"
vs.
ruby -e 'p defined? OpenSSL' # => nil
help you?
That is, checking whether the return value of defined?(OpenSSL) is non-nil?
We commonly use this in tests to exclude tests at runtime where features that are not available to all versions of OpenSSL are used, and to exclude tests completely (if defined? OpenSSL) if OpenSSL is not present as an extension.

How to compile Ruby?

Is there a tool that can allow me to compile Ruby code so that it runs somewhat faster?
For example, I have heard that there is a tool for Python called "pyc" that allows us to compile the code, so that it runs 10 times faster.
The simple answer is that you can't, at least with MRI 1.8 (the standard). This is because 1.8 works by walking the Abstract Syntax Tree. Python, Ruby 1.9, JRuby, and Rubinius use byte code, which allows compilation to an Intermediate Representation (byte code). From MRI Ruby 2.3 it has become easy to do this, see this answer below.
With Rubinius, you can do something as described in this post: http://rubini.us/2011/03/17/running-ruby-with-no-ruby/
In JRuby you can use the "Ahead Of Time" compiler through, I believe, jrubyc.
This isn't really the standard way of doing things and you're generally better off just letting your Ruby implementation handle it like it wants to. Rubinius, at least, will cache byte code after the first compilation, updating it as it needs to.
From ruby 2.3.0 its so easy to compile your source code to bytecodes that the Ruby-VM understands.
byte_code = RubyVM::InstructionSequence.compile_file '/home/john/somefile.rb'
File.binwrite '/home/john/bytecode', byte_code.to_binary
and in Command Line
$ cat bytecode
YARB�
IUsx86_64-linux*.*1
+1�!AA*1
!qy��������yyQ� E/home/john/somefile.rbE<main>E <class:A>EshivaEhelloEAEputsEcore#define_methodu����� 5M
The content of the file
class A
def shiva
puts 'hello'
end
end
What is the purpose?
Well, ruby takes time to compile your source code into byte codes so you can load your bytecodes directly into ruby and execute. No overhead of grammar checking and compilation. It much faster than normal processes.
How to load byte code?
bytecode = File.binread('/home/john/bytecode')
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary bytecode
instruction_from_byte_code.eval
# => :shiva
Note: This answer is tested in MRI only. It might or might not work in other Ruby Implementations
In the beginning of 2013 there is not a way to translate Ruby into C/C++ source and then compile it.
However, I heard Matz (Yukihiro Matsumoto) say that a researcher is creating this tool in Japan. The project should be founded by the Japanese government.
Otherwise you could use JRuby and compile it in Java byte-code or you could use Rubinius. Rubinius compiles automatically in byte-code (JIT compiler) for the Rubinius VM. It is possible to convert Rubinius in byte-code into LLVM IR and LLVM can generate machine code.
I know this is an old question but I found a very interesting project that may provide an answer to your question: http://crystal-lang.org/
It basically compiles Ruby to native machine code. That's not exactly true because Crystal is not exactly Ruby and you might have to make some modifications to your code. There are also libraries that are not supported (yet) but to me it all looks very promising.
Check the Unholy git repo
The following "selfcontained" ruby test-case is based on the examples from this very thread, from the comment/answer of the user named illusionist.
#!/usr/bin/env ruby
#==========================================================================
# This file is in public domain.
# The code of this file is based on the code fragments at the
# 2018_12_09 version of the:
#
# https://stackoverflow.com/questions/5902334/how-to-compile-ruby
#
# This file has been tested with the ruby version
#
# ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]
#
#-----start--of--the--boilerplate------------------------------------------
s_fp_home=ENV["HOME"].to_s
s_fp_tmp=s_fp_home+"/tmp" # using /tmp can be a security risk
s_fp_demofolder=s_fp_tmp+"/ruby_bytecode_usage_demo_01"
def create_folder_if_needed(s_fp_in)
if !Dir.exists? s_fp_in
Dir.mkdir(s_fp_in)
if !Dir.exists? s_fp_in
raise(Exception.new("\n\n Folder creation failed.\n"+
"GUID=='d6e409cb-e072-4441-9421-22630190c2e7'\n"))
end # if
end # if
end # create_folder_if_needed
create_folder_if_needed(s_fp_tmp)
create_folder_if_needed(s_fp_demofolder)
s_rand=""
7.times{s_rand<<("_"+rand(100).to_s)}
s_fp_bytecode=s_fp_demofolder+"/awesome_bytecode"+s_rand
s_fp_src=s_fp_demofolder+"/x"+s_rand+".rb"
if File.exists? s_fp_src
raise(Exception.new("\n\n This file should not exist yet.\n"+
" s_fp_src=="+s_fp_src+"\n"+
"GUID=='43ab3d45-1324-47af-9441-22630190c2e7'\n"))
end # if
IO.write(s_fp_src,"puts('');puts('Greetings from bytecode!');puts('')")
if !File.exists? s_fp_src
raise(Exception.new("\n\n The file \n"+s_fp_src+"\n is missing.\n"+
"GUID=='4aeb5e54-efe0-4111-a851-22630190c2e7'\n"))
end # if
#-----start--of--the--core--of--the--demo----------------------------------
bytecode_out = RubyVM::InstructionSequence.compile_file(s_fp_src)
IO.binwrite(s_fp_bytecode, bytecode_out.to_binary)
bytecode_in = IO.binread(s_fp_bytecode)
instruction_from_byte_code = RubyVM::InstructionSequence.load_from_binary(bytecode_in)
instruction_from_byte_code.eval
#==========================================================================
Try ruby-packer which creates executables from Ruby and Ruby on Rails applications
I am assuming you're running CRuby.
You could experiment with the --jit flag when running Ruby to see if you gain any speed. Otherwise, I don't think you can compile Ruby scripts into native code yet. Only to bytecode via the RubyVM module but I don't think you'll gain anything from doing it.
Crystal-lang or GraalVM could be your alternative (with some possible changes) for higher performance.

Resources