robut-quiz 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
+