vedeu 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (85) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +1 -0
  3. data/README.md +1 -2
  4. data/Rakefile +5 -5
  5. data/bin/vedeu +8 -4
  6. data/docs/api.md +3 -1
  7. data/docs/events.md +43 -29
  8. data/docs/getting_started.md +2 -0
  9. data/examples/cursor_app/cursor_app.rb +85 -0
  10. data/examples/lines_app/lines_app.rb +60 -0
  11. data/lib/vedeu.rb +9 -3
  12. data/lib/vedeu/api/api.rb +28 -7
  13. data/lib/vedeu/api/composition.rb +2 -0
  14. data/lib/vedeu/api/helpers.rb +2 -0
  15. data/lib/vedeu/api/interface.rb +2 -20
  16. data/lib/vedeu/api/keymap.rb +2 -0
  17. data/lib/vedeu/api/line.rb +2 -0
  18. data/lib/vedeu/api/menu.rb +3 -1
  19. data/lib/vedeu/api/stream.rb +25 -2
  20. data/lib/vedeu/application.rb +4 -4
  21. data/lib/vedeu/configuration/api.rb +327 -0
  22. data/lib/vedeu/configuration/cli.rb +110 -0
  23. data/lib/vedeu/{configuration.rb → configuration/configuration.rb} +49 -99
  24. data/lib/vedeu/launcher.rb +0 -1
  25. data/lib/vedeu/models/attributes/colour_translator.rb +2 -2
  26. data/lib/vedeu/models/colour.rb +0 -1
  27. data/lib/vedeu/models/composition.rb +2 -8
  28. data/lib/vedeu/models/cursor.rb +261 -0
  29. data/lib/vedeu/models/geometry.rb +11 -19
  30. data/lib/vedeu/models/interface.rb +2 -12
  31. data/lib/vedeu/models/keymap.rb +2 -0
  32. data/lib/vedeu/models/line.rb +2 -0
  33. data/lib/vedeu/models/stream.rb +2 -0
  34. data/lib/vedeu/models/style.rb +2 -0
  35. data/lib/vedeu/output/clear.rb +0 -1
  36. data/lib/vedeu/output/compositor.rb +0 -1
  37. data/lib/vedeu/output/refresh.rb +3 -0
  38. data/lib/vedeu/output/render.rb +12 -6
  39. data/lib/vedeu/output/view.rb +1 -0
  40. data/lib/vedeu/repositories/cursors.rb +98 -0
  41. data/lib/vedeu/repositories/events.rb +0 -1
  42. data/lib/vedeu/repositories/focus.rb +18 -0
  43. data/lib/vedeu/repositories/menus.rb +4 -4
  44. data/lib/vedeu/support/common.rb +2 -1
  45. data/lib/vedeu/support/event.rb +1 -10
  46. data/lib/vedeu/support/grid.rb +1 -2
  47. data/lib/vedeu/{repositories → support}/keymap_validator.rb +5 -4
  48. data/lib/vedeu/support/log.rb +3 -0
  49. data/lib/vedeu/support/menu.rb +4 -1
  50. data/lib/vedeu/support/registrar.rb +2 -1
  51. data/test/integration/defining_interfaces_test.rb +0 -1
  52. data/test/integration/views/basic_view_test.rb +741 -739
  53. data/test/lib/vedeu/api/api_test.rb +14 -3
  54. data/test/lib/vedeu/api/helpers_test.rb +3 -3
  55. data/test/lib/vedeu/api/interface_test.rb +17 -70
  56. data/test/lib/vedeu/api/keymap_test.rb +2 -0
  57. data/test/lib/vedeu/api/line_test.rb +4 -4
  58. data/test/lib/vedeu/api/menu_test.rb +6 -5
  59. data/test/lib/vedeu/api/stream_test.rb +18 -0
  60. data/test/lib/vedeu/configuration/api_test.rb +248 -0
  61. data/test/lib/vedeu/configuration/cli_test.rb +88 -0
  62. data/test/lib/vedeu/configuration/configuration_test.rb +67 -0
  63. data/test/lib/vedeu/input/input_test.rb +2 -2
  64. data/test/lib/vedeu/models/attributes/background_test.rb +3 -3
  65. data/test/lib/vedeu/models/attributes/foreground_test.rb +3 -3
  66. data/test/lib/vedeu/models/composition_test.rb +0 -222
  67. data/test/lib/vedeu/models/cursor_test.rb +164 -0
  68. data/test/lib/vedeu/models/interface_test.rb +0 -11
  69. data/test/lib/vedeu/output/compositor_test.rb +2 -4
  70. data/test/lib/vedeu/output/render_test.rb +4 -41
  71. data/test/lib/vedeu/repositories/cursors_test.rb +13 -0
  72. data/test/lib/vedeu/repositories/focus_test.rb +14 -4
  73. data/test/lib/vedeu/repositories/menus_test.rb +36 -29
  74. data/test/lib/vedeu/{repositories → support}/keymap_validator_test.rb +0 -0
  75. data/test/lib/vedeu/support/menu_test.rb +3 -3
  76. data/test/lib/vedeu/support/registrar_test.rb +6 -0
  77. data/test/lib/vedeu/support/terminal_test.rb +2 -2
  78. data/test/test_helper.rb +1 -1
  79. data/vedeu.gemspec +1 -1
  80. metadata +23 -14
  81. data/elements.txt +0 -118
  82. data/lib/vedeu/support/cursor.rb +0 -96
  83. data/test/lib/vedeu/configuration_test.rb +0 -154
  84. data/test/lib/vedeu/support/cursor_test.rb +0 -79
  85. data/test/support/model_test_data.json +0 -437
@@ -0,0 +1,88 @@
1
+ require 'test_helper'
2
+
3
+ module Vedeu
4
+ module Configuration
5
+
6
+ describe CLI do
7
+
8
+ # describe '#colour_mode' do
9
+ # it '--colour-mode' do
10
+ # Configuration.configure(['--colour-mode', '16777216'])
11
+ # Configuration.colour_mode.must_equal(16777216)
12
+ # end
13
+
14
+ # it '--colour-mode' do
15
+ # Configuration.configure(['--colour-mode', '256'])
16
+ # Configuration.colour_mode.must_equal(256)
17
+ # end
18
+
19
+ # it '--colour-mode' do
20
+ # Configuration.configure(['--colour-mode', '16'])
21
+ # Configuration.colour_mode.must_equal(16)
22
+ # end
23
+
24
+ # it '--colour-mode' do
25
+ # Configuration.configure(['--colour-mode', '348'])
26
+ # Configuration.colour_mode.must_equal(8)
27
+ # end
28
+ # end
29
+
30
+ # describe '#debug?' do
31
+ # it '--debug' do
32
+ # Configuration.configure(['--debug'])
33
+ # Configuration.debug?.must_equal(true)
34
+ # end
35
+ # end
36
+
37
+ # describe '#interactive?' do
38
+ # it '--interactive' do
39
+ # Configuration.configure(['--interactive'])
40
+ # Configuration.interactive?.must_equal(true)
41
+ # end
42
+
43
+ # it '--noninteractive' do
44
+ # Configuration.configure(['--noninteractive'])
45
+ # Configuration.interactive?.must_equal(false)
46
+ # end
47
+
48
+ # it '--standalone' do
49
+ # Configuration.configure(['--standalone'])
50
+ # Configuration.interactive?.must_equal(false)
51
+ # end
52
+ # end
53
+
54
+ # describe '#once?' do
55
+ # it '--run-once' do
56
+ # Configuration.configure(['--run-once'])
57
+ # Configuration.once?.must_equal(true)
58
+ # end
59
+
60
+ # it '--run-many' do
61
+ # Configuration.configure(['--run-many'])
62
+ # Configuration.once?.must_equal(false)
63
+ # end
64
+ # end
65
+
66
+ # describe '#terminal_mode' do
67
+ # it '--cooked' do
68
+ # Configuration.configure(['--cooked'])
69
+ # Configuration.terminal_mode.must_equal(:cooked)
70
+ # end
71
+
72
+ # it '--raw' do
73
+ # Configuration.configure(['--raw'])
74
+ # Configuration.terminal_mode.must_equal(:raw)
75
+ # end
76
+ # end
77
+
78
+ # describe '#trace?' do
79
+ # it '--trace' do
80
+ # Configuration.configure(['--trace'])
81
+ # Configuration.trace?.must_equal(true)
82
+ # end
83
+ # end
84
+
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,67 @@
1
+ require 'test_helper'
2
+
3
+ module Vedeu
4
+ describe Configuration do
5
+ before { Configuration.reset }
6
+ after { Configuration.reset }
7
+
8
+ describe '#colour_mode' do
9
+ it 'returns the value of the colour_mode option' do
10
+ ENV['VEDEU_TERM'] = 'xterm-truecolor'
11
+ Configuration.colour_mode.must_equal(16777216)
12
+ end
13
+ end
14
+
15
+ describe '#debug?' do
16
+ it 'returns the value of the debug option' do
17
+ Configuration.debug?.must_equal(false)
18
+ end
19
+ end
20
+
21
+ describe '#interactive?' do
22
+ it 'returns the value of the interactive option' do
23
+ Configuration.interactive?.must_equal(true)
24
+ end
25
+ end
26
+
27
+ describe '#once?' do
28
+ it 'returns the value of the once option' do
29
+ Configuration.once?.must_equal(false)
30
+ end
31
+ end
32
+
33
+ describe '#terminal_mode' do
34
+ it 'returns the value of the mode option' do
35
+ Configuration.terminal_mode.must_equal(:raw)
36
+ end
37
+ end
38
+
39
+ describe '#trace?' do
40
+ it 'returns the value of the trace option' do
41
+ Configuration.trace?.must_equal(false)
42
+ end
43
+ end
44
+
45
+ describe '.configure' do
46
+ it 'returns the options configured' do
47
+ Configuration.configure.must_equal(
48
+ {
49
+ colour_mode: 16777216,
50
+ debug: false,
51
+ interactive: true,
52
+ once: false,
53
+ system_keys: {
54
+ exit: "q",
55
+ focus_next: :tab,
56
+ focus_prev: :shift_tab,
57
+ mode_switch: :escape
58
+ },
59
+ terminal_mode: :raw,
60
+ trace: false
61
+ }
62
+ )
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -54,8 +54,8 @@ module Vedeu
54
54
  end
55
55
 
56
56
  it 'switches the terminal mode when escape is pressed' do
57
- skip # TODO: Fix this; it intermittently fails because the event isn't
58
- # registered some of the time.
57
+ skip "Fix this; it intermittently fails because the event isn't " \
58
+ "registered some of the time."
59
59
  Terminal.stub :input, "\e" do
60
60
  Vedeu.stub :log, nil do
61
61
  proc { Input.capture }.must_raise(ModeSwitch)
@@ -16,7 +16,7 @@ module Vedeu
16
16
  magenta: "\e[45m",
17
17
  white: "\e[47m",
18
18
  default: "\e[49m",
19
- unknown: "",
19
+ unknown: '',
20
20
  }.map do |colour, result|
21
21
  it "returns the correct escape sequence for #{colour}" do
22
22
  Background.escape_sequence(colour).must_equal(result)
@@ -32,8 +32,8 @@ module Vedeu
32
32
  118 => "\e[48;5;118m",
33
33
  143 => "\e[48;5;143m",
34
34
  219 => "\e[48;5;219m",
35
- -2 => "",
36
- 442 => ""
35
+ -2 => '',
36
+ 442 => ''
37
37
  }.map do |colour, result|
38
38
  it "returns the correct escape sequence for #{colour}" do
39
39
  Background.escape_sequence(colour).must_equal(result)
@@ -16,7 +16,7 @@ module Vedeu
16
16
  magenta: "\e[35m",
17
17
  white: "\e[37m",
18
18
  default: "\e[39m",
19
- unknown: "",
19
+ unknown: '',
20
20
  }.map do |colour, result|
21
21
  it "returns the correct escape sequence for #{colour}" do
22
22
  Foreground.escape_sequence(colour).must_equal(result)
@@ -32,8 +32,8 @@ module Vedeu
32
32
  118 => "\e[38;5;118m",
33
33
  143 => "\e[38;5;143m",
34
34
  219 => "\e[38;5;219m",
35
- -2 => "",
36
- 442 => ""
35
+ -2 => '',
36
+ 442 => ''
37
37
  }.map do |colour, result|
38
38
  it "returns the correct escape sequence for #{colour}" do
39
39
  Foreground.escape_sequence(colour).must_equal(result)
@@ -4,9 +4,6 @@ require 'json'
4
4
 
5
5
  module Vedeu
6
6
  describe Composition do
7
- let(:json) { File.read('test/support/model_test_data.json') }
8
- let(:attributes) { JSON.load(json, nil, symbolize_names: true) }
9
-
10
7
  before { Buffers.reset }
11
8
 
12
9
  describe '#initialize' do
@@ -36,224 +33,5 @@ module Vedeu
36
33
  end
37
34
  end
38
35
 
39
- # describe '#to_s' do
40
- # it 'returns the stringified content for a single interface, single line, single stream' do
41
- # Vedeu.interface('int1_lin1_str1') do
42
- # y 3
43
- # x 3
44
- # width 15
45
- # height 3
46
- # end
47
-
48
- # Composition.new(attributes[:test_0001]).to_s.must_equal(
49
- # "\e[3;3H \e[3;3H" \
50
- # "\e[4;3H \e[4;3H" \
51
- # "\e[5;3H \e[5;3H" \
52
- # "\e[3;3HSome text...\e[?25h"
53
- # )
54
- # end
55
-
56
- # it 'returns the stringified content for a single interface, single line, multiple streams' do
57
- # Vedeu.interface('int1_lin1_str3') do
58
- # y 3
59
- # x 3
60
- # width 30
61
- # height 3
62
- # end
63
-
64
- # Composition.new(attributes[:test_0002]).to_s.must_equal(
65
- # "\e[3;3H \e[3;3H" \
66
- # "\e[4;3H \e[4;3H" \
67
- # "\e[5;3H \e[5;3H" \
68
- # "\e[3;3HSome text... more text...\e[?25h"
69
- # )
70
- # end
71
-
72
- # it 'returns the stringified content for a single interface, multiple lines, single stream' do
73
- # Vedeu.interface('int1_lin2_str1') do
74
- # y 3
75
- # x 3
76
- # width 15
77
- # height 3
78
- # end
79
-
80
- # Composition.new(attributes[:test_0003]).to_s.must_equal(
81
- # "\e[3;3H \e[3;3H" \
82
- # "\e[4;3H \e[4;3H" \
83
- # "\e[5;3H \e[5;3H" \
84
- # "\e[3;3HSome text..." \
85
- # "\e[4;3HSome text...\e[?25h"
86
- # )
87
- # end
88
-
89
- # it 'returns the stringified content for a single interface, multiple lines, multiple streams' do
90
- # Vedeu.interface('int1_lin2_str3') do
91
- # y 3
92
- # x 3
93
- # width 30
94
- # height 3
95
- # end
96
-
97
- # Composition.new(attributes[:test_0004]).to_s.must_equal(
98
- # "\e[3;3H \e[3;3H" \
99
- # "\e[4;3H \e[4;3H" \
100
- # "\e[5;3H \e[5;3H" \
101
- # "\e[3;3HSome text... more text..." \
102
- # "\e[4;3HSome text... more text...\e[?25h"
103
- # )
104
- # end
105
-
106
- # it 'returns the stringified content for a single interface, multiple lines, multiple streams, streams contain styles' do
107
- # Vedeu.interface('int1_lin2_str3_styles') do
108
- # y 3
109
- # x 3
110
- # width 30
111
- # height 3
112
- # end
113
-
114
- # Composition.new(attributes[:test_0005]).to_s.must_equal(
115
- # "\e[3;3H \e[3;3H" \
116
- # "\e[4;3H \e[4;3H" \
117
- # "\e[5;3H \e[5;3H" \
118
- # "\e[3;3H\e[38;2;0;0;0m\e[48;2;0;0;255m\e[24m\e[22m\e[27m\e[4mSome text...\e[38;2;255;255;0m\e[48;2;0;255;0m\e[24m\e[22m\e[27m \e[38;2;255;255;255m\e[48;2;255;0;255m\e[1mmore text...\e[?25h"
119
- # )
120
- # end
121
-
122
- # it 'returns the stringified content for multiple interfaces, single line, single stream' do
123
- # Vedeu.interface('int2_lin1_str1_1') do
124
- # y 3
125
- # x 3
126
- # width 15
127
- # height 3
128
- # end
129
- # Vedeu.interface('int2_lin1_str1_2') do
130
- # y 6
131
- # x 6
132
- # width 15
133
- # height 3
134
- # end
135
-
136
- # Composition.new(attributes[:test_0006]).to_s.must_equal(
137
- # "\e[3;3H \e[3;3H" \
138
- # "\e[4;3H \e[4;3H" \
139
- # "\e[5;3H \e[5;3H" \
140
- # "\e[3;3HSome text...\e[?25h" \
141
- # "\e[6;6H \e[6;6H" \
142
- # "\e[7;6H \e[7;6H" \
143
- # "\e[8;6H \e[8;6H" \
144
- # "\e[6;6HSome text...\e[?25h"
145
- # )
146
- # end
147
-
148
- # it 'returns the stringified content for multiple interfaces, single line, multiple streams' do
149
- # Vedeu.interface('int2_lin1_str3_1') do
150
- # y 3
151
- # x 3
152
- # width 30
153
- # height 3
154
- # end
155
- # Vedeu.interface('int2_lin1_str3_2') do
156
- # y 6
157
- # x 6
158
- # width 30
159
- # height 3
160
- # end
161
-
162
- # Composition.new(attributes[:test_0007]).to_s.must_equal(
163
- # "\e[3;3H \e[3;3H" \
164
- # "\e[4;3H \e[4;3H" \
165
- # "\e[5;3H \e[5;3H" \
166
- # "\e[3;3HSome text... more text...\e[?25h" \
167
- # "\e[6;6H \e[6;6H" \
168
- # "\e[7;6H \e[7;6H" \
169
- # "\e[8;6H \e[8;6H" \
170
- # "\e[6;6HSome text... more text...\e[?25h"
171
- # )
172
- # end
173
-
174
- # it 'returns the stringified content for multiple interfaces, multiple lines, single stream' do
175
- # Vedeu.interface('int2_lin2_str1_1') do
176
- # y 3
177
- # x 3
178
- # width 15
179
- # height 3
180
- # end
181
- # Vedeu.interface('int2_lin2_str1_2') do
182
- # y 6
183
- # x 6
184
- # width 15
185
- # height 3
186
- # end
187
-
188
- # Composition.new(attributes[:test_0008]).to_s.must_equal(
189
- # "\e[3;3H \e[3;3H" \
190
- # "\e[4;3H \e[4;3H" \
191
- # "\e[5;3H \e[5;3H" \
192
- # "\e[3;3HSome text..." \
193
- # "\e[4;3HSome text...\e[?25h" \
194
- # "\e[3;3H \e[3;3H" \
195
- # "\e[4;3H \e[4;3H" \
196
- # "\e[5;3H \e[5;3H" \
197
- # "\e[3;3HSome text..." \
198
- # "\e[4;3HSome text...\e[?25h"
199
- # )
200
- # end
201
-
202
- # it 'returns the stringified content for multiple interfaces, multiple lines, multiple streams' do
203
- # Vedeu.interface('int2_lin2_str3_1') do
204
- # y 3
205
- # x 3
206
- # width 30
207
- # height 3
208
- # end
209
- # Vedeu.interface('int2_lin2_str3_2') do
210
- # y 6
211
- # x 6
212
- # width 30
213
- # height 3
214
- # end
215
-
216
- # Composition.new(attributes[:test_0009]).to_s.must_equal(
217
- # "\e[3;3H \e[3;3H" \
218
- # "\e[4;3H \e[4;3H" \
219
- # "\e[5;3H \e[5;3H" \
220
- # "\e[3;3HSome text... more text..." \
221
- # "\e[4;3HSome text... more text...\e[?25h" \
222
- # "\e[6;6H \e[6;6H" \
223
- # "\e[7;6H \e[7;6H" \
224
- # "\e[8;6H \e[8;6H" \
225
- # "\e[6;6HSome text... more text..." \
226
- # "\e[7;6HSome text... more text...\e[?25h"
227
- # )
228
- # end
229
-
230
- # it 'returns the stringified content for multiple interfaces, multiple lines, multiple streams, streams contain styles' do
231
- # Vedeu.interface('int2_lin2_str3_styles_1') do
232
- # y 3
233
- # x 3
234
- # width 30
235
- # height 3
236
- # end
237
- # Vedeu.interface('int2_lin2_str3_styles_2') do
238
- # y 6
239
- # x 6
240
- # width 30
241
- # height 3
242
- # end
243
-
244
- # Composition.new(attributes[:test_0010]).to_s.must_equal(
245
- # "\e[3;3H \e[3;3H" \
246
- # "\e[4;3H \e[4;3H" \
247
- # "\e[5;3H \e[5;3H" \
248
- # "\e[3;3H\e[38;2;0;0;0m\e[48;2;0;0;255m\e[24m\e[22m\e[27m\e[4mSome text...\e[38;2;255;255;0m\e[48;2;0;255;0m\e[24m\e[22m\e[27m \e[38;2;255;255;255m\e[48;2;255;0;255m\e[1mmore text..." \
249
- # "\e[4;3H\e[38;2;0;0;0m\e[48;2;0;0;255m\e[24m\e[22m\e[27m\e[4mSome text...\e[38;2;255;255;0m\e[48;2;0;255;0m\e[24m\e[22m\e[27m \e[38;2;255;255;255m\e[48;2;255;0;255m\e[1mmore text...\e[?25h" \
250
- # "\e[6;6H \e[6;6H" \
251
- # "\e[7;6H \e[7;6H" \
252
- # "\e[8;6H \e[8;6H" \
253
- # "\e[6;6H\e[38;2;0;0;0m\e[48;2;0;0;255m\e[24m\e[22m\e[27m\e[4mSome text...\e[38;2;255;255;0m\e[48;2;0;255;0m\e[24m\e[22m\e[27m \e[38;2;255;255;255m\e[48;2;255;0;255m\e[1mmore text..." \
254
- # "\e[7;6H\e[38;2;0;0;0m\e[48;2;0;0;255m\e[24m\e[22m\e[27m\e[4mSome text...\e[38;2;255;255;0m\e[48;2;0;255;0m\e[24m\e[22m\e[27m \e[38;2;255;255;255m\e[48;2;255;0;255m\e[1mmore text...\e[?25h"
255
- # )
256
- # end
257
- # end
258
36
  end
259
37
  end
@@ -0,0 +1,164 @@
1
+ require 'test_helper'
2
+
3
+ module Vedeu
4
+ describe Cursor do
5
+ let(:attributes) {
6
+ {
7
+ name: 'silver',
8
+ state: :show,
9
+ x: 12,
10
+ y: 5,
11
+ }
12
+ }
13
+
14
+ before do
15
+ Interfaces.reset
16
+ Vedeu.interface 'silver' do
17
+ width 10
18
+ height 4
19
+ x 12
20
+ y 5
21
+ end
22
+ end
23
+
24
+ describe '#initialize' do
25
+ it 'returns an instance of itself' do
26
+ Cursor.new(attributes).must_be_instance_of(Cursor)
27
+ end
28
+ end
29
+
30
+ describe '#attributes' do
31
+ it 'returns a hash containing the attributes of the instance' do
32
+ Cursor.new(attributes).attributes.must_equal(
33
+ { name: 'silver', state: :show, x: 12, y: 5 }
34
+ )
35
+ end
36
+ end
37
+
38
+ describe '#move_up' do
39
+ it 'does not move up when already at the top' do
40
+ cursor = Cursor.new(attributes)
41
+ cursor.move_up
42
+ cursor.attributes.must_equal(
43
+ { name: 'silver', state: :show, x: 12, y: 5 }
44
+ )
45
+ end
46
+
47
+ it 'moves the cursor up' do
48
+ cursor = Cursor.new(attributes)
49
+ 3.times { cursor.move_down }
50
+ cursor.move_up
51
+ cursor.attributes.must_equal(
52
+ { name: 'silver', state: :show, x: 12, y: 7 }
53
+ )
54
+ end
55
+ end
56
+
57
+ describe '#move_down' do
58
+ it 'moves the cursor down' do
59
+ cursor = Cursor.new(attributes)
60
+ cursor.move_down
61
+ cursor.attributes.must_equal(
62
+ { name: 'silver', state: :show, x: 12, y: 6 }
63
+ )
64
+ end
65
+
66
+ it 'does not move down when already at the bottom' do
67
+ cursor = Cursor.new(attributes)
68
+ 5.times { cursor.move_down }
69
+ cursor.attributes.must_equal(
70
+ { name: 'silver', state: :show, x: 12, y: 8 }
71
+ )
72
+ end
73
+ end
74
+
75
+ describe '#move_left' do
76
+ it 'does not move left when already at leftmost' do
77
+ cursor = Cursor.new(attributes)
78
+ cursor.move_left
79
+ cursor.attributes.must_equal(
80
+ { name: 'silver', state: :show, x: 12, y: 5 }
81
+ )
82
+ end
83
+
84
+ it 'moves the cursor left' do
85
+ cursor = Cursor.new(attributes)
86
+ 3.times { cursor.move_right }
87
+ cursor.move_left
88
+ cursor.attributes.must_equal(
89
+ { name: 'silver', state: :show, x: 14, y: 5 }
90
+ )
91
+ end
92
+ end
93
+
94
+ describe '#move_right' do
95
+ it 'does not move right when already at rightmost' do
96
+ cursor = Cursor.new(attributes)
97
+ 11.times { cursor.move_right }
98
+ cursor.attributes.must_equal(
99
+ { name: 'silver', state: :show, x: 21, y: 5 }
100
+ )
101
+ end
102
+
103
+ it 'moves the cursor right' do
104
+ cursor = Cursor.new(attributes)
105
+ cursor.move_right
106
+ cursor.attributes.must_equal(
107
+ { name: 'silver', state: :show, x: 13, y: 5 }
108
+ )
109
+ end
110
+ end
111
+
112
+ describe '#show' do
113
+ it 'sets the state attribute to :show' do
114
+ cursor = Cursor.new(attributes)
115
+ cursor.hide
116
+ cursor.attributes.must_equal(
117
+ { name: 'silver', state: :hide, x: 12, y: 5 }
118
+ )
119
+ cursor.show
120
+ cursor.attributes.must_equal(
121
+ { name: 'silver', state: :show, x: 12, y: 5 }
122
+ )
123
+ end
124
+ end
125
+
126
+ describe '#hide' do
127
+ it 'sets the state attribute to :hide' do
128
+ cursor = Cursor.new(attributes)
129
+ cursor.hide
130
+ cursor.attributes.must_equal(
131
+ { name: 'silver', state: :hide, x: 12, y: 5 }
132
+ )
133
+ end
134
+ end
135
+
136
+ describe '#toggle' do
137
+ it 'sets the visibility to the opposite of its current state' do
138
+ cursor = Cursor.new(attributes)
139
+ cursor.toggle
140
+ cursor.attributes.must_equal(
141
+ { name: 'silver', state: :hide, x: 12, y: 5 }
142
+ )
143
+ cursor.toggle
144
+ cursor.attributes.must_equal(
145
+ { name: 'silver', state: :show, x: 12, y: 5 }
146
+ )
147
+ end
148
+ end
149
+
150
+ describe '#to_s' do
151
+ it 'returns the escape sequence to position and set the visibility of ' \
152
+ 'the cursor' do
153
+ Cursor.new(attributes).to_s.must_equal("\e[5;12H\e[?25h")
154
+ end
155
+
156
+ it 'returns the escape sequence to position and set the visibility of ' \
157
+ 'the cursor and returns to that position after yielding the block' do
158
+ Cursor.new(attributes).to_s do
159
+ # ...
160
+ end.must_equal("\e[5;12H\e[?25h\e[5;12H\e[?25h")
161
+ end
162
+ end
163
+ end
164
+ end