tty-prompt 0.18.1 → 0.23.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +95 -0
  3. data/README.md +598 -256
  4. data/lib/tty-prompt.rb +1 -2
  5. data/lib/tty/prompt.rb +192 -144
  6. data/lib/tty/prompt/answers_collector.rb +5 -5
  7. data/lib/tty/prompt/{enum_paginator.rb → block_paginator.rb} +20 -19
  8. data/lib/tty/prompt/choice.rb +9 -10
  9. data/lib/tty/prompt/choices.rb +30 -12
  10. data/lib/tty/prompt/confirm_question.rb +42 -16
  11. data/lib/tty/prompt/const.rb +17 -0
  12. data/lib/tty/prompt/converter_dsl.rb +6 -7
  13. data/lib/tty/prompt/converter_registry.rb +31 -26
  14. data/lib/tty/prompt/converters.rb +139 -32
  15. data/lib/tty/prompt/enum_list.rb +81 -26
  16. data/lib/tty/prompt/errors.rb +31 -0
  17. data/lib/tty/prompt/evaluator.rb +2 -2
  18. data/lib/tty/prompt/expander.rb +45 -15
  19. data/lib/tty/prompt/keypress.rb +33 -36
  20. data/lib/tty/prompt/list.rb +198 -63
  21. data/lib/tty/prompt/mask_question.rb +11 -8
  22. data/lib/tty/prompt/multi_list.rb +131 -28
  23. data/lib/tty/prompt/multiline.rb +9 -7
  24. data/lib/tty/prompt/paginator.rb +38 -26
  25. data/lib/tty/prompt/question.rb +92 -37
  26. data/lib/tty/prompt/question/checks.rb +20 -2
  27. data/lib/tty/prompt/question/modifier.rb +4 -2
  28. data/lib/tty/prompt/question/validation.rb +3 -3
  29. data/lib/tty/prompt/selected_choices.rb +77 -0
  30. data/lib/tty/prompt/slider.rb +125 -30
  31. data/lib/tty/prompt/statement.rb +3 -3
  32. data/lib/tty/prompt/suggestion.rb +7 -6
  33. data/lib/tty/prompt/symbols.rb +58 -34
  34. data/lib/tty/prompt/test.rb +36 -0
  35. data/lib/tty/prompt/timer.rb +75 -0
  36. data/lib/tty/prompt/utils.rb +1 -3
  37. data/lib/tty/prompt/version.rb +1 -1
  38. metadata +29 -227
  39. data/Rakefile +0 -8
  40. data/examples/ask.rb +0 -7
  41. data/examples/ask_valid.rb +0 -12
  42. data/examples/collect.rb +0 -21
  43. data/examples/echo.rb +0 -11
  44. data/examples/enum_select.rb +0 -7
  45. data/examples/enum_select_disabled.rb +0 -16
  46. data/examples/enum_select_paged.rb +0 -9
  47. data/examples/enum_select_wrapped.rb +0 -15
  48. data/examples/expand.rb +0 -29
  49. data/examples/in.rb +0 -9
  50. data/examples/inputs.rb +0 -10
  51. data/examples/key_events.rb +0 -15
  52. data/examples/keypress.rb +0 -9
  53. data/examples/mask.rb +0 -13
  54. data/examples/multi_select.rb +0 -8
  55. data/examples/multi_select_disabled.rb +0 -17
  56. data/examples/multi_select_paged.rb +0 -9
  57. data/examples/multi_select_wrapped.rb +0 -15
  58. data/examples/multiline.rb +0 -9
  59. data/examples/pause.rb +0 -9
  60. data/examples/select.rb +0 -24
  61. data/examples/select_disabled.rb +0 -18
  62. data/examples/select_enum.rb +0 -8
  63. data/examples/select_filtered.rb +0 -11
  64. data/examples/select_paginated.rb +0 -11
  65. data/examples/select_wrapped.rb +0 -15
  66. data/examples/slider.rb +0 -6
  67. data/examples/validation.rb +0 -9
  68. data/examples/yes_no.rb +0 -7
  69. data/lib/tty/prompt/messages.rb +0 -49
  70. data/lib/tty/prompt/timeout.rb +0 -78
  71. data/lib/tty/test_prompt.rb +0 -20
  72. data/spec/spec_helper.rb +0 -45
  73. data/spec/unit/ask_spec.rb +0 -132
  74. data/spec/unit/choice/eql_spec.rb +0 -22
  75. data/spec/unit/choice/from_spec.rb +0 -96
  76. data/spec/unit/choices/add_spec.rb +0 -12
  77. data/spec/unit/choices/each_spec.rb +0 -13
  78. data/spec/unit/choices/find_by_spec.rb +0 -10
  79. data/spec/unit/choices/new_spec.rb +0 -10
  80. data/spec/unit/choices/pluck_spec.rb +0 -9
  81. data/spec/unit/collect_spec.rb +0 -96
  82. data/spec/unit/converters/convert_bool_spec.rb +0 -58
  83. data/spec/unit/converters/convert_char_spec.rb +0 -11
  84. data/spec/unit/converters/convert_custom_spec.rb +0 -14
  85. data/spec/unit/converters/convert_date_spec.rb +0 -34
  86. data/spec/unit/converters/convert_file_spec.rb +0 -18
  87. data/spec/unit/converters/convert_number_spec.rb +0 -39
  88. data/spec/unit/converters/convert_path_spec.rb +0 -15
  89. data/spec/unit/converters/convert_range_spec.rb +0 -22
  90. data/spec/unit/converters/convert_regex_spec.rb +0 -12
  91. data/spec/unit/converters/convert_string_spec.rb +0 -21
  92. data/spec/unit/converters/on_error_spec.rb +0 -9
  93. data/spec/unit/distance/distance_spec.rb +0 -73
  94. data/spec/unit/enum_paginator_spec.rb +0 -75
  95. data/spec/unit/enum_select_spec.rb +0 -446
  96. data/spec/unit/error_spec.rb +0 -20
  97. data/spec/unit/evaluator_spec.rb +0 -67
  98. data/spec/unit/expand_spec.rb +0 -198
  99. data/spec/unit/keypress_spec.rb +0 -72
  100. data/spec/unit/mask_spec.rb +0 -132
  101. data/spec/unit/multi_select_spec.rb +0 -511
  102. data/spec/unit/multiline_spec.rb +0 -77
  103. data/spec/unit/new_spec.rb +0 -20
  104. data/spec/unit/ok_spec.rb +0 -10
  105. data/spec/unit/paginator_spec.rb +0 -73
  106. data/spec/unit/question/checks_spec.rb +0 -97
  107. data/spec/unit/question/default_spec.rb +0 -31
  108. data/spec/unit/question/echo_spec.rb +0 -38
  109. data/spec/unit/question/in_spec.rb +0 -115
  110. data/spec/unit/question/initialize_spec.rb +0 -12
  111. data/spec/unit/question/modifier/apply_to_spec.rb +0 -24
  112. data/spec/unit/question/modifier/letter_case_spec.rb +0 -41
  113. data/spec/unit/question/modifier/whitespace_spec.rb +0 -51
  114. data/spec/unit/question/modify_spec.rb +0 -41
  115. data/spec/unit/question/required_spec.rb +0 -92
  116. data/spec/unit/question/validate_spec.rb +0 -115
  117. data/spec/unit/question/validation/call_spec.rb +0 -31
  118. data/spec/unit/question/validation/coerce_spec.rb +0 -30
  119. data/spec/unit/result_spec.rb +0 -40
  120. data/spec/unit/say_spec.rb +0 -67
  121. data/spec/unit/select_spec.rb +0 -660
  122. data/spec/unit/slider_spec.rb +0 -100
  123. data/spec/unit/statement/initialize_spec.rb +0 -15
  124. data/spec/unit/subscribe_spec.rb +0 -22
  125. data/spec/unit/suggest_spec.rb +0 -28
  126. data/spec/unit/warn_spec.rb +0 -21
  127. data/spec/unit/yes_no_spec.rb +0 -251
  128. data/tasks/console.rake +0 -11
  129. data/tasks/coverage.rake +0 -11
  130. data/tasks/spec.rake +0 -29
  131. data/tty-prompt.gemspec +0 -33
@@ -1,20 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'question'
4
- require_relative 'symbols'
3
+ require_relative "question"
5
4
 
6
5
  module TTY
7
6
  class Prompt
8
7
  class MaskQuestion < Question
8
+ # Names for delete keys
9
+ DELETE_KEYS = %i[backspace delete].freeze
10
+
9
11
  # Create masked question
10
12
  #
11
13
  # @param [Hash] options
12
14
  # @option options [String] :mask
13
15
  #
14
16
  # @api public
15
- def initialize(prompt, options = {})
17
+ def initialize(prompt, **options)
16
18
  super
17
- @mask = options.fetch(:mask) { Symbols.symbols[:dot] }
19
+ @mask = options.fetch(:mask) { @prompt.symbols[:dot] }
18
20
  @done_masked = false
19
21
  @failure = false
20
22
  end
@@ -28,19 +30,20 @@ module TTY
28
30
  # @api public
29
31
  def mask(char = (not_set = true))
30
32
  return @mask if not_set
33
+
31
34
  @mask = char
32
35
  end
33
36
 
34
- def keyreturn(event)
37
+ def keyreturn(_event)
35
38
  @done_masked = true
36
39
  end
37
40
 
38
- def keyenter(event)
41
+ def keyenter(_event)
39
42
  @done_masked = true
40
43
  end
41
44
 
42
45
  def keypress(event)
43
- if [:backspace, :delete].include?(event.key.name)
46
+ if DELETE_KEYS.include?(event.key.name)
44
47
  @input.chop! unless @input.empty?
45
48
  elsif event.value =~ /^[^\e\n\r]/
46
49
  @input += event.value
@@ -76,7 +79,7 @@ module TTY
76
79
  def read_input(question)
77
80
  @done_masked = false
78
81
  @failure = false
79
- @input = ''
82
+ @input = ""
80
83
  @prompt.print(question)
81
84
  until @done_masked
82
85
  @prompt.read_keypress
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'list'
3
+ require_relative "list"
4
+ require_relative "selected_choices"
4
5
 
5
6
  module TTY
6
7
  class Prompt
@@ -9,33 +10,83 @@ module TTY
9
10
  #
10
11
  # @api private
11
12
  class MultiList < List
12
- HELP = '(Use arrow%s keys, press Space to select and Enter to finish%s)'
13
-
14
13
  # Create instance of TTY::Prompt::MultiList menu.
15
14
  #
16
15
  # @param [Prompt] :prompt
17
16
  # @param [Hash] options
18
17
  #
19
18
  # @api public
20
- def initialize(prompt, options)
19
+ def initialize(prompt, **options)
21
20
  super
22
- @selected = []
21
+ @selected = SelectedChoices.new
23
22
  @help = options[:help]
24
23
  @echo = options.fetch(:echo, true)
24
+ @min = options[:min]
25
+ @max = options[:max]
26
+ end
27
+
28
+ # Set a minimum number of choices
29
+ #
30
+ # @api public
31
+ def min(value)
32
+ @min = value
25
33
  end
26
34
 
35
+ # Set a maximum number of choices
36
+ #
37
+ # @api public
38
+ def max(value)
39
+ @max = value
40
+ end
41
+
42
+ # Callback fired when enter/return key is pressed
43
+ #
44
+ # @api private
45
+ def keyenter(*)
46
+ valid = true
47
+ valid = @min <= @selected.size if @min
48
+ valid = @selected.size <= @max if @max
49
+
50
+ super if valid
51
+ end
52
+ alias keyreturn keyenter
53
+
27
54
  # Callback fired when space key is pressed
28
55
  #
29
56
  # @api private
30
57
  def keyspace(*)
31
58
  active_choice = choices[@active - 1]
32
59
  if @selected.include?(active_choice)
33
- @selected.delete(active_choice)
60
+ @selected.delete_at(@active - 1)
34
61
  else
35
- @selected << active_choice
62
+ return if @max && @selected.size >= @max
63
+
64
+ @selected.insert(@active - 1, active_choice)
36
65
  end
37
66
  end
38
67
 
68
+ # Selects all choices when Ctrl+A is pressed
69
+ #
70
+ # @api private
71
+ def keyctrl_a(*)
72
+ return if @max && @max < choices.size
73
+
74
+ @selected = SelectedChoices.new(choices.enabled, choices.enabled_indexes)
75
+ end
76
+
77
+ # Revert currently selected choices when Ctrl+I is pressed
78
+ #
79
+ # @api private
80
+ def keyctrl_r(*)
81
+ return if @max && @max < choices.size
82
+
83
+ indexes = choices.each_with_index.reduce([]) do |acc, (choice, idx)|
84
+ acc << idx if !choice.disabled? && !@selected.include?(choice)
85
+ acc
86
+ end
87
+ @selected = SelectedChoices.new(choices.enabled - @selected.to_a, indexes)
88
+ end
89
+
39
90
  private
40
91
 
41
92
  # Setup default options and active selection
@@ -44,12 +95,23 @@ module TTY
44
95
  def setup_defaults
45
96
  validate_defaults
46
97
  # At this stage, @choices matches all the visible choices.
47
- @selected = @choices.values_at(*@default.map { |d| d - 1 })
98
+ default_indexes = @default.map do |d|
99
+ if d.to_s =~ INTEGER_MATCHER
100
+ d - 1
101
+ else
102
+ choices.index(choices.find_by(:name, d.to_s))
103
+ end
104
+ end
105
+ @selected = SelectedChoices.new(@choices.values_at(*default_indexes),
106
+ default_indexes)
48
107
 
49
- if !@default.empty?
108
+ if @default.empty?
109
+ # no default, pick the first non-disabled choice
110
+ @active = choices.index { |choice| !choice.disabled? } + 1
111
+ elsif @default.last.to_s =~ INTEGER_MATCHER
50
112
  @active = @default.last
51
- else
52
- @active = @choices.index { |choice| !choice.disabled? } + 1
113
+ elsif default_choice = choices.find_by(:name, @default.last.to_s)
114
+ @active = choices.index(default_choice) + 1
53
115
  end
54
116
  end
55
117
 
@@ -59,23 +121,63 @@ module TTY
59
121
  #
60
122
  # @api private
61
123
  def selected_names
62
- @selected.map(&:name).join(', ')
124
+ @selected.map(&:name).join(", ")
125
+ end
126
+
127
+ # Header part showing the minimum/maximum number of choices
128
+ #
129
+ # @return [String]
130
+ #
131
+ # @api private
132
+ def minmax_help
133
+ help = []
134
+ help << "min. #{@min}" if @min
135
+ help << "max. #{@max}" if @max
136
+ "(%s) " % [help.join(", ")]
137
+ end
138
+
139
+ # Build a default help text
140
+ #
141
+ # @return [String]
142
+ #
143
+ # @api private
144
+ def default_help
145
+ str = []
146
+ str << "(Press "
147
+ str << "#{arrows_help} arrow"
148
+ str << " or 1-#{choices.size} number" if enumerate?
149
+ str << " to move, Space"
150
+ str << "/Ctrl+A|R" if @max.nil?
151
+ str << " to select"
152
+ str << " (all|rev)" if @max.nil?
153
+ str << (filterable? ? "," : " and")
154
+ str << " Enter to finish"
155
+ str << " and letters to filter" if filterable?
156
+ str << ")"
157
+ str.join
63
158
  end
64
159
 
65
160
  # Render initial help text and then currently selected choices
66
161
  #
67
162
  # @api private
68
163
  def render_header
69
- instructions = @prompt.decorate(help, :bright_black)
164
+ instructions = @prompt.decorate(help, @help_color)
165
+ minmax_suffix = @min || @max ? minmax_help : ""
166
+ print_selected = @selected.size.nonzero? && @echo
167
+
70
168
  if @done && @echo
71
169
  @prompt.decorate(selected_names, @active_color)
72
- elsif @selected.size.nonzero? && @echo
73
- help_suffix = filterable? && @filter.any? ? " #{filter_help}" : ""
74
- selected_names + (@first_render ? " #{instructions}" : help_suffix)
75
- elsif @first_render
76
- instructions
170
+ elsif (@first_render && (help_start? || help_always?)) ||
171
+ (help_always? && !@filter.any? && !@done)
172
+ minmax_suffix +
173
+ (print_selected ? "#{selected_names} " : "") +
174
+ instructions
77
175
  elsif filterable? && @filter.any?
78
- filter_help
176
+ minmax_suffix +
177
+ (print_selected ? "#{selected_names} " : "") +
178
+ @prompt.decorate(filter_help, @help_color)
179
+ else
180
+ minmax_suffix + (print_selected ? selected_names : "")
79
181
  end
80
182
  end
81
183
 
@@ -96,21 +198,22 @@ module TTY
96
198
  def render_menu
97
199
  output = []
98
200
 
99
- @paginator.paginate(choices, @active, @per_page) do |choice, index|
100
- num = enumerate? ? (index + 1).to_s + @enum + ' ' : ''
101
- indicator = (index + 1 == @active) ? @marker : ' '
102
- indicator += ' '
201
+ sync_paginators if @paging_changed
202
+ paginator.paginate(choices, @active, @per_page) do |choice, index|
203
+ num = enumerate? ? (index + 1).to_s + @enum + " " : ""
204
+ indicator = (index + 1 == @active) ? @symbols[:marker] : " "
205
+ indicator += " "
103
206
  message = if @selected.include?(choice) && !choice.disabled?
104
- selected = @prompt.decorate(symbols[:radio_on], @active_color)
207
+ selected = @prompt.decorate(@symbols[:radio_on], @active_color)
105
208
  "#{selected} #{num}#{choice.name}"
106
209
  elsif choice.disabled?
107
- @prompt.decorate(symbols[:cross], :red) +
210
+ @prompt.decorate(@symbols[:cross], :red) +
108
211
  " #{num}#{choice.name} #{choice.disabled}"
109
212
  else
110
- "#{symbols[:radio_off]} #{num}#{choice.name}"
213
+ "#{@symbols[:radio_off]} #{num}#{choice.name}"
111
214
  end
112
- max_index = paginated? ? @paginator.max_index : choices.size - 1
113
- newline = (index == max_index) ? '' : "\n"
215
+ end_index = paginated? ? paginator.end_index : choices.size - 1
216
+ newline = (index == end_index) ? "" : "\n"
114
217
  output << indicator + message + newline
115
218
  end
116
219
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'question'
4
- require_relative 'symbols'
3
+ require_relative "question"
4
+ require_relative "symbols"
5
5
 
6
6
  module TTY
7
7
  class Prompt
@@ -9,9 +9,9 @@ module TTY
9
9
  #
10
10
  # @api private
11
11
  class Multiline < Question
12
- HELP = '(Press CTRL-D or CTRL-Z to finish)'.freeze
12
+ HELP = "(Press Ctrl+D or Ctrl+Z to finish)".freeze
13
13
 
14
- def initialize(prompt, options = {})
14
+ def initialize(prompt, **options)
15
15
  super
16
16
  @help = options[:help] || self.class::HELP
17
17
  @first_render = true
@@ -25,6 +25,7 @@ module TTY
25
25
  # @api public
26
26
  def help(value = (not_set = true))
27
27
  return @help if not_set
28
+
28
29
  @help = value
29
30
  end
30
31
 
@@ -42,7 +43,7 @@ module TTY
42
43
  if !echo?
43
44
  header
44
45
  elsif @done
45
- header << @prompt.decorate("#{@input}", @active_color)
46
+ header << @prompt.decorate(@input.to_s, @active_color)
46
47
  elsif @first_render
47
48
  header << @prompt.decorate(help, @help_color)
48
49
  @first_render = false
@@ -55,8 +56,9 @@ module TTY
55
56
  @prompt.print(question)
56
57
  @lines = read_input
57
58
  @input = "#{@lines.first.strip} ..." unless @lines.first.to_s.empty?
58
- if Utils.blank?(@input)
59
- @input = default? ? default : nil
59
+ if Utils.blank?(@input) && default?
60
+ @input = default
61
+ @lines = default
60
62
  end
61
63
  @evaluator.(@lines)
62
64
  end
@@ -5,23 +5,33 @@ module TTY
5
5
  class Paginator
6
6
  DEFAULT_PAGE_SIZE = 6
7
7
 
8
+ # The 0-based index of the first item on this page
9
+ attr_accessor :start_index
10
+
11
+ # The 0-based index of the last item on this page
12
+ attr_reader :end_index
13
+
14
+ # The 0-based index of the active item on this page
15
+ attr_reader :current_index
16
+
17
+ # The 0-based index of the previously active item on this page
18
+ attr_reader :last_index
19
+
8
20
  # Create a Paginator
9
21
  #
10
22
  # @api private
11
- def initialize(options = {})
23
+ def initialize(**options)
12
24
  @last_index = Array(options[:default]).flatten.first || 0
13
25
  @per_page = options[:per_page]
14
- @lower_index = Array(options[:default]).flatten.first
26
+ @start_index = Array(options[:default]).flatten.first
15
27
  end
16
28
 
17
- # Maximum index for current pagination
29
+ # Reset current page indexes
18
30
  #
19
- # @return [Integer]
20
- #
21
- # @api public
22
- def max_index
23
- raise ArgumentError, 'no max index' unless @per_page
24
- @lower_index + @per_page - 1
31
+ # @api private
32
+ def reset!
33
+ @start_index = nil
34
+ @end_index = nil
25
35
  end
26
36
 
27
37
  # Check if page size is valid
@@ -30,7 +40,7 @@ module TTY
30
40
  #
31
41
  # @api private
32
42
  def check_page_size!
33
- raise InvalidArgument, 'per_page must be > 0' if @per_page < 1
43
+ raise InvalidArgument, "per_page must be > 0" if @per_page < 1
34
44
  end
35
45
 
36
46
  # Paginate collection given an active index
@@ -43,21 +53,21 @@ module TTY
43
53
  # number of choice items per page
44
54
  #
45
55
  # @return [Enumerable]
56
+ # the list between start and end index
46
57
  #
47
58
  # @api public
48
59
  def paginate(list, active, per_page = nil, &block)
49
60
  current_index = active - 1
50
61
  default_size = (list.size <= DEFAULT_PAGE_SIZE ? list.size : DEFAULT_PAGE_SIZE)
51
62
  @per_page = @per_page || per_page || default_size
52
- @lower_index ||= current_index
53
- @upper_index ||= max_index
54
-
55
63
  check_page_size!
64
+ @start_index ||= (current_index / @per_page) * @per_page
65
+ @end_index ||= @start_index + @per_page - 1
56
66
 
57
67
  # Don't paginate short lists
58
68
  if list.size <= @per_page
59
- @lower_index = 0
60
- @upper_index = list.size - 1
69
+ @start_index = 0
70
+ @end_index = list.size - 1
61
71
  if block
62
72
  return list.each_with_index(&block)
63
73
  else
@@ -65,33 +75,35 @@ module TTY
65
75
  end
66
76
  end
67
77
 
78
+ step = (current_index - @last_index).abs
68
79
  if current_index > @last_index # going up
69
- if current_index > @upper_index && current_index < list.size - 1
70
- @lower_index += 1
80
+ if current_index >= @end_index && current_index < list.size - 1
81
+ last_page = list.size - @per_page
82
+ @start_index = [@start_index + step, last_page].min
71
83
  end
72
84
  elsif current_index < @last_index # going down
73
- if current_index < @lower_index && current_index > 0
74
- @lower_index -= 1
85
+ if current_index <= @start_index && current_index > 0
86
+ @start_index = [@start_index - step, 0].max
75
87
  end
76
88
  end
77
89
 
78
90
  # Cycle list
79
91
  if current_index.zero?
80
- @lower_index = 0
92
+ @start_index = 0
81
93
  elsif current_index == list.size - 1
82
- @lower_index = list.size - 1 - (@per_page - 1)
94
+ @start_index = list.size - 1 - (@per_page - 1)
83
95
  end
84
96
 
85
- @upper_index = @lower_index + (@per_page - 1)
97
+ @end_index = @start_index + (@per_page - 1)
86
98
  @last_index = current_index
87
99
 
88
- sliced_list = list[@lower_index..@upper_index]
89
- indices = (@lower_index..@upper_index)
100
+ sliced_list = list[@start_index..@end_index]
101
+ page_range = (@start_index..@end_index)
90
102
 
91
- return sliced_list.zip(indices).to_enum unless block_given?
103
+ return sliced_list.zip(page_range).to_enum unless block_given?
92
104
 
93
105
  sliced_list.each_with_index do |item, index|
94
- block[item, @lower_index + index]
106
+ block[item, @start_index + index]
95
107
  end
96
108
  end
97
109
  end # Paginator