curses_menu 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d07858a5e2aad9b9633584a1e0b2c06b9a13ad5b69752ef7b4808ed614e7a889
4
- data.tar.gz: 65f6f0b04deea7b529d136fe6fa3fea72fcfc98cfc0fc8d651863814a4bde162
3
+ metadata.gz: 8dc4a9d14a6f315f6e2fba464d40d58d7a17922ee9afe1aabc1c045a4731a561
4
+ data.tar.gz: fde73b88bf3972e2b4353911dea6278cd606a2a8e673feeab8dff41a87a0f3e8
5
5
  SHA512:
6
- metadata.gz: f322978d91a509bf1696d1da056f65a7dc097bf65e61ebf46194c1bc555dad59caadadd8cca9f2c5b8bf4aea87a0d086a22555b8084e06c6a15c56c5a9ccd3f3
7
- data.tar.gz: 744ed073c7e764068f3b97a528255371b70dedd99c1d164e4cc2f8981069dfd8e1ec5c606df74f3b4df00c232d3995cd31037c53401fc7bc092b1e6313da596a
6
+ metadata.gz: 6f9e782b2d1264e4b8b2e3b5f721574ba62abb20935a6d61fe6a70647d73386da9fc6c429689f35de3463f2d6aa6ce5d799fe8d17793b05a5621a27128bb3456
7
+ data.tar.gz: c39295fce31482e5f3dd91f2a0de36658912c4fd0d6da3d7a18d0ae55671b74dd5d13e6b74037c96b57993716776697f3b5cb01e5da484b660dc459cd2fe9d1a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # [v0.1.0](https://github.com/Muriel-Salvan/curses_menu/compare/v0.0.6...v0.1.0) (2022-10-12 15:58:25)
2
+
3
+ ### Features
4
+
5
+ * [[#5] [feature] Add possibility to render menu item titles in a lazy way](https://github.com/Muriel-Salvan/curses_menu/commit/6997c846f800d37441ea40bce109345e725ff12c)
6
+
7
+ # [v0.0.6](https://github.com/Muriel-Salvan/curses_menu/compare/v0.0.5...v0.0.6) (2022-10-12 15:48:18)
8
+
9
+ ### Patches
10
+
11
+ * [Bump versions](https://github.com/Muriel-Salvan/curses_menu/commit/ec272ce612c45a127f90613f3133e0186eab8e22)
12
+
1
13
  # [v0.0.5](https://github.com/Muriel-Salvan/curses_menu/compare/v0.0.4...v0.0.5) (2021-08-18 11:48:24)
2
14
 
3
15
  ### Patches
@@ -0,0 +1,14 @@
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 "I am a normal item, rendered at #{Time.now}"
7
+ menu.item(proc do
8
+ "I am a lazy item, rendered at #{Time.now}"
9
+ end)
10
+ end
11
+ menu.item 'Refresh menu' do
12
+ :menu_refresh
13
+ end
14
+ end
@@ -1,5 +1,5 @@
1
1
  class CursesMenu
2
2
 
3
- VERSION = '0.0.5'
3
+ VERSION = '0.1.0'
4
4
 
5
5
  end
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[:title],
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,
@@ -74,7 +76,7 @@ class CursesMenu
74
76
  }
75
77
  if current_items[selected_idx][:actions]
76
78
  display_actions.merge!(
77
- current_items[selected_idx][:actions].map do |action_shortcut, action_info|
79
+ current_items[selected_idx][:actions].to_h do |action_shortcut, action_info|
78
80
  [
79
81
  case action_shortcut
80
82
  when KEY_ENTER
@@ -84,7 +86,7 @@ class CursesMenu
84
86
  end,
85
87
  action_info[:name]
86
88
  ]
87
- end.to_h
89
+ end
88
90
  )
89
91
  end
90
92
  print(
@@ -159,7 +161,7 @@ class CursesMenu
159
161
  # This method is meant to be called from a choose_from call.
160
162
  #
161
163
  # Parameters::
162
- # * *title* (String or CursesRow): Text to be displayed for this item
164
+ # * *title* (String, CursesRow or Proc): Text to be displayed for this item, or Proc returning this text when needed (lazy loading)
163
165
  # * *actions* (Hash<Object, Hash<Symbol,Object> >): Associated actions to this item, per shortcut [default: {}]
164
166
  # * *name* (String): Name of this action (displayed at the bottom of the menu)
165
167
  # * *execute* (Proc): Code called when this action is selected
@@ -7,7 +7,7 @@ describe CursesMenu do
7
7
  actioned = true
8
8
  end
9
9
  end
10
- expect(actioned).to eq(true)
10
+ expect(actioned).to be(true)
11
11
  end
12
12
 
13
13
  it 'actions the default selection when pressed enter on the correct item' do
@@ -115,7 +115,7 @@ describe CursesMenu do
115
115
  :menu_exit
116
116
  end
117
117
  end
118
- expect(quit).to eq(true)
118
+ expect(quit).to be(true)
119
119
  end
120
120
 
121
121
  it 'navigates in sub-menus' do
@@ -15,9 +15,7 @@ describe CursesMenu do
15
15
  # This test is pending a better support for UTF-8.
16
16
  # cf https://github.com/ruby/curses/issues/65
17
17
  # TODO: Uncomment when Ruby curses will be fixed.
18
- # rubocop:disable Style/AsciiComments
19
18
  # assert_line 3, 'Simple string - 単純な文字列'
20
- # rubocop:enable Style/AsciiComments
21
19
  assert_line 3, /^Simple string - .+$/
22
20
  end
23
21
 
@@ -245,7 +243,7 @@ describe CursesMenu do
245
243
 
246
244
  it 'does not exceed line when several cells are too long' do
247
245
  nbr_visible_chars = Curses.stdscr.maxx
248
- nbr_chars_per_cell = nbr_visible_chars / 3 + 1
246
+ nbr_chars_per_cell = (nbr_visible_chars / 3) + 1
249
247
  test_menu do |menu|
250
248
  menu.item CursesMenu::CursesRow.new(
251
249
  {
@@ -257,13 +255,13 @@ describe CursesMenu do
257
255
  )
258
256
  menu.item 'Menu item 2'
259
257
  end
260
- assert_line 3, "#{'1' * nbr_chars_per_cell} #{'2' * nbr_chars_per_cell} #{'3' * (nbr_visible_chars - 2 * nbr_chars_per_cell - 3)}"
258
+ assert_line 3, "#{'1' * nbr_chars_per_cell} #{'2' * nbr_chars_per_cell} #{'3' * (nbr_visible_chars - (2 * nbr_chars_per_cell) - 3)}"
261
259
  assert_line 4, 'Menu item 2'
262
260
  end
263
261
 
264
262
  it 'does not exceed line when several cells are too long due to separators' do
265
263
  nbr_visible_chars = Curses.stdscr.maxx
266
- nbr_chars_per_cell = nbr_visible_chars / 3 + 1
264
+ nbr_chars_per_cell = (nbr_visible_chars / 3) + 1
267
265
  test_menu do |menu|
268
266
  menu.item CursesMenu::CursesRow.new(
269
267
  {
@@ -274,7 +272,7 @@ describe CursesMenu do
274
272
  )
275
273
  menu.item 'Menu item 2'
276
274
  end
277
- assert_line 3, "#{'1' * nbr_chars_per_cell}#{'2' * nbr_chars_per_cell}#{'3' * (nbr_visible_chars - 2 * nbr_chars_per_cell - 1)}"
275
+ assert_line 3, "#{'1' * nbr_chars_per_cell}#{'2' * nbr_chars_per_cell}#{'3' * (nbr_visible_chars - (2 * nbr_chars_per_cell) - 1)}"
278
276
  assert_line 4, 'Menu item 2'
279
277
  end
280
278
 
@@ -0,0 +1,127 @@
1
+ describe CursesMenu do
2
+
3
+ it 'displays a menu with 1 item with lazy rendering' do
4
+ render_called = false
5
+ test_menu(title: 'Menu title') 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(title: 'Menu title') 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 'doesn\'t lazy render when the item is not displayed' do
28
+ nbr_visible_items = Curses.stdscr.maxy - 5
29
+ render_called = false
30
+ test_menu(title: 'Menu title') do |menu|
31
+ (nbr_visible_items * 2).times do |idx|
32
+ menu.item "Menu item #{idx}"
33
+ end
34
+ menu.item(proc do
35
+ render_called = true
36
+ 'Menu item lazy'
37
+ end)
38
+ end
39
+ expect(render_called).to be false
40
+ end
41
+
42
+ it 'keeps lazy rendered titles in a cache while navigating' do
43
+ nbr_renders = 0
44
+ test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_DOWN, Curses::KEY_DOWN]) do |menu|
45
+ menu.item 'Menu item 1'
46
+ menu.item(proc do
47
+ nbr_renders += 1
48
+ 'Menu item 2 Lazy'
49
+ end)
50
+ menu.item 'Menu item 3'
51
+ menu.item 'Menu item 4', actions: { 'a' => { name: 'Special action', execute: proc {} } }
52
+ end
53
+ expect(nbr_renders).to eq 1
54
+ assert_line(-1, '= Arrows/Home/End: Navigate | Esc: Exit | a: Special action')
55
+ end
56
+
57
+ it 'keeps lazy rendered titles in a cache while navigating across pages' do
58
+ nbr_renders = 0
59
+ nbr_visible_items = Curses.stdscr.maxy - 5
60
+ 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|
61
+ (nbr_visible_items * 2).times do |idx|
62
+ menu.item "Menu item #{idx}"
63
+ end
64
+ menu.item(proc do
65
+ nbr_renders += 1
66
+ 'Menu item Lazy'
67
+ end)
68
+ end
69
+ expect(nbr_renders).to eq 1
70
+ assert_line(-3, 'Menu item Lazy')
71
+ end
72
+
73
+ it 'refreshes lazy rendered titles between menu refreshes' do
74
+ nbr_renders = 0
75
+ test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_UP, CursesMenu::KEY_ENTER, Curses::KEY_DOWN, Curses::KEY_UP]) do |menu|
76
+ menu.item 'Menu item Refresh' do
77
+ :menu_refresh
78
+ end
79
+ menu.item(proc do
80
+ nbr_renders += 1
81
+ 'Menu item Lazy'
82
+ end)
83
+ end
84
+ expect(nbr_renders).to eq 2
85
+ end
86
+
87
+ it 'does not refresh lazy rendered titles when executing actions' do
88
+ nbr_renders = 0
89
+ test_menu(keys: [Curses::KEY_DOWN, Curses::KEY_UP, CursesMenu::KEY_ENTER, Curses::KEY_DOWN, Curses::KEY_UP]) do |menu|
90
+ menu.item 'Menu item' do
91
+ # Do nothing
92
+ end
93
+ menu.item(proc do
94
+ nbr_renders += 1
95
+ 'Menu item Lazy'
96
+ end)
97
+ end
98
+ expect(nbr_renders).to eq 1
99
+ end
100
+
101
+ it 'does not refresh lazy rendered titles when getting into sub-menus' do
102
+ nbr_renders = 0
103
+ test_menu(
104
+ keys: [
105
+ # Enter sub-menu
106
+ CursesMenu::KEY_ENTER,
107
+ Curses::KEY_DOWN,
108
+ # Back to first menu
109
+ CursesMenu::KEY_ESCAPE,
110
+ Curses::KEY_DOWN
111
+ ]
112
+ ) do |menu, key_presses|
113
+ menu.item 'Sub-menu' do
114
+ described_class.new('Sub-menu title', key_presses: key_presses) do |sub_menu|
115
+ sub_menu.item 'Sub-menu item 1'
116
+ sub_menu.item 'Sub-menu item 2'
117
+ end
118
+ end
119
+ menu.item(proc do
120
+ nbr_renders += 1
121
+ 'Menu item Lazy'
122
+ end)
123
+ end
124
+ expect(nbr_renders).to eq 1
125
+ end
126
+
127
+ end
@@ -45,7 +45,7 @@ describe CursesMenu do
45
45
  end
46
46
  end
47
47
  assert_line 3, "Menu item #{nbr_visible_items - 2}"
48
- assert_line(-3, "Menu item #{2 * nbr_visible_items - 3}")
48
+ assert_line(-3, "Menu item #{(2 * nbr_visible_items) - 3}")
49
49
  end
50
50
 
51
51
  it 'scrolls by using page down key' do
@@ -56,7 +56,7 @@ describe CursesMenu do
56
56
  end
57
57
  end
58
58
  assert_line 3, "Menu item #{nbr_visible_items - 1}"
59
- assert_line(-3, "Menu item #{nbr_visible_items * 2 - 2}")
59
+ assert_line(-3, "Menu item #{(nbr_visible_items * 2) - 2}")
60
60
  end
61
61
 
62
62
  it 'scrolls by using page up key' do
@@ -78,7 +78,7 @@ describe CursesMenu do
78
78
  end
79
79
  end
80
80
  assert_line 3, "Menu item #{nbr_visible_items}"
81
- assert_line(-3, "Menu item #{nbr_visible_items * 2 - 1}")
81
+ assert_line(-3, "Menu item #{(nbr_visible_items * 2) - 1}")
82
82
  end
83
83
 
84
84
  it 'scrolls by using home key' do
@@ -36,7 +36,7 @@ module CursesMenuTest
36
36
  window.setpos old_y, old_x
37
37
  # Build the map of colors per color pair acutally registered
38
38
  colors_left_shift = Curses::A_COLOR.to_s(2).match(/^1+(0+)$/)[1].size
39
- color_pairs = CursesMenu.constants.select { |const| const.to_s.start_with?('COLORS_') }.map do |const|
39
+ color_pairs = CursesMenu.constants.select { |const| const.to_s.start_with?('COLORS_') }.to_h do |const|
40
40
  color_pair = CursesMenu.const_get(const)
41
41
  [
42
42
  # On Windows using Curses.color_pair can result in bugs [BUG] Unnormalized Fixnum value when using/displaying the value.
@@ -46,7 +46,7 @@ module CursesMenuTest
46
46
  color_pair << colors_left_shift,
47
47
  const
48
48
  ]
49
- end.to_h
49
+ end
50
50
  chars.
51
51
  map do |chr|
52
52
  {
@@ -57,7 +57,7 @@ module CursesMenuTest
57
57
  # In this case we just force an ASCII version of it.
58
58
  (chr & 255).chr(Encoding::UTF_8)
59
59
  end,
60
- color: color_pairs[chr & Curses::A_COLOR] || chr & Curses::A_COLOR,
60
+ color: color_pairs[chr & Curses::A_COLOR] || (chr & Curses::A_COLOR),
61
61
  attributes: chr & Curses::A_ATTRIBUTES
62
62
  }
63
63
  end.
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.5
4
+ version: 0.1.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: 2021-08-18 00:00:00.000000000 Z
11
+ date: 2022-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: curses
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.10'
33
+ version: '3.11'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.10'
40
+ version: '3.11'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: sem_ver_components
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,28 +58,28 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.19'
61
+ version: '1.36'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.19'
68
+ version: '1.36'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubocop-rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '2.4'
75
+ version: '2.13'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '2.4'
82
+ version: '2.13'
83
83
  description:
84
84
  email:
85
85
  - muriel@x-aeon.com
@@ -87,17 +87,18 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files:
89
89
  - CHANGELOG.md
90
- - README.md
91
90
  - LICENSE.md
92
- - examples/utf_8.rb
93
- - examples/hello.rb
94
- - examples/sub_menus.rb
91
+ - README.md
92
+ - examples/actions.rb
95
93
  - examples/automatic_key_presses.rb
96
- - examples/refresh.rb
97
94
  - examples/formatting.rb
98
- - examples/several_items.rb
99
- - examples/actions.rb
95
+ - examples/hello.rb
96
+ - examples/lazy_menu_items.rb
97
+ - examples/refresh.rb
100
98
  - examples/scrolling.rb
99
+ - examples/several_items.rb
100
+ - examples/sub_menus.rb
101
+ - examples/utf_8.rb
101
102
  files:
102
103
  - CHANGELOG.md
103
104
  - LICENSE.md
@@ -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
@@ -126,6 +129,7 @@ licenses:
126
129
  - BSD-3-Clause
127
130
  metadata:
128
131
  homepage_uri: https://github.com/Muriel-Salvan/curses_menu
132
+ rubygems_mfa_required: 'true'
129
133
  post_install_message:
130
134
  rdoc_options: []
131
135
  require_paths:
@@ -141,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
145
  - !ruby/object:Gem::Version
142
146
  version: '0'
143
147
  requirements: []
144
- rubygems_version: 3.1.6
148
+ rubygems_version: 3.3.7
145
149
  signing_key:
146
150
  specification_version: 4
147
151
  summary: Simple menu offering choices with navigation keys using curses