gipper 0.0.1

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.
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
+