questions 1.0.1

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: 41e385aa0a2fa87149846bfa99223235a5910887
4
+ data.tar.gz: 5aa6e4a359aad4dc0bfa7232b79daabc4a746934
5
+ SHA512:
6
+ metadata.gz: c1056f0f6f023509511d95659796f301be00924d129e2c2a38cdffed01df1899b2adf275367c1e662c5dfc959bd2c874a323fce5ce66a2dae997ee013b145d08
7
+ data.tar.gz: c74a6eca07e5d9a80327b2df544bae4bd9adfe042479a37eb9e1d109266d1b781a2d10022842d990a69866a7e6674bd2db36a9be8f96b2d11cbc3eea60ddddfa
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in questions.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 DSIW
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,62 @@
1
+ # Question
2
+
3
+ Ask human a question. She or he has to select one answer.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'questions'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install questions
18
+
19
+ ## Usage
20
+
21
+ ### Preamble
22
+ ``` ruby
23
+ require "questions"
24
+ include Questions
25
+ ```
26
+
27
+ ### Long way
28
+ ``` ruby
29
+ q = Question.new("File does exist, what should be done?")
30
+ q.answers = [:skip, :overwrite, :abort]
31
+ answer = q.ask
32
+ # SHELL:
33
+ # $ File does exist, what should be done? [s]kip, [o]verwrite, [a]bort
34
+ # s<enter>
35
+ answer #=> :skip
36
+ ```
37
+
38
+ ### Short way
39
+ ``` ruby
40
+ answer = Question.ask "File does exist, what should be done?", [:skip, :overwrite, :abort]
41
+ # SHELL:
42
+ # $ File does exist, what should be done? [s]kip, [o]verwrite, [a]bort
43
+ # s<enter>
44
+ answer #=> :skip
45
+ ```
46
+
47
+ ### Hashish way
48
+ ``` ruby
49
+ answer = Question.ask "File does exist, what should be done?", skip: true, overwrite: false, abort: true
50
+ # SHELL:
51
+ # $ File does exist, what should be done? [s]kip, [a]bort
52
+ # s<enter>
53
+ answer #=> :skip
54
+ ```
55
+
56
+ ## Contributing
57
+
58
+ 1. Fork it
59
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
60
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
61
+ 4. Push to the branch (`git push origin my-new-feature`)
62
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,34 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/clean'
4
+ require 'rake/version_task'
5
+
6
+ require 'rspec/core/rake_task'
7
+
8
+ RSpec::Core::RakeTask.new do |t|
9
+ # Put spec opts in a file named .rspec in root
10
+ end
11
+
12
+ Rake::VersionTask.new
13
+
14
+ task :doc => [ 'doc:clean', 'doc:api' ]
15
+
16
+ CLOBBER << "doc"
17
+ CLEAN << "doc"
18
+ namespace :doc do
19
+ require 'yard'
20
+ YARD::Rake::YardocTask.new(:api) do |t|
21
+ t.files = ['lib/**/*.rb']
22
+ t.options = [
23
+ '--output-dir', 'doc/api',
24
+ '--markup', 'markdown'
25
+ ]
26
+ end
27
+
28
+ desc 'Remove YARD Documentation'
29
+ task :clean do
30
+ system("rm -rf #{File.dirname(__FILE__)}/doc/api")
31
+ end
32
+ end
33
+
34
+ task :default => [:spec]
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.1
@@ -0,0 +1,129 @@
1
+ # encoding: utf-8
2
+
3
+ module Questions
4
+ class Answer
5
+ SPECIAL_ENDINGS = [:all]
6
+
7
+ # Instantiates new Answer object.
8
+ #
9
+ # Only the first key value pair will be used.
10
+ #
11
+ # @param [Hash] answer_hash Key (instruction); value (activeness) is `true` or `false`.
12
+ #
13
+ # @example Hash with one item
14
+ # Answer.new({:overwrite => true}) #=> [o]verwrite
15
+ # Answer.new(:overwrite => true) #=> [o]verwrite
16
+ # Answer.new(:overwrite) #=> [o]verwrite
17
+ # Answer.new({:overwrite => false}) #=> ""
18
+ # Answer.new(:overwrite => false) #=> ""
19
+ # Answer.new({:overwrite => nil}) #=> ""
20
+ #
21
+ # @example Items of hash with more than one item will be ignored
22
+ # Answer.new({:overwrite => true, :overwrite_all => false}) #=> [o]verwrite
23
+ # Answer.new({:overwrite => true, :overwrite_all => true}) #=> [o]verwrite
24
+ def initialize(*answer_hash)
25
+ hash = answer_hash.first
26
+ hash = {hash => true} if hash.is_a? Symbol
27
+
28
+ unless [Hash, Symbol].any? { |class_name| hash.is_a? class_name }
29
+ raise ArgumentError, "Parameter has to be a key-value-pair or a symbol"
30
+ end
31
+
32
+ array = hash.first
33
+ @instruction = array[0]
34
+ @active = array[1]
35
+ end
36
+
37
+ # Gets instruction
38
+ #
39
+ # @example Hash with one item
40
+ # Answer.new(overwrite: true).instruction #=> :overwrite
41
+ # Answer.new(overwrite: false).instruction #=> :overwrite
42
+ attr_reader :instruction
43
+
44
+ # Is answer active?
45
+ #
46
+ # @example Hash with one item
47
+ # Answer.new(overwrite: true).active? #=> true
48
+ # Answer.new(overwrite: false).active? #=> false
49
+ #
50
+ # @see {true?}
51
+ def active?
52
+ @active
53
+ end
54
+ alias :true? :active?
55
+
56
+ # Is answer inactive?
57
+ #
58
+ # @example Hash with one item
59
+ # Answer.new(overwrite: true).inactive? #=> false
60
+ # Answer.new(overwrite: false).inactive? #=> true
61
+ #
62
+ # @see {false?}
63
+ def inactive?
64
+ !active?
65
+ end
66
+ alias :false? :inactive?
67
+
68
+ # Sets indicator
69
+ #
70
+ # @example Hash with one item
71
+ # answer = Answer.new(overwrite: true)
72
+ # answer.indicator = :ov
73
+ # answer.indicator #=> :ov
74
+ attr_writer :indicator
75
+
76
+ # Gets indicator
77
+ #
78
+ # @example with true answer
79
+ # a = Answer.new(overwrite: true)
80
+ # a.indicator #=> :o
81
+ # a.indicator(2) #=> :ov
82
+ #
83
+ # @example with special true answer
84
+ # Answer.new(overwrite_all: true).indicator(2) #=> :OV
85
+ #
86
+ # @example with inactive answer
87
+ # Answer.new(overwrite: false).indicator #=> nil
88
+ #
89
+ # @example set indicator
90
+ # a = Answer.new(overwrite: true)
91
+ # a.indicator #=> :o
92
+ # a.indicator = :ov
93
+ # a.indicator #=> :ov
94
+ def indicator(first_chars=1)
95
+ return nil if inactive?
96
+ return @indicator if @indicator
97
+ indicator = instruction.to_s[0...first_chars]
98
+ indicator.upcase! if special?
99
+ indicator.to_sym
100
+ end
101
+
102
+ # Returns `true` if answer is special. Special answers are answers which ends with one of the {SPECIAL_ENDINGS}, `false` otherwise.
103
+ def special?
104
+ SPECIAL_ENDINGS.any? { |ending| instruction.to_s =~ /#{ending}$/ }
105
+ end
106
+
107
+ # Gets indicator hash
108
+ #
109
+ # @example Hash with one item
110
+ # Answer.new(overwrite: true).indicator_hash #=> {:o => :overwrite}
111
+ # Answer.new(overwrite: false).indicator_hash #=> nil
112
+ def indicator_hash
113
+ return nil if inactive?
114
+ {indicator => instruction}
115
+ end
116
+
117
+ # Gets string representation
118
+ #
119
+ # @example Hash with one item
120
+ # Answer.new(overwrite: true).to_s #=> "[o]verwrite"
121
+ # Answer.new(overwrite: false).to_s #=> ""
122
+ def to_s
123
+ return nil if inactive?
124
+ instruction_without_indicator = instruction.to_s[indicator.length..-1]
125
+ humanized = instruction_without_indicator.gsub("_", " ")
126
+ "[#{indicator}]#{humanized}"
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,196 @@
1
+ # encoding: utf-8
2
+
3
+ module Questions
4
+ class Answers < Array
5
+ # Instantiates a new Answers object.
6
+ #
7
+ # @param args [Answer, Symbol, Array, Hash] Initial answers
8
+ #
9
+ # Each parameter will be send to {#<<}.
10
+ #
11
+ # @example parameter as Answer
12
+ # answers = Answers.new Answer.new(:abort)
13
+ # answers.first.instruction #=> :abort
14
+ # answers.first.active #=> true
15
+ #
16
+ # @example parameter as Symbol
17
+ # answers = Answers.new :abort
18
+ # answers.first.instruction #=> :abort
19
+ # answers.first.active #=> true
20
+ #
21
+ # @example parameter as Array
22
+ # answers = Answers.new [:abort, Answer.new(:overwrite)]
23
+ # answers.first.instruction #=> :abort
24
+ # answers.first.active #=> true
25
+ # answers.last.instruction #=> :overwrite
26
+ # answers.last.active #=> true
27
+ #
28
+ # @example parameter as Hash
29
+ # answers = Answers.new({abort: true, overwrite: false, "non-symbol" => "ignored"})
30
+ # answers.size #=> 2
31
+ # answers.first.instruction #=> :abort
32
+ # answers.first.active #=> true
33
+ # answers.last.instruction #=> :overwrite
34
+ # answers.last.active #=> false
35
+ def initialize(*args)
36
+ args.each { |arg| self << arg }
37
+ end
38
+
39
+ # Adds answer. Answer can be an instance of {Answer}, {Symbol}, a {Hash} or an {Array}. Chaining is
40
+ # supported.
41
+ #
42
+ # @example parameter as Answer
43
+ # answers = Answers.new
44
+ # answers << Answer.new(:abort)
45
+ # answers.first.instruction #=> :abort
46
+ # answers.first.active #=> true
47
+ #
48
+ # @example parameter as Symbol
49
+ # answers = Answers.new
50
+ # answers << :abort << :overwrite
51
+ # answers.first.instruction #=> :abort
52
+ # answers.first.active #=> true
53
+ # answers.last.instruction #=> :overwrite
54
+ # answers.last.active #=> true
55
+ #
56
+ # @example parameter as Array
57
+ # answers = Answers.new
58
+ # answers << [:abort, Answer.new(:overwrite)]
59
+ # answers.first.instruction #=> :abort
60
+ # answers.first.active #=> true
61
+ # answers.last.instruction #=> :overwrite
62
+ # answers.last.active #=> true
63
+ #
64
+ # @example parameter as Hash
65
+ # answers = Answers.new
66
+ # answers << {abort: true, overwrite: false, "non-symbol" => "ignored"}
67
+ # answers.size #=> 2
68
+ # answers.first.instruction #=> :abort
69
+ # answers.first.active #=> true
70
+ # answers.last.instruction #=> :overwrite
71
+ # answers.last.active #=> false
72
+ #
73
+ # @return [Answers] self
74
+ def <<(arg)
75
+ case arg
76
+ when Answer then super arg
77
+ when Symbol then super Answer.new(arg)
78
+ when Array
79
+ arg.each { |arg| self << arg } # call as Answer or Symbol
80
+ when Hash
81
+ self << convert_hash_to_answers(select_symbols(arg)) # call as Array
82
+ end
83
+ self
84
+ end
85
+
86
+ # Gets answer by indicator.
87
+ #
88
+ # @example
89
+ # answers = Answers.new [:abort, :overwrite]
90
+ # answers[:a].instruction #=> :abort
91
+ # answers[:o].instruction #=> :overwrite
92
+ #
93
+ # @return [Answer]
94
+ def [](indicator)
95
+ update_indicators_for_uniqueness!
96
+ select { |answer| answer.indicator == indicator }.first
97
+ end
98
+
99
+ # Updates indicators to get all unique.
100
+ #
101
+ # @example
102
+ # answers = Answers.new [:abort, :abort_all, :abc]
103
+ # answers.indicators #=> [:a, :A, :a]
104
+ # answers.has_unique_indicators? #=> false
105
+ # answers.update_indicators_for_uniqueness!
106
+ # answers.indicators #=> [:a, :A, :ab]
107
+ # answers.has_unique_indicators? #=> true
108
+ def update_indicators_for_uniqueness!
109
+ return if has_unique_indicators?
110
+
111
+ each_with_index do |answer, i|
112
+ other_indicators = first(i).map(&:indicator)
113
+ answer.indicator = free_indicator_of(answer, used_indicators: other_indicators)
114
+ end
115
+ end
116
+
117
+ # Gets all indicators of answers.
118
+ #
119
+ # @example
120
+ # answers = Answers.new [:abort, :abort_all, :abc]
121
+ # answers.indicators #=> [:a, :A, :a]
122
+ # answers.update_indicators_for_uniqueness!
123
+ # answers.indicators #=> [:a, :A, :ab]
124
+ def indicators
125
+ map(&:indicator)
126
+ end
127
+
128
+ # Returns true if indicators are unique, false otherwise.
129
+ #
130
+ # @example
131
+ # answers = Answers.new [:abort, :abort_all, :abc]
132
+ # answers.indicators #=> [:a, :A, :a]
133
+ # answers.has_unique_indicators? #=> false
134
+ # answers.update_indicators_for_uniqueness!
135
+ # answers.indicators #=> [:a, :A, :ab]
136
+ # answers.has_unique_indicators? #=> true
137
+ def has_unique_indicators?
138
+ indicators == indicators.uniq
139
+ end
140
+
141
+ # Returns all answers as choice string.
142
+ #
143
+ # @example with only true answers
144
+ # answers = Answers.new [:abort, :abort_all, :abc]
145
+ # answers.choice_string #=> "[a]bort, [A]bort all, [ab]c"
146
+ #
147
+ # @example with false answer
148
+ # answers = Answers.new {abort: true, abort_all: false, abc: true}
149
+ # answers.choice_string #=> "[a]bort, [ab]c"
150
+ def to_s
151
+ update_indicators_for_uniqueness!
152
+ map(&:to_s).compact.join(", ")
153
+ end
154
+
155
+ private
156
+
157
+ # {"abc" => true, abort: true, overwrite: false} => {abort: true}
158
+ def select_symbols(args)
159
+ args.select { |inst, value| inst.is_a?(Symbol) }
160
+ end
161
+
162
+ # {abort: true} => [Answer.new(:abort => true)]
163
+ def convert_hash_to_answers(answers)
164
+ answers.reduce([]) { |array, (inst, value)| array << Answer.new({inst => value}) }
165
+ end
166
+
167
+ # :symbol => Answer.new(:symbol)
168
+ # Answer.new(:symbol) => Answer.new(:symbol)
169
+ # "string" => raise ArgumentError
170
+ def convert_symbol_to_answer_or_send_through(arg)
171
+ case arg
172
+ when Answer then arg
173
+ when Symbol then Answer.new(arg)
174
+ else
175
+ raise ArgumentError
176
+ end
177
+ end
178
+
179
+ # Gets first free indicator for `answer` which isn't used by `used_indicators`.
180
+ def free_indicator_of answer, opts={}
181
+ opts = {:used_indicators => []}.merge(opts)
182
+ used_indicators = opts[:used_indicators]
183
+
184
+ i = 1
185
+ loop do
186
+ indicator = answer.indicator(i)
187
+ if used_indicators.include? indicator
188
+ i+=1
189
+ redo # next try
190
+ else
191
+ return indicator
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: utf-8
2
+
3
+ module Questions
4
+ # You can ask a question with answers for selection. User can select one answer.
5
+ #
6
+ # @example Long way
7
+ # q = Question.new("File does exist, what should be done?")
8
+ # q.answers = [:skip, :overwrite, :abort]
9
+ # answer = q.ask
10
+ # # SHELL:
11
+ # # $ File does exist, what should be done? [s]kip, [o]verwrite, [a]bort
12
+ # # s<enter>
13
+ # answer #=> :skip
14
+ #
15
+ # @example Short way
16
+ # answer = Question.ask "File does exist, what should be done?", [:skip, :overwrite, :abort]
17
+ # # SHELL:
18
+ # # $ File does exist, what should be done? [s]kip, [o]verwrite, [a]bort
19
+ # # s<enter>
20
+ # answer #=> :skip
21
+ #
22
+ # It's also possible to specify answers as an Hash:
23
+ #
24
+ # @example Hashish way
25
+ # answer = Question.ask "File does exist, what should be done?", skip: true, overwrite: false, abort: true
26
+ # # SHELL:
27
+ # # $ File does exist, what should be done? [s]kip, [a]bort
28
+ # # s<enter>
29
+ # answer #=> :skip
30
+ class Question
31
+ attr_reader :question
32
+ attr_reader :answers
33
+
34
+ # Instantiates a new Question object.
35
+ #
36
+ # @param question [String] This message will be printed
37
+ def initialize(question)
38
+ @question = question
39
+ @answers = Answers.new
40
+ end
41
+
42
+ # Sets answers
43
+ #
44
+ # @example
45
+ # q = Question.new("File does exist, what should be done?")
46
+ # q.answers = [:yes, :no]
47
+ # q.answers.size #=> 2
48
+ # q.answers.map(&:instruction) #=> [:yes, :no]
49
+ #
50
+ def answers=(*args)
51
+ @answers.clear
52
+ args.each { |arg| @answers << arg }
53
+ end
54
+
55
+ # Asks question to user. If user typed wrong indicator, then it will be asked again.
56
+ #
57
+ # @example without answers
58
+ # q = Question.new("What?")
59
+ # q.ask #=> raise Error
60
+ #
61
+ # @example with answers
62
+ # q = Question.new("What?")
63
+ # q.answers = [:yes, :no]
64
+ # q.ask #=> :yes if user typed 'y'
65
+ #
66
+ # @return [Symbol] selected answer
67
+ def ask
68
+ raise "You have to set answers" if answers.empty?
69
+ answer = gets "#{@question} #{answers}"
70
+ answers[answer.to_sym].instruction || ask
71
+ end
72
+
73
+ # Asks question.
74
+ #
75
+ # @param question [String] Message that will be printed
76
+ # @param answers [Array, Hash] Answers that are displayed for selection
77
+ #
78
+ # @example
79
+ # Question.ask("What are you doing?", [:nothing, :cleaning_up])
80
+ # # SHELL:
81
+ # # $ What are you doing? [n]othing, [c]leaning up
82
+ # # n<enter>
83
+ # # => :nothing
84
+ #
85
+ # @example Question with answers as hash.
86
+ # ask("Do you have a problem?", :yes => true, :no => true)
87
+ #
88
+ # @return [Symbol] selected answer
89
+ def self.ask(question, answers)
90
+ question = Question.new(question)
91
+ question.answers = answers
92
+ question.ask
93
+ end
94
+
95
+ private
96
+
97
+ # Prints `msg` and reads user input
98
+ def gets msg
99
+ STDOUT.print("#{msg} ")
100
+ STDOUT.flush
101
+ STDIN.gets.chomp
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,3 @@
1
+ module Questions
2
+ VERSION = File.read(File.absolute_path("../../../VERSION", __FILE__))
3
+ end
data/lib/questions.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "questions/version"
2
+ require "questions/answer"
3
+ require "questions/answers"
4
+ require "questions/question"
data/questions.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'questions/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "questions"
8
+ spec.version = Questions::VERSION
9
+ spec.authors = ["DSIW"]
10
+ spec.email = ["dsiw@dsiw-it.de"]
11
+ spec.description = %q{Ask human}
12
+ spec.summary = %q{Ask human}
13
+ spec.homepage = "https://github.com/DSIW/questions"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
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.3"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "version"
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "simplecov"
26
+ spec.add_development_dependency "yard"
27
+ spec.add_development_dependency "pry"
28
+ end
@@ -0,0 +1,120 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe :Answer do
6
+ shared_examples_for 'a true answer' do
7
+ its(:active?) { should be_true }
8
+ its(:inactive?) { should be_false }
9
+ its(:true?) { should be_true }
10
+ its(:false?) { should be_false }
11
+ its(:indicator) { should_not be_nil }
12
+ its(:instruction) { should_not == "" }
13
+ end
14
+
15
+ shared_examples_for 'a true normal answer' do
16
+ it_should_behave_like 'a true answer'
17
+ its(:instruction) { should == :overwrite }
18
+ its(:indicator_hash) { should == {:o => :overwrite} }
19
+ its(:to_s) { should == "[o]verwrite" }
20
+ its(:special?) { should be_false }
21
+
22
+ its(:indicator) { should == :o }
23
+ describe "indicator" do
24
+ it "#indicator(2) == :ov" do
25
+ subject.indicator(2) == :ov
26
+ end
27
+ it "#indicator(3) == :ove" do
28
+ subject.indicator(3) == :ove
29
+ end
30
+ end
31
+ end
32
+
33
+ shared_examples_for 'a true special answer' do
34
+ it_should_behave_like 'a true answer'
35
+ its(:instruction) { should == :overwrite_all }
36
+ its(:indicator_hash) { should == {:O => :overwrite_all} }
37
+ its(:to_s) { should == "[O]verwrite all" }
38
+ its(:special?) { should be_true }
39
+
40
+ its(:indicator) { should == :O }
41
+ describe "indicator" do
42
+ it "#indicator(2) == :OV" do
43
+ subject.indicator(2) == :OV
44
+ end
45
+ it "#indicator(3) == :OVE" do
46
+ subject.indicator(3) == :OVE
47
+ end
48
+ end
49
+ end
50
+
51
+ shared_examples_for 'a false answer' do
52
+ its(:active?) { should be_false }
53
+ its(:inactive?) { should be_true }
54
+ its(:true?) { should be_false }
55
+ its(:false?) { should be_true }
56
+ its(:indicator) { should be_nil }
57
+ its(:instruction) { should == :overwrite }
58
+ its(:indicator_hash) { should be_nil }
59
+ its(:to_s) { should == nil }
60
+ end
61
+
62
+ describe "#initialize" do
63
+ # true normal
64
+ context "with true as value" do
65
+ context "with braces" do
66
+ subject { Answer.new({:overwrite => true}) }
67
+ it_should_behave_like 'a true normal answer'
68
+ end
69
+ context "without braces" do
70
+ subject { Answer.new(:overwrite => true) }
71
+ it_should_behave_like 'a true normal answer'
72
+ end
73
+ end
74
+ context "as symbol" do
75
+ subject { Answer.new(:overwrite) }
76
+ it_should_behave_like 'a true normal answer'
77
+ end
78
+
79
+ # true special
80
+ context "with true as value" do
81
+ context "with braces" do
82
+ subject { Answer.new({:overwrite_all => true}) }
83
+ it_should_behave_like 'a true special answer'
84
+ end
85
+ context "without braces" do
86
+ subject { Answer.new(:overwrite_all => true) }
87
+ it_should_behave_like 'a true special answer'
88
+ end
89
+ end
90
+ context "as symbol" do
91
+ subject { Answer.new(:overwrite_all) }
92
+ it_should_behave_like 'a true special answer'
93
+ end
94
+
95
+ # false
96
+ context "with false as value" do
97
+ context "with braces" do
98
+ subject { Answer.new({:overwrite => false}) }
99
+ it_should_behave_like 'a false answer'
100
+ end
101
+ context "without braces" do
102
+ subject { Answer.new(:overwrite => false) }
103
+ it_should_behave_like 'a false answer'
104
+ end
105
+ end
106
+ context "with nil as value" do
107
+ subject { Answer.new(:overwrite => nil) }
108
+ it_should_behave_like 'a false answer'
109
+ end
110
+ end
111
+
112
+ describe "#indicator=" do
113
+ subject { Answer.new(:overwrite) }
114
+ its(:indicator) { should == :o }
115
+ it "should set indicator" do
116
+ subject.indicator = :ov
117
+ subject.indicator.should == :ov
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,255 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Answers do
6
+ let(:overwrite) { Answer.new(:overwrite) }
7
+ let(:no_overwrite) { Answer.new(:overwrite => false) }
8
+
9
+ let(:abort) { Answer.new(:abort) }
10
+ let(:no_abort) { Answer.new(:abort => false) }
11
+
12
+ let(:answers_array) { [overwrite, abort] }
13
+ let(:answers_array_with_false) { [overwrite, no_abort] }
14
+
15
+ let(:answers_hash) { {overwrite: true, abort: true} }
16
+ let(:answers_hash_with_false) { {overwrite: true, abort: false} }
17
+
18
+ shared_examples_for "one answer" do
19
+ its(:size) { should == 1 }
20
+ its(:first) { should == abort }
21
+ end
22
+
23
+ shared_examples_for "one symbol" do
24
+ its(:size) { should == 1 }
25
+ its(:first) { should be_kind_of Answer }
26
+ its("first.instruction") { should == :abort }
27
+ end
28
+
29
+ shared_examples_for "two answers" do
30
+ its(:size) { should == 2 }
31
+ it "each answer should be kind of Answer" do
32
+ subject.all? { |answer| answer.kind_of? Answer }
33
+ end
34
+ its("first.instruction") { should == :overwrite }
35
+ its("last.instruction") { should == :abort }
36
+ end
37
+
38
+ shared_examples_for "hash with two true items" do
39
+ its(:size) { should == 2 }
40
+ it "each answer should be kind of Answer" do
41
+ subject.all? { |answer| answer.kind_of? Answer }
42
+ end
43
+ it "should be :overwrite and :abort" do
44
+ subject.map(&:instruction).should == [:overwrite, :abort]
45
+ end
46
+ it "each answer should be true" do
47
+ subject.map(&:true?).should == [true, true]
48
+ end
49
+ end
50
+
51
+ shared_examples_for "hash with one true and one false item" do
52
+ its(:size) { should == 2 }
53
+ it "each answer should be kind of Answer" do
54
+ subject.all? { |answer| answer.kind_of? Answer }
55
+ end
56
+ it "should be :overwrite and :abort" do
57
+ subject.map(&:instruction).should == [:overwrite, :abort]
58
+ end
59
+ it "should be true and false" do
60
+ subject.map(&:true?).should == [true, false]
61
+ end
62
+ end
63
+
64
+ describe "#init" do
65
+ context "when parameter is Answer" do
66
+ subject { Answers.new(abort) }
67
+ include_examples "one answer"
68
+ end
69
+ context "when parameter is Symbol" do
70
+ subject { Answers.new(:abort) }
71
+ include_examples "one symbol"
72
+ end
73
+
74
+ context "when parameter is array" do
75
+ subject { Answers.new(answers_array) }
76
+ include_examples "two answers"
77
+ end
78
+ context "when parameter is array filled with symbols" do
79
+ subject { Answers.new([:overwrite, :abort]) }
80
+ include_examples "two answers"
81
+ end
82
+ context "mixed array filled with symbols and answers" do
83
+ subject { Answers.new([:overwrite, abort]) }
84
+ include_examples "two answers"
85
+ end
86
+
87
+ context "when parameter is Hash with true values" do
88
+ subject { Answers.new(answers_hash) }
89
+ include_examples "hash with two true items"
90
+ end
91
+ context "when parameter is Hash with value false" do
92
+ subject { Answers.new(answers_hash_with_false) }
93
+ include_examples "hash with one true and one false item"
94
+ end
95
+ end
96
+
97
+ describe "#<<" do
98
+ subject { Answers.new }
99
+
100
+ context "when parameter is Answer" do
101
+ before { subject << abort }
102
+ include_examples "one answer"
103
+ end
104
+ context "when parameters are Answers with chaining" do
105
+ before { subject << overwrite << abort }
106
+ include_examples "two answers"
107
+ end
108
+ context "when parameter is Symbol" do
109
+ before { subject << :abort }
110
+ include_examples "one symbol"
111
+ end
112
+
113
+ context "when parameter is array" do
114
+ before { subject << answers_array }
115
+ include_examples "two answers"
116
+ end
117
+ context "when parameter is array filled with symbols" do
118
+ before { subject << [:overwrite, :abort] }
119
+ include_examples "two answers"
120
+ end
121
+ context "mixed array filled with symbols and answers" do
122
+ before { subject << [:overwrite, abort] }
123
+ include_examples "two answers"
124
+ end
125
+
126
+ context "when parameter is Hash with true values" do
127
+ before { subject << answers_hash }
128
+ include_examples "hash with two true items"
129
+ end
130
+ context "when parameter is Hash with value false" do
131
+ before { subject << answers_hash_with_false }
132
+ include_examples "hash with one true and one false item"
133
+ end
134
+ end
135
+
136
+ describe "#update_indicators_for_uniqueness!" do
137
+ before { subject << [:abort, :abort_all, :abc] }
138
+ before { subject.send(:update_indicators_for_uniqueness!) }
139
+ let(:indicators) { subject.map(&:indicator) }
140
+ it "indicators should == [:a, :A, :ab]" do
141
+ indicators.should == [:a, :A, :ab]
142
+ end
143
+ it "indicators should only exist unique answers" do
144
+ indicators.should == indicators.uniq
145
+ end
146
+ end
147
+
148
+ describe "#[]" do
149
+ before { subject << [:abort, :abort_all, :abc] }
150
+ it "should select answer by indicator" do
151
+ subject[:a].indicator.should == :a
152
+ subject[:a].instruction.should == :abort
153
+
154
+ subject[:A].indicator.should == :A
155
+ subject[:A].instruction.should == :abort_all
156
+ end
157
+ end
158
+
159
+ describe "#have_unique_indicators?" do
160
+ before { subject << [:abort, :abort_all, :abc] }
161
+ it { should_not have_unique_indicators }
162
+ context "after updating indicators for uniqueness" do
163
+ before { subject.update_indicators_for_uniqueness! }
164
+ it { should have_unique_indicators }
165
+ end
166
+ end
167
+
168
+ describe "#indicators" do
169
+ before { subject << [:abort, :abort_all, :abc] }
170
+ its(:indicators) { should == [:a, :A, :a] }
171
+ context "after updating indicators for uniqueness" do
172
+ before { subject.update_indicators_for_uniqueness! }
173
+ its(:indicators) { should == [:a, :A, :ab] }
174
+ end
175
+ end
176
+
177
+ describe "#to_s" do
178
+ context "all true" do
179
+ before { subject << [:abort, :abort_all, :abc] }
180
+ its(:to_s) { should == "[a]bort, [A]bort all, [ab]c" }
181
+ end
182
+ context "with false value" do
183
+ before { subject << {abort: true, abort_all: false, abc: true} }
184
+ its(:to_s) { should == "[a]bort, [ab]c" }
185
+ end
186
+ end
187
+
188
+ describe "Private:" do
189
+ describe "#select_symbols" do
190
+ let(:hash) { {"abc" => true, abort: true, overwrite: false} }
191
+ it "should return {abort: true, overwrite: false}" do
192
+ subject.send(:select_symbols, hash).should == { abort: true, overwrite: false }
193
+ end
194
+ end
195
+
196
+ describe "#convert_hash_to_answers" do
197
+ let(:hash) { {abort: true, overwrite: false} }
198
+ subject do
199
+ Answers.new.send(:convert_hash_to_answers, hash)
200
+ end
201
+ it "each entry should be kind of Answer" do
202
+ subject.all? { |answer| answer.kind_of? Answer }
203
+ end
204
+ its("first.instruction") { should == :abort }
205
+ its("first.true?") { should be_true }
206
+ its("last.instruction") { should == :overwrite }
207
+ its("last.true?") { should be_false }
208
+ end
209
+
210
+ describe "#convert_symbol_to_answer_or_send_through" do
211
+ subject do
212
+ Answers.new.send(:convert_symbol_to_answer_or_send_through, parameter)
213
+ end
214
+ context "when parameter is a Symbol" do
215
+ let(:parameter) { :abort }
216
+ it { should be_kind_of Answer }
217
+ its(:instruction) { should == :abort }
218
+ end
219
+ context "when parameter is an answer" do
220
+ let(:parameter) { abort }
221
+ it { should == abort }
222
+ end
223
+ context "when parameter is an other object" do
224
+ let(:parameter) { "string" }
225
+ it "should raise an ArgumentError" do
226
+ expect { subject }.to raise_error ArgumentError
227
+ end
228
+ end
229
+ end
230
+
231
+ describe "#free_indicator_of" do
232
+ context ":abc" do
233
+ it "should return :a if it isn't already used" do
234
+ subject.send(:free_indicator_of, abort, :used_indicators => [:b]).should == :a
235
+ end
236
+
237
+ it "should return :a if :used_indicators is empty" do
238
+ subject.send(:free_indicator_of, abort, :used_indicators => []).should == :a
239
+ end
240
+
241
+ it "should return :a if no :used_indicators is set" do
242
+ subject.send(:free_indicator_of, abort).should == :a
243
+ end
244
+
245
+ it "should reuturn :ab if :a is used" do
246
+ subject.send(:free_indicator_of, abort, :used_indicators => [:a]).should == :ab
247
+ end
248
+
249
+ it "should return :ab if :a and :A is used" do
250
+ subject.send(:free_indicator_of, abort, :used_indicators => [:a, :A]).should == :ab
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Question do
6
+ let(:answers_array) { [Answer.new(:overwrite), Answer.new(:abort)] }
7
+
8
+ let(:question_msg) { "What to do?" }
9
+ let(:question) { Question.new(question_msg) }
10
+ subject { question }
11
+
12
+ describe "#init" do
13
+ its(:answers) { should be_kind_of Answers }
14
+ its("answers.size") { should == 0 }
15
+ its(:question) { should == question_msg }
16
+ end
17
+
18
+ describe "#answers=" do
19
+ before { subject.answers = [:abort, :overwrite] }
20
+ its(:answers) { should be_kind_of Answers }
21
+ its("answers.size") { should == 2 }
22
+ end
23
+
24
+ describe "#ask" do
25
+ it "should raise an error without answers" do
26
+ expect { subject.ask }.to raise_error /have to set answers/
27
+ end
28
+
29
+ context "with answers" do
30
+ before { subject.answers = answers_array }
31
+ before do
32
+ subject.should_receive(:gets).with("#{question_msg} [o]verwrite, [a]bort").and_return("o")
33
+ end
34
+ its(:ask) { should == :overwrite }
35
+ end
36
+ end
37
+
38
+ describe "::ask" do
39
+ context "with answers as array" do
40
+ subject { Question.ask(question_msg, [:all, :nothing]) }
41
+ before do
42
+ Question.any_instance.should_receive(:gets).with("#{question_msg} [A]ll, [n]othing").and_return("A")
43
+ end
44
+ it { should == :all }
45
+ end
46
+ context "with answers as hash" do
47
+ subject { Question.ask(question_msg, all: true, nothing: true) }
48
+ before do
49
+ Question.any_instance.should_receive(:gets).with("#{question_msg} [A]ll, [n]othing").and_return("A")
50
+ end
51
+ it { should == :all }
52
+ end
53
+ context "with answers as hash with false value" do
54
+ subject { Question.ask(question_msg, all: true, not: false, nothing: true) }
55
+ before do
56
+ Question.any_instance.should_receive(:gets).with("#{question_msg} [A]ll, [n]othing").and_return("A")
57
+ end
58
+ it { should == :all }
59
+ end
60
+ end
61
+
62
+ describe "Privates:" do
63
+ describe "#gets" do
64
+ before do
65
+ STDOUT.should_receive(:print).with(question_msg + " ")
66
+ STDOUT.should_receive(:flush)
67
+ STDIN.should_receive(:gets).and_return("y\n")
68
+ end
69
+ it { subject.send(:gets, question_msg).should == "y" }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,12 @@
1
+ require 'rspec'
2
+ require 'questions'
3
+
4
+ RSpec.configure do |config|
5
+ include Questions
6
+
7
+ config.mock_with :rspec
8
+
9
+ config.treat_symbols_as_metadata_keys_with_true_values = true
10
+ config.filter_run :focus => true
11
+ config.run_all_when_everything_filtered = true
12
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: questions
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - DSIW
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-03-17 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.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: version
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
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: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: yard
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: Ask human
112
+ email:
113
+ - dsiw@dsiw-it.de
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - .gitignore
119
+ - .rspec
120
+ - Gemfile
121
+ - LICENSE.txt
122
+ - README.md
123
+ - Rakefile
124
+ - VERSION
125
+ - lib/questions.rb
126
+ - lib/questions/answer.rb
127
+ - lib/questions/answers.rb
128
+ - lib/questions/question.rb
129
+ - lib/questions/version.rb
130
+ - questions.gemspec
131
+ - spec/questions/answer_spec.rb
132
+ - spec/questions/answers_spec.rb
133
+ - spec/questions/question_spec.rb
134
+ - spec/spec_helper.rb
135
+ homepage: https://github.com/DSIW/questions
136
+ licenses:
137
+ - MIT
138
+ metadata: {}
139
+ post_install_message:
140
+ rdoc_options: []
141
+ require_paths:
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ requirements:
145
+ - - '>='
146
+ - !ruby/object:Gem::Version
147
+ version: '0'
148
+ required_rubygems_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ requirements: []
154
+ rubyforge_project:
155
+ rubygems_version: 2.0.0
156
+ signing_key:
157
+ specification_version: 4
158
+ summary: Ask human
159
+ test_files:
160
+ - spec/questions/answer_spec.rb
161
+ - spec/questions/answers_spec.rb
162
+ - spec/questions/question_spec.rb
163
+ - spec/spec_helper.rb
164
+ has_rdoc: