Rake vs. Thor for automation scripts? - ruby

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?

Related

A variation on internally distributing a rails app

I have written a ruby service that I want to package and distribute internally to a specific environment (a standardized linux host). After digging around a bit for the best ways to create a distribution, I've come across a lot of blogs and answers here that recommend bundler and gem packaging as well as a lot of binary distribution options (e.g. traveling-ruby), but these all seem like a bit too much for a relatively simple service that will get deployed to a known environment. I want to create a distribution that doesn't require dependencies to be resolved at deploy time (e.g. bundle install --deployment is not the approach I want).
So with this in mind, is there an available framework that is commonly in use by ruby apps that would create a redistributable package with all dependencies included in it? I am currently doing this in 2 steps and wondering if there's a "better" ruby-way of doing it - something along the lines of gem build ... that creates dependency-inclusive archive?
# Assuming `bundle install` was run on developer workstation and there's a `Gemfile.lock`
$ bundle install --deployment
$ tar zcf ../my-app.tar.gz ./
my-app.tar.gz can now be distributed and if I have an executable to run it with, I can do so with bundle exec bin/run from within the directory after it's extracted. This a good approach?
I've seen a gem called crate that might be able to work....

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

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.

How can I package Ruby code in an NPM package?

I'm writing a node module to be open sourced and there's a dependency on some Ruby code (see Can I include a Ruby Gem in a Node.js project? for details). I made a Ruby project that requires some gems and all of that works well. In my node_module, I want to interface it via exec to the Ruby code.
But now there's Ruby dependencies as well. So can I somehow specify the Ruby version, and the gemset required to run my node package?
Ambiguous question perhaps. I can clarify if anything is unclear.
I don't think you can/should specify the Ruby version to use when executing your code. That should be up the library consumer so choose. Since you want to execute your code with exec, the library consumer will have the added responsbility of making ruby accessible to the node process. How that happens is not up to you as the library developer.
As for dependencies/gemsets, just use bundler.
Maybe you could do something like this - without more information it's hard to say.
On the ruby side, build your gem to do whatever it needs to do and then add a rake task to it. How you build this rake task is obviously up to the demands of the project and how it will be used, but it will provide a way for you to interface from the outside.
In the 'middle' build a bash script that includes RVM - this way you can require a specific gemset/do specifc things before running the rake task. Another benefit is that if you want to change the gemset or other implementation details, you just change the bash script.
On the node side, call the bash script. More info on that in this answer.

Using thor for complex command line tool

i want to create a command line tool in Ruby using Thor. This tool should be packaged as a gem so that it is easily installed and uninstalled.
Creating and publishing the gem, I have done. I also created several Thor scripts which also work. However, I do not know how to combine them.
My aim is to be able to call my tool the following way:
mytool task param --options
mytool taskgroup:task param --options
I know how to make one Thor script to be executable. However, how do I make a bunch of thor scripts accessible throw one command?
According to the relevant Gem documentation, you could specify (in your .gemspec):
spec.executables = ['bin/foo', 'bin/bar']
spec.default_executable = 'bin/bar'
and have your gem install a bunch of executables (foo and bar). Or you write a wrapper for all your Thor scripts and specify:
spec.executables = ['bin/wrapper']
and have your gem install only one executable (wrapper).
The teletype gem (https://github.com/piotrmurach/tty) does an amazing job at setting up all the scaffolding for this. Create your project with teletype and then just fill in the implementation.

Ruby gems in lib - spare tire principle

I'm working on a console ruby application (not rails!) I will be installing this application on several machines. I was wondering if there is a way i can build it so i dont have to install the gems i'm using for the app on each machine. I'd like to be able to just copy the directory to each machine and run it. Ideally, i'd like to put the gems in the lib folder or something and reference them from there, so i don't have to even install them on my dev machine. Is there a way to do this?
In .net, we call this the "spare tire" principle.
thanks,
Craig
How about using bundler?
Then you can include a Gemfile that specifies all the necssary gems and just run "bundle install" on each machine to pull them down.
If you really want to bundle them with the app run "bundle package" and the gems will be stored in vendor/cache.
You could take the same approach as rails allows and "vendor" your gems. This involves creating a new directory (rails uses vendor/gems) and unpack the gem into this directory, using gem unpack.
You then configure your load path to include all of the sub-folders below that.
Edit
You can configure your load path by doing something like this
Dir.glob(File.join("vendor", "gems", "*", "lib")).each do |lib|
$LOAD_PATH.unshift(File.expand_path(lib))
end

Resources