ruql 0.0.8 → 1.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.
@@ -2,24 +2,8 @@ class Quiz
2
2
  @@quizzes = []
3
3
  @@yaml_file = nil
4
4
  @quiz_yaml = {}
5
+ @@options = {}
5
6
  def self.quizzes ; @@quizzes ; end
6
- @@default_options =
7
- {
8
- :open_time => Time.now,
9
- :soft_close_time => Time.now + 24*60*60,
10
- :hard_close_time => Time.now + 24*60*60,
11
- :maximum_submissions => 1,
12
- :duration => 3600,
13
- :retry_delay => 600,
14
- :parameters => {
15
- :show_explanations => {
16
- :question => 'before_soft_close_time',
17
- :option => 'before_soft_close_time',
18
- :score => 'before_soft_close_time',
19
- }
20
- },
21
- :maximum_score => 1,
22
- }
23
7
 
24
8
  attr_reader :renderer
25
9
  attr_reader :questions
@@ -29,36 +13,56 @@ class Quiz
29
13
  attr_reader :logger
30
14
  attr_accessor :title
31
15
 
32
- def initialize(title, yaml, options={})
16
+ def initialize(title, options={})
33
17
  @output = ''
34
18
  @questions = options[:questions] || []
35
19
  @title = title
36
- @options = @@default_options.merge(options)
20
+ @options = @@options.merge(options)
37
21
  @seed = srand
38
22
  @logger = Logger.new(STDERR)
39
- @logger.level = Logger.const_get (options.delete('l') ||
40
- options.delete('log') || 'warn').upcase
41
- @quiz_yaml = yaml
42
- end
43
-
44
- def self.get_renderer(renderer)
45
- Object.const_get(renderer.to_s + 'Renderer') rescue nil
23
+ @logger.level = (@options['-V'] || @options['--verbose']) ? Logger::INFO : Logger::WARN
24
+ #@quiz_yaml = yaml
46
25
  end
47
26
 
48
27
  def render_with(renderer,options={})
49
28
  srand @seed
50
- @renderer = Quiz.get_renderer(renderer).send(:new,self,options)
29
+ @renderer = renderer.send(:new,self,options)
51
30
  @renderer.render_quiz
52
31
  @output = @renderer.output
53
32
  end
54
33
 
55
- def self.set_yaml_file(file)
56
- @@yaml_file = file && YAML::load_file(file)
34
+ def self.set_options(options)
35
+ @@options = options
36
+ end
37
+
38
+ def ungrouped_questions
39
+ questions.filter { |q| q.question_group.to_s == '' }
40
+ end
41
+
42
+ def grouped_questions
43
+ questions.filter { |q| q.question_group.to_s != '' }.sort_by(&:question_group)
44
+ end
45
+
46
+ def groups ; questions.map(&:question_group).uniq.reject { |g| g.to_s == '' } ; end
47
+
48
+ def ungrouped_points
49
+ ungrouped_questions.map(&:points).sum
57
50
  end
58
51
 
59
- def points ; questions.map(&:points).inject { |sum,points| sum + points } ; end
52
+ def grouped_points
53
+ gq = grouped_questions
54
+ groups.sum do |g|
55
+ gq.detect { |q| q.question_group == g }.points
56
+ end
57
+ end
60
58
 
61
- def num_questions ; questions.length ; end
59
+ def points
60
+ ungrouped_points + grouped_points
61
+ end
62
+
63
+ def num_questions
64
+ groups.length + ungrouped_questions.length
65
+ end
62
66
 
63
67
  def random_seed(num)
64
68
  @seed = num.to_i
@@ -129,8 +133,8 @@ class Quiz
129
133
  @questions << q
130
134
  end
131
135
 
132
- def self.quiz(*args, &block)
133
- quiz = Quiz.new(*args, (@@yaml_file.shift if @@yaml_file))
136
+ def self.quiz(title, args={}, &block)
137
+ quiz = Quiz.new(title, args)
134
138
  quiz.instance_eval(&block)
135
139
  @@quizzes << quiz
136
140
  end
@@ -7,14 +7,47 @@ class Html5Renderer
7
7
  def initialize(quiz,options={})
8
8
  @css = options.delete('c') || options.delete('css')
9
9
  @show_solutions = options.delete('s') || options.delete('solutions')
10
+ @show_tags = options.delete('T') || options.delete('show-tags')
10
11
  @template = options.delete('t') ||
11
12
  options.delete('template') ||
12
- File.join(Gem.loaded_specs['ruql'].full_gem_path, 'templates/html5.html.erb')
13
+ File.join((Gem.loaded_specs['ruql'].full_gem_path rescue '.'), 'templates/html5.html.erb')
13
14
  @output = ''
14
15
  @quiz = quiz
15
16
  @h = Builder::XmlMarkup.new(:target => @output, :indent => 2)
16
17
  end
17
18
 
19
+ def allowed_options
20
+ opts = [
21
+ ['-c', '--css', Getopt::REQUIRED],
22
+ ['-t', '--template', Getopt::REQUIRED],
23
+ ['-s', '--solutions', Getopt::BOOLEAN],
24
+ ['-T', '--show-tags', Getopt::BOOLEAN]
25
+ ]
26
+ help = <<eos
27
+ The HTML5 and HTML Forms renderers supports these options:
28
+ -c <href>, --css=<href>
29
+ embed <href> for stylesheet into generated HTML5
30
+ -j <src>, --js=<src>
31
+ embed <src> for JavaScrips
32
+ -t <file.html.erb>, --template=<file.html.erb>
33
+ Use file.html.erb as HTML template rather than generating our own file.
34
+ file.html.erb should have <%= yield %> where questions should go.
35
+ An example is in the templates/ directory of RuQL.
36
+ The following local variables will be replaced with their values in
37
+ the template:
38
+ <%= quiz.title %> - the quiz title
39
+ <%= quiz.num_questions %> - total number of questions
40
+ <%= quiz.points %> - total number of points for whole quiz
41
+ -T, --show-tags
42
+ Show the tag(s) associated with a question within an element <div class="tags">.
43
+ -s, --solutions
44
+ generate solutions (showing correct answers and explanations)
45
+ NOTE: If there is more than one quiz (collection of questions) in the file,
46
+ a complete <html>...</html> block is produced in the output for EACH quiz.
47
+ eos
48
+ return(
49
+
50
+
18
51
  def render_quiz
19
52
  if @template
20
53
  render_with_template do
@@ -132,6 +165,11 @@ class Html5Renderer
132
165
  if question.class == FillIn then question.question_text.gsub(/\-+/, '_____________________________')
133
166
  else question.question_text
134
167
  end
168
+ if @show_tags
169
+ @h.div(:class => 'text') do
170
+ question.tags.join(',')
171
+ end
172
+ end
135
173
  if question.raw?
136
174
  @h.p { |p| p << qtext }
137
175
  else
@@ -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
@@ -0,0 +1,3 @@
1
+ module Ruql
2
+ VERSION = '1.0.1'
3
+ end
@@ -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,51 +1,108 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Armando Fox
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-13 00:00:00.000000000 Z
11
+ date: 2020-06-03 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
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.17'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.17'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: byebug
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
17
60
  - !ruby/object:Gem::Version
18
61
  version: '3.0'
62
+ type: :development
19
63
  prerelease: false
20
- name: builder
21
64
  version_requirements: !ruby/object:Gem::Requirement
22
65
  requirements:
23
- - - ~>
66
+ - - "~>"
24
67
  - !ruby/object:Gem::Version
25
68
  version: '3.0'
26
- type: :runtime
27
69
  - !ruby/object:Gem::Dependency
70
+ name: rspec_its
28
71
  requirement: !ruby/object:Gem::Requirement
29
72
  requirements:
30
- - - '='
73
+ - - ">="
31
74
  - !ruby/object:Gem::Version
32
- version: 1.4.2
75
+ version: '0'
76
+ type: :development
33
77
  prerelease: false
34
- name: getopt
35
78
  version_requirements: !ruby/object:Gem::Requirement
36
79
  requirements:
37
- - - '='
80
+ - - ">="
38
81
  - !ruby/object:Gem::Version
39
- version: 1.4.2
40
- type: :runtime
82
+ version: '0'
41
83
  description: Ruby-embedded DSL for creating short-answer quiz questions
42
- email: fox@cs.berkeley.edu
84
+ email: fox@berkeley.edu
43
85
  executables:
44
86
  - ruql
45
87
  extensions: []
46
88
  extra_rdoc_files: []
47
89
  files:
90
+ - ".gitignore"
91
+ - ".travis.yml"
92
+ - Gemfile
93
+ - LICENSE
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
48
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
49
106
  - lib/ruql.rb
50
107
  - lib/ruql/answer.rb
51
108
  - lib/ruql/dropdown.rb
@@ -67,32 +124,34 @@ files:
67
124
  - lib/ruql/renderers/qualtrics_renderer.rb
68
125
  - lib/ruql/renderers/xml_renderer.rb
69
126
  - lib/ruql/select_multiple.rb
127
+ - lib/ruql/stats.rb
70
128
  - lib/ruql/tex_output.rb
71
129
  - lib/ruql/true_false.rb
72
- - templates/autoqcm.tex.erb
73
- - templates/html5.html.erb
74
- - templates/htmlform.html.erb
130
+ - lib/ruql/version.rb
131
+ - ruql.gemspec
75
132
  homepage: http://github.com/saasbook/ruql
76
133
  licenses:
77
134
  - CC By-SA
78
- metadata: {}
135
+ metadata:
136
+ allowed_push_host: https://rubygems.org
137
+ homepage_uri: http://github.com/saasbook/ruql
138
+ source_code_uri: http://github.com/saasbook/ruql
79
139
  post_install_message:
80
140
  rdoc_options: []
81
141
  require_paths:
82
142
  - lib
83
143
  required_ruby_version: !ruby/object:Gem::Requirement
84
144
  requirements:
85
- - - '>='
145
+ - - ">="
86
146
  - !ruby/object:Gem::Version
87
147
  version: '0'
88
148
  required_rubygems_version: !ruby/object:Gem::Requirement
89
149
  requirements:
90
- - - '>='
150
+ - - ">="
91
151
  - !ruby/object:Gem::Version
92
152
  version: '0'
93
153
  requirements: []
94
- rubyforge_project:
95
- rubygems_version: 2.2.5
154
+ rubygems_version: 3.0.8
96
155
  signing_key:
97
156
  specification_version: 4
98
157
  summary: Ruby question language
@@ -1 +0,0 @@
1
- <%= yield %>
@@ -1,42 +0,0 @@
1
- <html>
2
- <head>
3
- <title><%= quiz.title %></title>
4
- <style type="text/css" media="all">
5
- body { font-family: Times, serif; }
6
- .header { text-align: right; font-weight: bold; padding-right: 30%; line-height: 300%; }
7
- h1 { text-align: center; }
8
- ol.questions { list-style-type: number; }
9
- li.question { page-break-inside: avoid; border-bottom: 1px solid grey; }
10
- li.multiplechoice ol.answers { list-style-type: lower-alpha; }
11
- li.selectmultiple ol.answers { vertical-align: center; list-style-type: none; list-style-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUAQMAAAC3R49OAAAABlBMVEUAAAD///+l2Z/dAAAAEklEQVQImWNgAIL6/w+ogoEAAKI4Kp2NVIeDAAAAAElFTkSuQmCC'); }
12
- li.truefalse ol.answers { list-style-type: none; }
13
- .correct { color: green; font-weight: bold; border: 1px solid black; padding: 0.2ex; }
14
- .incorrect { color: red }
15
- .explanation { font-style: italic }
16
- .instructions { clear: both; border: 1px solid black; align: center; padding: 2ex; margin: 2ex; }
17
- </style>
18
- </head>
19
- <body>
20
- <div class="header">
21
- <div id="name">Name:</div>
22
- <div id="sid">SID:</div>
23
- </div>
24
- <h1><%= quiz.title %></h1>
25
- <div class="instructions">
26
- <ul>
27
- <li>No books, notes, or electronic devices allowed. </li>
28
- <li>Time limit is 30 minutes.</li>
29
- <li><%= quiz.num_questions %> multiple-choice questions, points indicated per question,
30
- <%= quiz.points %> points total. Points per question are intended
31
- to reflect approximate times they should take, at about 1 point per minute.</li>
32
- <li>For 'select all that apply' questions worth N points,
33
- you get 1/N of the points for each RIGHT answer that you check, plus
34
- 1/N of the points for each WRONG answer that you correctly
35
- leave unchecked. That is, equal weight is given to deciding
36
- whether each choice is part of the right answer or not.</li>
37
- </ul>
38
- <b>Good skill!</b>
39
- </div>
40
- <%= yield %>
41
- </body>
42
- </html>
@@ -1,44 +0,0 @@
1
- <html>
2
- <head>
3
- <title><%= quiz.title %></title>
4
- <style type="text/css" media="all">
5
- body { font-family: Times, serif; }
6
- .header { text-align: right; font-weight: bold; padding-right: 30%; line-height: 300%; }
7
- h1 { text-align: center; }
8
- ol.questions { list-style-type: number; }
9
- li.question { page-break-inside: avoid; border-bottom: 1px solid grey; padding-bottom: 2ex; }
10
- li.multiplechoice ol.answers { list-style-type: lower-alpha; }
11
- li.multiplechoice ol.answers li { padding-bottom: 0.5ex; }
12
- li.selectmultiple ol.answers { vertical-align: center; list-style-type: none; list-style-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUAQMAAAC3R49OAAAABlBMVEUAAAD///+l2Z/dAAAAEklEQVQImWNgAIL6/w+ogoEAAKI4Kp2NVIeDAAAAAElFTkSuQmCC'); }
13
- li.truefalse ol.answers { list-style-type: none; }
14
- li.truefalse ol.answers li { width: 15%; display: inline-block; }
15
- .correct { color: green }
16
- .incorrect { color: red }
17
- .explanation { font-style: italic }
18
- .instructions { clear: both; border: 1px solid black; align: center; padding: 2ex; margin: 2ex; }
19
- </style>
20
- </head>
21
- <body>
22
- <div class="header">
23
- <div id="name">Name:</div>
24
- <div id="sid">SID:</div>
25
- </div>
26
- <h1><%= quiz.title %></h1>
27
- <div class="instructions">
28
- <ul>
29
- <li>No books, notes, or electronic devices allowed. </li>
30
- <li>Time limit is 30 minutes.</li>
31
- <li><%= quiz.num_questions %> multiple-choice questions, points indicated per question,
32
- <%= quiz.points %> points total. Points per question are intended
33
- to reflect approximate times they should take, at about 1 point per minute.</li>
34
- <li>For 'select all that apply' questions worth N points,
35
- you get 1/N of the points for each RIGHT answer that you check, plus
36
- 1/N of the points for each WRONG answer that you correctly
37
- leave unchecked. That is, equal weight is given to deciding
38
- whether each choice is part of the right answer or not.</li>
39
- </ul>
40
- <b>Good skill!</b>
41
- </div>
42
- <%= yield %>
43
- </body>
44
- </html>