Skip to content
This repository was archived by the owner on Mar 12, 2023. It is now read-only.

Commit 27f13b1

Browse files
committed
Clean up and fulfill tests for the KeyBindings class
1 parent fc1b2a2 commit 27f13b1

File tree

2 files changed

+153
-21
lines changed

2 files changed

+153
-21
lines changed

lib/ruby_jard/key_bindings.rb

+16-21
Original file line numberDiff line numberDiff line change
@@ -6,35 +6,17 @@ module RubyJard
66
# match a key binding sequence from input.
77
# As this class is performant-sensitive, a lookup tree is built
88
# and updated whenever a new key is added.
9-
# TODO: Write tests for this file
109
class KeyBindings
1110
attr_reader :indexes
1211

13-
def initialize(sequences)
12+
def initialize(sequences = [])
1413
@key_bindings = []
1514
@indexes = {}
1615
sequences.each do |sequence, action|
1716
push(sequence, action)
1817
end
1918
end
2019

21-
def to_a
22-
@key_bindings.dup
23-
end
24-
25-
def push(sequence, action)
26-
if sequence.is_a?(Array)
27-
sequence.each { |s| push(s, action) }
28-
return
29-
end
30-
31-
raise RubyJard::Error if sequence.to_s.empty?
32-
33-
key_binding = RubyJard::KeyBinding.new(sequence, action)
34-
reindex(key_binding)
35-
@key_bindings << key_binding
36-
end
37-
3820
def match(&read_key)
3921
raise RubyJard::Error, 'This method requires a block' unless block_given?
4022

@@ -59,8 +41,8 @@ def match(&read_key)
5941
elsif node[byte].nil?
6042
# It's sure that no more bindings to match
6143
return buffer
62-
elsif buffer == node[byte].sequence
63-
# Exact match current key binding
44+
elsif buffer.start_with?(node[byte].sequence)
45+
# Match current key binding. Discard the rest
6446
return node[byte]
6547
else
6648
return buffer
@@ -71,6 +53,19 @@ def match(&read_key)
7153

7254
private
7355

56+
def push(sequence, action)
57+
if sequence.is_a?(Array)
58+
sequence.each { |s| push(s, action) }
59+
return
60+
end
61+
62+
raise RubyJard::Error if sequence.to_s.empty?
63+
64+
key_binding = RubyJard::KeyBinding.new(sequence, action)
65+
reindex(key_binding)
66+
@key_bindings << key_binding
67+
end
68+
7469
def reindex(key_binding)
7570
parent = nil
7671
node = @indexes

spec/ruby_jard/key_bindings_spec.rb

+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RubyJard::KeyBindings do
4+
let(:sample_sequences) do
5+
{
6+
"\eOQ" => 'jard filter switch',
7+
"\e[15~" => 'list',
8+
"\e[17~" => 'up',
9+
"\e[17;2~" => 'down',
10+
"\e[18;2~" => 'step'
11+
}
12+
end
13+
14+
describe '#initialize' do
15+
context 'when where is no input sequence' do
16+
it 'reset indexs to an empty hash' do
17+
key_bindings = described_class.new
18+
expect(key_bindings.indexes).to eql({})
19+
end
20+
end
21+
22+
context 'when there are some input sequences' do
23+
it 'establishes the indexes for input sequences' do
24+
key_bindings = described_class.new(sample_sequences)
25+
expect(key_bindings.indexes.keys).not_to eql([])
26+
end
27+
end
28+
end
29+
30+
describe '#match' do
31+
let(:key_bindings) { described_class.new(sample_sequences) }
32+
33+
context 'when input keys do not match any key binding' do
34+
it 'returns all keys after the first read' do
35+
keys = ["\f1234", '56']
36+
read_keys = key_bindings.match { keys.shift }
37+
expect(read_keys).to eql("\f1234")
38+
end
39+
end
40+
41+
context 'when input keys do not match any key binding after multiple reads' do
42+
it 'returns all keys after the first read' do
43+
keys = ["\e[18;", '3~']
44+
read_keys = key_bindings.match { keys.shift }
45+
expect(read_keys).to eql("\e[18;3~")
46+
end
47+
end
48+
49+
context 'when input keys match a part of a key binding' do
50+
it 'returns all keys' do
51+
keys = ["\e[17", nil]
52+
read_keys = key_bindings.match { keys.shift }
53+
expect(read_keys).to eql("\e[17")
54+
end
55+
end
56+
57+
context 'when input keys match an unique key binding' do
58+
it 'returns a key binding object' do
59+
keys = ["\eOQ", nil]
60+
read_keys = key_bindings.match { keys.shift }
61+
expect(read_keys).to be_a(RubyJard::KeyBinding)
62+
expect(read_keys.action).to eql('jard filter switch')
63+
end
64+
end
65+
66+
context 'when input keys match a key binding' do
67+
it 'returns a key binding object' do
68+
keys = ["\e[17~", nil]
69+
read_keys = key_bindings.match { keys.shift }
70+
expect(read_keys).to be_a(RubyJard::KeyBinding)
71+
expect(read_keys.action).to eql('up')
72+
end
73+
end
74+
75+
context 'when input keys match the longer key binding' do
76+
it 'returns the longer key binding object' do
77+
keys = ["\e[17;2~", nil]
78+
read_keys = key_bindings.match { keys.shift }
79+
expect(read_keys).to be_a(RubyJard::KeyBinding)
80+
expect(read_keys.action).to eql('down')
81+
end
82+
end
83+
84+
context 'when input keys match a key binding after multiple reads' do
85+
it 'returns a key binding object' do
86+
keys = ["\e[1", '7~']
87+
read_keys = key_bindings.match { keys.shift }
88+
expect(read_keys).to be_a(RubyJard::KeyBinding)
89+
expect(read_keys.action).to eql('up')
90+
end
91+
end
92+
93+
context 'when input keys match the longer key binding after multiple reads' do
94+
it 'returns the longer key binding object' do
95+
keys = ["\e[17;", '2~']
96+
read_keys = key_bindings.match { keys.shift }
97+
expect(read_keys).to be_a(RubyJard::KeyBinding)
98+
expect(read_keys.action).to eql('down')
99+
end
100+
end
101+
102+
context 'when input keys have trailing charcters after a valid key binding' do
103+
it 'returns discards trailing charcters' do
104+
keys = ["\e[17~abcdef"]
105+
read_keys = key_bindings.match { keys.shift }
106+
expect(read_keys).to be_a(RubyJard::KeyBinding)
107+
expect(read_keys.action).to eql('up')
108+
end
109+
end
110+
111+
context 'when input keys have trailing charcters after a valid key binding after multiple reads' do
112+
it 'returns discards trailing charcters' do
113+
keys = ["\e[1", '7~abcdef']
114+
read_keys = key_bindings.match { keys.shift }
115+
expect(read_keys).to be_a(RubyJard::KeyBinding)
116+
expect(read_keys.action).to eql('up')
117+
end
118+
end
119+
120+
context 'when input keys include multiple key bindings' do
121+
it 'returns the first key binding object' do
122+
keys = ["\e[1", "7~\e[18;2~"]
123+
read_keys = key_bindings.match { keys.shift }
124+
expect(read_keys).to be_a(RubyJard::KeyBinding)
125+
expect(read_keys.action).to eql('up')
126+
end
127+
end
128+
129+
context 'when input keys has prefixed charcters' do
130+
it 'returns all the keys by design' do
131+
keys = ["123\e[17~"]
132+
read_keys = key_bindings.match { keys.shift }
133+
expect(read_keys).to eql("123\e[17~")
134+
end
135+
end
136+
end
137+
end

0 commit comments

Comments
 (0)