gipper 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +7 -0
  2. data/PostInstall.txt +5 -0
  3. data/README.rdoc +49 -0
  4. data/Rakefile +69 -0
  5. data/VERSION.yml +4 -0
  6. data/docs/gift_reference.pdf +0 -0
  7. data/features/fixtures/matching.gift +9 -0
  8. data/features/fixtures/missing_word.gift +8 -0
  9. data/features/fixtures/multiple_choice.gift +41 -0
  10. data/features/fixtures/numerical.gift +10 -0
  11. data/features/fixtures/short_answer.gift +10 -0
  12. data/features/fixtures/super_gift.txt +169 -0
  13. data/features/fixtures/true_or_false.gift +19 -0
  14. data/features/gift_parsing.feature +10 -0
  15. data/features/parse_matching_questions.feature +10 -0
  16. data/features/parse_missing_word.feature +10 -0
  17. data/features/parse_multiple_choice_questions.feature +10 -0
  18. data/features/parse_numerical_questions.feature +10 -0
  19. data/features/parse_short_answer_questions.feature +10 -0
  20. data/features/parse_true_or_false_questions.feature +10 -0
  21. data/features/steps/gift_parsing_steps.rb +546 -0
  22. data/features/steps/parse_matching_steps.rb +30 -0
  23. data/features/steps/parse_missing_word_steps.rb +58 -0
  24. data/features/steps/parse_multiple_choice_steps.rb +107 -0
  25. data/features/steps/parse_numerical_steps.rb +35 -0
  26. data/features/steps/parse_short_answer_steps.rb +42 -0
  27. data/features/steps/parse_steps.rb +7 -0
  28. data/features/steps/parse_true_or_false_steps.rb +61 -0
  29. data/features/support/env.rb +10 -0
  30. data/lib/answer.rb +165 -0
  31. data/lib/answers.rb +99 -0
  32. data/lib/gipper.rb +15 -0
  33. data/lib/question.rb +53 -0
  34. data/lib/quiz.rb +31 -0
  35. data/lib/special_charater_handler.rb +8 -0
  36. data/script/txt2html +71 -0
  37. data/script/txt2html.cmd +1 -0
  38. data/tasks/rspec.rake +21 -0
  39. data/test/answer_test.rb +152 -0
  40. data/test/answers_test.rb +126 -0
  41. data/test/custom_assertions.rb +68 -0
  42. data/test/fixtures/begins_with_comment.txt +6 -0
  43. data/test/question_test.rb +86 -0
  44. data/test/quiz_test.rb +65 -0
  45. data/test/special_character_handler_test.rb +43 -0
  46. data/test/test_helper.rb +19 -0
  47. metadata +125 -0
@@ -0,0 +1,30 @@
1
+
2
+ Given /^a GIFT file of matching questions$/ do
3
+ file = File.open(File.join(File.dirname(__FILE__), *%w[.. fixtures matching.gift]))
4
+ @data = file.read
5
+ assert @data.length > 0
6
+ end
7
+
8
+ Then /^contains the correct matching questions$/ do
9
+ #//My file of matching questions about emoticons
10
+ #::Intro to matching questions
11
+ #::Match the emoticon to the correct emotion:{
12
+ #=:) -> smiling
13
+ #=:D -> crazy happy
14
+ #=\(^_^)/ -> yay!
15
+ #=:( -> sad
16
+ #}
17
+ assert_equal 1, @questions.length
18
+
19
+ question = @questions[0]
20
+ assert_equal 4, question.answer.length
21
+ assert_question question, :style => :matching,
22
+ :text => "Match the emoticon to the correct emotion:",
23
+ :title => "Intro to matching questions"
24
+
25
+ assert_answer question.answer[0], :correct => "smiling", :text => ":)"
26
+ assert_answer question.answer[1], :correct => "crazy happy", :text => ":D"
27
+ assert_answer question.answer[2], :correct => "yay!", :text => '\\(^_^)/'
28
+ assert_answer question.answer[3], :correct => "sad", :text => ":("
29
+ end
30
+
@@ -0,0 +1,58 @@
1
+ Given /^a GIFT file of missing word questions$/ do
2
+ file = File.open(File.join(File.dirname(__FILE__), *%w[.. fixtures missing_word.gift]))
3
+ @data = file.read
4
+ @data.length.should be > 0
5
+ end
6
+
7
+ Then /^contains the correct missing word questions$/ do
8
+ @questions.length.should be(4)
9
+
10
+ #Sally sells { =seashells ~snails} by the seashore.
11
+ question = @questions[0]
12
+ assert_equal 2, question.answer.length
13
+ assert_question question, :style => :missing_word,
14
+ :text => "Sally sells",
15
+ :title => nil,
16
+ :text_post => "by the seashore."
17
+
18
+ assert_answer question.answer[0], :correct => true, :text => "seashells"
19
+ assert_answer question.answer[1], :correct => false, :text => "snails"
20
+
21
+
22
+ #::Hamster Tree::
23
+ #Oh woe is me, {~oh =doh!} woe is me!
24
+ question = @questions[1]
25
+ assert_equal 2, question.answer.length
26
+ assert_question question, :style => :missing_word,
27
+ :text => "Oh woe is me,",
28
+ :title => "Hamster Tree",
29
+ :text_post => "woe is me!"
30
+
31
+ assert_answer question.answer[0], :correct => false, :text => "oh"
32
+ assert_answer question.answer[1], :correct => true, :text => "doh!"
33
+
34
+ #You say that, "money is the root of all evil", I ask you "what is the root of all {~honey ~bunnies =money}?"
35
+ question = @questions[2]
36
+ assert_equal 3, question.answer.length
37
+ assert_question question, :style => :missing_word,
38
+ :text => 'You say that, "money is the root of all evil", I ask you "what is the root of all',
39
+ :title => nil,
40
+ :text_post => '?"'
41
+
42
+ assert_answer question.answer[0], :correct => false, :text => "honey"
43
+ assert_answer question.answer[1], :correct => false, :text => "bunnies"
44
+ assert_answer question.answer[2], :correct => true, :text => "money"
45
+
46
+ #Ooh Eee \{Uh\} Ooh Ah Ah {=Ting Tang ~Tung Ting ~Wing Wang} Walla Walla Bing Bang!
47
+ question = @questions[3]
48
+ assert_equal 3, question.answer.length
49
+ assert_question question, :style => :missing_word,
50
+ :text => 'Ooh Eee {Uh} Ooh Ah Ah',
51
+ :title => nil,
52
+ :text_post => "Walla Walla Bing Bang!"
53
+
54
+ assert_answer question.answer[0], :correct => true, :text => "Ting Tang"
55
+ assert_answer question.answer[1], :correct => false, :text => "Tung Ting"
56
+ assert_answer question.answer[2], :correct => false, :text => "Wing Wang"
57
+ end
58
+
@@ -0,0 +1,107 @@
1
+
2
+ Given /^a GIFT file of multiple choice questions$/ do
3
+ file = File.open(File.join(File.dirname(__FILE__), *%w[.. fixtures multiple_choice.gift]))
4
+ @data = file.read
5
+ @data.length.should be > 0
6
+ end
7
+
8
+ Then /^contains the correct multiple choice questions$/ do
9
+ @questions.length.should be(6)
10
+
11
+
12
+ #::Ninjas and the future::In the future, ninjas will be able to{= Travel to the moon ~play tennis ~eat apples ~play fable 2 ~code in Assembly }
13
+ question = @questions[0]
14
+ assert_equal 5, question.answer.length
15
+ assert_question question, :style => :multiple_choice,
16
+ :text => "In the future, ninjas will be able to",
17
+ :title => "Ninjas and the future"
18
+
19
+ assert_answer question.answer[0], :correct => true, :text => "Travel to the moon"
20
+ assert_answer question.answer[1], :correct => false, :text => "play tennis"
21
+ assert_answer question.answer[2], :correct => false, :text => "eat apples"
22
+ assert_answer question.answer[3], :correct => false, :text => "play fable 2"
23
+ assert_answer question.answer[4], :correct => false, :text => "code in Assembly"
24
+
25
+ #// question: 2 name: Ninjas and you
26
+ #::Ninjas and you::
27
+ # If you see a ninja you should: {~offer them a crunchy frog =run ~attack them }
28
+ question = @questions[1]
29
+ assert_equal 3, question.answer.length
30
+ assert_question question, :style => :multiple_choice,
31
+ :text => "If you see a ninja you should:",
32
+ :title => "Ninjas and you"
33
+
34
+ assert_answer question.answer[0], :correct => false, :text => "offer them a crunchy frog"
35
+ assert_answer question.answer[1], :correct => true, :text => "run"
36
+ assert_answer question.answer[2], :correct => false, :text => "attack them"
37
+
38
+ #Ninjas will only attack when {~provoked ~ upset ~off duty =none of the above}
39
+ question = @questions[2]
40
+ assert_equal 4, question.answer.length
41
+ assert_question question, :style => :multiple_choice,
42
+ :text => "Ninjas will only attack when",
43
+ :title => nil
44
+
45
+ assert_answer question.answer[0], :correct => false, :text => "provoked"
46
+ assert_answer question.answer[1], :correct => false, :text => "upset"
47
+ assert_answer question.answer[2], :correct => false, :text => "off duty"
48
+ assert_answer question.answer[3], :correct => true, :text => "none of the above"
49
+
50
+ #One way ninjas are like a snake is: {~Ninjas have scales ~Ninjas eat rodents =Ninjas can spit venom}
51
+ question = @questions[3]
52
+ assert_equal 3, question.answer.length
53
+ assert_question question, :style => :multiple_choice,
54
+ :text => "One way ninjas are like a snake is:",
55
+ :title => nil
56
+
57
+ assert_answer question.answer[0], :correct => false, :text => "Ninjas have scales"
58
+ assert_answer question.answer[1], :correct => false, :text => "Ninjas eat rodents"
59
+ assert_answer question.answer[2], :correct => true, :text => "Ninjas can spit venom"
60
+
61
+ #::Supercomputing Ninjas
62
+ #::Ninjas can recite the value of pi to how many digits?{
63
+ #~10
64
+ ## do you even know what a ninja is?
65
+ #~100
66
+ ## are you crazy?
67
+ #~100,000
68
+ ## that is pitiful
69
+ #=twice the US national debt
70
+ ## if not more!
71
+ #}
72
+ question = @questions[4]
73
+ assert_equal 4, question.answer.length
74
+ assert_question question, :style => :multiple_choice,
75
+ :text => "Ninjas can recite the value of pi to how many digits?",
76
+ :title => "Supercomputing Ninjas"
77
+
78
+ assert_answer question.answer[0], :correct => false, :text => "10", :comment => "do you even know what a ninja is?"
79
+ assert_answer question.answer[1], :correct => false, :text => "100", :comment => "are you crazy?"
80
+ assert_answer question.answer[2], :correct => false, :text => "100,000", :comment => "that is pitiful"
81
+ assert_answer question.answer[3], :correct => true, :text => "twice the US national debt", :comment => "if not more!"
82
+
83
+ #// Ninjas can be commented on
84
+ #::Are you a Ninja?::
85
+ #When confronted by a zombie army of terracotta kung-fu masters, you would: {
86
+ #~ cry
87
+ ## not even baby ninjas would do that
88
+ #~ try to fight
89
+ ## fight or fight not, there is no try.
90
+ #= slay them all with a single strike before they even saw you.
91
+ ## You are Ninja!
92
+ #~ run away
93
+ ## You would make a poor ninja.
94
+ #}
95
+ question = @questions[5]
96
+ assert_equal 4, question.answer.length
97
+ assert_question question, :style => :multiple_choice,
98
+ :text => "When confronted by a zombie army of terracotta kung-fu masters, you would:",
99
+ :title => "Are you a Ninja?"
100
+
101
+ assert_answer question.answer[0], :correct => false, :text => "cry", :comment => "not even baby ninjas would do that"
102
+ assert_answer question.answer[1], :correct => false, :text => "try to fight", :comment => "fight or fight not, there is no try."
103
+ assert_answer question.answer[2], :correct => true, :text => "slay them all with a single strike before they even saw you.", :comment => "You are Ninja!"
104
+ assert_answer question.answer[3], :correct => false, :text => "run away", :comment => "You would make a poor ninja."
105
+
106
+ end
107
+
@@ -0,0 +1,35 @@
1
+ Given /^a GIFT file of numerical questions$/ do
2
+ file = File.open(File.join(File.dirname(__FILE__), *%w[.. fixtures numerical.gift]))
3
+ @data = file.read
4
+ @data.length.should be > 0
5
+ end
6
+
7
+ Then /^contains the correct numerical questions$/ do
8
+ @questions.length.should be(2)
9
+
10
+ #When was Harvey D. Smith born?{#1945:5}
11
+ question = @questions[0]
12
+ assert_equal 1, question.answer.length
13
+ assert_question question, :style => :numerical,
14
+ :text => "When was Harvey D. Smith born?",
15
+ :title => nil
16
+
17
+ assert_answer question.answer[0], :correct => 1945, :range => 5, :weight => nil
18
+
19
+ #//this comment will be ignored in the import process
20
+ #::Numerical example::
21
+ #When was Elizabeth M. Danson born? {#
22
+ # =1993:0 #Correct! you will get full credit for this answer
23
+ # =%50%1993:2 #She was born in 1993.
24
+ # You get 50% credit for being close.
25
+ #}
26
+ question = @questions[1]
27
+ assert_equal 2, question.answer.length
28
+ assert_question question, :style => :numerical,
29
+ :text => "When was Elizabeth M. Danson born?",
30
+ :title => "Numerical example"
31
+
32
+ assert_answer question.answer[0], :correct => 1993, :range => 0, :weight => nil, :comment => "Correct! you will get full credit for this answer"
33
+ assert_answer question.answer[1], :correct => 1993, :range => 2, :weight => 50, :comment => "She was born in 1993.\n You get 50% credit for being close."
34
+ end
35
+
@@ -0,0 +1,42 @@
1
+
2
+ Given(/^a GIFT file of short answer questions$/) do
3
+ file = File.open(File.join(File.dirname(__FILE__), *%w[.. fixtures short_answer.gift]))
4
+ @data = file.read
5
+ @data.length.should be > 0
6
+ end
7
+
8
+ Then(/^contains the correct short answer questions$/) do
9
+ @questions.length.should be(3)
10
+
11
+ #//File of short answer questions
12
+ #::Intro question about coffee::
13
+ #Coffee is made from {=ground coffee beans and water =burnt beans = the nectar of the gods}
14
+ question = @questions[0]
15
+ assert_equal 3, question.answer.length
16
+ assert_question question, :style => :short_answer,
17
+ :text => "Coffee is made from",
18
+ :title => "Intro question about coffee"
19
+
20
+ assert_answer question.answer[0], :correct => true, :text => "ground coffee beans and water"
21
+ assert_answer question.answer[1], :correct => true, :text => "burnt beans"
22
+ assert_answer question.answer[2], :correct => true, :text => "the nectar of the gods"
23
+
24
+ #Coffee is best when{ = hot = cold}
25
+ question = @questions[1]
26
+ assert_equal 2, question.answer.length
27
+ assert_question question, :style => :short_answer,
28
+ :text => "Coffee is best when",
29
+ :title => nil
30
+
31
+ assert_answer question.answer[0], :correct => true, :text => "hot"
32
+ assert_answer question.answer[1], :correct => true, :text => "cold"
33
+
34
+ #The only way to spell coffee is:{=coffee}
35
+ question = @questions[2]
36
+ assert_equal 1, question.answer.length
37
+ assert_question question, :style => :short_answer,
38
+ :text => "The only way to spell coffee is:",
39
+ :title => nil
40
+
41
+ assert_answer question.answer[0], :correct => true, :text => "coffee"
42
+ end
@@ -0,0 +1,7 @@
1
+ When(/^I tell gipper to parse the file$/)do
2
+ @questions = Gipper::Quiz.parse @data
3
+ end
4
+
5
+ Then(/^I will get an array of questions and answers$/)do
6
+ @questions.class.should eql(Array)
7
+ end
@@ -0,0 +1,61 @@
1
+ Given(/^a GIFT file of true or false questions$/) do
2
+ file = File.open(File.join(File.dirname(__FILE__), *%w[.. fixtures true_or_false.gift]))
3
+ @data = file.read
4
+ @data.length.should be > 0
5
+ end
6
+
7
+ Then(/^contains the correct true or false questions$/)do
8
+ @questions.length.should be(6)
9
+
10
+ #:trueStatement about monkeys::Monkeys like to fly like ninjas.{T}
11
+ question = @questions[0]
12
+ assert_question question, :style => :true_false,
13
+ :text => "Monkeys like to fly like ninjas.",
14
+ :title => "TrueStatement about monkeys"
15
+
16
+ assert_answer question.answer[0], :correct => true
17
+
18
+ #// question: 0 name: TrueStatement
19
+ #::A Second TrueStatement about monkeys::
20
+ #Monkeys roam in packs with swords.{True}
21
+ question = @questions[1]
22
+ assert_question question, :style => :true_false,
23
+ :text => "Monkeys roam in packs with swords.",
24
+ :title => "A Second TrueStatement about monkeys"
25
+
26
+ assert_answer question.answer[0], :correct => true
27
+
28
+ #Monkeys will jump from buildings without fear. {T}
29
+ question = @questions[2]
30
+ assert_question question, :style => :true_false,
31
+ :text => "Monkeys will jump from buildings without fear.",
32
+ :title => nil
33
+
34
+ assert_answer question.answer[0], :correct => true
35
+
36
+ #Monkeys have a formal system of government{False}
37
+ question = @questions[3]
38
+ assert_question question, :style => :true_false,
39
+ :text => "Monkeys have a formal system of government",
40
+ :title => nil
41
+
42
+ assert_answer question.answer[0], :correct => false
43
+
44
+ #::A Second FalseStatement about monkeys
45
+ #::Monkeys wear suits and sit around in corporate offices.{False}
46
+ question = @questions[4]
47
+ assert_question question, :style => :true_false,
48
+ :text => "Monkeys wear suits and sit around in corporate offices.",
49
+ :title => "A Second FalseStatement about monkeys"
50
+
51
+ assert_answer question.answer[0], :correct => false
52
+
53
+ #// question: 6 name: FalseStatement
54
+ #::A Third FalseStatement about monkeys:: Monkeys can operate heavy machinery.{F}
55
+ question = @questions[5]
56
+ assert_question question, :style => :true_false,
57
+ :text => "Monkeys can operate heavy machinery.",
58
+ :title => "A Third FalseStatement about monkeys"
59
+
60
+ assert_answer question.answer[0], :correct => false
61
+ end
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.join [File.dirname(__FILE__), "..", "..", "lib"])
2
+ require 'gipper'
3
+
4
+ $LOAD_PATH.unshift(File.join [File.dirname(__FILE__), "..", "..", "test"])
5
+ require 'custom_assertions'
6
+ include CustomAssertions
7
+
8
+ require 'test/unit/assertions'
9
+
10
+ World(Test::Unit::Assertions)
@@ -0,0 +1,165 @@
1
+ require 'special_charater_handler'
2
+
3
+ module Gipper
4
+ # == Gipper::Answer
5
+ #
6
+ # Represents the single correct answer if there is only one answer,
7
+ # or one of the answer choices if multiple are provided for a question.
8
+ #
9
+ # To populate the answer from a string use the parse method
10
+ #
11
+ # answer = Gipper::Answer.new
12
+ # answer.parse "= foo #bar"
13
+ #
14
+ # answer.correct
15
+ # >> true
16
+ #
17
+ # answer.text
18
+ # >> foo
19
+ #
20
+ # answer.comment
21
+ # >> bar
22
+ #
23
+ # or
24
+ #
25
+ # answer.parse "F"
26
+ #
27
+ # answer.correct
28
+ # >> false
29
+ #
30
+ class Answer
31
+ include Oniguruma
32
+ include Gipper::SpecialCharacterHandler
33
+ attr_reader :weight, :correct, :comment, :range, :text
34
+
35
+ # Will parse a single answer into it's parts.
36
+ # If the answer type is numerical, pass :numerical as the optional second parameter.
37
+ def parse answer, style_hint = nil
38
+ if style_hint == :numerical
39
+ parse_as_numerical answer
40
+ else
41
+ parse_standard answer
42
+ end
43
+ end
44
+
45
+ private
46
+ def can_parse_as_true_false? answer
47
+ return false if answer.nil?
48
+ answer.downcase.strip =~ /^(t|f|true|false)$/
49
+ end
50
+
51
+ def parse_standard answer
52
+ correct, text = split_correct answer
53
+
54
+ split_matching(text) do |t, c|
55
+ text, correct = t, c
56
+ end
57
+
58
+ text, weight = split_weight(text)
59
+ @weight = weight.to_i if weight
60
+ @text, @comment = split_comment(text).map { |item| unescape item }
61
+
62
+ @correct = correct
63
+
64
+ # handle true false
65
+ if can_parse_as_true_false?(@text)
66
+ convert_to_true_false!
67
+ end
68
+ end
69
+
70
+ def parse_as_numerical answer
71
+ correct, range = answer.split(":", 2)
72
+ range, comment = split_comment range
73
+ correct.gsub!("=", "")
74
+ weight = 100
75
+
76
+ correct, weight = split_weight(correct)
77
+ @weight = weight.to_i if weight
78
+
79
+ @comment = comment
80
+ parts = correct.split(/\.\./)
81
+ if parts.length == 2
82
+ parts.map! { |s| to_num(s) }
83
+ @correct = ((parts[0] + parts[1]) /2)
84
+ @range = ((parts[1] - parts[0]) /2)
85
+ else
86
+ @correct = to_num(correct)
87
+ @range = to_num(range)
88
+ end
89
+ end
90
+
91
+ def convert_to_true_false!
92
+ @correct = is_true(@text)
93
+ @text = nil
94
+ end
95
+
96
+ def to_num(val)
97
+ if val && val.include?(".")
98
+ val.to_f
99
+ else
100
+ val.to_i
101
+ end
102
+ end
103
+
104
+ def is_true answer
105
+ !(answer.downcase.strip =~ /^(t|true)$/).nil?
106
+ end
107
+
108
+ def split_correct clause
109
+ correct = []
110
+
111
+ if clause =~ /^[~=]/
112
+ correct[0] = eval_correctness(clause[0])
113
+ correct[1] = clause[1..clause.length].strip
114
+ else
115
+ correct[0] = true
116
+ correct[1] = clause
117
+ end
118
+
119
+ return correct
120
+ end
121
+
122
+ def split_matching answers
123
+ reg = Regexp.new('(.*)\-\>(.*)', Regexp::MULTILINE)
124
+ matches = reg.match answers
125
+
126
+ if matches
127
+ yield matches.captures.map {|s| s.strip}
128
+ end
129
+ end
130
+
131
+ def split_weight answer
132
+ return [answer, nil] unless answer.class == String
133
+ matches = answer.match(/%(-?\d+)%(.+)/)
134
+ if matches
135
+ weight = matches.captures[0]
136
+ correct = matches.captures[1]
137
+ return [correct, weight]
138
+ end
139
+
140
+ return [answer, nil]
141
+ end
142
+
143
+ def eval_correctness indicator
144
+ { 61 => true, 126 => false}[indicator]
145
+ end
146
+
147
+ def split_comment answer_text
148
+ return [nil, nil] if blank?(answer_text)
149
+
150
+ answer_text.strip!
151
+ reg = ORegexp.new('(?<before>.*)(?<!\\\\)#(?<after>.*)', :options => OPTION_MULTILINE)
152
+ match = reg.match(answer_text)
153
+ return [answer_text, nil] unless match
154
+
155
+ text = match[:before].strip
156
+ feedback_comment = match[:after].strip
157
+ [text, feedback_comment]
158
+ end
159
+
160
+ def blank? text
161
+ text.nil? || text == ""
162
+ end
163
+ end
164
+ end
165
+