I have a set of files that seem to be obfuscated or compiled by Ruby. If I do a file [sic] to one of the files:
a /usr/bin/env ruby script text executable
all of them start with this:
#!/usr/bin/env ruby
require 'iseq';RubyVM::InstructionSequence.load(Marshal.load(File.read(__FILE__,nil,113))).eval
What is this file? How can I see the code or debug it?
NOTE: Ruby version ruby 2.1.3p242 (2014-09-19 revision 47630) [x86_64-linux]
This is code compiled to a Ruby Virtual Machine. It is using the iseq gem which exposes the private method RubyVM::InstructionSequence::load.
You can't extract the original source code from it, but the debugger should work. You can read the compiled code in something like a human readable form with RubyVM::InstructionSequence#disassemble. Assuming Marshal.load returns a RubyVM::InstructionSequence object, this should do it.
require 'iseq';puts RubyVM::InstructionSequence.load(Marshal.load(File.read(__FILE__,nil,161))).disassemble
Related
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}"
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.
I've a small ruby program that require files in the same directory. Program works perfect on my mac and when I run a test ruby script without any require it also works so. It seems the ruby program doesn't look in the current directory for the file by default. e.g. the . dir. In windows where do I need to update this so ruby does look in the current dir for requires?
Chances are that your Mac is running Ruby 1.8 and Windows is running Ruby 1.9. As of 1.9, the default load path no longer includes the current directory. A common practice is to add this to the top of your ruby file before your require statements
$LOAD_PATH.unshift File.dirname(__FILE__)
require 'my_file.rb'
You can also use the shorthand $: instead of $LOAD_PATH:
$:.unshift File.dirname(__FILE__)
Another alternative is adding the load path on the command line instead:
ruby -I. my_ruby_file.rb
Ok, I understand now since 1.9.2 for "Security" reasons they don't allow require to work like that anymore. The neatest way I found to solve it strangely was to put './' in front of every require.
e.g.
require "./myfile.rb"
"." was removed from $: was removed from Ruby 1.9.2 to be precise. Do
puts RUBY_VERSION
puts $:.inspect
on Ruby 1.8 (what's installed on your Mac) and Ruby 1.9.2 (what's installed on your windows machine) if you don't believe me.
Why does Ruby 1.9.2 remove "." from LOAD_PATH, and what's the alternative? discusses why "." was removed.
I wrote a program in Ruby but I want to make an executable file from my program in order to run it in any computers( that they don't have ruby).How can I make executable file?
thanks
You could use RubyScript2Exe
http://www.erikveen.dds.nl/rubyscript2exe/
.. it collects all necessary files to run your application on an other machine: the Ruby application, the Ruby interpreter and the Ruby runtime library (stripped down for your application)
You should look at this list of options given your needs:
http://ruby-toolbox.com/categories/packaging_to_executables.html
They all have their strengths and drawbacks. NOTE: I have not used any of them.
Take a look on my rb2exe. It supports Rails and Gemfile.
gem install rb2exe
echo "puts 'Hello world'" > test.rb
rb2exe test.rb
./test
You can also check my detailed step-by-step how to, here:
http://www.learnwithdaniel.com/2016/08/ruby-to-portable-exe-app/
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.