ruql 0.1.5 → 1.0.5
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.
- checksums.yaml +5 -5
- data/.gitignore +14 -0
- data/.travis.yml +7 -0
- data/Gemfile +6 -0
- data/LICENSE +6 -0
- data/README.md +318 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/ruql +90 -114
- data/bin/setup +8 -0
- data/examples/estilo.css +1 -0
- data/examples/example.rb +37 -0
- data/examples/file.html +94 -0
- data/examples/help.txt +55 -0
- data/examples/preguntas-TFG-20140224-0050.txt +32 -0
- data/examples/preguntas-TFG-20140224-0050.xml +168 -0
- data/examples/prueba.js +3 -0
- data/lib/ruql.rb +10 -3
- data/lib/ruql/answer.rb +6 -14
- data/lib/ruql/json.rb +12 -0
- data/lib/ruql/multiple_choice.rb +1 -1
- data/lib/ruql/open_assessment/open_assessment.rb +1 -1
- data/lib/ruql/question.rb +27 -56
- data/lib/ruql/quiz.rb +50 -69
- data/lib/ruql/renderers/edxml_renderer.rb +1 -1
- data/lib/ruql/renderers/html5_renderer.rb +65 -27
- data/lib/ruql/renderers/json_renderer.rb +35 -1
- data/lib/ruql/renderers/xml_renderer.rb +148 -0
- data/lib/ruql/select_multiple.rb +5 -1
- data/lib/ruql/stats.rb +18 -0
- data/lib/ruql/true_false.rb +1 -1
- data/lib/ruql/version.rb +3 -0
- data/ruql.gemspec +43 -0
- metadata +71 -38
- data/templates/autoqcm.tex.erb +0 -1
- data/templates/html5.html.erb +0 -42
- data/templates/htmlform.html.erb +0 -44
@@ -10,6 +10,40 @@ class JSONRenderer
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def render_quiz
|
13
|
-
@
|
13
|
+
@quiz.questions.each do |question|
|
14
|
+
case question
|
15
|
+
when MultipleChoice, SelectMultiple, TrueFalse then render_multiple_choice(question)
|
16
|
+
when FillIn then render_fill_in(question) # not currently supported
|
17
|
+
else
|
18
|
+
raise "Unknown question type: #{question}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@output = JSON.pretty_generate(@json_array)
|
14
22
|
end
|
23
|
+
|
24
|
+
def render_multiple_choice(question)
|
25
|
+
question_hash = {
|
26
|
+
"text" => question.question_text,
|
27
|
+
"answers" => answers_to_json_array(question.answers)
|
28
|
+
}
|
29
|
+
@json_array.push(question_hash)
|
30
|
+
end
|
31
|
+
|
32
|
+
def answers_to_json_array(answers)
|
33
|
+
answers_array = []
|
34
|
+
answers.each do |answer|
|
35
|
+
answer_json = {
|
36
|
+
"text" => answer.answer_text,
|
37
|
+
"explanation" => answer.explanation,
|
38
|
+
"correct" => answer.correct
|
39
|
+
}
|
40
|
+
answers_array.push(answer_json)
|
41
|
+
end
|
42
|
+
answers_array
|
43
|
+
end
|
44
|
+
|
45
|
+
def render_fill_in(q)
|
46
|
+
# fill-in-the-blank questions not currently supported
|
47
|
+
end
|
48
|
+
|
15
49
|
end
|
@@ -0,0 +1,148 @@
|
|
1
|
+
class XMLRenderer
|
2
|
+
require 'builder'
|
3
|
+
|
4
|
+
attr_reader :output
|
5
|
+
def initialize(quiz,options={})
|
6
|
+
@output = ''
|
7
|
+
@b = Builder::XmlMarkup.new(:target => @output, :indent => 2)
|
8
|
+
@quiz = quiz
|
9
|
+
end
|
10
|
+
|
11
|
+
def render(thing)
|
12
|
+
case thing
|
13
|
+
when MultipleChoice,SelectMultiple,TrueFalse then render_multiple_choice(thing)
|
14
|
+
when FillIn then render_fill_in(thing)
|
15
|
+
else
|
16
|
+
raise "Unknown question type: #{thing}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def render_quiz
|
21
|
+
# entire quiz can be in one question group, as long as we specify
|
22
|
+
# that ALL question from the group must be used to make the quiz.
|
23
|
+
xml_quiz do
|
24
|
+
# after preamble...
|
25
|
+
@b.question_groups do
|
26
|
+
@b.question_group(:select => @quiz.questions.length) do
|
27
|
+
@quiz.questions.each do |question|
|
28
|
+
self.render(question)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
@output
|
34
|
+
end
|
35
|
+
|
36
|
+
def render_fill_in(question)
|
37
|
+
@b.question :type => 'GS_Short_Answer_Question_Simple', :id => question.object_id.to_s(16) do
|
38
|
+
@b.metadata {
|
39
|
+
@b.parameters {
|
40
|
+
@b.rescale_score question.points
|
41
|
+
@b.type 'regexp'
|
42
|
+
}
|
43
|
+
}
|
44
|
+
# since we want all the options to appear, we create N option
|
45
|
+
# groups each containig 1 option, and specify that option to
|
46
|
+
# always be selected for inclusion in the quiz. If the original
|
47
|
+
# question specified 'random', use the 'randomize' attribute on
|
48
|
+
# option_groups to scramble the order in which displayed;
|
49
|
+
# otherwise, display in same order as answers appear in source.
|
50
|
+
@b.data {
|
51
|
+
@b.text { @b.cdata!(question.question_text) }
|
52
|
+
@b.option_groups(:randomize => !!question.randomize) {
|
53
|
+
@b.option_group(:select => 'all') {
|
54
|
+
question.answers.each do |answer|
|
55
|
+
option_args = {}
|
56
|
+
option_args['selected_score'] = answer.correct? ? 1 : 0
|
57
|
+
option_args['unselected_score'] =
|
58
|
+
question.multiple ? 1 - option_args['selected_score'] : 0
|
59
|
+
option_args['id'] = answer.object_id.to_s(16)
|
60
|
+
@b.option(option_args) do
|
61
|
+
answer_text = answer.answer_text
|
62
|
+
if answer_text.kind_of?(Regexp)
|
63
|
+
answer_text = answer_text.inspect
|
64
|
+
if !question.case_sensitive
|
65
|
+
answer_text += 'i'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
@b.text { @b.cdata!(answer_text) }
|
69
|
+
@b.explanation { @b.cdata!(answer.explanation) } if answer.has_explanation?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def render_multiple_choice(question)
|
79
|
+
@b.question :type => 'GS_Choice_Answer_Question', :id => question.object_id.to_s(16) do
|
80
|
+
@b.metadata {
|
81
|
+
@b.parameters {
|
82
|
+
@b.rescale_score question.points
|
83
|
+
@b.choice_type (question.multiple ? 'checkbox' : 'radio')
|
84
|
+
}
|
85
|
+
}
|
86
|
+
# since we want all the options to appear, we create N option
|
87
|
+
# groups each containig 1 option, and specify that option to
|
88
|
+
# always be selected for inclusion in the quiz. If the original
|
89
|
+
# question specified 'random', use the 'randomize' attribute on
|
90
|
+
# option_groups to scramble the order in which displayed;
|
91
|
+
# otherwise, display in same order as answers appear in source.
|
92
|
+
@b.data {
|
93
|
+
@b.text { @b.cdata!(question.question_text) }
|
94
|
+
@b.option_groups(:randomize => !!question.randomize) {
|
95
|
+
question.answers.each do |a|
|
96
|
+
@b.option_group(:select => 'all') {
|
97
|
+
self.render_multiple_choice_answer a, question.multiple
|
98
|
+
}
|
99
|
+
end
|
100
|
+
}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
alias :render_true_false :render_multiple_choice
|
105
|
+
|
106
|
+
def render_multiple_choice_answer(answer, multiple_allowed)
|
107
|
+
option_args = {}
|
108
|
+
option_args['selected_score'] = answer.correct? ? 1 : 0
|
109
|
+
option_args['unselected_score'] =
|
110
|
+
multiple_allowed ? 1 - option_args['selected_score'] : 0
|
111
|
+
option_args['id'] = answer.object_id.to_s(16)
|
112
|
+
@b.option(option_args) do
|
113
|
+
@b.text { @b.cdata!(answer.answer_text) }
|
114
|
+
@b.explanation { @b.cdata!(answer.explanation) } if answer.has_explanation?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def options_to_xml(h)
|
121
|
+
h.each_pair do |k,v|
|
122
|
+
if v.is_a?(Hash)
|
123
|
+
@b.__send__(k.to_sym) do
|
124
|
+
options_to_xml v
|
125
|
+
end
|
126
|
+
else
|
127
|
+
@b.__send__(k.to_sym, v)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
def xml_quiz
|
134
|
+
@b.quiz do
|
135
|
+
@b.metadata do
|
136
|
+
@b.type 'quiz'
|
137
|
+
@b.title @quiz.title
|
138
|
+
options_to_xml @quiz.options
|
139
|
+
end
|
140
|
+
@b.preamble
|
141
|
+
@b.data do
|
142
|
+
yield
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
data/lib/ruql/select_multiple.rb
CHANGED
data/lib/ruql/stats.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Ruql
|
2
|
+
class Stats
|
3
|
+
attr_reader :output, :quiz
|
4
|
+
# a pseudo-renderer that just prints stats about the quiz
|
5
|
+
def initialize(quiz, options={})
|
6
|
+
@quiz = quiz
|
7
|
+
@output = []
|
8
|
+
end
|
9
|
+
def render_quiz
|
10
|
+
@output << "%3d questions" % quiz.questions.length
|
11
|
+
@output << " %3d (%d points) in no group" % [quiz.ungrouped_questions.length, quiz.ungrouped_points]
|
12
|
+
@output << " %3d (%d points) in %d groups" % [quiz.grouped_questions.length, quiz.grouped_points, quiz.groups.length]
|
13
|
+
@output << "%3d effective questions on quiz" % quiz.num_questions
|
14
|
+
@output << "%3d max points possible" % quiz.points
|
15
|
+
@output.join("\n")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/ruql/true_false.rb
CHANGED
data/lib/ruql/version.rb
ADDED
data/ruql.gemspec
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
|
4
|
+
require 'ruql/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'ruql'
|
8
|
+
s.version = Ruql::VERSION
|
9
|
+
s.summary = "Ruby question language"
|
10
|
+
s.description = "Ruby-embedded DSL for creating short-answer quiz questions"
|
11
|
+
s.authors = ["Armando Fox"]
|
12
|
+
s.email = 'fox@berkeley.edu'
|
13
|
+
s.homepage = 'http://github.com/saasbook/ruql'
|
14
|
+
s.license = 'CC By-SA'
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
+
if s.respond_to?(:metadata)
|
19
|
+
s.metadata["allowed_push_host"] = "https://rubygems.org"
|
20
|
+
|
21
|
+
s.metadata["homepage_uri"] = s.homepage
|
22
|
+
s.metadata["source_code_uri"] = s.homepage
|
23
|
+
#s.metadata["changelog_uri"] = ''
|
24
|
+
else
|
25
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
26
|
+
"public gem pushes."
|
27
|
+
end
|
28
|
+
|
29
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
30
|
+
s.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
31
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
32
|
+
end
|
33
|
+
|
34
|
+
s.executables << 'ruql'
|
35
|
+
|
36
|
+
s.require_paths= ['lib']
|
37
|
+
|
38
|
+
s.add_development_dependency "bundler", "~> 1.17"
|
39
|
+
s.add_development_dependency "rake", "~> 10.0"
|
40
|
+
s.add_development_dependency "byebug"
|
41
|
+
s.add_development_dependency "rspec", "~> 3.0"
|
42
|
+
s.add_development_dependency "rspec_its"
|
43
|
+
end
|
metadata
CHANGED
@@ -1,83 +1,113 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Armando Fox
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-12-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- -
|
17
|
+
- - "~>"
|
17
18
|
- !ruby/object:Gem::Version
|
18
|
-
version: '
|
19
|
+
version: '1.17'
|
20
|
+
type: :development
|
19
21
|
prerelease: false
|
20
|
-
name: builder
|
21
22
|
version_requirements: !ruby/object:Gem::Requirement
|
22
23
|
requirements:
|
23
|
-
- -
|
24
|
+
- - "~>"
|
24
25
|
- !ruby/object:Gem::Version
|
25
|
-
version: '
|
26
|
-
type: :runtime
|
26
|
+
version: '1.17'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- -
|
31
|
+
- - "~>"
|
31
32
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
33
35
|
prerelease: false
|
34
|
-
name: getopt
|
35
36
|
version_requirements: !ruby/object:Gem::Requirement
|
36
37
|
requirements:
|
37
|
-
- -
|
38
|
+
- - "~>"
|
38
39
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
40
|
-
type: :runtime
|
40
|
+
version: '10.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
+
name: byebug
|
42
43
|
requirement: !ruby/object:Gem::Requirement
|
43
44
|
requirements:
|
44
|
-
- -
|
45
|
+
- - ">="
|
45
46
|
- !ruby/object:Gem::Version
|
46
|
-
version: '
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
47
49
|
prerelease: false
|
48
|
-
name: rspec
|
49
50
|
version_requirements: !ruby/object:Gem::Requirement
|
50
51
|
requirements:
|
51
|
-
- -
|
52
|
+
- - ">="
|
52
53
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
54
|
-
type: :development
|
54
|
+
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
56
57
|
requirement: !ruby/object:Gem::Requirement
|
57
58
|
requirements:
|
58
|
-
- - ~>
|
59
|
+
- - "~>"
|
59
60
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
61
|
+
version: '3.0'
|
62
|
+
type: :development
|
61
63
|
prerelease: false
|
62
|
-
name: activesupport
|
63
64
|
version_requirements: !ruby/object:Gem::Requirement
|
64
65
|
requirements:
|
65
|
-
- - ~>
|
66
|
+
- - "~>"
|
66
67
|
- !ruby/object:Gem::Version
|
67
|
-
version: '
|
68
|
+
version: '3.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec_its
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
68
76
|
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
69
83
|
description: Ruby-embedded DSL for creating short-answer quiz questions
|
70
|
-
email: fox@
|
84
|
+
email: fox@berkeley.edu
|
71
85
|
executables:
|
72
86
|
- ruql
|
73
87
|
extensions: []
|
74
88
|
extra_rdoc_files: []
|
75
89
|
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".travis.yml"
|
92
|
+
- Gemfile
|
93
|
+
- LICENSE
|
94
|
+
- README.md
|
95
|
+
- Rakefile
|
96
|
+
- bin/console
|
76
97
|
- bin/ruql
|
98
|
+
- bin/setup
|
99
|
+
- examples/estilo.css
|
100
|
+
- examples/example.rb
|
101
|
+
- examples/file.html
|
102
|
+
- examples/help.txt
|
103
|
+
- examples/preguntas-TFG-20140224-0050.txt
|
104
|
+
- examples/preguntas-TFG-20140224-0050.xml
|
105
|
+
- examples/prueba.js
|
77
106
|
- lib/ruql.rb
|
78
107
|
- lib/ruql/answer.rb
|
79
108
|
- lib/ruql/dropdown.rb
|
80
109
|
- lib/ruql/fill_in.rb
|
110
|
+
- lib/ruql/json.rb
|
81
111
|
- lib/ruql/multiple_choice.rb
|
82
112
|
- lib/ruql/open_assessment/criterion.rb
|
83
113
|
- lib/ruql/open_assessment/open_assessment.rb
|
@@ -93,34 +123,37 @@ files:
|
|
93
123
|
- lib/ruql/renderers/html_form_renderer.rb
|
94
124
|
- lib/ruql/renderers/json_renderer.rb
|
95
125
|
- lib/ruql/renderers/qualtrics_renderer.rb
|
126
|
+
- lib/ruql/renderers/xml_renderer.rb
|
96
127
|
- lib/ruql/select_multiple.rb
|
128
|
+
- lib/ruql/stats.rb
|
97
129
|
- lib/ruql/tex_output.rb
|
98
130
|
- lib/ruql/true_false.rb
|
99
|
-
-
|
100
|
-
-
|
101
|
-
- templates/htmlform.html.erb
|
131
|
+
- lib/ruql/version.rb
|
132
|
+
- ruql.gemspec
|
102
133
|
homepage: http://github.com/saasbook/ruql
|
103
134
|
licenses:
|
104
|
-
-
|
105
|
-
metadata:
|
106
|
-
|
135
|
+
- CC By-SA
|
136
|
+
metadata:
|
137
|
+
allowed_push_host: https://rubygems.org
|
138
|
+
homepage_uri: http://github.com/saasbook/ruql
|
139
|
+
source_code_uri: http://github.com/saasbook/ruql
|
140
|
+
post_install_message:
|
107
141
|
rdoc_options: []
|
108
142
|
require_paths:
|
109
143
|
- lib
|
110
144
|
required_ruby_version: !ruby/object:Gem::Requirement
|
111
145
|
requirements:
|
112
|
-
- -
|
146
|
+
- - ">="
|
113
147
|
- !ruby/object:Gem::Version
|
114
148
|
version: '0'
|
115
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
150
|
requirements:
|
117
|
-
- -
|
151
|
+
- - ">="
|
118
152
|
- !ruby/object:Gem::Version
|
119
153
|
version: '0'
|
120
154
|
requirements: []
|
121
|
-
|
122
|
-
|
123
|
-
signing_key:
|
155
|
+
rubygems_version: 3.0.8
|
156
|
+
signing_key:
|
124
157
|
specification_version: 4
|
125
158
|
summary: Ruby question language
|
126
159
|
test_files: []
|