How do I easily condense a whole ruby program into one file? - ruby

I really like writing command line applications in ruby. However, when working on lots of ruby projects I end up switching between different ruby versions with something like rvm, rbenv or chruby. This means I need to install ruby command line utilities for every version of ruby I work on. I've gotten used to this, but when distributing ruby command line apps to other devs they get confused when running whateverrubyapp that worked in one directory now doesn't work in another directory because the ruby version is different, or even worse they're using gemsets.
Is there an easy way to bundle up a ruby application with all it's dependencies including gems into a single file so that I can just have people put that file in their ~/bin dir so that it behaved somewhat as though it were a compiled application?
For example, I whipped up a little rake task to take a project with no gem dependencies and put it all into one file https://github.com/mmrobins/git-rank/blob/master/Rakefile. However, I have much more complex command line apps that have gem dependencies I would want to include into a single file for easy distribution.

Related

Packaging Compiled Binary /w a Ruby Gem

I am creating a small daemon, written in Ruby, which relies in part on a small binary utility compiled from C code. I want to package this as a gem and include this dependency along with it.
Essentially, this daemon will need to run commands such as ip addr add ... without requiring sudo, so I created a small C program to proxy those commands which must be compiled, chowned to root, and have the setuid bit set.
I would like to have the gem compile and install this dependency along with the daemon, but I am unsure how to do so. I understand extensions can be compiled via extconf.rb, but that is specifically meant for managing Ruby extensions, right? Would it be an ugly hack to have this compile and install a binary to /usr/local/bin or similar?
Does anyone know of an existing gem which does a similar thing which I can study as an example?
Here's a gem that packages the pdftk binary.
https://github.com/charliemaffitt/pdftk-heroku

Is there a way to use Gems in Vim's 'embedded' Ruby?

I'm trying to use the tinder gem from inside Vim. I'd like to be able to write to the Vim buffers, so I need to use Vim's embedded Ruby using :ruby as opposed to externally calling !ruby.
I have run gem install tinder with no problems on the command line, but embedded ruby doesn't seem to have the relevant directories on its load path to be able to require it.
I've tried manipulating the load path by trying things like:
:ruby `gem env gempath`.strip.split(':').each { |p| $:.unshift(p) }
... but with little success.
I've also tried a similar thing with:
Gem.path.unshift ...
... but, again, with little success.
I've tried unpacking Tinder and requiring an absolute path, which does seem to work, but unpack doesn't unpack the gem's dependencies, so it cannot find 'faraday', for example. Perhaps I could recursively unpack?
Does anyone have any thoughts on this issue?
I've googled around a lot and looked at the source of projects like Vmail, but as far as I can tell, no one is using Gems within Vim's Ruby. This seems an awful shame.
I'm pretty sure gem native extensions will never work, whatever I try- but I'd be very happy just being able to require pure Ruby gems.
Many thanks.
After hunting around for a long time, it's actually pretty simple.
The easiest way is to compile Vim against a version of Ruby that's 1.9 or greater. Vim will use whichever Ruby is first in your load path when you compile.
Then you just need to install gems through the conventional means for the version you compiled with.
The gems will be available in your load path by default in 1.9 and onwards because they made some changes to the way rubygems gets autoloaded.

What can I remove from Ruby and still have it support Rake/gems?

I'm building a large .NET project using Rake . We committed the Ruby environment to our source control and install gems to this "local" environment (like Albacore, Nokogiri, etc). We're essentially following this guidance, using the RubyInstaller for Windows zip package.
trunk/
source/
packages/
ruby/ <-- ruby here!
build.bat <-- helper scripts (call Ruby/rake)
Solution.sln
However, our source control server is remotely hosted, on a virtual machine, and the link speed is slow. I've read that some people have trimmed down the Ruby environment, like in the Machine.Specifications project. But, that looks extreme! (is there even gem support there?)
I could just start deleting files and directories to see what works, but there must be some known set of files that can be removed and still support basic Ruby, Rake, and gems?
From my own experimentation and investigation, it's kind of hard to determine what's "required" and what's optional. There are some files that appear very safe and easy to remove and others that I'd rather not play with. My results below only save about 5 MB... probably not enough to warrant doing this at all.
bin
The ruby/bin directory contains many batch scripts that are simply helpers to invoke the ruby executable with the correct "applicaton", like Rake or Gem. For example, rake.bat contains this line
#"%~dp0ruby.exe" "%~dpn0" %*
You can replace this with the right comamnd in your build.bat script (assuming it's "up" one level above the ruby environment, probably at the solution root)
#"%~dp0ruby\bin\ruby.exe" "%~dp0ruby\bin\rake" %*
You could dump the rest of the batch scripts, but then you'll have a little more trouble installing gems into the local environment.
cmd> ruby\bin\ruby.exe ruby\bin\gem install <whatever>
And, as of Ruby 1.9.3, that's only saving you 1.38KB. I'm sure some of those other non-extension files in this directory can be removed, but, without knowing what they do, it's unsafe to proceed.
include (175 KB)
The ruby/include directory appears to contain only C header files for developing against Ruby (I'm winging it here). I removed it and everything ran fine.
lib/tcltk (4.7 MB)
The ruby/lib/tcltk looks a lot like the include directory, but for Tcl programming.
lib/ruby
The ruby/lib/ruby directory contains the gems for this installation and a whole lot more scary stuff. I'd stay out of this directory unless you want to inadvertently cripple your environment.
share (27 KB)
The ruby/share directory appears to contain only help pages, dump 'em!

Are bundle exec and require 'bundler/setup' equivalent?

Do these things accomplish exactly the same?
starting a ruby process with bundle exec ruby foo.rb
having require "bundler/setup" as the first line of foo.rb
In your specific example they can be considered the same, however in reality they are not the same.
bundle exec makes some changes to the environment that bundler/setup does not make. If your foo.rb never runs a subshell, or never tries to run other ruby executables in subshells, then both versions are equivalent (they will both load bundled gems correctly and work exactly the same).
The whole idea with bundle exec is to enable you to run executables that were not originally designed with bundler in mind. Like rspec, rails, rackup. If your own app (foo.rb) does not try to run such executables that might be dependent on your bundles, then it makes no difference either way. Since all you want to make sure with bundler is that you load the correct gems, and for that bundler/setup works exactly as expected in your case.
From the bundler docs when talking about running ruby system executables:
In some cases, running executables without bundle exec may work, if the executable happens to be installed in your system and does not pull in any gems that conflict with your bundle.
However, this is unreliable and is the source of considerable pain. Even if it looks like it works, it may not work in the future or on another machine.
Then from the manpage of bundle exec you can get some additional clues as to what bundle exec actually does:
ENVIRONMENT MODIFICATIONS
make sure that it's still possible to shell out to bundle from inside a command invoked by bundle exec (using $BUNDLE_BIN_PATH)
put the directory containing executables (like rails, rspec, rackup) for your bundle on $PATH
make sure that if bundler is invoked in the subshell, it uses the same Gemfile (by setting BUNDLE_GEMFILE)
add -rbundler/setup to $RUBYOPT, which makes sure that Ruby programs invoked in the subshell can see the gems in the bundle
So if you build your app with bundler support in mind, then you never need to bundle exec your app.
But if you need to use other tools that load your app code that might load gems before they load your app code (which then might pull in a wrong non-bundled gem), then you need to use bundle exec.

Rake vs. Thor for automation scripts?

I want to automate things like:
Creating a new Ruby on Rails application with pre-selected database, Git initialize it, create a Heroku project, commit all files, etc.
Upload all files in folder to another computer through SSH, but do not overwrite files.
Upgrade Ubuntu, install all basic packages through apt-get.
From what I understand, tools for this are Rake and Thor, however, which one should I use?
Rake seems to me more de-facto and popular. I have heard people recommending Thor.
How do these stand to each other in a rundown?
Rake and Thor serve different purposes.
Rake is a general build script tool that is project-specific. In other words, you put your rakefile into your project folder and in your project's source control, and you can create, build and do other automation tasks that are specific to your project in that rakefile. Rake requires a rakefile to run.
Thor is a general purpose command line scripting tool that makes it very easy to re-use scripts across many projects and to do project setup, etc., like you are suggesting. Thor allows you to "install" an executable script that you can call from anywhere on your system, similar to calling "ruby", "gem" or "rake" command lines. However, Thor's scripts are more suited to general purpose, cross-application automation because the Thor script does not rely on a file sitting in your project-specific folder. A Thor script is the entire script, packed and installed for re-use anywhere.
Based on your stated needs, you are better off using Thor because you will be able to install your script in one location and have it work anywhere on your system. You will not be bound to where a Rake file is sitting or anything like that.
By the way, Rails 3 uses Thor for pretty much everything that is not project specific. You still have a Rake file and you still run things like "rake db:migrate" or "rake test:units". Thor is used for things like "rails new ...", "rails server" and "rails generate ..." The use of Thor AND Rake in Rails 3 is the perfect illustration of where each of these tools is best suited.
For setting up Ubuntu chores, Chef might be a better option.
From their web site:
Chef is an open source systems integration framework, built to bring the benefits of server configuration management to your entire infrastructure.
It's written in Ruby and there are tons of Chef recipes/cookbooks. Chef will handle setting up Ubuntu and installing packages, servers, etc.
I don't know if you are working with virtual machines, but Vagrant will set up a virtual machine and then use Chef to configure it.
There is something important to mention here.
http://guides.rubyonrails.org/generators.html in its section 8 Application Templates.
You can execute git commands, select gems, capify project.
And you could also execute system commands to satisfy your last point: Upgrade Ubuntu, install all basic packages through apt-get.
I would go with puppet.
By the way, maybe vagrant is useful to you?

Resources