robut-quiz 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.
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source :rubygems
2
+
3
+ gem 'robut'
4
+
5
+ group :test do
6
+ gem 'rspec'
7
+ gem 'guard'
8
+ gem 'guard-rspec'
9
+ gem 'growl_notify'
10
+ end
@@ -0,0 +1,8 @@
1
+
2
+
3
+ guard 'rspec', :version => 2, :cli => '--color --format d' do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec" }
7
+ end
8
+
@@ -0,0 +1,4 @@
1
+ === 0.1.0 / 2011-10-23
2
+
3
+ * Initial Release
4
+ * User is able to ask polar question
@@ -0,0 +1,30 @@
1
+ # Robut-Quiz
2
+
3
+ A Plugin for [Robut](https://github.com/justinweiss/robut) that allows you to ask questions and collect the results from all participants within the chatroom.
4
+
5
+ ## Usage
6
+
7
+ ### Polar Question (Yes/No)
8
+
9
+ ```
10
+ user_a > @robut ask 'Do you want to go to the bar at 4:30?' for 5 minutes.
11
+ robut > @user I have enqueued your question
12
+ robut > @all Question: 'Do you want to go to the bar at 4:30?'
13
+ user_a > @robut answer YES
14
+ user_b > @robut answer yes
15
+ user_c > @robut answer n
16
+ robut > @all The results are in for 'Do you want to go to the bar at 4:30?:'
17
+ 2 YES votes and 1 NO vote
18
+ ```
19
+
20
+ ## Installation
21
+
22
+ Install the gem
23
+
24
+ gem install robut-quiz
25
+
26
+ Add the plugin to your [Chatfile](https://github.com/justinweiss/robut/blob/master/examples/Chatfile)
27
+
28
+ require 'robut_quiz'
29
+
30
+ Robut::Plugin.plugins << Robut::Plugin::Quiz
@@ -0,0 +1,47 @@
1
+ # encoding: UTF-8
2
+
3
+ class Robut::Plugin::Quiz::Polar
4
+ include Robut::Plugin::Quiz::Question
5
+
6
+ YES_ANSWER = /y|yes/i
7
+ NO_ANSWER = /n|no/i
8
+
9
+ def handle_response(sender_nick,response)
10
+
11
+ if response =~ YES_ANSWER
12
+ store_positive_response_for sender_nick
13
+ true
14
+ elsif response =~ NO_ANSWER
15
+ store_negative_response_for sender_nick
16
+ true
17
+ else
18
+ nil
19
+ end
20
+
21
+ end
22
+
23
+ def results
24
+
25
+ yes_votes = no_votes = 0
26
+
27
+ captured_results.each_pair do |key,value|
28
+ yes_votes = yes_votes + 1 if value
29
+ no_votes = no_votes + 1 unless value
30
+ end
31
+
32
+ "#{yes_votes} YES vote#{yes_votes != 1 ? 's' : ''} and #{no_votes} NO vote#{no_votes != 1 ? 's' : ''}"
33
+ end
34
+
35
+ def captured_results
36
+ @captured_results ||= {}
37
+ end
38
+
39
+ def store_positive_response_for sender_nick
40
+ captured_results[sender_nick] = true
41
+ end
42
+
43
+ def store_negative_response_for sender_nick
44
+ captured_results[sender_nick] = false
45
+ end
46
+
47
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: UTF-8
2
+
3
+ module Robut::Plugin::Quiz::Question
4
+
5
+ # @see ask%20%3F(choice%7Cpolar%7Cscale)%3F%20(%3F%3Aquestion%20)%3F'(%5B%5E'%5D%2B)'%5B%5Cs%2C%5D*((%3F%3A'%5B%5E'%5D%2B'%5B%5Cs%2C%5D*)*)%2B(%3F%3A(%3F%3Afor%20)%3F(%5Cd%2B)%20minutes%3F)%3F
6
+ #
7
+ # 1st: question type - choice, polar, scale
8
+ # 2nd: question
9
+ # 3rd: choices
10
+ #
11
+ QUESTION_REGEX = /^ask ?(choice|polar|scale)? (?:question )?['"]([^'"]+)['"][\s,]*((?:['"][^'"]+['"][\s,]*)*)*(?:(?:for )?(\d+) minutes?)?$/
12
+
13
+ # This regex will find all the questions and parameters specified with the question
14
+ GROUP_REGEX = /['"]([^'"]+)['"]/
15
+
16
+ def initialize(sender,request)
17
+ @sender = sender
18
+ process_question(request)
19
+ end
20
+
21
+ def process_question(request)
22
+
23
+ request =~ QUESTION_REGEX
24
+ @question = Regexp.last_match(2)
25
+ # After the target, question type, question, and answer length has been determined
26
+ # look at all the single quoted items to find the list of parameters if there are any
27
+ @parameters = request.scan(GROUP_REGEX)[1..-1].flatten
28
+
29
+ end
30
+
31
+ def to_s
32
+ @question
33
+ end
34
+
35
+ def ask
36
+ "@all Question '#{@question}'"
37
+ end
38
+
39
+ end
@@ -0,0 +1,120 @@
1
+ # encoding: UTF-8
2
+ require 'robut'
3
+
4
+ class Robut::Plugin::Quiz
5
+ include Robut::Plugin
6
+
7
+ def usage
8
+ [
9
+ "#{at_nick} ask polar 'Should I continue the presentation?' for 3 minutes",
10
+ ]
11
+ end
12
+
13
+ def handle(time, sender_nick, message)
14
+
15
+ # check to see if the user is asking the bot a question
16
+ request = words(message).join(" ")
17
+
18
+ if sent_to_me? message and is_a_valid_question? request
19
+
20
+ enqueue_the_question sender_nick, request
21
+ reply "@#{sender_nick}, I have added your question to the list."
22
+ quizmaster
23
+
24
+ end
25
+
26
+ if sent_to_me? message and currently_asking_a_question? and is_a_valid_response? request
27
+ process_response_for_active_question sender_nick, request
28
+ end
29
+
30
+ end
31
+
32
+ QUESTION_REGEX = /^ask ?(choice|polar|scale)? (?:question )?.+(?:(?:for )?(\d+) minutes?)$/
33
+
34
+ def is_a_valid_question? message
35
+ QUESTION_REGEX =~ message
36
+ end
37
+
38
+ ANSWER_REGEX = /^answer .+$/
39
+
40
+ def is_a_valid_response? message
41
+ ANSWER_REGEX =~ message
42
+ end
43
+
44
+ def enqueue_the_question(sender,question)
45
+ (store["quiz::question::queue"] ||= []) << [sender,question]
46
+ end
47
+
48
+ def quizmaster
49
+ @@quizmaster ||= Thread.new { pop_the_question until there_are_no_more_questions_to_pop }
50
+ end
51
+
52
+ def pop_the_question
53
+ if popped_question = (store["quiz::question::queue"] ||= []).pop
54
+ process_the_question *popped_question
55
+ end
56
+ end
57
+
58
+ def there_are_no_more_questions_to_pop
59
+ (store["quiz::question::queue"] ||= []).empty?
60
+ end
61
+
62
+ def currently_asking_a_question?
63
+ defined? @@current_question and @@current_question
64
+ end
65
+
66
+ def process_the_question(sender,request)
67
+
68
+ request =~ QUESTION_REGEX
69
+ type = Regexp.last_match(1) || 'polar'
70
+ question_length = Regexp.last_match(2) || '2'
71
+
72
+ set_current_question create_the_question_based_on_type(type,sender,request), question_length
73
+ end
74
+
75
+ #
76
+ # @param [String] question_type the name of the question type which will be
77
+ # converted from a String to the Class name within the current namespace.
78
+ # @param [String] sender the sender of the question
79
+ # @param [String] request the entire message that initiated the question
80
+ #
81
+ def create_the_question_based_on_type(question_type,sender,request)
82
+ self.class.const_get(question_type.capitalize).new sender, request
83
+ end
84
+
85
+ def set_current_question(question,length_of_time)
86
+
87
+ start_accepting_responses_for_this_question question
88
+
89
+ reply question.ask
90
+
91
+ sleep length_of_time.to_i * 60
92
+
93
+ stop_accepting_responses_for_this_question question
94
+
95
+ reply "The results are in for '#{question}':"
96
+ reply question.results
97
+
98
+ end
99
+
100
+ def start_accepting_responses_for_this_question(question)
101
+ @@current_question = question
102
+ end
103
+
104
+ def stop_accepting_responses_for_this_question(question)
105
+ @@current_question = nil
106
+ end
107
+
108
+ def process_response_for_active_question(sender_nick, request)
109
+ if @@current_question.handle_response sender_nick, request
110
+ reply "Thank you, @#{sender_nick}, I have recorded your response."
111
+ else
112
+ reply "Sorry, @#{sender_nick}, I was unable to record that answer"
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+
119
+ require_relative 'question'
120
+ require_relative 'polar'
@@ -0,0 +1,10 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'robut'
4
+
5
+ class Robut::Plugin::Quiz
6
+ VERSION = "0.1.0"
7
+ end
8
+
9
+ require_relative 'quiz'
10
+
@@ -0,0 +1,59 @@
1
+ require './lib/robut_quiz'
2
+
3
+ class Robut::Plugin::Quiz
4
+ def self.show_version_changes(version)
5
+ date = ""
6
+ changes = []
7
+ grab_changes = false
8
+
9
+ File.open("#{File.dirname(__FILE__)}/History.txt",'r') do |file|
10
+ while (line = file.gets) do
11
+
12
+ if line =~ /^===\s*#{version.gsub('.','\.')}\s*\/\s*(.+)\s*$/
13
+ grab_changes = true
14
+ date = $1.strip
15
+ elsif line =~ /^===\s*.+$/
16
+ grab_changes = false
17
+ elsif grab_changes
18
+ changes = changes << line
19
+ end
20
+
21
+ end
22
+ end
23
+
24
+ { :date => date, :changes => changes }
25
+ end
26
+ end
27
+
28
+ Gem::Specification.new do |s|
29
+ s.name = 'robut-quiz'
30
+ s.version = ::Robut::Plugin::Quiz::VERSION
31
+ s.authors = ["Franklin Webber"]
32
+ s.description = %{ Robut plugin that provides quiz asking functionality. }
33
+ s.summary = "Quiz asking Robut"
34
+ s.email = 'franklin.webber@gmail.com'
35
+ s.homepage = "http://github.com/burtlo/robut-quiz"
36
+
37
+ s.platform = Gem::Platform::RUBY
38
+
39
+ changes = Robut::Plugin::Quiz.show_version_changes(::Robut::Plugin::Quiz::VERSION)
40
+
41
+ s.post_install_message = "
42
+ --------------------------------------------------------------------------------
43
+ ___
44
+ !(O-0)! ~ Thank you for installing robut-quiz #{::Robut::Plugin::Quiz::VERSION} / #{changes[:date]}
45
+ >==[ ]==<
46
+ @ @
47
+
48
+ Changes:
49
+ #{changes[:changes].collect{|change| " #{change}"}.join("")}
50
+ --------------------------------------------------------------------------------"
51
+
52
+ s.add_dependency 'robut', '~> 0.3'
53
+
54
+ s.rubygems_version = "1.3.7"
55
+ s.files = `git ls-files`.split("\n")
56
+ s.extra_rdoc_files = ["README.md", "History.txt"]
57
+ s.rdoc_options = ["--charset=UTF-8"]
58
+ s.require_path = "lib"
59
+ end
@@ -0,0 +1,117 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Robut::Plugin::Quiz::Polar do
4
+
5
+ subject do
6
+ Robut::Plugin::Quiz::Polar.new 'person',"ask polar 'Should I continue the presentation?' for 3 minutes"
7
+ end
8
+
9
+ let(:time) { Time.now }
10
+
11
+ describe "#handle_response" do
12
+
13
+ context "when the response is a 'yes'" do
14
+
15
+ it "should store positive response for the user" do
16
+
17
+ subject.should_receive(:store_positive_response_for).with('person')
18
+ subject.handle_response('person','yes')
19
+
20
+ end
21
+
22
+ end
23
+
24
+ context "when the response is a 'y'" do
25
+
26
+ it "should store a positive response for the user" do
27
+
28
+ subject.should_receive(:store_positive_response_for).with('person')
29
+ subject.handle_response('person','y')
30
+
31
+ end
32
+ end
33
+
34
+ context "when the response is a 'no'" do
35
+
36
+ it "should store negative response for the user" do
37
+
38
+ subject.should_receive(:store_negative_response_for).with('person')
39
+ subject.handle_response('person','no')
40
+
41
+ end
42
+
43
+ end
44
+
45
+ context "when the response is a 'n'" do
46
+
47
+ it "should store negative response for the user" do
48
+
49
+ subject.should_receive(:store_negative_response_for).with('person')
50
+ subject.handle_response('person','n')
51
+
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+
58
+ describe "#declare_results" do
59
+
60
+ context "when there have been no votes" do
61
+
62
+ it "should reply that there are zero YES votes and zero NO votes" do
63
+
64
+ subject.results.should eq "0 YES votes and 0 NO votes"
65
+
66
+ end
67
+
68
+ end
69
+
70
+ context "when there has been a yes vote" do
71
+
72
+ it "should reply that there is 1 YES vote" do
73
+
74
+ subject.handle_response('person','yes')
75
+ subject.results.should eq "1 YES vote and 0 NO votes"
76
+
77
+ end
78
+
79
+ end
80
+
81
+ context "when there has been a no vote" do
82
+
83
+ it "should reply that there is 1 NO vote" do
84
+
85
+ subject.handle_response('person','no')
86
+ subject.results.should eq "0 YES votes and 1 NO vote"
87
+
88
+ end
89
+
90
+ end
91
+
92
+ context "when there has been multiple votes by the same user" do
93
+
94
+ it "should count as one vote" do
95
+
96
+ subject.handle_response('person','no')
97
+ subject.handle_response('person','no')
98
+ subject.handle_response('person','no')
99
+ subject.results.should eq "0 YES votes and 1 NO vote"
100
+
101
+ end
102
+
103
+ it "should only count the last vote" do
104
+
105
+ subject.handle_response('person','yes')
106
+ subject.handle_response('person','yes``')
107
+ subject.handle_response('person','no')
108
+ subject.results.should eq "0 YES votes and 1 NO vote"
109
+
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+
117
+ end
@@ -0,0 +1,156 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe Robut::Plugin::Quiz do
4
+
5
+ subject {
6
+ connection = double("connection")
7
+ connection.stub_chain(:config, :nick) { "quizmaster" }
8
+ connection.stub(:store).and_return(store)
9
+ connection.stub(:reply).and_return(nil)
10
+ Robut::Plugin::Quiz.new connection
11
+ }
12
+
13
+ let!(:store) { {} }
14
+
15
+ let(:time) { Time.now }
16
+
17
+ [
18
+ "ask choice 'What do you want for lunch?', 'pizza', 'sandwich', 'salad' for 1 minute",
19
+ "ask polar 'Should I continue the presentation?' for 3 minutes",
20
+ "ask scale question 'how much did you like the presentation?', '1..5' for 10 minutes",
21
+ "ask 'Should I continue the presentation?', 'y|yes', 'n|no' for 1 minutes",
22
+ "ask polar 'Should I continue the presentation?' for 3 minutes"
23
+
24
+ ].each do |question|
25
+
26
+ it "should match the question: '#{question}'" do
27
+
28
+ subject.is_a_valid_question?(question).should be_true
29
+
30
+ end
31
+
32
+ end
33
+
34
+ describe "#handle" do
35
+
36
+ context "when a question is asked" do
37
+
38
+ it "should be enqueued to be asked" do
39
+
40
+ subject.should_receive(:enqueue_the_question).with('person',"ask polar 'Should I continue the presentation?' for 3 minutes")
41
+ subject.handle time,'person',"@quizmaster ask polar 'Should I continue the presentation?' for 3 minutes"
42
+
43
+ end
44
+
45
+ end
46
+
47
+ context "when currently asking a question" do
48
+
49
+ context "when the response is not an answer to the question" do
50
+
51
+ it "should not process response for the question" do
52
+
53
+ subject.stub(:currently_asking_a_question?).and_return(true)
54
+ subject.stub(:is_a_valid_response?).and_return(false)
55
+
56
+ subject.should_not_receive(:process_response_for_active_question)
57
+
58
+ subject.handle time,'person',"@quizmaster ask polar 'Should I continue the presentation?' for 3 minutes"
59
+
60
+ end
61
+
62
+ end
63
+
64
+ context "when the response is an answer to the question" do
65
+
66
+ it "should process response for the question" do
67
+ subject.stub(:sent_to_me?).and_return(true)
68
+ subject.stub(:currently_asking_a_question?).and_return(true)
69
+ subject.stub(:is_a_valid_response?).and_return(true)
70
+
71
+ subject.should_receive(:process_response_for_active_question)
72
+
73
+ subject.handle time,'person',"@quizmaster ask polar 'Should I continue the presentation?' for 3 minutes"
74
+
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
83
+
84
+
85
+ describe "#process_the_question" do
86
+
87
+ context "when a polar question is asked" do
88
+
89
+ it "should find all the components of the question" do
90
+
91
+ expected_question = Robut::Plugin::Quiz::Polar.new 'person',"ask polar 'Should I continue the presentation?' for 3 minutes"
92
+
93
+ subject.should_receive(:create_the_question_based_on_type).and_return(expected_question)
94
+
95
+ subject.should_receive(:set_current_question).with(expected_question,'3')
96
+ subject.process_the_question 'person',"ask polar 'Should I continue the presentation?' for 3 minutes"
97
+
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+
104
+
105
+ describe "#set_current_question" do
106
+
107
+ before :each do
108
+ subject.stub(:sleep)
109
+ end
110
+
111
+ let(:question) do
112
+ Robut::Plugin::Quiz::Polar.new 'person',"ask polar 'Should I continue the presentation?' for 3 minutes"
113
+ end
114
+
115
+ it "should place robut in the mode where it is asking a question" do
116
+
117
+ subject.should_receive(:start_accepting_responses_for_this_question)
118
+ subject.set_current_question(question,'3')
119
+
120
+ end
121
+
122
+ it "should ask the question" do
123
+
124
+ question.should_receive(:ask)
125
+ subject.set_current_question(question,'3')
126
+
127
+ end
128
+
129
+ it "should wait until the question time is done" do
130
+
131
+ subject.should_receive(:sleep).with(180)
132
+ subject.set_current_question(question,'3')
133
+
134
+ end
135
+
136
+ context "when it is done waiting" do
137
+
138
+ it "should take robut out of the mdoe where it is asking a question" do
139
+
140
+ subject.should_receive(:stop_accepting_responses_for_this_question)
141
+ subject.set_current_question(question,'3')
142
+
143
+ end
144
+
145
+ it "should process the results for the question" do
146
+
147
+ question.should_receive(:results)
148
+ subject.set_current_question(question,'3')
149
+
150
+ end
151
+
152
+ end
153
+
154
+ end
155
+
156
+ end
@@ -0,0 +1 @@
1
+ require_relative '../lib/robut_quiz'
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: robut-quiz
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - Franklin Webber
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-23 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: robut
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ~>
22
+ - !ruby/object:Gem::Version
23
+ version: "0.3"
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ description: " Robut plugin that provides quiz asking functionality. "
27
+ email: franklin.webber@gmail.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README.md
34
+ - History.txt
35
+ files:
36
+ - Gemfile
37
+ - Guardfile
38
+ - History.txt
39
+ - README.md
40
+ - lib/polar.rb
41
+ - lib/question.rb
42
+ - lib/quiz.rb
43
+ - lib/robut_quiz.rb
44
+ - robut-quiz.gemspec
45
+ - spec/polar_spec.rb
46
+ - spec/quiz_spec.rb
47
+ - spec/spec_helper.rb
48
+ homepage: http://github.com/burtlo/robut-quiz
49
+ licenses: []
50
+
51
+ post_install_message: "\n\
52
+ --------------------------------------------------------------------------------\n ___\n !(O-0)! ~ Thank you for installing robut-quiz 0.1.0 / 2011-10-23\n >==[ ]==<\n @ @\n\n Changes:\n \n * Initial Release\n * User is able to ask polar question\n\n\
53
+ --------------------------------------------------------------------------------"
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: "0"
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.8.10
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Quiz asking Robut
77
+ test_files: []
78
+