question 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d3a0d376bc7b786a49fd2def503783d20b3faba4
4
+ data.tar.gz: b5c4c650182334f747a56f2afac3edf8af9825d4
5
+ SHA512:
6
+ metadata.gz: 57062767899bae46121b0c5c6d96f1b711fc3084c0fbd75a1be1f4fff8e873b308bd7aa5fe845642a07be83b858e7bafe284979c7bcb3b9fc0b5e21f81d7867d
7
+ data.tar.gz: 8ae38cbddfffb390264432f21af1bbc4872c642927abde1a4a5a230046816295486d2ccfcfd36f84871ce170118e54f187554fda399a081989ebb0d73ad2938e
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ /vendor
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in question.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 probablycorey
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Question
2
+
3
+ ![https://s3.amazonaws.com/f.cl.ly/items/2K3w1Y0F2T2o1505191J/Image%202015-01-14%20at%2012.35.04%20PM.png](https://s3.amazonaws.com/f.cl.ly/items/2K3w1Y0F2T2o1505191J/Image%202015-01-14%20at%2012.35.04%20PM.png)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'question'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install question
20
+
21
+ ## Usage
22
+
23
+ See `examples/example.rb`
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ end
7
+
8
+ task :default => :test
9
+
@@ -0,0 +1,24 @@
1
+ require "pp"
2
+
3
+ require "question"
4
+
5
+ choices = [
6
+ { label: "red", value: {r: 255, g: 0, b: 0} },
7
+ { label: "blue", value: "#0000FF" },
8
+ { label: "green", value: "green" }
9
+ ]
10
+
11
+ question = Question::CheckboxList.new("What colors do you like", choices, default: choices[1..-1])
12
+ pp question.ask
13
+
14
+ question = Question::List.new("What is your FAVORITE color", choices)
15
+ pp question.ask
16
+
17
+ question = Question::Input.new("What is your name?", default: ENV["USER"])
18
+ pp question.ask
19
+
20
+ question = Question::Password.new("Enter something secret")
21
+ pp question.ask
22
+
23
+ question = Question::Confirm.new("Do you understand")
24
+ pp question.ask
@@ -0,0 +1,81 @@
1
+ module Question
2
+ class CheckboxList
3
+ def initialize(question, choices, default: nil)
4
+ @question = question
5
+ @choices = choices
6
+ @active_index = 0
7
+ @selected_choices = default || []
8
+ @finished = false
9
+ @modified = false
10
+ end
11
+
12
+ def ask
13
+ TTY.interactive do
14
+ while !@finished
15
+ render
16
+ handle_input
17
+ end
18
+ render # render the results a final time and clear the screen
19
+ end
20
+
21
+ @selected_choices
22
+ end
23
+
24
+ def handle_input
25
+ case TTY.input
26
+ when TTY::CODE::SIGINT
27
+ exit 130
28
+ when TTY::CODE::RETURN
29
+ @finished = true
30
+ when TTY::CODE::DOWN
31
+ @active_index += 1
32
+ @active_index = 0 if @active_index >= @choices.length
33
+ when TTY::CODE::UP
34
+ @active_index -= 1
35
+ @active_index = @choices.length - 1 if @active_index < 0
36
+ when TTY::CODE::SPACE
37
+ @modified = true
38
+ active_choice = @choices[@active_index]
39
+ if @selected_choices.include? active_choice
40
+ @selected_choices.delete(active_choice)
41
+ else
42
+ @selected_choices.push(active_choice)
43
+ end
44
+ end
45
+ end
46
+
47
+ def instructions
48
+ "(Use <space>, <up>, <down> – Press <enter> when finished)"
49
+ end
50
+
51
+ def render
52
+ TTY.clear
53
+ print "? ".colorize(:cyan)
54
+ print @question
55
+ print ": "
56
+ if @finished
57
+ print @selected_choices.map { |choice| choice[:label] }.join(", ").colorize(:green)
58
+ elsif @modified
59
+ print @selected_choices.map { |choice| choice[:label] }.join(", ")
60
+ else
61
+ print instructions.colorize(:light_white)
62
+ end
63
+ print "\n"
64
+
65
+ unless @finished
66
+ @choices.each_with_index do |choice, index|
67
+ print index == @active_index ? TTY::UI::SELECTED : TTY::UI::UNSELECTED
68
+ print " "
69
+ if @selected_choices.include?(choice)
70
+ print TTY::UI::CHECKBOX_CHECKED.colorize(:green)
71
+ else
72
+ print TTY::UI::CHECKBOX_UNCHECKED.colorize(:red)
73
+ end
74
+ print " "
75
+ print choice[:label]
76
+ print "\n"
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,49 @@
1
+ module Question
2
+ class Confirm
3
+ def initialize(question, default:true)
4
+ @question = question
5
+ @finished = false
6
+ @default = default
7
+ @answer = nil
8
+ end
9
+
10
+ def ask
11
+ print TTY::CODE::SAVE
12
+ question = colorized_question
13
+ if @default
14
+ question += "(Y/n) ".colorize(:light_white)
15
+ else
16
+ question += "(y/N) ".colorize(:light_white)
17
+ end
18
+
19
+ # Use readline so keyboard shortcuts like alt-backspace work
20
+ @answer = Readline.readline(question, true)
21
+ @answer = if @answer =~ /^y/i
22
+ true
23
+ elsif @answer =~ /^n/i
24
+ false
25
+ else
26
+ @default
27
+ end
28
+
29
+ render
30
+
31
+ @answer
32
+ rescue Interrupt
33
+ exit 1
34
+ end
35
+
36
+ def render
37
+ TTY.clear
38
+ print colorized_question
39
+ print (@answer ? "Yes" : "No").colorize(:blue)
40
+ print "\n"
41
+ end
42
+
43
+ def colorized_question
44
+ colorized_question = "? ".colorize(:cyan)
45
+ colorized_question += @question
46
+ colorized_question += ": "
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ module Question
2
+ class Input
3
+ def initialize(question, default:nil)
4
+ @question = question
5
+ @finished = false
6
+ @default = default
7
+ @answer = nil
8
+ end
9
+
10
+ def ask
11
+ print TTY::CODE::SAVE
12
+ question = colorized_question
13
+ question += "(#{@default}) ".colorize(:light_white) if @default
14
+
15
+ # Use readline so keyboard shortcuts like alt-backspace work
16
+ @answer = Readline.readline(question, true)
17
+ @answer = @default if @default && @answer.length == 0
18
+
19
+ render
20
+ @answer
21
+ rescue Interrupt
22
+ exit 1
23
+ end
24
+
25
+ def render
26
+ TTY.clear
27
+ print colorized_question
28
+ print @answer.colorize(:blue)
29
+ print "\n"
30
+ end
31
+
32
+ def colorized_question
33
+ colorized_question = "? ".colorize(:cyan)
34
+ colorized_question += @question
35
+ colorized_question += ": "
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,63 @@
1
+ module Question
2
+ class List
3
+ def initialize(question, choices)
4
+ @question = question
5
+ @choices = choices
6
+ @active_index = 0
7
+ @finished = false
8
+ end
9
+
10
+ def ask
11
+ TTY.interactive do
12
+ while !@finished
13
+ render
14
+ handle_input
15
+ end
16
+ render # render the results a final time and clear the screen
17
+ end
18
+
19
+ @choices[@active_index]
20
+ end
21
+
22
+ def handle_input
23
+ case TTY.input
24
+ when TTY::CODE::SIGINT
25
+ exit 130
26
+ when TTY::CODE::RETURN, TTY::CODE::SPACE
27
+ @finished = true
28
+ when TTY::CODE::DOWN
29
+ @active_index += 1
30
+ @active_index = 0 if @active_index >= @choices.length
31
+ when TTY::CODE::UP
32
+ @active_index -= 1
33
+ @active_index = @choices.length - 1 if @active_index < 0
34
+ end
35
+ end
36
+
37
+ def instructions
38
+ "(Press <enter> when to make selection)"
39
+ end
40
+
41
+ def render
42
+ TTY.clear
43
+ print "? ".colorize(:cyan)
44
+ print @question
45
+ print ": "
46
+ if @finished
47
+ print @choices[@active_index][:label].colorize(:green)
48
+ else
49
+ print instructions.colorize(:light_white)
50
+ end
51
+ print "\n"
52
+
53
+ unless @finished
54
+ @choices.each_with_index do |choice, index|
55
+ print index == @active_index ? TTY::UI::SELECTED : TTY::UI::UNSELECTED
56
+ print " "
57
+ print choice[:label]
58
+ print "\n"
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,45 @@
1
+ module Question
2
+ class Password
3
+ def initialize(question)
4
+ @question = question
5
+ @finished = false
6
+ @finished = false
7
+ @answer = ""
8
+ end
9
+
10
+ def ask
11
+ TTY.interactive do
12
+ while !@finished
13
+ render
14
+ handle_input
15
+ end
16
+ end
17
+ render
18
+
19
+ @answer
20
+ end
21
+
22
+ def handle_input
23
+ case input = TTY.input
24
+ when TTY::CODE::SIGINT
25
+ exit 130
26
+ when TTY::CODE::RETURN
27
+ @finished = true
28
+ when TTY::CODE::BACKSPACE, TTY::CODE::DELETE
29
+ @answer.chop! unless @answer.length == 0
30
+ when /^[^\e]/
31
+ @answer += input
32
+ end
33
+ end
34
+
35
+ def render
36
+ obscured_password = TTY::UI::SECURE * @answer.length
37
+ TTY.clear
38
+ print "? ".colorize(:cyan)
39
+ print @question
40
+ print ": "
41
+ print @finished ? obscured_password.colorize(:blue) : obscured_password
42
+ print "\n"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,63 @@
1
+ module Question
2
+ class TTY
3
+ module CODE
4
+ SPACE = " "
5
+ TAB = "\t"
6
+ RETURN = "\r"
7
+ LINEFEED = "\n"
8
+ ESCAPE = "\e"
9
+ UP = "\e[A"
10
+ DOWN = "\e[B"
11
+ RIGHT = "\e[C"
12
+ LEFT = "\e[D"
13
+ BACKSPACE = "\b"
14
+ DELETE = "\e[3"
15
+ SIGINT = "\003"
16
+
17
+ HIDE = "\e[?25l"
18
+ SHOW = "\e[?25h"
19
+ CLEAR_DOWN = "\e[0J"
20
+ SAVE = "\e7"
21
+ RESTORE = "\e8"
22
+ end
23
+
24
+ module UI
25
+ SECURE = "•"
26
+ SELECTED = "‣"
27
+ UNSELECTED = " "
28
+ CHECKBOX_CHECKED = "⬢"
29
+ CHECKBOX_UNCHECKED = "⬡"
30
+ end
31
+
32
+ def self.interactive(&block)
33
+ begin
34
+ print TTY::CODE::SAVE
35
+ sync_value = $stdout.sync
36
+ $stdout.sync = true
37
+ print TTY::CODE::HIDE
38
+ block.call
39
+ ensure
40
+ print TTY::CODE::SHOW
41
+ $stdout.sync = sync_value
42
+ end
43
+ end
44
+
45
+ def self.clear
46
+ print TTY::CODE::RESTORE
47
+ print TTY::CODE::CLEAR_DOWN
48
+ end
49
+
50
+ def self.input
51
+ input = $stdin.getch
52
+ return input unless input == "\e"
53
+ begin
54
+ Timeout.timeout(0.01) do
55
+ input += $stdin.getch
56
+ input += $stdin.getch
57
+ end
58
+ rescue Timeout::Error
59
+ end
60
+ input
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Question
2
+ VERSION = "0.1.0"
3
+ end
data/lib/question.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "io/console"
2
+ require "pp"
3
+ require "readline"
4
+ require "timeout"
5
+
6
+ require "colorize"
7
+
8
+ require "question/version"
9
+ require "question/tty"
10
+ require "question/checkbox_list"
11
+ require "question/list"
12
+ require "question/input"
13
+ require "question/password"
14
+ require "question/confirm"
15
+
16
+ module Question
17
+ end
data/question.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'question/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "question"
8
+ spec.version = Question::VERSION
9
+ spec.authors = ["probablycorey"]
10
+ spec.email = ["probablycorey@gmail.com"]
11
+ spec.summary = %q{Interactive command line UI.}
12
+ spec.description = %q{Inspired by Inquirer.js}
13
+ spec.homepage = "https://github.com/probablycorey/question"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "minitest", "~> 1.1"
24
+
25
+ spec.add_runtime_dependency('colorize', '~> 0.7')
26
+ end
@@ -0,0 +1,4 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'question'
3
+
4
+ require 'minitest/autorun'
@@ -0,0 +1,35 @@
1
+ require 'minitest_helper'
2
+
3
+ describe Question do
4
+ describe "CheckboxList" do
5
+ it "returns checked choices" do
6
+
7
+ message = "How are you feeling"
8
+ choices = [
9
+ { label: "good", value: {sub: 1} },
10
+ { label: "neutral", value: 0 },
11
+ { label: "horrible", value: [1,2,3] }
12
+ ]
13
+
14
+ # Fake input
15
+ input = [
16
+ Question::TTY::CODE::UP,
17
+ Question::TTY::CODE::SPACE,
18
+ Question::TTY::CODE::DOWN,
19
+ Question::TTY::CODE::SPACE,
20
+ Question::TTY::CODE::RETURN
21
+ ]
22
+ input_proc = Proc.new { input.shift }
23
+
24
+ result = $stdin.stub :getch, input_proc do
25
+ question = Question::CheckboxList.new(message, choices)
26
+ question.ask()
27
+ end
28
+
29
+ assert_equal result, [
30
+ { label: "horrible", value: [1,2,3] },
31
+ { label: "good", value: {sub: 1} }
32
+ ]
33
+ end
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: question
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - probablycorey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: colorize
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.7'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.7'
69
+ description: Inspired by Inquirer.js
70
+ email:
71
+ - probablycorey@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - Gemfile
78
+ - LICENSE.txt
79
+ - README.md
80
+ - Rakefile
81
+ - examples/example.rb
82
+ - lib/question.rb
83
+ - lib/question/checkbox_list.rb
84
+ - lib/question/confirm.rb
85
+ - lib/question/input.rb
86
+ - lib/question/list.rb
87
+ - lib/question/password.rb
88
+ - lib/question/tty.rb
89
+ - lib/question/version.rb
90
+ - question.gemspec
91
+ - test/minitest_helper.rb
92
+ - test/test_question.rb
93
+ homepage: https://github.com/probablycorey/question
94
+ licenses:
95
+ - MIT
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.2.2
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Interactive command line UI.
117
+ test_files:
118
+ - test/minitest_helper.rb
119
+ - test/test_question.rb