keys = {
"a" => %w(q w s z),
"b" => %w(v n g h),
"c" => %w(x d f v)
...
}
p keys["b"]
Refactorings
No refactoring yet !
Joran Jessurun
October 23, 2007, October 23, 2007 14:28, permalink
This is my attempt. Not really ruby like but more a general solution.
@keyboard_layout = [
"1234567890-=",
"qwertyuiop[]",
"asdfghjkl;'",
"zxcvbnm,./",
]
def key_coordinates(key)
@keyboard_layout.each_with_index do |line, i|
return [line.index(key), i] if line.include?(key)
end
[nil, nil]
end
def get_key(x, y)
return nil if y < 0 || y >= @keyboard_layout.size
line = @keyboard_layout[y]
return nil if x < 0 || x > line.size
line[x..x]
end
def keys_around(key)
x, y = key_coordinates(key)
if x && y
[
get_key(x - 1, y), get_key(x - 1, y + 1),
get_key(x, y - 1), get_key(x, y + 1),
get_key(x + 1, y - 1), get_key(x + 1, y)
].compact
end
end
p keys_around('b')
Scott Patten
October 23, 2007, October 23, 2007 17:14, permalink
Here it is. That would make a good Ruby Quiz. You should submit it.
You may disagree with my definition of neighbours, I didn't include punctuation as neighbours, and this will only work on a North American keyboard as is, but it seems to work.
To use it, require this file, and then call something like
Keyboard.neighbours('f')
#!/usr/bin/env ruby
class Keyboard
QWERTY = [ "qwertyuiop".split(''), "asdfghjkl".split(''), "zxcvbnm".split('')]
def initialize(char)
@char = char
end
def neighbours
(row_neighbours + row_above_neighbours + row_below_neighbours).sort.join
end
def Keyboard.neighbours(char)
Keyboard.new(char).neighbours
end
private
def row
QWERTY.detect {|row| row.include?(@char)}
end
def row_above
QWERTY[row_num - 1] if row_num() -1 >= 0
end
def row_below
QWERTY[row_num + 1] if row_num() + 1 < QWERTY.length
end
def row_num
QWERTY.index(row)
end
def in_row_index
row.index(@char)
end
def select_from_row(row_string, indices)
return [] unless row_string
indices.collect {|n| row_string[n .. n] if n >= 0 and n < row_string.length}.compact.sort
end
def row_neighbours
select_from_row(row, [in_row_index() - 1, in_row_index() + 1])
end
def row_above_neighbours
select_from_row(row_above, [in_row_index() , in_row_index() + 1 ])
end
def row_below_neighbours
select_from_row(row_below, [in_row_index() -1, in_row_index() ])
end
end
require 'test/unit'
class KeyboardNeighboursTest < Test::Unit::TestCase
def test_neighbours
expected_neighbours = {'q'=> 'aw', 't' => 'fgry', 'i' => 'jkou', 'p' => 'lo', 'a' => 'qswz',
'f' => 'cdgrtv', 'j' => 'hikmnu', 'l' => 'kop', 'z' => 'asx', 'v' => 'bcfg',
'n' => 'bhjm', 'm' => 'jkn'}
expected_neighbours.each do |key, neighbours|
assert_equal neighbours, Keyboard.neighbours(key)
end
end
end
Marco Valtas
October 24, 2007, October 24, 2007 02:45, permalink
Hi, I don't how to write a Ruby solution but you can have some idea looking at this Perl module.
http://search.cpan.org/~krburton/String-KeyboardDistance-1.01/KeyboardDistance.pm
This is not really a refactoring as much as a request of solution for my problem.
The problem is: I'd like some ruby-ish way of returning an array of keys-next-to-character. For instance: passing "b" would return v,n,h,g (the keys next to b on a keyboard)
The solution i have on my mind needs to create some kind of big hash with all the keys, but there must a better way?