Better iOS Projects: Advanced Usages of rbenv

In the series “Better iOS Projects”, we have a look at the various tools and environments that are useful to have a more convenient and efficient handling of iOS projects.

June 11, 2018, by Wolfgang Lutz

Digging deeper with ruby Digging deeper with ruby

Updates

  • 24. February 2021: Checked for validity, updated the deprecated use of --binstubs, minor text changes.

Special Note

You should not have to use root user permissions via sudo for any of the calls that follow. If you seem to need to, you most likely already had a permission problem before or you did not install and setup rbenv correctly.

Advanced Usages of rbenv

After we learnt to install and use rbenv and bundler in the previous post of the series “Better iOS Projects”, How to manage the ruby environment of your iOS Project using rbenv, we continue by having a look at some of the more advanced features and pitfalls of using rbenv and bundler.

How do I use bundler in ruby-scripts?

To ensure that the correct versions of gems are used inside a ruby script, you need to require rubygems and bundler/setup at the top of the script:

#!/usr/bin/ruby

# Non-Bundler Dependencies
require 'optparse'
require 'ostruct'

# Support for Bundler and Gems
require 'rubygems'
require 'bundler/setup'

# Now, the version of xcodeproj defined via Bundler is used
require 'xcodeproj'

Using binstubs

To ensure that all calls use the version defined in the Gemfile without prefixing the call with bundle exec, you can use the binstubs command along with the gems to stub to the installation command:

bundle binstubs fastlane

It is recommended to explicitly name the gems you want to stub to avoid conflicts with gems that deliver their own stubs, e.g. rake.

Then, you can call the command by prepending bin/, e.g.

bin/fastlane

You can also add export PATH="./bin:$PATH" to your shell’s rc file (see above) to always search the bin folder (where binstubs are installed to) when running commands. This might have security implications though. If you do this, it is enough to type

fastlane

As an alternative to binstubs, you can also add the alias alias be="bundle exec" to your .rc file, to make the original call shorter:

be fastlane

Bonus: How to automate installing the correct ruby version and gems

At Number42, we always include a script called bootstrap.sh in our projects, which does the most basic setup calls needed to run the project afterwards. Whenever something does not work out of the box after cloning (or pulling) a project, calling sh bootstrap.sh is able to sort out the larger part of problems in most cases. We use this the same way for iOS and web projects. We will have a closer look at the bootstrap script in an upcoming episode of this series.

Among those are the installation of ruby, Bundler and Gems:

#!/bin/sh

# exit script on error
set -e

# define colors
RED=`tput setaf 1`
GREEN=`tput setaf 2`
NOCOLOR=`tput sgr0`

# Guard to update brew only once and only if necessary
NEEDS_TO_UPDATE_BREW=1

# Helper to install brew dependencies
installDependencyWithBrew(){
  if [ $NEEDS_TO_UPDATE_BREW -eq 1 ]; then
    echo ""
    echo  "${GREEN} UPDATING BREW ${NOCOLOR}";

    # update brew to keep dependencies up to date
    brew update || echo "${RED} FAILED TO UPDATE BREW ${NOCOLOR}";
    NEEDS_TO_UPDATE_BREW=0
  fi

  echo ""
  echo  "${GREEN} INSTALLING $1 WITH BREW ${NOCOLOR}";

  # install dependency, if is not installed
  brew list $1 || brew install $1 || echo "${RED} FAILED TO INSTALL $1 ${NOCOLOR}";

  # upgrade dependency, if it is outdated
  brew outdated $1 || brew upgrade $1 || echo "${RED} FAILED TO UPGRADE $1 ${NOCOLOR}";
}

# Install ruby if a .ruby-version exists
if [ -e ".ruby-version" ]; then
  echo ""
  echo  "${GREEN} SETTING UP RUBY ${NOCOLOR}";

  installDependencyWithBrew rbenv
  installDependencyWithBrew ruby-build
  # install ruby version from .ruby-version, skipping if already installed (-s)
  rbenv install -s
fi

# Install gems if a Gemfile exists
if [ -e "Gemfile" ]; then
  echo ""
  echo  "${GREEN} INSTALLING GEMS ${NOCOLOR}";

  # install bundler gem for ruby dependency management
  gem install bundler --no-document || echo "${RED} FAILED TO INSTALL BUNDLER ${NOCOLOR}";
  bundle install || echo "${RED} FAILED TO INSTALL BUNDLE ${NOCOLOR}";
fi

Glossary

  • .ruby-version: a simple file that defines, what version of ruby you want to use for the project
  • bash: The default shell for most Linux and UNIX systems, see BASH
  • bundler: the ruby dependency manager
  • gem: a ruby dependency
  • Gemfile: the definition file, where all the dependencies are listed that bundler should install
  • Gemfile.lock: the file, where bundler saves the exact versions of all dependencies and their dependencies, as resolved during install
  • oh-my-zsh: a collection of configurations and scripts for zsh
  • rbenv: a tool to manage multiple versions of ruby on the same computer
  • ruby-build: a tool to install ruby versions
  • ruby: a programming language
  • zsh: the Z Shell

Acknowledgments

Thanks, as always, to Melanie Kloss for the great banner image.

Everything from the series ‘Better iOS Projects’: