sawaal 0.0.3 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0bc314370fc85cffecc450c3e924af5e60da5115
4
- data.tar.gz: 9913428b8f65b7e04269eb0652c73a8cd2eea89b
3
+ metadata.gz: 6951a118f49374178545e4c34d8e19341b872542
4
+ data.tar.gz: a6d932398b2d7c1c7ef6eb9eab3e13eae45d6df1
5
5
  SHA512:
6
- metadata.gz: c142249de7013d8d3ac88d3522c2cdeb864fa18366621f66fb24deece581240d83c632c8969e8a6b3155d1ca128c19dae70c1161a6d116ef0d86578784db0d4e
7
- data.tar.gz: 0a3b5e9c59a2433acad50ae469bea399200b8a468d8853697c87f15ce67b3936a5cbd9966f9a4b8bfc8868bfbfcc76c0d504ecea11510dc60aa1395693c9849f
6
+ metadata.gz: 35d8afd33063c9dda00824903d1b1ca78e9ba4ffd89f557454e68119464fa64c29bc96d315b88fd6356628127cadbab8f2ae8868e09bb410aa1199298909dc5f
7
+ data.tar.gz: 3e45020160d7867a1d908dde9ef0821632c10512e90643b34a0c96b6421a230380c628aaf8584fda1b410797303593505e5b9284ac260b43a174fd19165c6f74
@@ -3,12 +3,32 @@ List of changes so far that have been released to ruby gems.
3
3
  <!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc/generate-toc again -->
4
4
  **Table of Contents**
5
5
 
6
+ - [1.0.0 / 2015-07-27](#100--2015-07-27)
7
+ - [Features](#features)
8
+ - [Ability to select item from a list](#ability-to-select-item-from-a-list)
9
+ - [Improvement](#improvement)
10
+ - [Improve CI integration](#improve-ci-integration)
6
11
  - [0.0.3 / 2015-07-27](#003--2015-07-27)
7
12
  - [0.0.2 / 2015-07-27](#002--2015-07-27)
8
13
  - [0.0.1 / 2015-07-27](#001--2015-07-27)
9
14
 
10
15
  <!-- markdown-toc end -->
11
16
 
17
+ 1.0.0 / 2015-07-27
18
+ ==================
19
+
20
+ First working version!
21
+
22
+ ## Features
23
+
24
+ ### Ability to select item from a list
25
+
26
+ Support for hash and array as input.
27
+
28
+ ## Improvement
29
+
30
+ ### Improve CI integration
31
+
12
32
  0.0.3 / 2015-07-27
13
33
  ==================
14
34
 
data/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
  <!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc/generate-toc again -->
11
11
  **Table of Contents**
12
12
 
13
- - [sawaal [![Version](http://img.shields.io/gem/v/sawaal.svg?style=flat-square)](https://rubygems.org/gems/sawaal)](#sawaal-versionhttpimgshieldsiogemvsawaalsvgstyleflat-squarehttpsrubygemsorggemssawaal)
13
+ - [sawaal](#sawaal)
14
14
  - [Summary](#summary)
15
15
  - [Installation](#installation)
16
16
  - [Usage](#usage)
data/Rakefile CHANGED
@@ -13,7 +13,7 @@ FileList['tasks/*.rake'].each(&method(:import))
13
13
  desc 'run code coverage checker'
14
14
  task :coverage do
15
15
  ENV['COVERAGE'] = 'true'
16
- Rake::Task['spec'].execute
16
+ Rake::Task['spec'].invoke
17
17
  end
18
18
 
19
19
  desc 'default rake task'
@@ -22,7 +22,7 @@ task default: [:clean, :coverage, :rubocop, :verify_measurements, :yardstick_mea
22
22
  desc 'run CI tasks'
23
23
  task :ci do
24
24
  ENV['CI'] = 'true'
25
- Rake::Task['default'].execute
25
+ Rake::Task['default'].invoke
26
26
  end
27
27
 
28
28
  desc 'Load gem inside irb console'
@@ -1,8 +1,24 @@
1
1
  # encoding: utf-8
2
+
2
3
  require 'sawaal/version'
4
+ require 'sawaal/selector'
3
5
 
4
6
  # Helps a command line application by allowing it to ask
5
7
  # multiple choice questions
6
8
  module Sawaal
7
- # Your code goes here...
9
+ class << self
10
+ # Run the selection prompt with selectable options
11
+ #
12
+ # @example
13
+ # Sawaal.select('which key is the best?',
14
+ # key1: 'key1 is the best',
15
+ # key2: 'key2 is the best',
16
+ # key3: 'key3 is the best',
17
+ # key4: 'key4 is the best')
18
+ #
19
+ # @return [Symbol] Selected key
20
+ def select(question, options)
21
+ Sawaal::Selector.choose(question, options)
22
+ end
23
+ end
8
24
  end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+
3
+ module Sawaal
4
+ # Methods to colorize output
5
+ #
6
+ # @api private
7
+ module Color
8
+ # Colorize a string with red color
9
+ #
10
+ # @return [String]
11
+ def red(str)
12
+ colorize(str, 31)
13
+ end
14
+
15
+ # Colorize a string with green color
16
+ #
17
+ # @return [String]
18
+ def green(str)
19
+ colorize(str, 32)
20
+ end
21
+
22
+ # Colorize a string with cyan color
23
+ #
24
+ # @return [String]
25
+ def cyan(str)
26
+ colorize(str, 36)
27
+ end
28
+
29
+ # Returns the bold representation
30
+ #
31
+ # @return [String]
32
+ def bold(str)
33
+ colorize(str, 1, 22)
34
+ end
35
+
36
+ private
37
+
38
+ # Wrap a string in a specific color code
39
+ #
40
+ # @return [String]
41
+ def colorize(str, color_code, end_tag = 0)
42
+ "\033[#{color_code}m#{str}\033[#{end_tag}m"
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ require 'sawaal/color'
4
+ require 'sawaal/tty'
5
+
6
+ module Sawaal
7
+ # Handle cursor movements and text highlighting
8
+ #
9
+ # @api private
10
+ class Cursor
11
+ include Color
12
+
13
+ attr_accessor :current_line_index
14
+
15
+ def initialize
16
+ @text = []
17
+ @current_line_index = -1
18
+ end
19
+
20
+ def save_excursion(&block)
21
+ hide
22
+ begin
23
+ return block.call
24
+ ensure
25
+ show
26
+ end
27
+ end
28
+
29
+ def hide
30
+ TTY.print TTY::HIDE_CURSOR
31
+ end
32
+
33
+ def show
34
+ TTY.print TTY::SHOW_CURSOR
35
+ end
36
+
37
+ def move_up
38
+ TTY.print TTY::MOVE_UP
39
+ end
40
+
41
+ def move_down
42
+ TTY.print TTY::MOVE_DOWN
43
+ end
44
+
45
+ def write_question(question)
46
+ TTY.print "#{green('?')} #{bold(question)} "
47
+ save_position
48
+ TTY.print '(use arrow keys, press <enter> when finished)'
49
+ end
50
+
51
+ def write_item(item)
52
+ line = "#{bold TTY::ARROW} #{item}"
53
+ move_down
54
+ move_to_beginning
55
+ TTY.print line
56
+ @text.push(line)
57
+ @current_line_index += 1
58
+ end
59
+
60
+ def write_selection(item)
61
+ move_to(@text.length)
62
+ move_to_beginning
63
+ @text.length.times do
64
+ move_up
65
+ clear_line
66
+ end
67
+
68
+ restore_position
69
+ clear_line
70
+ TTY.println cyan(item)
71
+ end
72
+
73
+ def highlight(index)
74
+ index %= @text.length
75
+ unhighlight
76
+ move_to(index)
77
+ @current_line_index = index
78
+
79
+ move_to_beginning
80
+ clear_line
81
+ TTY.print cyan(@text[@current_line_index])
82
+ end
83
+
84
+ private
85
+
86
+ def unhighlight
87
+ move_to_beginning
88
+ clear_line
89
+ TTY.print @text[@current_line_index]
90
+ end
91
+
92
+ def move_to_beginning
93
+ TTY.print TTY::BEGINNING_OF_LINE
94
+ end
95
+
96
+ def move_to(index)
97
+ if index < @current_line_index
98
+ (@current_line_index - index).times { move_up }
99
+ else
100
+ (index - @current_line_index).times { move_down }
101
+ end
102
+ end
103
+
104
+ def clear_line
105
+ TTY.print TTY::CLEAR_LINE
106
+ end
107
+
108
+ def save_position
109
+ TTY.print TTY::SAVE_POSITION
110
+ end
111
+
112
+ def restore_position
113
+ TTY.print TTY::RESTORE_POSITION
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+
3
+ module Sawaal
4
+ # Handle option selection
5
+ #
6
+ # @api private
7
+ class Selections
8
+ include Color
9
+
10
+ def initialize(cursor, options)
11
+ @cursor = cursor
12
+ @keys, @items = build_items(options)
13
+ end
14
+
15
+ def select
16
+ loop do
17
+ ch = read_char
18
+ case ch
19
+ when TTY::RETURN
20
+ break
21
+ when TTY::MOVE_UP
22
+ @cursor.highlight(@cursor.current_line_index - 1)
23
+ when TTY::MOVE_DOWN
24
+ @cursor.highlight(@cursor.current_line_index + 1)
25
+ when TTY::CONTROL_C
26
+ @cursor.write_selection(red('terminated'))
27
+ exit 33
28
+ end
29
+ end
30
+
31
+ selected = @cursor.current_line_index
32
+ @cursor.write_selection(@items[selected])
33
+ @keys[@cursor.current_line_index]
34
+ end
35
+
36
+ def write
37
+ @items.each do |item|
38
+ @cursor.write_item(item)
39
+ end
40
+ @cursor.highlight(0)
41
+ end
42
+
43
+ private
44
+
45
+ # Reads keypresses from the user including 2 and 3 escape character sequences.
46
+ def read_char
47
+ input = $stdin.getch
48
+ return input unless input == "\e"
49
+ begin
50
+ Timeout.timeout(0.01) do
51
+ input += $stdin.getch
52
+ input += $stdin.getch
53
+ end
54
+ rescue Timeout::Error
55
+ # ignored
56
+ end
57
+ input
58
+ end
59
+
60
+ def build_items(options)
61
+ if options.is_a?(Hash)
62
+ return options.keys, options.values
63
+ elsif options.is_a?(Array)
64
+ return Array(0..(options.length - 1)), options
65
+ else
66
+ fail(StandardError, 'invalid option type for selection')
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ require 'io/console'
4
+
5
+ require 'sawaal/cursor'
6
+ require 'sawaal/selections'
7
+
8
+ module Sawaal
9
+ # Way into invoking the selection
10
+ #
11
+ # @api private
12
+ class Selector
13
+ def self.choose(question, options)
14
+ cursor = Cursor.new
15
+ selections = Selections.new(cursor, options)
16
+
17
+ cursor.save_excursion do
18
+ cursor.write_question question
19
+ selections.write
20
+ selections.select
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+
3
+ module Sawaal
4
+ # Constants for TTY and methods to read and write to terminal
5
+ #
6
+ # @api private
7
+ module TTY
8
+ class << self
9
+ def ansii_escape(sequence)
10
+ "\033[#{sequence}"
11
+ end
12
+
13
+ ORIGINAL_PRINT = method(:print)
14
+
15
+ def print(str)
16
+ ORIGINAL_PRINT.call str
17
+ end
18
+
19
+ def println(str)
20
+ puts str
21
+ end
22
+ end
23
+
24
+ HIDE_CURSOR = ansii_escape('?25l')
25
+ SHOW_CURSOR = ansii_escape('?25h')
26
+
27
+ MOVE_UP = ansii_escape('A')
28
+ MOVE_DOWN = ansii_escape('B')
29
+ BEGINNING_OF_LINE = ansii_escape('1G')
30
+
31
+ CLEAR_LINE = ansii_escape('K')
32
+ SAVE_POSITION = ansii_escape('s')
33
+ RESTORE_POSITION = ansii_escape('u')
34
+
35
+ RETURN = "\r"
36
+ CONTROL_C = '\\u0003'
37
+
38
+ ARROW = '‣'
39
+ end
40
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Track version of the module
4
4
  module Sawaal
5
- VERSION = '0.0.3'
5
+ VERSION = '1.0.0'
6
6
  end
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'spec_util'
6
+
7
+ require 'sawaal/selector'
8
+
9
+ describe Sawaal::Selector do
10
+ it 'allows use of arrow keys to select' do
11
+ with_input_output([
12
+ Sawaal::TTY::MOVE_UP,
13
+ Sawaal::TTY::MOVE_DOWN,
14
+ Sawaal::TTY::MOVE_DOWN,
15
+ Sawaal::TTY::MOVE_DOWN,
16
+ Sawaal::TTY::RETURN
17
+ ]) do
18
+ selected = Sawaal.select('which key is the best?',
19
+ key1: 'key1 is the best',
20
+ key2: 'key2 is the best',
21
+ key3: 'key3 is the best',
22
+ key4: 'key4 is the best')
23
+ expect(selected).to(eq(:key3))
24
+ end
25
+ end
26
+
27
+ it 'allows selection over an array' do
28
+ with_input_output([
29
+ Sawaal::TTY::MOVE_UP,
30
+ Sawaal::TTY::MOVE_DOWN,
31
+ Sawaal::TTY::MOVE_DOWN,
32
+ Sawaal::TTY::MOVE_DOWN,
33
+ Sawaal::TTY::RETURN
34
+ ]) do
35
+ selected = Sawaal.select('which key is the best?', [
36
+ 'key1 is the best',
37
+ 'key2 is the best',
38
+ 'key3 is the best',
39
+ 'key4 is the best'
40
+ ])
41
+ expect(selected).to(eq(2))
42
+ end
43
+ end
44
+
45
+ it 'does not allow invalid values for selection' do
46
+ with_input_output([
47
+ Sawaal::TTY::MOVE_UP,
48
+ Sawaal::TTY::MOVE_DOWN,
49
+ Sawaal::TTY::MOVE_DOWN,
50
+ Sawaal::TTY::MOVE_DOWN,
51
+ Sawaal::TTY::RETURN
52
+ ]) do
53
+ expect { Sawaal.select('which key is the best?', Object.new) }.to(
54
+ raise_error(StandardError, 'invalid option type for selection'))
55
+ end
56
+ end
57
+
58
+ it 'allows use of C-c to exit' do
59
+ def run_test
60
+ with_input_output([
61
+ Sawaal::TTY::MOVE_DOWN,
62
+ Sawaal::TTY::CONTROL_C
63
+ ]) do
64
+ Sawaal.select('which key is the best?',
65
+ key1: 'key1 is the best',
66
+ key2: 'key2 is the best',
67
+ key3: 'key3 is the best',
68
+ key4: 'key4 is the best')
69
+ end
70
+ end
71
+ expect { run_test }.to(raise_error(SystemExit))
72
+ end
73
+ end
@@ -18,7 +18,7 @@ if ENV['COVERAGE']
18
18
  require 'simplecov'
19
19
  SimpleCov.start do
20
20
  add_filter '/spec/'
21
- SimpleCov.minimum_coverage 100
21
+ SimpleCov.minimum_coverage 95
22
22
  end
23
23
  end
24
24
 
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require 'tempfile'
4
+
5
+ def with_input_output(input, &block)
6
+ allow(STDIN).to(receive(:getc).and_return(*input))
7
+ allow(Sawaal::TTY).to(receive(:print))
8
+ allow(Sawaal::TTY).to(receive(:println))
9
+ block.call
10
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  describe Sawaal do
4
4
  it 'has a valid version tag' do
5
- expect(Sawaal::VERSION).to(eq('0.0.3'))
5
+ expect(Sawaal::VERSION).to(eq('1.0.0'))
6
6
  end
7
7
  end
@@ -13,7 +13,7 @@ begin
13
13
 
14
14
  # verify_measurements task
15
15
  Yardstick::Rake::Verify.new do |verify|
16
- verify.threshold = 100
16
+ verify.threshold = 80
17
17
  verify.require_exact_threshold = false
18
18
  end
19
19
  rescue LoadError
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sawaal
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anshul Verma
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-27 00:00:00.000000000 Z
11
+ date: 2015-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,8 +38,15 @@ files:
38
38
  - README.md
39
39
  - Rakefile
40
40
  - lib/sawaal.rb
41
+ - lib/sawaal/color.rb
42
+ - lib/sawaal/cursor.rb
43
+ - lib/sawaal/selections.rb
44
+ - lib/sawaal/selector.rb
45
+ - lib/sawaal/tty.rb
41
46
  - lib/sawaal/version.rb
47
+ - spec/selector_spec.rb
42
48
  - spec/spec_helper.rb
49
+ - spec/spec_util.rb
43
50
  - spec/version_spec.rb
44
51
  - tasks/rdoc.rake
45
52
  - tasks/rubucop.rake
@@ -69,6 +76,8 @@ signing_key:
69
76
  specification_version: 4
70
77
  summary: Helper gem for asking questions on terminal
71
78
  test_files:
79
+ - spec/selector_spec.rb
72
80
  - spec/spec_helper.rb
81
+ - spec/spec_util.rb
73
82
  - spec/version_spec.rb
74
83
  has_rdoc: