In our applications we have a version file that has three variables that are then joined to create a string that can be used for the semantic version.

The file looks like:

# frozen_string_literal: true

major = 0
minor = 1
patch = 0

PORTAL_VERSION = [major, minor, patch].join('.')

And then we update it using the following from our CI server:

@version = '0.1.1' # this is passed from somewhere

puts 'updating version'
version_file = File.open("version.rb").read
version = @version.split('.')
version_file = version_file.gsub(/(major = \w)/, "major = #{version[0]}")
version_file = version_file.gsub(/(minor = \w)/, "minor = #{version[1]}")
version_file = version_file.gsub(/(patch = \w)/, "patch = #{version[2]}")
File.open('version.rb', 'wb') { |file| file.write(version_file) }
puts "updated version to #{@version}"

Is there a better way to do the replacement using the regex? As by having to find each line and then replace it feels a little dirty, plus if there was or wasn't spaces between the variable name and value it wouldn't work. So it feels a little fragile.

  • \$\begingroup\$ Why not generate a new version.rb from scratch instead of trying to edit it? \$\endgroup\$ May 8, 2018 at 20:44

1 Answer 1


There might be two easier options:

  • Generate the file using a template file something like the following

    major = {{major}}
    minor = {{minor}}
    patch = {{patch}}

that has strings that are easy to search for. You could also use ERB to generate the file.

  • Put the logic in your version.rb file something like:

    PORTAL_VERSION = '1.2.3'
    major, minor, path = PORTAL_VERSION.split('.').map(&:to_i)

This way you would just have to replace the first line.

  • If you want to do it using your logic I would change the regex from /(patch = \w)/ to /(patch\s*=\s*\w+)/ this would handle extra whitespace and version numbers bigger than 9

  • Note you can also do variable substitution in Regexes so you could write your code as:

    ['major', 'minor', 'patch'].each.with_index do |key, i|
      version_file.sub!(/(#{key}\s*=\s*\w+)/, "#{key} = #{version[i]}")

Note that gsub isn't necessary as you only expect one occurrence.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.