美文网首页
Highline的使用

Highline的使用

作者: wangzzzzz | 来源:发表于2018-03-06 19:48 被阅读0次

    前言

    HighLine是一个简化控制台输入输出的工具,它内部是使用像gets和puts这样低层次的方法来实现的。Highline提供了一个健壮的系统来获取用户的输入,并且对外提供了接口来对用户的输入进行错误检测和验证,最终会将输入的字符串转换成你想要的格式。

    要想对一个系统进行深入了解,首先必须要非常熟悉他的使用方法。那么,Highline作为一款输入输出工具,它对外提供了四种常用的方法,分别是say、ask、agree和choose。(默认情况下,Highine都是与终端进行交互)

    1. say

    say()的作用和我们常用的puts非常相似,都是将文本输出到终端进行显示。那么say()到底有什么优势呢。
    当我们需要向终端输入一段文本时,puts和say()分别是这样写的:

    puts "ruby is good"
    
    require "highline/import"
    
    say "ruby is good"
    

    二者几乎是一样的写法,但是使用say()还需要引入类库,好像是puts更胜一筹。
    在作出判断之前,我们再来看一个需求,现在我们需要向终端输入一段带颜色的文本了,那么puts和say()分别是如何的写:

    puts "\e[31mruby\e[0m is good"
    
    require "highline/import"
    
    say "<%=color('Ruby',:red) %> is good"
    

    看到这里,可以说say()的优势非常明显了,使用puts输入带颜色的文字,我们不仅要记住\e[31m这样繁琐的写法,而且还要非常准确的记住red就是31m而不是32m、33m;而使用say()就没那么麻烦了,只需要记住一个:red或者一个:green就行了。

    say()方法声明

    #@param statement [Question, String] 最终会被显示在终端上
    def say(statement)
    

    以下是say()方法常用的使用方式

    require 'highline/import'
    
    #一般的文本
    say('This is general text!') 
    
    #带颜色的文本
    say("This should be <%= color('red', :red) %>!")
    
    #带背景色的文本
    say("This should be <%= color('red on red', :on_red) %>!")
    
    #带粗体的文本
    say("This should be <%= color('bold', :bold) %>!")
    
    #带下划线的文本
    say("This should be <%= color('underline', :underline) %>!")
    
    #带闪烁的文本
    say("This should be <%= color('blink', :blink) %>!")
    

    在终端中执行这段代码


    换行
    require "highline/import"
    
    line = "This is a long flowing paragraph meant to span " \ 
          "several lines.  This text should definitely be " \ 
          "wrapped at the set limit, in the result.  Your code " \ 
          "does well with things like this.\n\n"
    
    puts "初始文本:" 
    puts line
    
    puts "格式化后的文本:"
    HighLine.default_instance.wrap_at = 71
    say line
    

    执行结果



    图中,wrap_at设置为71, 表示每一个行字符数最多为71,如果超过了,错过部分被截断后放到下一行,如果被截断处是一个单词(即没有包含空格),则这个单词整个放到下一行。如图中,在初始文本的第一行最后的"This tex"处是第71个字符,由于text是一个完整的单词,所以最终"text"整个被放到下一行了。(目前highline还不能准确的给带特殊格式(颜色、粗体等)的文本换行)

    分页
    require 'highline/import'
    
    HighLine.default_instance.page_at = 2 
    say( (1..5).map { |n| "This is line #{n}.\n"}.join)
    

    执行结果


    2. ask

    ask()的作用是在终端打印一个字符串,然后捕获用户的输入。
    ask()方法声明

    # @param template_or_question [String, Question],显示在终端中的question
    # @param answer_type [Class],指出你想要返回的answer的类型
    # @param details[Proc],设置Question相关的参数
     def ask(template_or_question, answer_type = nil, &details)
    

    一个简单的使用

    require 'highline/import'
    
    # Basic usage
    answer = ask "What do you think?"
    puts "You have answered: #{answer}"
    

    执行结果



    从图中可以看出,ask()方法的执行流程可以简单的分为三步:

    1. 输出question
    2. 获取用户输入
    3. 返回answer

    在这三个步骤之间,Highline内部会执行许多操作,比如在第一步时,传给ask()方法的参数template_or_question可能是一个ERB模板字符串,则需要将其转换成常规的字符串;在第二步时,获取用户的输入之后,可能还需要进行验证,如验证失败,则需要重新输入;在第三步时,则需要根据参数answer_type,对用户的输入进行转换。

    下面看一个例子,可以更好的表示这个流程

    require 'highline/import'
    
    answer = ask("Age?  ", Integer) { |q| q.in = 0..105 }
    puts "your answer is #{answer}"
    puts "your answer's class is #{answer.class}"
    

    执行结果



    在上述例子中,answer_type = Integer,所以在第一次输入ab之后,Highline会调用Kenel.Integer('ab'),很明显'ab'无法被转换成整数,故在传入'ab'之后,抛出异常,Highline截获异常之后,输出异常信息,然后等待用户重新输入;在上述例子中,在detail这个block中,设置了q.in = 0..105,表示只接受0到105这个范围的输入,故在输入'120'之后,需要重新输入。

    以上两个例子只是展示了ask()方法的一小部分功能,如果要更深入的了解,可以下载源代码,执行一遍源代码中的例子,如果想要更全面的了解,可以看看源代码中的测试用例。

    3. agree

    agree()方法的作用是在终端打印一个字符串,然后等待用户输入y(es)或n(o)。
    agree()方法是ask()方法的一个快捷方式,它内部最终会使用ask()方法来实现,agree()只是在ask()的基础上预先设置了一些参数,比如用户输入的验证规则和返回类型。
    agree()方法声明

    # @param yes_or_no_question [String],一个接受yes或no作为回答的问题
    # @param character [Boolean, :getc, nil],决定用户输入方式,比如单字符输入或字符串输入
    def agree(yes_or_no_question, character = nil) 
    

    agree()方法是专门用在需要用户确认的场景。具体的流程是:

    1. 输出question
    2. 获取用户输入,且只接受y(es)或n(o)(忽略大小写)
    3. 返回值是true 或 false

    下面看一个简单的使用例子

    require 'highline/import'
    
    answer = agree("Yes or no?"){ |q| q.default = "y" }
    puts "your answer is #{answer}"
    puts "your answer's class is #{answer.class}"
    

    执行结果



    从上述例子可以看出,调用agree()非常简洁,而且由于在agree()内部预先设置了验证规则或返回类型,所以即使不传入别的参数,功能上也能满足我们。在上述例子中,因为 我们在block中设置了默认值,所以第二次运行这个例子时,直接按回车键,而没有输入任何字符,程序也能成功执行,最终返回的answer等于true(因为默认值等于'y')。

    4. choose

    choose()的作用是在终端打印一个可选列表,然后等待用户输入序号或内容进行选择。
    choose()同样也是调用ask()来实现的,它内部会预先设置一些参数来控制如何将各个参数组装成question、如何验证用户的输入等
    choose()方法声明

    # @param items [Array<String>] 快速设置menu的items
    # @param details [Proc] 进一步设置menu的属性
    def choose(*items, &details)
    

    同样的,我们通过一个简单的例子来快速了解一下choose()的功能

    require 'highline/import'
    
    answer = choose("apple", "orange", "pear", "banana") do |menu|
        menu.header = "which fruit do you like"
    end     
    puts "your answer is #{answer}"
    

    执行结果



    从上述列子中,我们可以看出,choose()的执行流程大体上没有改变,仍然是上面提到的那三个步骤:

    1. 输出带有列表的question
    2. 获取用户的选择
    3. 返回answer。

    第一步同样是输出question,只是比之前多了一个可选列表,第二步则限制了用户只能输入列表中的选项或其对应的序列号。

    对比agree(),我们发现choose()和agree()非常类似,它们都是在ask()的基础上进行了二次封装,它们都深入到了具体的使用场景中:agree()专门使用在需要用户确认的场景中,而choose则专门使用在需要用户选择的场景中。而ask()更加灵活,可以用于更多的场景,当然使用起来也更加繁琐。

    以下是choose()的一个常用场景

    require 'highline/import'
    
    answer = choose do |menu|
      menu.header = "There are some fruit"
      menu.prompt = "What's your favourite fruit?"
      
      menu.index = :letter
      menu.index_suffix = ") "
      menu.index_color  = :red 
    
      menu.choice(:apple) do |answer| 
         say("Good choice!")
         answer
      end 
      menu.choices(:orange, :pear) do |answer|
          say("Bad choice!")
          answer
      end 
    end
    
    puts "your answer is #{answer}"
    

    在这个例子中,除了给menu设置header,还增加了prompt,它们分别被打印在可选列表的前面和后面。对于序列号,进行了更细致的修改,增加了一个序列号的前缀")",并设置了序列号的颜色。
    除此以外,还给列表中的每一个选项增加了一个响应block,就是说在选择了这个选项之后,会执行这个block。

    执行结果



    可以看出,question是由header、list、prompt从上到下组成的,可以通过设置这几个参数来自定义设置question。
    在用户输入时,只能输入列表中的选项或其对应序列号,否则需要重新输入。
    如果给选项添加了响应block,则这个block会先被保存起来,然后在用户输入且验证通过之后,这个block会被执行,执行的结果作为answer返回;如果没有传入block,则返回被选中选项的name作为answer(比如选中b,则返回orange)。

    相关文章

      网友评论

          本文标题:Highline的使用

          本文链接:https://www.haomeiwen.com/subject/qfpcfftx.html