Running external commands with Open3

There are various ways to run external commands from within Ruby, but the most powerful ones are Open3.capture3 and Open3.popen3. Since those can do almost everything you would possibly need in a clean way, I prefer to simply always use them.

Behind the scenes, Open3 actually just uses Ruby's spawn command, but gives you a much better API.

Open3.capture3

Basic usage is

require 'open3'

stdout_str, error_str, status = Open3.capture3('/some/binary', 'with', 'some', 'args')
if status.success?...

rbenv: A basic introduction

Why

We have projects that have been developed using many different versions of Ruby. Since we do not want to constantly update every old project, we need to have many Ruby versions installed on our development machines.

Rbenv does that for us.

How it works

Rbenv installs ruby version and ruby gems to ~/.rbenv/versions/VERSION_NUMBER/.... This way many different Rubies can be installed at once.

When you run ruby or gem or bundler or any other Ruby binary

  • rbenv looks for a file...

When upgrading/downgrading RubyGems and Bundler on a server, you must clear bundled gems

On application servers, gems are usually bundled into the project directory, at a location shared across deployments.

This is usually shared/bundle inside your project's root directory, e.g. /var/www/your-project/shared/bundle/.
If you can't find that, take a look at current/.bundle/config and look for BUNDLE_PATH.

When you are changing the version of RubyGems or Bundler on a system where gems are installed this way, you must wipe that bundle directory in addition to the user and system gems or gems that are already ins...

Ruby 1.8.7: Bundler crashes with "deadlock" and core dump

Error

deadlock 0x7f8a4160a360: sleep:- (main) - /home/me/.rbenv/versions/1.8.7-p375/lib/ruby/gems/1.8/gems/bundler-1.14.3/lib/bundler/worker.rb:43
deadlock 0x7f8a38c03b08: sleep:-  - /home/me/.rbenv/versions/1.8.7-p375/lib/ruby/gems/1.8/gems/bundler-1.14.3/lib/bundler/worker.rb:56
*** longjmp causes uninitialized stack frame ***: /home/me/.rbenv/versions/1.8.7-p375/bin/ruby terminated

... followed by a backtrace, memory map and more.

Fix

The culprit seems to be Bundler 1.14 when used with Ruby 1.8.7. [Downgrade to the maximu...

How to tackle complex refactorings in big projects

Sometimes huge refactorings or refactoring of core concepts of your application are necessary for being able to meet new requirements or to keep your application maintainable on the long run. Here are some thoughts about how to approach such challenges.

Break it down

Try to break your refactoring down in different parts. Try to make tests green for each part of your refactoring as soon as possible and only move to the next big part if your tests are fixed. It's not a good idea to work for weeks or months and wait for all puzzle pieces ...

Enabling ** in your bash

You may know the double asterisk operator from Ruby snippets like Dir['spec/**/*_spec.rb'] where it expands to an arbitrary number of directories.
However, it is disabled by default on most systems. Here is how to enable it.

If you check your globstar shell option, it is probably disabled:

$ shopt globstar
globstar           off

In that case, ** behaves just like * and will match exactly 1 directory level.

$ ls spec/**/*_spec.rb
spec/models/user_spec.rb

To enable it, run

shopt -s globstar

The double ast...

Ruby: String representations of regular expressions

Ruby's regular expressions can be represented differently.
When serializing them, you probably want to use inspect instead of to_s.

For the examples below, consider the following Regexp object.

regexp = /^f(o+)!/mi

to_s

Using to_s will use a format that is correct but often hard to read.

>> regexp.to_s
=> "(?mi-x:^f(o+)!)"

inspect

As the Ruby docs say:

...

Fix Rubygems binary error: undefined method `activate_bin_path' for Gem:Module (NoMethodError)

So you're getting an error like this:

undefined method `activate_bin_path' for Gem:Module (NoMethodError)

Here is what happened:

  • You installed a recent version of Rubygems
  • You installed some gems that install a binary (like bundle, rake or rails) with code that only works with modern Rubygems versions
  • You downgraded Rubygems to an older versions, which doesn't change any binaries
  • When calling binaries with the old Rubygems version, it cannot process the line Gem.activate_pin_path(...) that was written out by th...

Net::SSH::Exception: could not settle on encryption_client algorithm

TL;DR: Update the 'net-ssh' gem by adding to your Gemfile:

gem 'net-ssh', '=2.9.1'

Now run bundle update net-ssh. It has no dependencies so it shouldn't update other gems.

If you're using Ruby 1.8.7 and want to update net-ssh to a version > 2.9.1 you also need to add this to your gemfile:

gem 'backports', :require => false

... and in your deploy.rb add this:

require 'backports/1.9.2/array/select' 

Background

You propably have an older version of Capistrano and thereby an older version of `n...

Bundler: Gemfile.lock is corrupt & gems are missing from the DEPENDENCIES section

So you're getting this failure when running bundle install on an older project:

Your Gemfile.lock is corrupt. The following gems are missing from the DEPENDENCIES section: 'archive-tar-minitar' 'hoe' 'rcov'

This happens when you are using a new version of Bundler with a project that was bundled with a very old version of Bundler. For reasons unknown, the Bundler dependency API returns different dependencies for some gems (like ruby-debug or rainpress) than the dependencies found in the downloaded gemspecs. While old versi...

A collection of graph and diagram tools

Summarizing heredoc in Ruby and Rails

This card tries to summarize by example the different uses of heredoc.

  • In Ruby << vs. <<- vs. <<~
  • In Rails strip_heredoc vs. squish

strip_heredoc should be used for a text, where you want to preserve newlines. (multi-line -> multi-line)

squish should be used for a text, where you want to squish newlines. (multi-line -> one-line)

Ruby 2.3+

def foo
  bar = <<~TEXT
    line1
    line2
    line3
  TEXT
  puts bar.inspect
end
foo => "line1\nline2\nline3\n"

Read more: [Unindent HEREDOCs in Ruby 2.3](/m...

Linux: Using grep with a regular expression

You can use three different versions of the regular expression syntax in grep:

  • basic: -G
  • extended: -E(POSIX)
  • perl: -P (PCRE)

Difference between basic and extended:

In basic regular expressions the meta-characters '?', '+', '{', '|', '(', and ')' loose their special meaning; instead use the backslashed versions '?', '+', '{', '|', '(', and ')'.

Difference between extended (POSIX) and perl (PCRE): E.g. \d is not supported in POSIX.

This g...

Ruby: Writing specs for (partially) memoized code

When you're writing specs for ActiveRecord models that use memoization, a simple #reload will not do:

it 'updates on changes' do
  subject.seat_counts = [5]
  subject.seat_total.should == 5
  # seat_total is either memoized itself, or using some
  # private memoized method
  
  subject.seat_counts = [5, 1]
  subject.seat_total.reload.should == 6 # => Still 5
end

You might be tempted to manually unmemoize any memoized internal method to get #seat_total to update, but that has two disadvant...

How to monitor Sidekiq: A working example

In order to have monitoring for Sidekiq (like queue sizes, last run of Sidekiq) your application should have a monitoring route which returns a json looking like this:

{
  "sidekiq": {
    "totals": {
      "failed": 343938,
      "processed": 117649167
    },
    "recent_history": {
      "failed": {
        "2016-11-06": 1,
        "2016-11-07": 46,
        "2016-11-08": 0,
        "2016-11-09": 0,
        "2016-11-10": 0
      },
      "processed": {
        "2016-11-06": 230653,
        "2016-11-07": 230701,
        "2016-11-08"...

Detecting if a Ruby gem is loaded

Detect if a gem has been activated

A gem is activated if it is either in the current bundle (Gemfile.lock), or if you have manually activated it using Kernel#gem (old-school).

To detect if e.g. activerecord has been activated:

if Gem.loaded_specs.has_key?('activerecord')
  # ActiveRecord was activated
end

Detect if a particular gem version has been activated

To detect if e.g. activerecord ma...