curses_menu 0.0.5 → 0.1.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 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