robut-quiz 0.1.0 → 0.2.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 +2 -1
- data/History.txt +5 -0
- data/lib/polar.rb +2 -2
- data/lib/question.rb +39 -14
- data/lib/quiz.rb +40 -9
- data/lib/range.rb +73 -0
- data/lib/robut_quiz.rb +1 -1
- data/spec/polar_spec.rb +1 -1
- data/spec/question_spec.rb +64 -0
- data/spec/quiz_spec.rb +9 -9
- data/spec/range_spec.rb +100 -0
- metadata +6 -3
data/Gemfile
CHANGED
data/History.txt
CHANGED
data/lib/polar.rb
CHANGED
@@ -32,8 +32,8 @@ class Robut::Plugin::Quiz::Polar
|
|
32
32
|
"#{yes_votes} YES vote#{yes_votes != 1 ? 's' : ''} and #{no_votes} NO vote#{no_votes != 1 ? 's' : ''}"
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
@
|
35
|
+
def ask
|
36
|
+
"@all Question '#{@question}' (yes/no)"
|
37
37
|
end
|
38
38
|
|
39
39
|
def store_positive_response_for sender_nick
|
data/lib/question.rb
CHANGED
@@ -2,38 +2,63 @@
|
|
2
2
|
|
3
3
|
module Robut::Plugin::Quiz::Question
|
4
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
5
|
# This regex will find all the questions and parameters specified with the question
|
14
6
|
GROUP_REGEX = /['"]([^'"]+)['"]/
|
15
7
|
|
16
|
-
|
8
|
+
#
|
9
|
+
# Initialize the question with the asker of the question and the details about
|
10
|
+
# question that is being asked.
|
11
|
+
#
|
12
|
+
# @param [String] sender the name of the person asking the question.
|
13
|
+
# @param [String] question_with_parameters this is the remaining question and
|
14
|
+
# parameters left on the question posed to the chat room.
|
15
|
+
#
|
16
|
+
def initialize(sender,question_with_parameters)
|
17
17
|
@sender = sender
|
18
|
-
process_question(
|
18
|
+
process_question(question_with_parameters)
|
19
19
|
end
|
20
20
|
|
21
|
-
|
21
|
+
#
|
22
|
+
# This is used internally to process the the question and parameters that sent
|
23
|
+
# to the question.
|
24
|
+
#
|
25
|
+
# @param [String] question_with_parameters this is the remaining question and
|
26
|
+
# parameters left on the question posed to the chat room.
|
27
|
+
#
|
28
|
+
def process_question(question_with_parameters)
|
22
29
|
|
23
|
-
|
24
|
-
|
30
|
+
parsed_elements = question_with_parameters.scan(GROUP_REGEX)
|
31
|
+
|
32
|
+
@question = parsed_elements.first.first
|
25
33
|
# After the target, question type, question, and answer length has been determined
|
26
34
|
# look at all the single quoted items to find the list of parameters if there are any
|
27
|
-
@parameters =
|
35
|
+
@parameters = Array(parsed_elements[1..-1].flatten)
|
28
36
|
|
29
37
|
end
|
30
38
|
|
39
|
+
#
|
40
|
+
# @return [String] the question that is being asked.
|
31
41
|
def to_s
|
32
42
|
@question
|
33
43
|
end
|
34
44
|
|
45
|
+
#
|
46
|
+
# Ask the question that has been proposed.
|
47
|
+
#
|
48
|
+
# @return [String] a string that asks the question in the chat room.
|
35
49
|
def ask
|
36
50
|
"@all Question '#{@question}'"
|
37
51
|
end
|
38
52
|
|
53
|
+
#
|
54
|
+
# Maintains a list of the results that have been captured for the question.
|
55
|
+
# The hash that is maintained would be used with the user's nickname as the
|
56
|
+
# key and the value as a response to the question.
|
57
|
+
#
|
58
|
+
# @return [Hash] used for storing responses from the various senders.
|
59
|
+
#
|
60
|
+
def captured_results
|
61
|
+
@captured_results ||= {}
|
62
|
+
end
|
63
|
+
|
39
64
|
end
|
data/lib/quiz.rb
CHANGED
@@ -4,12 +4,23 @@ require 'robut'
|
|
4
4
|
class Robut::Plugin::Quiz
|
5
5
|
include Robut::Plugin
|
6
6
|
|
7
|
+
#
|
8
|
+
# @return [Array<String>] contains the various types of responses that are
|
9
|
+
# valid usage examples that would be returned by the Help Plugin
|
10
|
+
#
|
7
11
|
def usage
|
8
12
|
[
|
9
|
-
"#{at_nick} ask
|
13
|
+
"#{at_nick} ask 'Should we break for lunch?'",
|
14
|
+
"#{at_nick} ask for 3 minutes 'Should I continue the presentation?'",
|
15
|
+
"#{at_nick} answer yes"
|
10
16
|
]
|
11
17
|
end
|
12
18
|
|
19
|
+
#
|
20
|
+
# @param [Time] time at which the message has arrived
|
21
|
+
# @param [String] sender_nick the sender
|
22
|
+
# @param [String] message the message that was sent
|
23
|
+
#
|
13
24
|
def handle(time, sender_nick, message)
|
14
25
|
|
15
26
|
# check to see if the user is asking the bot a question
|
@@ -29,7 +40,7 @@ class Robut::Plugin::Quiz
|
|
29
40
|
|
30
41
|
end
|
31
42
|
|
32
|
-
QUESTION_REGEX = /^ask ?(choice|polar|
|
43
|
+
QUESTION_REGEX = /^ask ?(choice|polar|range)? (?:question )?(?:(?:for )?(\d+) minutes?)?(.+)$/
|
33
44
|
|
34
45
|
def is_a_valid_question? message
|
35
46
|
QUESTION_REGEX =~ message
|
@@ -45,8 +56,15 @@ class Robut::Plugin::Quiz
|
|
45
56
|
(store["quiz::question::queue"] ||= []) << [sender,question]
|
46
57
|
end
|
47
58
|
|
59
|
+
#
|
60
|
+
# Return a new thread which will pop questions in the queue of questions
|
61
|
+
#
|
48
62
|
def quizmaster
|
49
|
-
@@quizmaster
|
63
|
+
if not defined?(@@quizmaster) or @@quizmaster.nil? or !@@quizmaster.alive?
|
64
|
+
@@quizmaster = Thread.new { pop_the_question until there_are_no_more_questions_to_pop }
|
65
|
+
end
|
66
|
+
|
67
|
+
@@quizmaster
|
50
68
|
end
|
51
69
|
|
52
70
|
def pop_the_question
|
@@ -63,13 +81,17 @@ class Robut::Plugin::Quiz
|
|
63
81
|
defined? @@current_question and @@current_question
|
64
82
|
end
|
65
83
|
|
84
|
+
#
|
85
|
+
# @param [String] sender the user proposing the question
|
86
|
+
# @param [String] request the data related to the asking and the question data itself.
|
87
|
+
#
|
66
88
|
def process_the_question(sender,request)
|
67
|
-
|
68
89
|
request =~ QUESTION_REGEX
|
69
90
|
type = Regexp.last_match(1) || 'polar'
|
70
|
-
question_length = Regexp.last_match(2) || '2'
|
91
|
+
question_length = Regexp.last_match(2) || '2'
|
92
|
+
question_data = Regexp.last_match(3)
|
71
93
|
|
72
|
-
set_current_question create_the_question_based_on_type(type,sender,
|
94
|
+
set_current_question create_the_question_based_on_type(type,sender,question_data), question_length
|
73
95
|
end
|
74
96
|
|
75
97
|
#
|
@@ -95,6 +117,9 @@ class Robut::Plugin::Quiz
|
|
95
117
|
reply "The results are in for '#{question}':"
|
96
118
|
reply question.results
|
97
119
|
|
120
|
+
# allow some time between the results and asking the next question
|
121
|
+
sleep 10
|
122
|
+
|
98
123
|
end
|
99
124
|
|
100
125
|
def start_accepting_responses_for_this_question(question)
|
@@ -105,8 +130,13 @@ class Robut::Plugin::Quiz
|
|
105
130
|
@@current_question = nil
|
106
131
|
end
|
107
132
|
|
108
|
-
|
109
|
-
|
133
|
+
#
|
134
|
+
# @param [String] sender_nick the name of the person that is responding to
|
135
|
+
# the question.
|
136
|
+
# @param [String] response is the answer to the question proposed.
|
137
|
+
#
|
138
|
+
def process_response_for_active_question(sender_nick, response)
|
139
|
+
if @@current_question.handle_response sender_nick, response[/^answer (.+)$/,1]
|
110
140
|
reply "Thank you, @#{sender_nick}, I have recorded your response."
|
111
141
|
else
|
112
142
|
reply "Sorry, @#{sender_nick}, I was unable to record that answer"
|
@@ -117,4 +147,5 @@ end
|
|
117
147
|
|
118
148
|
|
119
149
|
require_relative 'question'
|
120
|
-
require_relative 'polar'
|
150
|
+
require_relative 'polar'
|
151
|
+
require_relative 'range'
|
data/lib/range.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class Robut::Plugin::Quiz::Range
|
4
|
+
include Robut::Plugin::Quiz::Question
|
5
|
+
|
6
|
+
RANGE_VALUES = /(\d+)(?:-|\.\.)(\d+)/
|
7
|
+
|
8
|
+
def handle_response(sender_nick,response)
|
9
|
+
|
10
|
+
if within_range? response
|
11
|
+
store_range_response_for sender_nick, response
|
12
|
+
true
|
13
|
+
else
|
14
|
+
false
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
def start_value
|
20
|
+
if Array(@parameters).first.to_s =~ RANGE_VALUES
|
21
|
+
Regexp.last_match(1).to_i
|
22
|
+
else
|
23
|
+
1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def highest_value
|
28
|
+
if Array(@parameters).first.to_s =~ RANGE_VALUES
|
29
|
+
Regexp.last_match(2).to_i
|
30
|
+
else
|
31
|
+
5
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def within_range?(value)
|
36
|
+
value.to_i >= start_value and value.to_i <= highest_value
|
37
|
+
end
|
38
|
+
|
39
|
+
def ask
|
40
|
+
"@all Question '#{@question}' (#{start_value}..#{highest_value})"
|
41
|
+
end
|
42
|
+
|
43
|
+
def results
|
44
|
+
return "I'm sorry, not enough votes were cast to be create a summary." if captured_results.length == 0
|
45
|
+
|
46
|
+
result_values = captured_results.values.extend Robut::Plugin::Quiz::Range::Averages
|
47
|
+
"#{result_values.length} votes with a mean of #{result_values.mean}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def store_range_response_for(sender_nick,value)
|
51
|
+
captured_results[sender_nick] = value.to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
module Averages
|
56
|
+
|
57
|
+
def sum
|
58
|
+
inject(:+)
|
59
|
+
end
|
60
|
+
|
61
|
+
def mean
|
62
|
+
return 0 if length == 0
|
63
|
+
sum.to_f / length.to_f
|
64
|
+
end
|
65
|
+
|
66
|
+
def mode
|
67
|
+
frequency = inject(Hash.new(0)) { |hash,value| hash[value] += 1; hash }
|
68
|
+
sort_by {|value| frequency[value] }.last
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
data/lib/robut_quiz.rb
CHANGED
data/spec/polar_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require_relative 'spec_helper'
|
|
3
3
|
describe Robut::Plugin::Quiz::Polar do
|
4
4
|
|
5
5
|
subject do
|
6
|
-
Robut::Plugin::Quiz::Polar.new 'person',"
|
6
|
+
Robut::Plugin::Quiz::Polar.new 'person',"'Should I continue the presentation?'"
|
7
7
|
end
|
8
8
|
|
9
9
|
let(:time) { Time.now }
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Robut::Plugin::Quiz::Question do
|
4
|
+
|
5
|
+
class TestQuestion
|
6
|
+
include Robut::Plugin::Quiz::Question
|
7
|
+
|
8
|
+
attr_accessor :question, :parameters, :captured_results
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
let(:question) { "Do you like questions?" }
|
13
|
+
let(:question_with_params) { "'#{question}', 'yes', 'no' 'maybe'" }
|
14
|
+
|
15
|
+
subject { TestQuestion.new "sender", question_with_params }
|
16
|
+
|
17
|
+
describe "#to_s" do
|
18
|
+
|
19
|
+
it "should be the question that was asked" do
|
20
|
+
subject.to_s.should == question
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#ask" do
|
26
|
+
|
27
|
+
it "should be the default statement to ask question" do
|
28
|
+
subject.ask.should == "@all Question '#{question}'"
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#process_question" do
|
34
|
+
|
35
|
+
context "when a question with parameters" do
|
36
|
+
|
37
|
+
it "should find the question" do
|
38
|
+
subject.process_question question_with_params
|
39
|
+
subject.question.should == question
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should find the parameters" do
|
43
|
+
subject.process_question question_with_params
|
44
|
+
subject.parameters.should == [ 'yes', 'no', 'maybe' ]
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
context "when only a question has been provided" do
|
50
|
+
|
51
|
+
it "should find the question" do
|
52
|
+
subject.process_question "'Ask more questions?'"
|
53
|
+
subject.question.should == 'Ask more questions?'
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "subject" do
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/spec/quiz_spec.rb
CHANGED
@@ -15,11 +15,11 @@ describe Robut::Plugin::Quiz do
|
|
15
15
|
let(:time) { Time.now }
|
16
16
|
|
17
17
|
[
|
18
|
-
"ask
|
19
|
-
"ask
|
20
|
-
"ask
|
21
|
-
"ask '
|
22
|
-
"ask
|
18
|
+
"ask 'Should I continue the presentation?'",
|
19
|
+
"ask for 3 minutes 'Should I continue the presentation?'",
|
20
|
+
"ask polar for 3 minutes 'Should I continue the presentation?'",
|
21
|
+
"ask choice 1 minute 'What do you want for lunch?', 'pizza', 'sandwich', 'salad'",
|
22
|
+
"ask scale question for 10 minutes 'how much did you like the presentation?', '1..5'"
|
23
23
|
|
24
24
|
].each do |question|
|
25
25
|
|
@@ -55,7 +55,7 @@ describe Robut::Plugin::Quiz do
|
|
55
55
|
|
56
56
|
subject.should_not_receive(:process_response_for_active_question)
|
57
57
|
|
58
|
-
subject.handle time,'person',"@quizmaster ask polar 'Should I continue the presentation?'
|
58
|
+
subject.handle time,'person',"@quizmaster ask polar for 3 minutes 'Should I continue the presentation?'"
|
59
59
|
|
60
60
|
end
|
61
61
|
|
@@ -70,7 +70,7 @@ describe Robut::Plugin::Quiz do
|
|
70
70
|
|
71
71
|
subject.should_receive(:process_response_for_active_question)
|
72
72
|
|
73
|
-
subject.handle time,'person',"@quizmaster ask polar 'Should I continue the presentation?'
|
73
|
+
subject.handle time,'person',"@quizmaster ask polar for 3 minutes 'Should I continue the presentation?'"
|
74
74
|
|
75
75
|
end
|
76
76
|
|
@@ -93,7 +93,7 @@ describe Robut::Plugin::Quiz do
|
|
93
93
|
subject.should_receive(:create_the_question_based_on_type).and_return(expected_question)
|
94
94
|
|
95
95
|
subject.should_receive(:set_current_question).with(expected_question,'3')
|
96
|
-
subject.process_the_question 'person',"ask polar 'Should I continue the presentation?'
|
96
|
+
subject.process_the_question 'person',"ask polar for 3 minutes 'Should I continue the presentation?'"
|
97
97
|
|
98
98
|
end
|
99
99
|
|
@@ -109,7 +109,7 @@ describe Robut::Plugin::Quiz do
|
|
109
109
|
end
|
110
110
|
|
111
111
|
let(:question) do
|
112
|
-
Robut::Plugin::Quiz::Polar.new 'person',"
|
112
|
+
Robut::Plugin::Quiz::Polar.new 'person',"'Should I continue the presentation?'"
|
113
113
|
end
|
114
114
|
|
115
115
|
it "should place robut in the mode where it is asking a question" do
|
data/spec/range_spec.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe Robut::Plugin::Quiz::Range do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
Robut::Plugin::Quiz::Range.new 'person',"ask range for 3 minutes 'Should I continue the presentation?'"
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#start_value" do
|
10
|
+
|
11
|
+
context "when no range has been specified" do
|
12
|
+
|
13
|
+
it "should default to the value 1" do
|
14
|
+
subject.start_value.should == 1
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#highest_value" do
|
22
|
+
|
23
|
+
context "when no range has been specified" do
|
24
|
+
|
25
|
+
it "should default to the value of 5" do
|
26
|
+
subject.highest_value.should == 5
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#within_range?" do
|
34
|
+
|
35
|
+
context "when the value is within range" do
|
36
|
+
|
37
|
+
it "should respond with true" do
|
38
|
+
subject.within_range?(3).should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context "when the value is not within range" do
|
44
|
+
|
45
|
+
it "should respond with false" do
|
46
|
+
subject.within_range?(6).should be_false
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#handle_response" do
|
54
|
+
|
55
|
+
context "with a valid response" do
|
56
|
+
|
57
|
+
it "should return true" do
|
58
|
+
subject.should_receive(:store_range_response_for).with("sender","1")
|
59
|
+
subject.handle_response("sender","1").should be_true
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
describe Robut::Plugin::Quiz::Range::Averages do
|
67
|
+
|
68
|
+
subject do
|
69
|
+
array = [1,1,2,2,2,3,4,5]
|
70
|
+
array.extend Robut::Plugin::Quiz::Range::Averages
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
describe "#sum" do
|
75
|
+
|
76
|
+
it "should return the correct value" do
|
77
|
+
subject.sum.should == 20
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#mean" do
|
83
|
+
|
84
|
+
it "should return the correct value" do
|
85
|
+
subject.mean.should == 2.5
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#mode" do
|
91
|
+
|
92
|
+
it "should return the correct value" do
|
93
|
+
subject.mode.should == 2
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: robut-quiz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Franklin Webber
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-10-
|
13
|
+
date: 2011-10-27 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: robut
|
@@ -40,16 +40,19 @@ files:
|
|
40
40
|
- lib/polar.rb
|
41
41
|
- lib/question.rb
|
42
42
|
- lib/quiz.rb
|
43
|
+
- lib/range.rb
|
43
44
|
- lib/robut_quiz.rb
|
44
45
|
- robut-quiz.gemspec
|
45
46
|
- spec/polar_spec.rb
|
47
|
+
- spec/question_spec.rb
|
46
48
|
- spec/quiz_spec.rb
|
49
|
+
- spec/range_spec.rb
|
47
50
|
- spec/spec_helper.rb
|
48
51
|
homepage: http://github.com/burtlo/robut-quiz
|
49
52
|
licenses: []
|
50
53
|
|
51
54
|
post_install_message: "\n\
|
52
|
-
--------------------------------------------------------------------------------\n ___\n !(O-0)! ~ Thank you for installing robut-quiz 0.
|
55
|
+
--------------------------------------------------------------------------------\n ___\n !(O-0)! ~ Thank you for installing robut-quiz 0.2.0 / 2011-10-26\n >==[ ]==<\n @ @\n\n Changes:\n \n * Changed the question syntax\n * Added a range question (1..5)\n \n\n\
|
53
56
|
--------------------------------------------------------------------------------"
|
54
57
|
rdoc_options:
|
55
58
|
- --charset=UTF-8
|