curses_menu 0.0.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/examples/lazy_menu_items.rb +25 -0
- data/lib/curses_menu/version.rb +1 -1
- data/lib/curses_menu.rb +29 -9
- data/spec/curses_menu_test/lazy_spec.rb +383 -0
- data/spec/curses_menu_test/simple_navigation_spec.rb +10 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '093b7bafe2adec885ebb1cd49607556b54a1925f416597d1ab220519ec6009f8'
|
4
|
+
data.tar.gz: f0a6110f5e1ae34026c3d6982a5f2e8c8f402849bd0a7805ed43f90a8b398cad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b8d1c93130d98de349183ffd888f21de3ea0023e0cd7372817dc7efa0606974c442b0c1bd1d10f946395deb62cac089a332a0fc7f35c13a662c6452147b736e
|
7
|
+
data.tar.gz: 15f764995f0baa99dca4da1e73a67c2079c4956f237f3975c3086f6f9678c212f10e6c40e8ae0d3d90ab4375463114c917708fd44ed1a058fe71239a61390254
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# [v0.2.0](https://github.com/Muriel-Salvan/curses_menu/compare/v0.1.0...v0.2.0) (2022-11-01 21:07:07)
|
2
|
+
|
3
|
+
### Features
|
4
|
+
|
5
|
+
* [[feature] [#6] Add lazy evaluation for actions](https://github.com/Muriel-Salvan/curses_menu/commit/0a5a96ae84fecdf982f763b833e8e863231dde73)
|
6
|
+
|
7
|
+
# [v0.1.0](https://github.com/Muriel-Salvan/curses_menu/compare/v0.0.6...v0.1.0) (2022-10-12 15:58:25)
|
8
|
+
|
9
|
+
### Features
|
10
|
+
|
11
|
+
* [[#5] [feature] Add possibility to render menu item titles in a lazy way](https://github.com/Muriel-Salvan/curses_menu/commit/6997c846f800d37441ea40bce109345e725ff12c)
|
12
|
+
|
1
13
|
# [v0.0.6](https://github.com/Muriel-Salvan/curses_menu/compare/v0.0.5...v0.0.6) (2022-10-12 15:48:18)
|
2
14
|
|
3
15
|
### Patches
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'curses_menu'
|
2
|
+
|
3
|
+
nbr_visible_items = Curses.stdscr.maxy - 5
|
4
|
+
CursesMenu.new 'Menu items using lazy rendering' do |menu|
|
5
|
+
(nbr_visible_items * 2).times do
|
6
|
+
menu.item "[Rendered at #{Time.now}] - I am a normal item"
|
7
|
+
menu.item(proc do
|
8
|
+
"[Rendered at #{Time.now}] - I am a lazy item"
|
9
|
+
end)
|
10
|
+
menu.item(
|
11
|
+
"[Rendered at #{Time.now}] - I am a normal item with lazy rendered action",
|
12
|
+
actions: proc do
|
13
|
+
{
|
14
|
+
'a' => {
|
15
|
+
name: "Action rendered at #{Time.now}",
|
16
|
+
execute: proc {}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
)
|
21
|
+
end
|
22
|
+
menu.item 'Refresh menu' do
|
23
|
+
:menu_refresh
|
24
|
+
end
|
25
|
+
end
|
data/lib/curses_menu/version.rb
CHANGED
data/lib/curses_menu.rb
CHANGED
@@ -55,9 +55,11 @@ class CursesMenu
|
|
55
55
|
# Display the menu
|
56
56
|
current_items[display_first_idx..display_first_idx + max_displayed_items - 1].each.with_index do |item_info, idx|
|
57
57
|
selected = display_first_idx + idx == selected_idx
|
58
|
+
# Keep a cache of titles as they can be loaded in a lazy way for performance
|
59
|
+
item_info[:title_cached] = item_info[:title].is_a?(Proc) ? item_info[:title].call : item_info[:title] unless item_info.key?(:title_cached)
|
58
60
|
print(
|
59
61
|
window,
|
60
|
-
item_info[:
|
62
|
+
item_info[:title_cached],
|
61
63
|
from: display_first_char_idx,
|
62
64
|
default_color_pair: item_info.key?(:actions) ? COLORS_MENU_ITEM : COLORS_LINE,
|
63
65
|
force_color_pair: selected ? COLORS_MENU_ITEM_SELECTED : nil,
|
@@ -72,9 +74,11 @@ class CursesMenu
|
|
72
74
|
'Arrows/Home/End' => 'Navigate',
|
73
75
|
'Esc' => 'Exit'
|
74
76
|
}
|
75
|
-
|
77
|
+
# Keep a cache of actions as they can be loaded in a lazy way for performance
|
78
|
+
current_items[selected_idx][:actions_cached] = current_items[selected_idx][:actions].is_a?(Proc) ? current_items[selected_idx][:actions].call : current_items[selected_idx][:actions] unless current_items[selected_idx].key?(:actions_cached)
|
79
|
+
if current_items[selected_idx][:actions_cached]
|
76
80
|
display_actions.merge!(
|
77
|
-
current_items[selected_idx][:
|
81
|
+
current_items[selected_idx][:actions_cached].to_h do |action_shortcut, action_info|
|
78
82
|
[
|
79
83
|
case action_shortcut
|
80
84
|
when KEY_ENTER
|
@@ -125,9 +129,11 @@ class CursesMenu
|
|
125
129
|
break
|
126
130
|
else
|
127
131
|
# Check actions
|
128
|
-
|
132
|
+
# Keep a cache of actions as they can be loaded in a lazy way for performance
|
133
|
+
current_items[selected_idx][:actions_cached] = current_items[selected_idx][:actions].is_a?(Proc) ? current_items[selected_idx][:actions].call : current_items[selected_idx][:actions] unless current_items[selected_idx].key?(:actions_cached)
|
134
|
+
if current_items[selected_idx][:actions_cached]&.key?(user_choice)
|
129
135
|
curses_menu_finalize
|
130
|
-
result = current_items[selected_idx][:
|
136
|
+
result = current_items[selected_idx][:actions_cached][user_choice][:execute].call
|
131
137
|
if result.is_a?(Symbol)
|
132
138
|
case result
|
133
139
|
when :menu_exit
|
@@ -159,10 +165,11 @@ class CursesMenu
|
|
159
165
|
# This method is meant to be called from a choose_from call.
|
160
166
|
#
|
161
167
|
# Parameters::
|
162
|
-
# * *title* (String or
|
163
|
-
# * *actions* (Hash<Object, Hash<Symbol,Object> >): Associated actions to this item, per shortcut [default: {}]
|
168
|
+
# * *title* (String, CursesRow or Proc): Text to be displayed for this item, or Proc returning this text when needed (lazy loading)
|
169
|
+
# * *actions* (Hash<Object, Hash<Symbol,Object> > or Proc): Associated actions to this item, per shortcut, or Proc returning those actions when needed (lazy loading) [default: {}]
|
164
170
|
# * *name* (String): Name of this action (displayed at the bottom of the menu)
|
165
171
|
# * *execute* (Proc): Code called when this action is selected
|
172
|
+
# In case of lazy loading (with a Proc), the title Proc will always be called first.
|
166
173
|
# * *&action* (Proc): Code called if the item is selected (action for the enter key) [optional].
|
167
174
|
# * Result::
|
168
175
|
# * Symbol or Object: If the code returns a symbol, the menu will behave in a specific way:
|
@@ -170,8 +177,21 @@ class CursesMenu
|
|
170
177
|
# * *menu_refresh*: The menu will compute again its items.
|
171
178
|
def item(title, actions: {}, &action)
|
172
179
|
menu_item_def = { title: title }
|
173
|
-
all_actions =
|
174
|
-
|
180
|
+
all_actions =
|
181
|
+
if action.nil?
|
182
|
+
actions
|
183
|
+
else
|
184
|
+
mapped_default_action = { KEY_ENTER => { name: 'Select', execute: action } }
|
185
|
+
if actions.is_a?(Proc)
|
186
|
+
# Make sure we keep the lazyness
|
187
|
+
proc do
|
188
|
+
actions.call.merge(mapped_default_action)
|
189
|
+
end
|
190
|
+
else
|
191
|
+
actions.merge(mapped_default_action)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
menu_item_def[:actions] = all_actions if all_actions.is_a?(Proc) || !all_actions.empty?
|
175
195
|
@current_menu_items << menu_item_def
|
176
196
|
end
|
177
197
|
|
@@ -0,0 +1,383 @@
|
|
1
|
+
describe CursesMenu do
|
2
|
+
|
3
|
+
it 'displays a menu with 1 item with lazy rendering' do
|
4
|
+
render_called = false
|
5
|
+
test_menu do |menu|
|
6
|
+
menu.item(proc do
|
7
|
+
render_called = true
|
8
|
+
'Menu item lazy'
|
9
|
+
end)
|
10
|
+
end
|
11
|
+
expect(render_called).to be true
|
12
|
+
assert_line 3, 'Menu item lazy'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'displays a menu with 1 item in a CursesRow with lazy rendering' do
|
16
|
+
render_called = false
|
17
|
+
test_menu do |menu|
|
18
|
+
menu.item(proc do
|
19
|
+
render_called = true
|
20
|
+
CursesMenu::CursesRow.new({ cell: { text: 'Menu item lazy' } })
|
21
|
+
end)
|
22
|
+
end
|
23
|
+
expect(render_called).to be true
|
24
|
+
assert_line 3, 'Menu item lazy'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'displays menu actions with lazy evaluation' do
|
28
|
+
render_called = false
|
29
|
+
action_executed = false
|
30
|
+
test_menu(keys: ['a']) do |menu|
|
31
|
+
menu.item('Menu item lazy', actions: proc do
|
32
|
+
render_called = true
|
33
|
+
{
|
34
|
+
'a' => {
|
35
|
+
name: 'Lazy action',
|
36
|
+
execute: proc do
|
37
|
+
action_executed = true
|
38
|
+
end
|
39
|
+
}
|
40
|
+
}
|
41
|
+
end)
|
42
|
+
end
|
43
|
+
assert_line 3, 'Menu item lazy'
|
44
|
+
assert_line(-1, '= Arrows/Home/End: Navigate | Esc: Exit | a: Lazy action')
|
45
|
+
expect(render_called).to be true
|
46
|
+
expect(action_executed).to be true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'displays menu actions with lazy evaluation and a default action' do
|
50
|
+
render_called = false
|
51
|
+
action_executed = false
|
52
|
+
default_executed = false
|
53
|
+
test_menu(keys: ['a', CursesMenu::KEY_ENTER]) do |menu|
|
54
|
+
menu.item(
|
55
|
+
'Menu item lazy',
|
56
|
+
actions: proc do
|
57
|
+
render_called = true
|
58
|
+
{
|
59
|
+
'a' => {
|
60
|
+
name: 'Lazy action',
|
61
|
+
execute: proc do
|
62
|
+
action_executed = true
|
63
|
+
end
|
64
|
+
}
|
65
|
+
}
|
66
|
+
end
|
67
|
+
) do
|
68
|
+
default_executed = true
|
69
|
+
end
|
70
|
+
end
|
71
|
+
assert_line 3, 'Menu item lazy'
|
72
|
+
assert_line(-1, '= Arrows/Home/End: Navigate | Enter: Select | Esc: Exit | a: Lazy action')
|
73
|
+
expect(render_called).to be true
|
74
|
+
expect(action_executed).to be true
|
75
|
+
expect(default_executed).to be true
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'doesn\'t lazy render when the item is not displayed' do
|
79
|
+
nbr_visible_items = Curses.stdscr.maxy - 5
|
80
|
+
render_called = false
|
81
|
+
test_menu do |menu|
|
82
|
+
(nbr_visible_items * 2).times do |idx|
|
83
|
+
menu.item "Menu item #{idx}"
|
84
|
+
end
|
85
|
+
menu.item(proc do
|
86
|
+
render_called = true
|
87
|
+
'Menu item lazy'
|
88
|
+
end)
|
89
|
+
end
|
90
|
+
expect(render_called).to be false
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'doesn\'t lazy evaluate actions when the item is not displayed' do
|
94
|
+
nbr_visible_items = Curses.stdscr.maxy - 5
|
95
|
+
render_called = false
|
96
|
+
test_menu do |menu|
|
97
|
+
(nbr_visible_items * 2).times do |idx|
|
98
|
+
menu.item "Menu item #{idx}"
|
99
|
+
end
|
100
|
+
menu.item('Menu item lazy', actions: proc do
|
101
|
+
render_called = true
|
102
|
+
{
|
103
|
+
'a' => {
|
104
|
+
name: 'Lazy action',
|
105
|
+
execute: proc {}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
end)
|
109
|
+
end
|
110
|
+
expect(render_called).to be false
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'doesn\'t lazy evaluate actions when the item is not selected' do
|
114
|
+
render_called = false
|
115
|
+
test_menu do |menu|
|
116
|
+
menu.item 'Menu item'
|
117
|
+
menu.item('Menu item lazy', actions: proc do
|
118
|
+
render_called = true
|
119
|
+
{
|
120
|
+
'a' => {
|
121
|
+
name: 'Lazy action',
|
122
|
+
execute: proc {}
|
123
|
+
}
|
124
|
+
}
|
125
|
+
end)
|
126
|
+
end
|
127
|
+
expect(render_called).to be false
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'lazy evaluates actions as soon as the item is selected' do
|
131
|
+
render_called = false
|
132
|
+
test_menu(keys: [Curses::KEY_DOWN]) do |menu|
|
133
|
+
menu.item 'Menu item'
|
134
|
+
menu.item('Menu item lazy', actions: proc do
|
135
|
+
render_called = true
|
136
|
+
{
|
137
|
+
'a' => {
|
138
|
+
name: 'Lazy action',
|
139
|
+
execute: proc {}
|
140
|
+
}
|
141
|
+
}
|
142
|
+
end)
|
143
|
+
end
|
144
|
+
expect(render_called).to be true
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'keeps lazy rendered titles in a cache while navigating' do
|
148
|
+
nbr_renders = 0
|
149
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_DOWN, Curses::KEY_DOWN]) do |menu|
|
150
|
+
menu.item 'Menu item 1'
|
151
|
+
menu.item(proc do
|
152
|
+
nbr_renders += 1
|
153
|
+
'Menu item 2 Lazy'
|
154
|
+
end)
|
155
|
+
menu.item 'Menu item 3'
|
156
|
+
menu.item 'Menu item 4', actions: { 'a' => { name: 'Special action', execute: proc {} } }
|
157
|
+
end
|
158
|
+
expect(nbr_renders).to eq 1
|
159
|
+
assert_line(-1, '= Arrows/Home/End: Navigate | Esc: Exit | a: Special action')
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'keeps lazy evaluated actions in a cache while navigating' do
|
163
|
+
nbr_renders = 0
|
164
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_DOWN, Curses::KEY_DOWN]) do |menu|
|
165
|
+
menu.item 'Menu item 1'
|
166
|
+
menu.item('Menu item 2 lazy', actions: proc do
|
167
|
+
nbr_renders += 1
|
168
|
+
{
|
169
|
+
'a' => {
|
170
|
+
name: 'Lazy action',
|
171
|
+
execute: proc {}
|
172
|
+
}
|
173
|
+
}
|
174
|
+
end)
|
175
|
+
menu.item 'Menu item 3'
|
176
|
+
menu.item 'Menu item 4', actions: { 'a' => { name: 'Special action', execute: proc {} } }
|
177
|
+
end
|
178
|
+
expect(nbr_renders).to eq 1
|
179
|
+
assert_line(-1, '= Arrows/Home/End: Navigate | Esc: Exit | a: Special action')
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'keeps lazy rendered titles in a cache while navigating across pages' do
|
183
|
+
nbr_renders = 0
|
184
|
+
nbr_visible_items = Curses.stdscr.maxy - 5
|
185
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_DOWN, Curses::KEY_END, Curses::KEY_HOME, Curses::KEY_END, Curses::KEY_HOME, Curses::KEY_END]) do |menu|
|
186
|
+
(nbr_visible_items * 2).times do |idx|
|
187
|
+
menu.item "Menu item #{idx}"
|
188
|
+
end
|
189
|
+
menu.item(proc do
|
190
|
+
nbr_renders += 1
|
191
|
+
'Menu item Lazy'
|
192
|
+
end)
|
193
|
+
end
|
194
|
+
expect(nbr_renders).to eq 1
|
195
|
+
assert_line(-3, 'Menu item Lazy')
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'keeps lazy evaluated actions in a cache while navigating across pages' do
|
199
|
+
nbr_renders = 0
|
200
|
+
nbr_visible_items = Curses.stdscr.maxy - 5
|
201
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_DOWN, Curses::KEY_END, Curses::KEY_HOME, Curses::KEY_END, Curses::KEY_HOME, Curses::KEY_END]) do |menu|
|
202
|
+
(nbr_visible_items * 2).times do |idx|
|
203
|
+
menu.item "Menu item #{idx}"
|
204
|
+
end
|
205
|
+
menu.item('Menu item lazy', actions: proc do
|
206
|
+
nbr_renders += 1
|
207
|
+
{
|
208
|
+
'a' => {
|
209
|
+
name: 'Lazy action',
|
210
|
+
execute: proc {}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
end)
|
214
|
+
end
|
215
|
+
expect(nbr_renders).to eq 1
|
216
|
+
assert_line(-1, '= Arrows/Home/End: Navigate | Esc: Exit | a: Lazy action')
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'refreshes lazy rendered titles between menu refreshes' do
|
220
|
+
nbr_renders = 0
|
221
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_UP, CursesMenu::KEY_ENTER, Curses::KEY_DOWN, Curses::KEY_UP]) do |menu|
|
222
|
+
menu.item 'Menu item Refresh' do
|
223
|
+
:menu_refresh
|
224
|
+
end
|
225
|
+
menu.item(proc do
|
226
|
+
nbr_renders += 1
|
227
|
+
'Menu item Lazy'
|
228
|
+
end)
|
229
|
+
end
|
230
|
+
expect(nbr_renders).to eq 2
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'refreshes lazy evaluated actions between menu refreshes' do
|
234
|
+
nbr_renders = 0
|
235
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_UP, CursesMenu::KEY_ENTER, Curses::KEY_DOWN, Curses::KEY_UP]) do |menu|
|
236
|
+
menu.item 'Menu item Refresh' do
|
237
|
+
:menu_refresh
|
238
|
+
end
|
239
|
+
menu.item('Menu item lazy', actions: proc do
|
240
|
+
nbr_renders += 1
|
241
|
+
{
|
242
|
+
'a' => {
|
243
|
+
name: 'Lazy action',
|
244
|
+
execute: proc {}
|
245
|
+
}
|
246
|
+
}
|
247
|
+
end)
|
248
|
+
end
|
249
|
+
expect(nbr_renders).to eq 2
|
250
|
+
end
|
251
|
+
|
252
|
+
it 'does not refresh lazy rendered titles when executing actions' do
|
253
|
+
nbr_renders = 0
|
254
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_UP, CursesMenu::KEY_ENTER, Curses::KEY_DOWN, Curses::KEY_UP]) do |menu|
|
255
|
+
menu.item 'Menu item' do
|
256
|
+
# Do nothing
|
257
|
+
end
|
258
|
+
menu.item(proc do
|
259
|
+
nbr_renders += 1
|
260
|
+
'Menu item Lazy'
|
261
|
+
end)
|
262
|
+
end
|
263
|
+
expect(nbr_renders).to eq 1
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'does not refresh lazy evaluated actions when executing actions' do
|
267
|
+
nbr_renders = 0
|
268
|
+
test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_UP, CursesMenu::KEY_ENTER, Curses::KEY_DOWN, Curses::KEY_UP]) do |menu|
|
269
|
+
menu.item 'Menu item' do
|
270
|
+
# Do nothing
|
271
|
+
end
|
272
|
+
menu.item('Menu item lazy', actions: proc do
|
273
|
+
nbr_renders += 1
|
274
|
+
{
|
275
|
+
'a' => {
|
276
|
+
name: 'Lazy action',
|
277
|
+
execute: proc {}
|
278
|
+
}
|
279
|
+
}
|
280
|
+
end)
|
281
|
+
end
|
282
|
+
expect(nbr_renders).to eq 1
|
283
|
+
end
|
284
|
+
|
285
|
+
it 'does not refresh lazy rendered titles when getting into sub-menus' do
|
286
|
+
nbr_renders = 0
|
287
|
+
test_menu(
|
288
|
+
keys: [
|
289
|
+
# Enter sub-menu
|
290
|
+
CursesMenu::KEY_ENTER,
|
291
|
+
Curses::KEY_DOWN,
|
292
|
+
# Back to first menu
|
293
|
+
CursesMenu::KEY_ESCAPE,
|
294
|
+
Curses::KEY_DOWN
|
295
|
+
]
|
296
|
+
) do |menu, key_presses|
|
297
|
+
menu.item 'Sub-menu' do
|
298
|
+
described_class.new('Sub-menu title', key_presses: key_presses) do |sub_menu|
|
299
|
+
sub_menu.item 'Sub-menu item 1'
|
300
|
+
sub_menu.item 'Sub-menu item 2'
|
301
|
+
end
|
302
|
+
end
|
303
|
+
menu.item(proc do
|
304
|
+
nbr_renders += 1
|
305
|
+
'Menu item Lazy'
|
306
|
+
end)
|
307
|
+
end
|
308
|
+
expect(nbr_renders).to eq 1
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'does not refresh lazy evaluated actions when getting into sub-menus' do
|
312
|
+
nbr_renders = 0
|
313
|
+
test_menu(
|
314
|
+
keys: [
|
315
|
+
# Enter sub-menu
|
316
|
+
CursesMenu::KEY_ENTER,
|
317
|
+
Curses::KEY_DOWN,
|
318
|
+
# Back to first menu
|
319
|
+
CursesMenu::KEY_ESCAPE,
|
320
|
+
Curses::KEY_DOWN
|
321
|
+
]
|
322
|
+
) do |menu, key_presses|
|
323
|
+
menu.item 'Sub-menu' do
|
324
|
+
described_class.new('Sub-menu title', key_presses: key_presses) do |sub_menu|
|
325
|
+
sub_menu.item 'Sub-menu item 1'
|
326
|
+
sub_menu.item 'Sub-menu item 2'
|
327
|
+
end
|
328
|
+
end
|
329
|
+
menu.item('Menu item lazy', actions: proc do
|
330
|
+
nbr_renders += 1
|
331
|
+
{
|
332
|
+
'a' => {
|
333
|
+
name: 'Lazy action',
|
334
|
+
execute: proc {}
|
335
|
+
}
|
336
|
+
}
|
337
|
+
end)
|
338
|
+
end
|
339
|
+
expect(nbr_renders).to eq 1
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'always lazy renders titles before lazy evaluating actions' do
|
343
|
+
lazy_renders = []
|
344
|
+
nbr_visible_items = Curses.stdscr.maxy - 5
|
345
|
+
test_menu(keys: [Curses::KEY_END, Curses::KEY_HOME, Curses::KEY_DOWN]) do |menu|
|
346
|
+
menu.item(
|
347
|
+
proc do
|
348
|
+
lazy_renders << :item_1_title
|
349
|
+
'Menu item 1 lazy'
|
350
|
+
end,
|
351
|
+
actions: proc do
|
352
|
+
lazy_renders << :item_1_action
|
353
|
+
{ 'a' => { name: 'Lazy action 1', execute: proc {} } }
|
354
|
+
end
|
355
|
+
)
|
356
|
+
menu.item(
|
357
|
+
proc do
|
358
|
+
lazy_renders << :item_2_title
|
359
|
+
'Menu item 2 lazy'
|
360
|
+
end,
|
361
|
+
actions: proc do
|
362
|
+
lazy_renders << :item_2_action
|
363
|
+
{ 'a' => { name: 'Lazy action 2', execute: proc {} } }
|
364
|
+
end
|
365
|
+
)
|
366
|
+
(nbr_visible_items * 2).times do |idx|
|
367
|
+
menu.item "Menu item #{idx}"
|
368
|
+
end
|
369
|
+
menu.item(
|
370
|
+
proc do
|
371
|
+
lazy_renders << :item_3_title
|
372
|
+
'Menu item 3 lazy'
|
373
|
+
end,
|
374
|
+
actions: proc do
|
375
|
+
lazy_renders << :item_3_action
|
376
|
+
{ 'a' => { name: 'Lazy action 3', execute: proc {} } }
|
377
|
+
end
|
378
|
+
)
|
379
|
+
end
|
380
|
+
expect(lazy_renders).to eq %i[item_1_title item_2_title item_1_action item_3_title item_3_action item_2_action]
|
381
|
+
end
|
382
|
+
|
383
|
+
end
|
@@ -9,6 +9,16 @@ describe CursesMenu do
|
|
9
9
|
assert_line(-1, '= Arrows/Home/End: Navigate | Esc: Exit')
|
10
10
|
end
|
11
11
|
|
12
|
+
it 'displays a menu with 1 item having a default action' do
|
13
|
+
test_menu(title: 'Menu title') do |menu|
|
14
|
+
menu.item 'Menu item' do
|
15
|
+
# Do nothing
|
16
|
+
end
|
17
|
+
end
|
18
|
+
assert_line 3, 'Menu item'
|
19
|
+
assert_line(-1, '= Arrows/Home/End: Navigate | Enter: Select | Esc: Exit')
|
20
|
+
end
|
21
|
+
|
12
22
|
it 'displays a menu with several items' do
|
13
23
|
test_menu do |menu|
|
14
24
|
menu.item 'Menu item 1'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curses_menu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Muriel Salvan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: curses
|
@@ -93,6 +93,7 @@ extra_rdoc_files:
|
|
93
93
|
- examples/automatic_key_presses.rb
|
94
94
|
- examples/formatting.rb
|
95
95
|
- examples/hello.rb
|
96
|
+
- examples/lazy_menu_items.rb
|
96
97
|
- examples/refresh.rb
|
97
98
|
- examples/scrolling.rb
|
98
99
|
- examples/several_items.rb
|
@@ -106,6 +107,7 @@ files:
|
|
106
107
|
- examples/automatic_key_presses.rb
|
107
108
|
- examples/formatting.rb
|
108
109
|
- examples/hello.rb
|
110
|
+
- examples/lazy_menu_items.rb
|
109
111
|
- examples/refresh.rb
|
110
112
|
- examples/scrolling.rb
|
111
113
|
- examples/several_items.rb
|
@@ -117,6 +119,7 @@ files:
|
|
117
119
|
- spec/curses_menu_test.rb
|
118
120
|
- spec/curses_menu_test/actions_spec.rb
|
119
121
|
- spec/curses_menu_test/formatting_spec.rb
|
122
|
+
- spec/curses_menu_test/lazy_spec.rb
|
120
123
|
- spec/curses_menu_test/rubocop_spec.rb
|
121
124
|
- spec/curses_menu_test/scrolling_spec.rb
|
122
125
|
- spec/curses_menu_test/simple_navigation_spec.rb
|