skip to Main Content

Basically, my goal is to print the rails version as a prompt segment to the terminator(terminal) as we enter a ROR project.

I have figured out a way how to display it as a custom segment in the terminator but I am having difficulty extracting the rails version. And to extract the rails version of a ROR project, there’s a file called Gemfile.lock which has a list of ruby gems and the exact rails version it has installed for the app.

This is what a Gemfile.lock looks like:

GEM
  remote: https://rubygems.org/
  specs:
    actioncable (7.0.3.1)
      actionpack (= 7.0.3.1)
      activesupport (= 7.0.3.1)
      nio4r (~> 2.0)
      websocket-driver (>= 0.6.1)
    actionmailbox (7.0.3.1)
      actionpack (= 7.0.3.1)
      activejob (= 7.0.3.1)
      activerecord (= 7.0.3.1)
      activestorage (= 7.0.3.1)
      activesupport (= 7.0.3.1)
      mail (>= 2.7.1)
      net-imap
      net-pop
      ....
      ....
      rails (7.0.3.1)
      actioncable (= 7.0.3.1)
      actionmailbox (= 7.0.3.1)
      actionmailer (= 7.0.3.1)
      actionpack (= 7.0.3.1)
      actiontext (= 7.0.3.1)
      actionview (= 7.0.3.1)
      activejob (= 7.0.3.1)
      activemodel (= 7.0.3.1)
     ....
     ....
DEPENDENCIES
  bootsnap
  capybara
  debug
  importmap-rails
  jbuilder
  puma (~> 5.0)
  rails (~> 7.0.3, >= 7.0.3.1)
  redis (~> 4.0)
  selenium-webdriver
  ....
  ....

The gem I want to extract is rails (7.0.3.1)

I am working on a .zshrc file to extract it and so far I have come up with this solution:

ver=`awk -F' ' '$1~/^rails/{print $0}' Gemfile.lock` 

which gives the following output

      rails-dom-testing (~> 2.0)
      rails-html-sanitizer (~> 1.0, >= 1.2.0)
      rails-dom-testing (~> 2.0)
      rails-html-sanitizer (~> 1.1, >= 1.2.0)
    rails (7.0.3.1)
    rails-dom-testing (2.0.3)
    rails-html-sanitizer (1.4.3)
  rails (~> 7.0.3, >= 7.0.3.1) 

As you can see there are multiple gems that include the name rails in them. But I only want to extract the version of this gem rails (7.0.3.1) which has a leading 4 space characters in it.

The expected output I am looking for is just the version of the gem like this: 7.0.3.1 without parenthesis and return as a string type. This will then be stored in a variable and then I will print it out in the terminal as a custom prompt segment with a custom color like:

local color="%F{#f7507b}"
# ver = ``
echo "%{$color%}$ver"

where ver is the variable that has rails version stored in it.

I have been trying for the past half day but no luck and I have also tried using [[:blank:]] & s but it doesn’t work for this context. I have also tried using rails -v where it outputs the rails version of the project directory we are in, but this will also give an error in rare cases where the user doesn’t have installed the ruby version specified in the Gemfile.

The output should give the version of rails the app uses regardless of whether the user has installed the particular version of ruby or rails in their system. So I think extracting the rails version from Gemfile.lock is the only way. But if you have any other approach towards this solution, I am all ears!

3

Answers


  1. Updated to extract just the version number – 7.0.3.1 – and store in a variable:

    $ awk '$1=="rails" {gsub(/[()]/,"",$2); print $2}' Gemfile.lock
    7.0.3.1
    
    $ ver=$(awk '$1=="rails" {gsub(/[()]/,"",$2); print $2}' Gemfile.lock)
    $ typeset -p ver
    declare -- ver="7.0.3.1"
    

    Couple issues with the current code:

    • -F' ' – not necessary since the default field delimiter is white space, ie, (multiple) spaces and tabs
    • since the desired line consists of the string rails with white space on each side we can simply use an equality comparison

    A few awk ideas:

    awk '{ if ($1 == "rails") print $0}' Gemfile.lock
    awk '$1 == "rails" { print $0 }' Gemfile.lock
    awk '$1 == "rails" { print }' Gemfile.lock
    awk '$1=="rails"' Gemfile.lock 
    

    All of these generate:

          rails (7.0.3.1)
    
    Login or Signup to reply.
  2. Using gnu awk you might use for example a pattern with a capture group.

    The pattern matches:

    • ^[[:space:]]* Match optional spaces from the start of the string
    • rails[[:space:]]+ match rails and 1+ spaces
    • ( match (
    • ([0-9][0-9.]*) Capture in group 1 matching a digit and optional dots and digits
    • ) Match )

    Example:

    gawk 'match($0, /^[[:space:]]*rails[[:space:]]+(([0-9][0-9.]*))/, a) {
      print a[1]
    }' Gemfile.lock
    

    Output

    7.0.3.1
    

    Or with awk and match

    awk '$1 == "rails" && match($2, /([0-9][0-9.]*)/) {
       print substr($2, RSTART+1, RLENGTH-2)
    }' Gemfile.lock
    
    Login or Signup to reply.
  3. Other great answers to the question you asked, I just wanted to suggest that instead of parsing/processing the Gemfile.lock yourself you can just use the rails executable:

    rails -v | awk '{ print $2 }'
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search