question 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 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