Autodetecting monitors in XFCE
First of all, the convention in ruby is to use snake_case, not camelCase for variable and method names. It's generally a good idea to adhere to a language's naming conventions - if only so that the code looks consistent when you're calling standard library methods as well as your own.



In your xrandrPairs method, you mention that you're using an index to iterate because you have to go through the array in pairs. You can avoid this by using each_cons(2) which will yield each item together with the item after it (e.g. [1,2,3].each_cons(2) will yield 1,2 in the first iteration and 2,3 in the second).

However there's a better way to do this then to iterate through the lines. You can use scan to find all the lines that start without spaces and extract the information you want in one go:

def xrandr_pairs (xrandr_output)
## Returns [[&lt;display name&gt;, &lt;max-resolution&gt;] ...]
  display_re = /^(\S+)/
  option_re = /^\s+(\S+)/
  xrandr_output.scan(/#{display_re}.*\n#{option_re}/)
end


Since scan returns an array containing one subarray per match where each item in the subarray corresponds to one capturing group in the regex, this will produce the output you want. Note that xrandr_pairs now takes xrandr's output as a string, not an array of lines.

In addition to using scan I also changed the regexen a bit: I replaced [^\s] with \S, which is equivalent but shorter, and used + instead of *, so it does not match empty strings.



The xrandr_string method can also be rewritten to be much nicer by using the each_cons method like this:

def xrandr_string (x_pairs)
## Takes [[&lt;display name&gt;, &lt;max-resolution&gt;] ...] and returns an xrandr command string
  s = "xrandr --output #{x_pairs[0][0]} --mode #{x_pairs[0][1]}"
  x_pairs.each_cons(2) do |(previous_output, previous_mode), (output, mode)|
      s += " --output #{output} --mode #{mode} --right-of #{previous_output}"
    end
  end
  s
end


You don't need to check that the size is at least 2 because each_cons simply doesn't do anything if the array is smaller than the given chunk-size.

I also used the destructuring bind of block arguments to assign the elements of the subarrays to variables directly.

Instead of building up the string imperatively you could also use map and join like this:

def xrandr_string (x_pairs)
## Takes [[&lt;display name&gt;, &lt;max-resolution&gt;] ...] and returns an xrandr command string
  cmd = "xrandr --output #{x_pairs[0][0]} --mode #{x_pairs[0][1]}"
  args = x_pairs.each_cons(2).map do |(previous_output, previous_mode), (output, mode)|
    "--output #{output} --mode #{mode} --right-of #{previous_output}"
  end
  [cmd, *args].join(" ")
end