Автоопределение мониторов в Xfce


Я заболела xrandering вручную вещи на моих компьютерах (тем более, что я всегда просто последовательность мониторы слева направо и установить каждый на самом высоком разрешении) поэтому я написал это:

#!/usr/bin/ruby

def xrandrPairs (xList)
## Takes a split list of xrandr output and returns [[<display name>, <max-resolution>], ...]
  pairs = [[matchDisplay(xList[0]), matchOption(xList[1])]]
  (2..xList.length-1).to_a.each do |i| # kind of hacky, but I need to reference car and cadr here, so a call to .map won't do it
    if xList[i] =~ /^\S/ 
      pairs.push([matchDisplay(xList[i]), matchOption(xList[i+1])]) 
    end
  end
  pairs
end

def matchDisplay (dispString)
## Matches a display name
  dispString.match(/^([^\s]*)/)[1]
end

def matchOption (optString)
## Matches a resolution string (since they have whitespace preceding them)
  optString.match(/^\s*([^\s]*)/)[1]
end

def xrandrString (xPairs)
## Takes [[<display name>, <max-resolution>] ...] and returns an xrandr command string
  s = "xrandr --output #{xPairs[0][0]} --mode #{xPairs[0][1]}"
  if xPairs.length >= 2
    (1..xPairs.length-1).to_a.each do |i| # same as above
      s += " --output #{xPairs[i][0]} --mode #{xPairs[i][1]} --right-of #{xPairs[i-1][0]}"
    end
  end
  s
end

exec xrandrString(xrandrPairs(`xrandr`.split("\n")[1..-1]))

Ключ заключается в том, что каждый компьютер я использую разные дисплеи (они названы по-разному и у них разные максимальные разрешения), так насколько я знаю, мне придется либо разбирать расширения xrandr output или писать различные сценарии для каждой машины.

Мне плевать, что это неэффективно (пересекая вывод xrandr поближе несколько раз, и делать какой-то зацикленный форматирование строк) потому что он работает только один раз во время запуска, и рассматривается список из 30 элементов снаружи. Я с помощью Ruby 1.8.7 прямо из РЕПО сжать для облегчения монтажа (вот почему я хотел бы быть показано, как это работает в Python/Perl с тех, кто приходит с системой).

Я могу сделать некоторые замечания по нему?



501
4
задан 4 февраля 2011 в 03:02 Источник Поделиться
Комментарии
1 ответ

В первую очередь, конвенции в Ruby является использование snake_case, не верблюжьего переменной и метод имена. Это обычно хорошая идея, чтобы придерживаться конвенций язык имен - если только так что код выглядит последовательным, когда ты называешь стандартными методами библиотека, а также свой собственный.


В вашем xrandrPairs способ, вы упомянули, что вы используете указатель для перебора, потому что вы должны идти через массив попарно. Вы можете избежать этого, используя each_cons(2) , которая даст каждому пункту пункт после это (например, [1,2,3].each_cons(2) будет давать 1,2 в первой итерации и 2,3 в секунду).

Однако есть лучший способ, чтобы сделать это, то для перебора строк. Вы можете использовать сканирование , чтобы найти все строки, которые начинаются без пробелов и извлечь нужную информацию на одном дыхании:

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

После сканирования возвращает массив, содержащий один подмассив за матч, где каждый элемент в подмассиве соответствует один захват группы в регулярное выражение, это даст выход вы хотите. Обратите внимание, что xrandr_pairs теперь занимает xrandr поближес выхода как строка, а не массив строк.

В дополнение к использованию сканирования я также изменил regexen немного: Я заменил [^\ы] с , что эквивалентно, но короче, и использовать + вместо *, чтобы оно не совпадало с пустыми строками.


В xrandr_string метод также может быть переписан, чтобы быть гораздо приятнее с помощью each_cons способ такой:

def xrandr_string (x_pairs)
## Takes [[<display name>, <max-resolution>] ...] 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

Вам не нужно, чтобы проверить, что размер по меньшей мере 2, потому что each_cons просто не делает ничего, если массив меньше, чем данный размер куска.

Я также использовал деструктурируется привязки аргументов блока, чтобы назначить элементы подмассивов к переменным напрямую.

Вместо наращивания строку императивно также можно использовать карту и присоединиться , как это:

def xrandr_string (x_pairs)
## Takes [[<display name>, <max-resolution>] ...] 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

3
ответ дан 4 февраля 2011 в 04:02 Источник Поделиться