highline 2.1.0 → 3.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: 0bb41764d2e42ab3b3c52ca1735f0cd6a587ff5ed3bb4525d0e7703dc4ccb61f
4
- data.tar.gz: 0424d1467c1f787881abfe6558afdc0aceeb0e854d05efac8c5c6db9d07ba3cf
3
+ metadata.gz: 68bd1dba0eea8f51020e4b42bf027a432313b312efcf1365c20a6d5ca2b13244
4
+ data.tar.gz: d1dd90401ba1b29581afe8e89ef5a2ad3b443184e61f73dd7a60252404c30172
5
5
  SHA512:
6
- metadata.gz: df0dd1fa4d206aace9512f7ad414bc1e6bdcbfe804fd91b3811a2bc5860dbe7862d3ab81a502fc812747134be1122a647ac9fdd8e95e88e3f9388f7a05f38c22
7
- data.tar.gz: 70cbe01e01aeff63d8321a4768caaa43992082030ad4e3f93533693d7f7908b30175852c11286fe3a744c4a3a3be63ad3328e7b5b605a045ad4f634887e1340d
6
+ metadata.gz: b7bcd45c71419a9e90c9cdc9f1dba9c42be76618068cadc8e30e41600272413b16df3cd95d95266fc4d24d70c00c53668f6fe7134fb1e5cee4780740eabc2378
7
+ data.tar.gz: 20cfca01c3f433766f9d0884b5ea32dcfa690e6b3652fc6aeb9e691f5eb62f1ffc99ec9941fe724603684b660d374af23b8819054a1e5dfffb5655ff8107df1e
@@ -10,14 +10,10 @@ jobs:
10
10
  os: [ubuntu-latest]
11
11
  ruby-version:
12
12
  - head
13
+ - '3.3'
13
14
  - '3.2'
14
15
  - '3.1'
15
16
  - '3.0'
16
- - '2.7'
17
- - '2.6'
18
- - '2.5'
19
- - '2.4'
20
- - '2.3'
21
17
  - jruby
22
18
  - jruby-head
23
19
  - truffleruby
@@ -27,7 +23,7 @@ jobs:
27
23
  - os: windows-latest
28
24
  ruby-version: head
29
25
  - os: windows-latest
30
- ruby-version: '3.1'
26
+ ruby-version: '3.3'
31
27
  - os: windows-latest
32
28
  ruby-version: mingw
33
29
  - os: windows-latest
@@ -37,10 +33,10 @@ jobs:
37
33
  - os: macos-latest
38
34
  ruby-version: 'head'
39
35
  - os: macos-latest
40
- ruby-version: '3.1'
36
+ ruby-version: '3.3'
41
37
  runs-on: ${{ matrix.os }}
42
38
  steps:
43
- - uses: actions/checkout@v3
39
+ - uses: actions/checkout@v4
44
40
  - name: Set up Ruby ${{ matrix.ruby-version }}
45
41
  uses: ruby/setup-ruby@v1
46
42
  with:
data/Changelog.md CHANGED
@@ -2,6 +2,28 @@
2
2
 
3
3
  Below is a complete listing of changes for each revision of HighLine.
4
4
 
5
+ ### 3.1.0 / 2024-07-15
6
+ * PR #272 / I #271 - Readline is now completed deprecated over Reline (@abinoam, issue by @64kramsystem)
7
+ * PR #269 - Provide a 'Changelog' link on rubygems.org/gems/highline (@mark-young-atg)
8
+
9
+ ### 3.0.1 / 2024-01-20
10
+ * PR #268 - Remove unused abbrev dependency (@zvkemp)
11
+
12
+ ### 3.0.0 / 2024-01-05
13
+ * PR #265 - Change Readline for Reline for Ruby 3.3 compat (@abinoam)
14
+ * PR #264 - Add abbrev gem as dependency (@mathieujobin)
15
+ * PR #263 - Release 3.0.0.pre.1
16
+ * Raise minimum Ruby version requirement to 3.0
17
+ * PR #262 - Do not call stty on non-tty (@kbrock)
18
+ * PR #260 / I #43 - Ctrl-U (erase line) handling (@abinoam, issue by @gutenye)
19
+ * PR #259 / I #236 - Handle Ctrl-C when Question#echo = false (@abinoam, @Fahhetah, issue by @aspyct)
20
+ * PR #258 / I #246 - Add validation class support (@abinoam, issue by @Joshfindit)
21
+ * Make it dry-types compatible through the use of `#valid?`
22
+ * Solve the multiple answers in one line problem with a combination of custom coercion (parser) and custom validation
23
+ * PR #257 / I #233 - Show Question#default hint for non String values (@abinoam, issue by @branch14)
24
+ * Add Question#default_hint_show to allow disabling it.
25
+ * PR #256 / I #249 - Fix Array validation in Question#in (@abinoam, issue by @esotericpig)
26
+
5
27
  ### 2.1.0 / 2022-12-31
6
28
  * PR #255 - Change minimum Ruby version requirement to 2.3 (@abinoam)
7
29
  * PR #254 - Improve Github Actions file (@abinoam)
data/README.md CHANGED
@@ -43,12 +43,48 @@ puts "You have answered: #{answer}"
43
43
 
44
44
  cli.ask("Company? ") { |q| q.default = "none" }
45
45
 
46
+ ## Disable default value hint showing
47
+
48
+ my_special_default_object = Object.new
49
+
50
+ cli.ask("Question? ") do |q|
51
+ q.default = my_special_default_object
52
+ q.default_hint_show = false
53
+ end
54
+
46
55
 
47
56
  # Validation
48
57
 
49
58
  cli.ask("Age? ", Integer) { |q| q.in = 0..105 }
50
59
  cli.ask("Name? (last, first) ") { |q| q.validate = /\A\w+, ?\w+\Z/ }
51
60
 
61
+ ## Validation with custom class
62
+ class ZeroToTwentyFourValidator
63
+ def self.valid?(answer)
64
+ (0..24).include? answer.to_i
65
+ end
66
+
67
+ def self.inspect
68
+ "(0..24) rule"
69
+ end
70
+ end
71
+
72
+ cli.ask("What hour of the day is it?: ", Integer) do |q|
73
+ q.validate = ZeroToTwentyFourValidator
74
+ end
75
+
76
+ ## Validation with Dry::Types
77
+ ## `Dry::Types` provides a `valid?` method so it can be used effortlessly
78
+
79
+ require 'dry-type'
80
+
81
+ module Types
82
+ include Dry.Types
83
+ end
84
+
85
+ cli.ask("Type an integer:", Integer) do |q|
86
+ q.validate = Types::Coercible::Integer
87
+ end
52
88
 
53
89
  # Type conversion for answers:
54
90
 
@@ -103,7 +139,7 @@ For more examples see the examples/ directory of this project.
103
139
  Requirements
104
140
  ------------
105
141
 
106
- HighLine from version >= 1.7.0 requires ruby >= 1.9.3
142
+ HighLine from version >= 3.0.0 requires ruby >= 3.0.0
107
143
 
108
144
  Installing
109
145
  ----------
@@ -0,0 +1,39 @@
1
+ require 'highline'
2
+
3
+ cli = HighLine.new
4
+
5
+ # The parser
6
+ class ArrayOfNumbersFromString
7
+ def self.parse(string)
8
+ string.scan(/\d+/).map(&:to_i)
9
+ end
10
+ end
11
+
12
+ # The validator
13
+ class ArrayOfNumbersFromStringInRange
14
+ def self.in?(range)
15
+ new(range)
16
+ end
17
+
18
+ attr_reader :range
19
+
20
+ def initialize(range)
21
+ @range = range
22
+ end
23
+
24
+ def valid?(answer)
25
+ ary = ArrayOfNumbersFromString.parse(answer)
26
+ ary.all? ->(number) { range.include? number }
27
+ end
28
+
29
+ def inspect
30
+ "in range #@range validator"
31
+ end
32
+ end
33
+
34
+ answer = cli.ask("Which number? (0 or <Enter> to skip): ", ArrayOfNumbersFromString) { |q|
35
+ q.validate = ArrayOfNumbersFromStringInRange.in?(0..10)
36
+ q.default = 0
37
+ }
38
+
39
+ puts "Your answer was: #{answer} and it was correctly validated and coerced into an #{answer.class}"
data/highline.gemspec CHANGED
@@ -27,9 +27,14 @@ DESCRIPTION
27
27
 
28
28
  spec.extra_rdoc_files = %w[README.md TODO Changelog.md LICENSE]
29
29
 
30
- spec.required_ruby_version = ">= 2.3"
30
+ spec.required_ruby_version = ">= 3.0"
31
31
 
32
32
  spec.add_development_dependency "bundler"
33
33
  spec.add_development_dependency "rake"
34
34
  spec.add_development_dependency "minitest"
35
+ spec.add_development_dependency "dry-types"
36
+
37
+ spec.add_runtime_dependency "reline"
38
+
39
+ spec.metadata["changelog_uri"] = spec.homepage + "/blob/master/Changelog.md"
35
40
  end
@@ -13,7 +13,7 @@ require "tempfile"
13
13
  #
14
14
 
15
15
  module IOConsoleCompatible
16
- def getch
16
+ def getch(min:nil, time:nil, intr: nil)
17
17
  getc
18
18
  end
19
19
 
@@ -9,7 +9,7 @@ class HighLine
9
9
  extend Forwardable
10
10
 
11
11
  def_delegators :@question,
12
- :answer, :answer=, :check_range,
12
+ :answer, :answer=,
13
13
  :directory, :answer_type, :choices_complete
14
14
 
15
15
  # It should be initialized with a Question object.
@@ -26,10 +26,7 @@ class HighLine
26
26
  # it makes the conversion and returns the answer.
27
27
  # @return [Object] the converted answer.
28
28
  def convert
29
- return unless answer_type
30
-
31
- self.answer = convert_by_answer_type
32
- check_range
29
+ self.answer = convert_by_answer_type if answer_type
33
30
  answer
34
31
  end
35
32
 
@@ -56,6 +56,7 @@ class HighLine
56
56
  @completion = @answer_type
57
57
 
58
58
  @echo = true
59
+ @default_hint_show = true
59
60
  @whitespace = :strip
60
61
  @case = nil
61
62
  @in = nil
@@ -115,7 +116,7 @@ class HighLine
115
116
  #
116
117
  attr_accessor :echo
117
118
  #
118
- # Use the Readline library to fetch input. This allows input editing as
119
+ # Use the Reline library to fetch input. This allows input editing as
119
120
  # well as keeping a history. In addition, tab will auto-complete
120
121
  # within an Array of choices or a file listing.
121
122
  #
@@ -124,6 +125,7 @@ class HighLine
124
125
  # specified _input_ stream.
125
126
  #
126
127
  attr_accessor :readline
128
+
127
129
  #
128
130
  # Used to control whitespace processing for the answer to this question.
129
131
  # See HighLine::Question.remove_whitespace() for acceptable settings.
@@ -136,10 +138,17 @@ class HighLine
136
138
  attr_accessor :case
137
139
  # Used to provide a default answer to this question.
138
140
  attr_accessor :default
141
+ # Set it to a truthy or falsy value to enable or disable showing the default
142
+ # value hint between vertical bars (pipes) when asking the question.
143
+ # Defaults to +true+
144
+ attr_accessor :default_hint_show
139
145
  #
140
146
  # If set to a Regexp, the answer must match (before type conversion).
141
147
  # Can also be set to a Proc which will be called with the provided
142
148
  # answer to validate with a +true+ or +false+ return.
149
+ # It's possible to use a custom validator class. It must respond to
150
+ # `#valid?`. The result of `#inspect` will be used in error messages.
151
+ # See README.md for details.
143
152
  #
144
153
  attr_accessor :validate
145
154
  # Used to control range checks for answer.
@@ -252,7 +261,7 @@ class HighLine
252
261
  # Same as {#answer_type}.
253
262
 
254
263
  def build_responses(message_source = answer_type)
255
- append_default if [::String, Symbol].include? default.class
264
+ append_default_to_template if default_hint_show
256
265
 
257
266
  new_hash = build_responses_new_hash(message_source)
258
267
  # Update our internal responses with the new hash
@@ -497,7 +506,8 @@ class HighLine
497
506
  def valid_answer?
498
507
  !validate ||
499
508
  (validate.is_a?(Regexp) && answer =~ validate) ||
500
- (validate.is_a?(Proc) && validate[answer])
509
+ (validate.is_a?(Proc) && validate[answer]) ||
510
+ (validate.respond_to?(:valid?) && validate.valid?(answer))
501
511
  end
502
512
 
503
513
  #
@@ -571,11 +581,6 @@ class HighLine
571
581
  end
572
582
  end
573
583
 
574
- # readline() needs to handle its own output, but readline only supports
575
- # full line reading. Therefore if question.echo is anything but true,
576
- # the prompt will not be issued. And we have to account for that now.
577
- # Also, JRuby-1.7's ConsoleReader.readLine() needs to be passed the prompt
578
- # to handle line editing properly.
579
584
  # @param highline [HighLine] context
580
585
  # @return [void]
581
586
  def show_question(highline)
@@ -607,15 +612,20 @@ class HighLine
607
612
  # Trailing whitespace is preserved so the function of HighLine.say() is
608
613
  # not affected.
609
614
  #
610
- def append_default
615
+ def append_default_to_template
616
+ return unless default.respond_to? :to_s
617
+
618
+ default_str = default.to_s
619
+ return if default_str.empty?
620
+
611
621
  if template =~ /([\t ]+)\Z/
612
- template << "|#{default}|#{Regexp.last_match(1)}"
622
+ template << "|#{default_str}|#{Regexp.last_match(1)}"
613
623
  elsif template == ""
614
- template << "|#{default}| "
624
+ template << "|#{default_str}| "
615
625
  elsif template[-1, 1] == "\n"
616
- template[-2, 0] = " |#{default}|"
626
+ template[-2, 0] = " |#{default_str}|"
617
627
  else
618
- template << " |#{default}|"
628
+ template << " |#{default_str}|"
619
629
  end
620
630
  end
621
631
 
@@ -24,13 +24,15 @@ class HighLine
24
24
  #
25
25
  # @return [String] answer
26
26
  def ask_once
27
- question.show_question(@highline)
27
+ # If in readline mode, let reline take care of the prompt
28
+ question.show_question(@highline) unless question.readline
28
29
 
29
30
  begin
30
31
  question.get_response_or_default(@highline)
31
32
  raise NotValidQuestionError unless question.valid_answer?
32
33
 
33
34
  question.convert
35
+ question.check_range
34
36
 
35
37
  if question.confirm
36
38
  confirmation = @highline.send(:confirm, question)
@@ -27,7 +27,7 @@ class HighLine
27
27
 
28
28
  # (see Terminal#get_character)
29
29
  def get_character
30
- input.getch # from ruby io/console
30
+ input.getch(intr: true) # from ruby io/console
31
31
  rescue Errno::ENOTTY
32
32
  input.getc
33
33
  end
@@ -20,7 +20,9 @@ class HighLine
20
20
  rescue LoadError
21
21
  end
22
22
 
23
- if /solaris/ =~ RUBY_PLATFORM &&
23
+ if !@output.tty?
24
+ [80, 24]
25
+ elsif /solaris/ =~ RUBY_PLATFORM &&
24
26
  `stty` =~ /\brows = (\d+).*\bcolumns = (\d+)/
25
27
  [Regexp.last_match(2), Regexp.last_match(1)].map(&:to_i)
26
28
  elsif `stty size` =~ /^(\d+)\s(\d+)$/
@@ -32,13 +34,13 @@ class HighLine
32
34
 
33
35
  # (see Terminal#raw_no_echo_mode)
34
36
  def raw_no_echo_mode
35
- @state = `stty -g`
36
- system "stty raw -echo -icanon isig"
37
+ save_stty
38
+ system "stty raw -echo -icanon isig" if input.tty?
37
39
  end
38
40
 
39
41
  # (see Terminal#restore_mode)
40
42
  def restore_mode
41
- system "stty #{@state}"
43
+ restore_stty
42
44
  print "\r"
43
45
  end
44
46
 
@@ -95,9 +95,9 @@ class HighLine
95
95
  # Get one line using #readline_read
96
96
  # @param (see #get_line)
97
97
  def get_line_with_readline(question, highline)
98
- require "readline" # load only if needed
98
+ require "reline" # load only if needed
99
99
 
100
- raw_answer = readline_read(question)
100
+ raw_answer = readline_read(question, highline)
101
101
 
102
102
  if !raw_answer && highline.track_eof?
103
103
  raise EOFError, "The input stream is exhausted."
@@ -109,20 +109,22 @@ class HighLine
109
109
  # Use readline to read one line
110
110
  # @param question [HighLine::Question] question from where to get
111
111
  # autocomplete candidate strings
112
- def readline_read(question)
112
+ def readline_read(question, highline)
113
113
  # prep auto-completion
114
114
  unless question.selection.empty?
115
- Readline.completion_proc = lambda do |str|
115
+ Reline.completion_proc = lambda do |str|
116
116
  question.selection.grep(/\A#{Regexp.escape(str)}/)
117
117
  end
118
118
  end
119
119
 
120
+ # TODO: Check if this is still needed after Reline
120
121
  # work-around ugly readline() warnings
121
122
  old_verbose = $VERBOSE
122
123
  $VERBOSE = nil
123
124
 
124
125
  raw_answer = run_preserving_stty do
125
- Readline.readline("", true)
126
+ prompt = highline.render_and_ident_statement(question)
127
+ Reline.readline(prompt, true)
126
128
  end
127
129
 
128
130
  $VERBOSE = old_verbose
@@ -176,7 +178,7 @@ class HighLine
176
178
  # Saves terminal state using shell stty command.
177
179
  def save_stty
178
180
  @stty_save = begin
179
- `stty -g`.chomp
181
+ `stty -g`.chomp if input.tty?
180
182
  rescue StandardError
181
183
  nil
182
184
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  class HighLine
4
4
  # The version of the installed library.
5
- VERSION = "2.1.0".freeze
5
+ VERSION = "3.1.0".freeze
6
6
  end
data/lib/highline.rb CHANGED
@@ -14,7 +14,6 @@ require "English"
14
14
  require "erb"
15
15
  require "optparse"
16
16
  require "stringio"
17
- require "abbrev"
18
17
  require "highline/terminal"
19
18
  require "highline/custom_errors"
20
19
  require "highline/question"
@@ -371,10 +370,8 @@ class HighLine
371
370
  #
372
371
  # @param statement [Statement, String] what to be said
373
372
  def say(statement)
374
- statement = render_statement(statement)
375
- return if statement.empty?
376
-
377
- statement = (indentation + statement)
373
+ statement = render_and_ident_statement(statement)
374
+ return statement if statement.empty?
378
375
 
379
376
  # Don't add a newline if statement ends with whitespace, OR
380
377
  # if statement ends with whitespace before a color escape code.
@@ -386,6 +383,18 @@ class HighLine
386
383
  end
387
384
  end
388
385
 
386
+ # Renders and indents a statement.
387
+ #
388
+ # Note: extracted here to be used by readline to render its prompt.
389
+ #
390
+ # @param statement [String] The statement to be rendered and indented.
391
+ # @return [String] The rendered and indented statement.
392
+ def render_and_ident_statement(statement)
393
+ statement = render_statement(statement)
394
+ statement = (indentation + statement) unless statement.empty?
395
+ statement
396
+ end
397
+
389
398
  # Renders a statement using {HighLine::Statement}
390
399
  # @param statement [String] any string
391
400
  # @return [Statement] rendered statement
@@ -538,6 +547,7 @@ class HighLine
538
547
  terminal.raw_no_echo_mode_exec do
539
548
  loop do
540
549
  character = terminal.get_character
550
+ raise Interrupt if character == "\u0003"
541
551
  break unless character
542
552
  break if ["\n", "\r"].include? character
543
553
 
@@ -545,6 +555,9 @@ class HighLine
545
555
  if character == "\b" || character == "\u007F"
546
556
  chopped = line.chop!
547
557
  output_erase_char if chopped && question.echo
558
+ elsif character == "\cU"
559
+ line.size.times { output_erase_char } if question.echo
560
+ line = ""
548
561
  elsif character == "\e"
549
562
  ignore_arrow_key
550
563
  else
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: highline
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Edward Gray II
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-31 00:00:00.000000000 Z
11
+ date: 2024-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-types
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: reline
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
55
83
  description: |
56
84
  A high-level IO library that provides validation, type conversion, and more for
57
85
  command-line interfaces. HighLine also includes a complete menu system that can
@@ -83,6 +111,7 @@ files:
83
111
  - examples/asking_for_arrays.rb
84
112
  - examples/basic_usage.rb
85
113
  - examples/color_scheme.rb
114
+ - examples/custom_parser_custom_validator.rb
86
115
  - examples/get_character.rb
87
116
  - examples/limit.rb
88
117
  - examples/menus.rb
@@ -127,8 +156,9 @@ files:
127
156
  homepage: https://github.com/JEG2/highline
128
157
  licenses:
129
158
  - Ruby
130
- metadata: {}
131
- post_install_message:
159
+ metadata:
160
+ changelog_uri: https://github.com/JEG2/highline/blob/master/Changelog.md
161
+ post_install_message:
132
162
  rdoc_options: []
133
163
  require_paths:
134
164
  - lib
@@ -136,15 +166,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
136
166
  requirements:
137
167
  - - ">="
138
168
  - !ruby/object:Gem::Version
139
- version: '2.3'
169
+ version: '3.0'
140
170
  required_rubygems_version: !ruby/object:Gem::Requirement
141
171
  requirements:
142
172
  - - ">="
143
173
  - !ruby/object:Gem::Version
144
174
  version: '0'
145
175
  requirements: []
146
- rubygems_version: 3.4.1
147
- signing_key:
176
+ rubygems_version: 3.5.9
177
+ signing_key:
148
178
  specification_version: 4
149
179
  summary: HighLine is a high-level command-line IO library.
150
180
  test_files: []