asker-tool 2.8.0 → 2.9.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.
- checksums.yaml +4 -4
- data/lib/asker/data/concept.rb +2 -2
- data/lib/asker/data/project_data.rb +1 -1
- data/lib/asker/exporter/doc/format_code2doc.rb +17 -0
- data/lib/asker/exporter/doc/format_concept2doc.rb +30 -0
- data/lib/asker/exporter/doc/format_problem2doc.rb +41 -0
- data/lib/asker/exporter/export2doc.rb +41 -0
- data/lib/asker/exporter/{data_gift_exporter.rb → export2gift.rb} +8 -8
- data/lib/asker/exporter/{data_moodle_exporter.rb → export2moodle_xml.rb} +13 -11
- data/lib/asker/exporter/export2yaml.rb +70 -0
- data/lib/asker/exporter/export_action.rb +18 -0
- data/lib/asker/exporter/{code_gift_exporter.rb → gift/export_code2gift.rb} +7 -6
- data/lib/asker/exporter/{concept_ai_gift_exporter.rb → gift/export_concept2gift.rb} +7 -8
- data/lib/asker/exporter/{problem_gift_exporter.rb → gift/export_problem2gift.rb} +2 -2
- data/lib/asker/{formatter → exporter/gift}/question_gift_formatter.rb +0 -3
- data/lib/asker/formatter/{question_hash_formatter.rb → question2hash.rb} +15 -7
- data/lib/asker/formatter/{question_moodle_formatter.rb → question2moodle_xml.rb} +3 -5
- data/lib/asker/loader/code_loader.rb +1 -1
- data/lib/asker/loader/content_loader.rb +1 -0
- data/lib/asker/loader/embedded_file/loader.rb +15 -4
- data/lib/asker/logger.rb +1 -1
- data/lib/asker/start.rb +2 -2
- data/lib/asker/version.rb +1 -1
- metadata +16 -15
- data/lib/asker/deprecated/question_moodlexml_formatter.rb +0 -69
- data/lib/asker/exporter/concept_ai_yaml_exporter.rb +0 -36
- data/lib/asker/exporter/concept_doc_exporter.rb +0 -24
- data/lib/asker/exporter/output_file_exporter.rb +0 -18
- data/lib/asker/formatter/concept_doc_formatter.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb6924c54cad0b4b8a04231d21f5b4e5e419f2150f6457b080eaa56ec45fc5bb
|
4
|
+
data.tar.gz: d6fac1e84e3e4c7f1e836acac9a050fd36b300960e122e993f4af676905b8aaa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee6ac3134f616e98e63f3ad2160325defc99b80e15082c62e8da378e401e3768bb6f75696e96d79f9e48ce1f652b0eeef8767796b8f61d53d717c1eaa405bebc
|
7
|
+
data.tar.gz: 766d487ea2ca668819b6dd0c27459843d20be17ec4c1c54f7f114024b68b12c95e63f8aeff9c81b8016efbbd70cc74a32fb513549ad6c10255e1e9d36be4200c
|
data/lib/asker/data/concept.rb
CHANGED
@@ -37,8 +37,8 @@ class Concept
|
|
37
37
|
|
38
38
|
@data = {}
|
39
39
|
@data[:tags] = []
|
40
|
-
@data[:texts] = []
|
41
|
-
@data[:images] = []
|
40
|
+
@data[:texts] = [] # Used by standard def inputs
|
41
|
+
@data[:images] = [] # Used by [type => file and type => image_url] def inputs
|
42
42
|
@data[:tables] = []
|
43
43
|
@data[:neighbors] = []
|
44
44
|
@data[:reference_to] = []
|
@@ -45,7 +45,7 @@ class ProjectData
|
|
45
45
|
@param[:logname] = "#{@param[:projectname]}.log"
|
46
46
|
@param[:outputname] = "#{@param[:projectname]}-gift.txt"
|
47
47
|
@param[:lessonname] = "#{@param[:projectname]}.txt"
|
48
|
-
@param[:yamlname] = "#{@param[:projectname]}
|
48
|
+
@param[:yamlname] = "#{@param[:projectname]}.yaml"
|
49
49
|
@param[:moodlename] = "#{@param[:projectname]}-moodle.xml"
|
50
50
|
|
51
51
|
outputdir = get(:outputdir)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class FormatCode2Doc
|
2
|
+
def call(code)
|
3
|
+
out = ""
|
4
|
+
title = "#{code.filename} (#{code.type})"
|
5
|
+
out << ("-" * title.size + "\n")
|
6
|
+
out << "#{title}\n"
|
7
|
+
if code.features.size.positive?
|
8
|
+
out << "* features: #{code.features.join(", ")}"
|
9
|
+
end
|
10
|
+
out << "\n"
|
11
|
+
code.lines.each_with_index do |line, index|
|
12
|
+
out << "#{index} | #{line}\n"
|
13
|
+
end
|
14
|
+
out << "\n"
|
15
|
+
out
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "terminal-table"
|
2
|
+
|
3
|
+
class FormatConcept2Doc
|
4
|
+
def call(concept)
|
5
|
+
out = ""
|
6
|
+
title = concept.names.join(", ")
|
7
|
+
out << ("-" * title.size + "\n")
|
8
|
+
out << "#{title}\n"
|
9
|
+
concept.texts.each { |text| out << "* #{text}\n" }
|
10
|
+
concept.images.each do |data|
|
11
|
+
out << "* (#{data[:type]}) #{data[:url]}\n"
|
12
|
+
end
|
13
|
+
out << "\n"
|
14
|
+
concept.tables.each do |table|
|
15
|
+
out << format_table(table)
|
16
|
+
end
|
17
|
+
out
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def format_table(table)
|
23
|
+
my_screen_table = Terminal::Table.new do |st|
|
24
|
+
st << table.fields
|
25
|
+
st << :separator
|
26
|
+
table.rows.each { |r| st.add_row r }
|
27
|
+
end
|
28
|
+
"#{my_screen_table}\n"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class FormatProblem2Doc
|
2
|
+
def initialize(problem)
|
3
|
+
@problem = problem
|
4
|
+
end
|
5
|
+
|
6
|
+
def call
|
7
|
+
# attr_accessor :varnames
|
8
|
+
# attr_accessor :cases
|
9
|
+
out = ""
|
10
|
+
title = "Problem: #{@problem.name}"
|
11
|
+
out << ("-" * title.size + "\n")
|
12
|
+
out << "#{title}\n"
|
13
|
+
desc = replace_case_values(@problem.desc)
|
14
|
+
out << "#{desc}\n"
|
15
|
+
@problem.asks.each_with_index do |ask, index|
|
16
|
+
text = replace_case_values(ask[:text])
|
17
|
+
out << "#{index + 1}) #{text}\n"
|
18
|
+
if ask[:answer]
|
19
|
+
answer = replace_case_values(ask[:answer])
|
20
|
+
out << " #{answer}\n"
|
21
|
+
else
|
22
|
+
ask[:steps].each do |step|
|
23
|
+
step = replace_case_values(step)
|
24
|
+
out << " #{step}\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
out << "\n"
|
29
|
+
out << "\n"
|
30
|
+
out
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def replace_case_values(text)
|
36
|
+
output = text.clone
|
37
|
+
keyvalues = @problem.varnames.zip @problem.cases[0]
|
38
|
+
keyvalues.each { |varname, value | output.gsub!(varname, value) }
|
39
|
+
output
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require_relative "doc/format_code2doc"
|
2
|
+
require_relative "doc/format_concept2doc"
|
3
|
+
require_relative "doc/format_problem2doc"
|
4
|
+
require_relative "../version"
|
5
|
+
|
6
|
+
class Export2Doc
|
7
|
+
def call(data, project)
|
8
|
+
file_open(project)
|
9
|
+
export_codes(data[:codes])
|
10
|
+
export_concepts(data[:concepts])
|
11
|
+
export_problems(data[:problems])
|
12
|
+
@file.close
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def file_open(project)
|
18
|
+
@file = File.new(project.get(:lessonpath), "w")
|
19
|
+
@file.write("Asker : version #{Asker::VERSION}\n")
|
20
|
+
@file.write("Filename : #{project.get(:lessonname)}\n")
|
21
|
+
@file.write("Datetime : #{Time.new}\n\n")
|
22
|
+
end
|
23
|
+
|
24
|
+
def export_codes(codes)
|
25
|
+
codes.each do |code|
|
26
|
+
@file.write(FormatCode2Doc.new.call(code)) if code.process
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def export_concepts(concepts)
|
31
|
+
concepts.each do |concept|
|
32
|
+
@file.write(FormatConcept2Doc.new.call(concept)) if concept.process
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def export_problems(problems)
|
37
|
+
problems.each do |problem|
|
38
|
+
@file.write(FormatProblem2Doc.new(problem).call) if problem.process
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
4
|
-
require_relative "
|
5
|
-
require_relative "
|
3
|
+
require_relative "gift/export_code2gift"
|
4
|
+
require_relative "gift/export_concept2gift"
|
5
|
+
require_relative "gift/export_problem2gift"
|
6
6
|
require_relative "../application"
|
7
7
|
require_relative "../version"
|
8
8
|
|
9
|
-
|
9
|
+
class Export2Gift
|
10
10
|
##
|
11
11
|
# Export an array of Data (ConceptAIs, Codes and Problems objects) into GIFT file
|
12
12
|
# @param data (Hash)
|
13
13
|
# @param project (Project)
|
14
|
-
def
|
14
|
+
def call(data, project)
|
15
15
|
file = File.open(project.get(:outputpath), "w")
|
16
16
|
file.write("// " + ("=" * 50) + "\n")
|
17
17
|
file.write("// #{Asker::NAME} : version #{Asker::VERSION}\n")
|
@@ -21,9 +21,9 @@ module DataGiftExporter
|
|
21
21
|
category = Application.instance.config["questions"]["category"]
|
22
22
|
file.write("$CATEGORY: $course$/#{category}\n") unless category.nil?
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
ExportConcept2Gift.new.call(data[:concepts_ai], file)
|
25
|
+
ExportCode2Gift.new.call(data[:codes_ai], file)
|
26
|
+
ExportProblem2Gift.new.call(data[:problems], file)
|
27
27
|
file.close
|
28
28
|
end
|
29
29
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require_relative "../application"
|
2
2
|
require_relative "../version"
|
3
|
-
require_relative "../formatter/
|
3
|
+
require_relative "../formatter/question2moodle_xml"
|
4
4
|
|
5
|
-
|
6
|
-
def
|
5
|
+
class Export2MoodleXML
|
6
|
+
def call(data, project)
|
7
7
|
file = File.open(project.get(:moodlepath), "w")
|
8
8
|
add_header(file, project)
|
9
9
|
|
@@ -14,7 +14,9 @@ module DataMoodleExporter
|
|
14
14
|
close(file)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
private
|
18
|
+
|
19
|
+
def add_header(file, project)
|
18
20
|
file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
|
19
21
|
file.write("<quiz>\n")
|
20
22
|
file.write("<!--\n#{"=" * 50}\n")
|
@@ -25,37 +27,37 @@ module DataMoodleExporter
|
|
25
27
|
file
|
26
28
|
end
|
27
29
|
|
28
|
-
def
|
30
|
+
def close(file)
|
29
31
|
file.write("</quiz>\n")
|
30
32
|
file.close
|
31
33
|
end
|
32
34
|
|
33
|
-
def
|
35
|
+
def export_concepts(concepts:, file:)
|
34
36
|
concepts.each do |concept_ai|
|
35
37
|
next unless concept_ai.concept.process?
|
36
38
|
|
37
39
|
Application.instance.config["questions"]["stages"].each do |stage|
|
38
40
|
concept_ai.questions[stage].each do |question|
|
39
|
-
file.write(
|
41
|
+
file.write(Question2MoodleXML.new.format(question))
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
45
|
-
def
|
47
|
+
def export_codes(codes:, file:)
|
46
48
|
codes.each do |code|
|
47
49
|
next unless code.process?
|
48
50
|
code.questions.each do |question|
|
49
|
-
file.write
|
51
|
+
file.write Question2MoodleXML.new.format(question)
|
50
52
|
end
|
51
53
|
end
|
52
54
|
end
|
53
55
|
|
54
|
-
def
|
56
|
+
def export_problems(problems:, file:)
|
55
57
|
problems.each do |problem|
|
56
58
|
next unless problem.process?
|
57
59
|
problem.questions.each do |question|
|
58
|
-
file.write
|
60
|
+
file.write Question2MoodleXML.new.format(question)
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "yaml"
|
2
|
+
require_relative "../formatter/question2hash"
|
3
|
+
|
4
|
+
class Export2YAML
|
5
|
+
##
|
6
|
+
# Export array of ConceptAI objects from Project to YAML output file
|
7
|
+
# @param concepts_ai (Array)
|
8
|
+
# @param project (Project)
|
9
|
+
def call(data, project)
|
10
|
+
questions = []
|
11
|
+
questions += get_questions_from_codes(data)
|
12
|
+
questions += get_questions_from_concepts(data)
|
13
|
+
questions += get_questions_from_problems(data)
|
14
|
+
|
15
|
+
output = {
|
16
|
+
lang: project.get(:lang_code),
|
17
|
+
projectname: project.get(:projectname),
|
18
|
+
questions: questions
|
19
|
+
}
|
20
|
+
|
21
|
+
yamlfile = File.open(project.get(:yamlpath), "w")
|
22
|
+
yamlfile.write(output.to_yaml)
|
23
|
+
yamlfile.close
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def get_questions_from_codes(data)
|
29
|
+
questions = []
|
30
|
+
data[:codes].each do |code|
|
31
|
+
next unless code.process
|
32
|
+
code.questions.each do |question|
|
33
|
+
questions << Question2Hash.new.format(question)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
questions
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_questions_from_concepts(data)
|
40
|
+
questions = []
|
41
|
+
data[:concepts_ai].each do |concept_ai|
|
42
|
+
questions += get_questions_from_concept concept_ai
|
43
|
+
end
|
44
|
+
questions
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_questions_from_concept(concept_ai)
|
48
|
+
questions = []
|
49
|
+
return questions unless concept_ai.concept.process?
|
50
|
+
|
51
|
+
Application.instance.config["questions"]["stages"].each do |stage|
|
52
|
+
concept_ai.questions[stage].each do |question|
|
53
|
+
question.lang = concept_ai.concept.lang
|
54
|
+
questions << Question2Hash.new.format(question)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
questions
|
58
|
+
end
|
59
|
+
|
60
|
+
def get_questions_from_problems(data)
|
61
|
+
questions = []
|
62
|
+
data[:problems].each do |problem|
|
63
|
+
next unless problem.process
|
64
|
+
problem.questions.each do |question|
|
65
|
+
questions << Question2Hash.new.format(question)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
questions
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative "export2doc"
|
2
|
+
require_relative "export2gift"
|
3
|
+
require_relative "export2moodle_xml"
|
4
|
+
require_relative "export2yaml"
|
5
|
+
|
6
|
+
##
|
7
|
+
# Export Output data files
|
8
|
+
# * YAML, Doc (txt), Gift (ConceptAI, Code) and Moodle XML (ConceptAI, Code)
|
9
|
+
class ExportAction
|
10
|
+
def call(data, project)
|
11
|
+
output = Application.instance.config["output"]
|
12
|
+
|
13
|
+
Export2Doc.new.call(data, project) if output["doc"] == "yes"
|
14
|
+
Export2Gift.new.call(data, project) if output["gift"] == "yes"
|
15
|
+
Export2MoodleXML.new.call(data, project) if output["moodle"] == "yes"
|
16
|
+
Export2YAML.new.call(data, project) if output["yaml"] == "yes"
|
17
|
+
end
|
18
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "question_gift_formatter"
|
2
2
|
|
3
|
-
|
3
|
+
class ExportCode2Gift
|
4
4
|
##
|
5
5
|
# Export an Array of codes to gift format file
|
6
6
|
# @param codes (Array)
|
7
|
-
def
|
7
|
+
def call(codes, file)
|
8
8
|
codes.each { |code| export(code, file) }
|
9
9
|
end
|
10
10
|
|
11
|
+
private
|
12
|
+
|
11
13
|
##
|
12
14
|
# Export 1 code to gift format file
|
13
|
-
|
14
|
-
def self.export(code, file)
|
15
|
+
def export(code, file)
|
15
16
|
return false unless code.process?
|
16
17
|
|
17
18
|
file.write head(code)
|
@@ -21,7 +22,7 @@ module CodeGiftExporter
|
|
21
22
|
true
|
22
23
|
end
|
23
24
|
|
24
|
-
|
25
|
+
def head(code)
|
25
26
|
s = "\n"
|
26
27
|
s += "// " + "=" * 50 + "\n"
|
27
28
|
s += "// Code #{code.type}: #{code.filename} (#{code.questions.size})\n"
|
@@ -1,22 +1,21 @@
|
|
1
|
-
|
1
|
+
require_relative "question_gift_formatter"
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
# Export ConceptIA data to gift to outputfile
|
6
|
-
module ConceptAIGiftExporter
|
3
|
+
class ExportConcept2Gift
|
7
4
|
##
|
8
5
|
# Export an array of ConceptAI objects from Project into GIFT outpufile
|
9
6
|
# @param concepts_ai (Array)
|
10
7
|
# @param file (File)
|
11
|
-
def
|
8
|
+
def call(concepts_ai, file)
|
12
9
|
concepts_ai.each { |concept_ai| export(concept_ai, file) }
|
13
10
|
end
|
14
11
|
|
12
|
+
private
|
13
|
+
|
15
14
|
##
|
16
15
|
# Export 1 concept_ai from project
|
17
16
|
# @param concept_ai (ConceptAI)
|
18
17
|
# @param file (File)
|
19
|
-
|
18
|
+
def export(concept_ai, file)
|
20
19
|
return unless concept_ai.concept.process?
|
21
20
|
|
22
21
|
file.write head(concept_ai.concept.name)
|
@@ -31,7 +30,7 @@ module ConceptAIGiftExporter
|
|
31
30
|
# Convert Concept name into gift format head
|
32
31
|
# @param name (String)
|
33
32
|
# @return String
|
34
|
-
|
33
|
+
def head(name)
|
35
34
|
s = "\n"
|
36
35
|
s += "// " + "=" * 50 + "\n"
|
37
36
|
s += "// Concept name: #{name}\n"
|
@@ -1,6 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require_relative "../logger"
|
2
|
+
|
3
|
+
class Question2Hash
|
4
|
+
def format(question)
|
4
5
|
@question = question
|
5
6
|
# Return question using YAML format
|
6
7
|
s = {}
|
@@ -9,23 +10,30 @@ module QuestionHashFormatter
|
|
9
10
|
s[:text] = sanitize(@question.text)
|
10
11
|
s[:type] = @question.type
|
11
12
|
s[:feedback] = sanitize(@question.feedback.to_s)
|
12
|
-
s[:lang] = @question.lang.code.to_sym
|
13
13
|
case @question.type
|
14
|
+
when :boolean
|
15
|
+
s[:answer] = @question.good
|
14
16
|
when :choice
|
15
17
|
s[:answer] = sanitize(@question.good)
|
16
18
|
s[:options] = (@question.bads + [@question.good]).shuffle
|
17
|
-
when :
|
18
|
-
s[:answer] = @question.
|
19
|
+
when :ddmatch
|
20
|
+
s[:answer] = @question.matching
|
19
21
|
when :match
|
20
22
|
s[:answer] = @question.matching
|
23
|
+
when :ordering
|
24
|
+
s[:answer] = @question.ordering
|
21
25
|
when :short
|
22
26
|
@question.shorts.uniq!
|
23
27
|
s[:answer] = @question.shorts
|
28
|
+
else
|
29
|
+
Logger.warn "[WARN] Question2Hash: Unkown type (#{@question.type})"
|
24
30
|
end
|
25
31
|
s
|
26
32
|
end
|
27
33
|
|
28
|
-
|
34
|
+
private
|
35
|
+
|
36
|
+
def sanitize(input = "")
|
29
37
|
output = input.dup
|
30
38
|
output.gsub!("#", "\\#")
|
31
39
|
output.tr!("\n", " ")
|
@@ -1,15 +1,13 @@
|
|
1
|
-
# frozen_string_literal: false
|
2
|
-
|
3
1
|
require "erb"
|
4
2
|
require_relative "../application"
|
5
3
|
|
6
4
|
# Transform Questions into Gift format
|
7
|
-
class
|
5
|
+
class Question2MoodleXML
|
8
6
|
##
|
9
7
|
# Convert question object into gift formatted string
|
10
8
|
# @param question (Question)
|
11
9
|
# @return String
|
12
|
-
def
|
10
|
+
def format(question)
|
13
11
|
case question.type
|
14
12
|
when :choice
|
15
13
|
fractions = Application.instance.config["questions"]["fractions"]
|
@@ -31,7 +29,7 @@ class QuestionMoodleFormatter
|
|
31
29
|
when :short
|
32
30
|
template = File.read(File.join(File.dirname(__FILE__), "moodle", "shortanswer.erb"))
|
33
31
|
else
|
34
|
-
warn "[ERROR]
|
32
|
+
warn "[ERROR] Question2MoodleXML: Unknown type (#{question.type})"
|
35
33
|
exit 1
|
36
34
|
end
|
37
35
|
renderer = ERB.new(template)
|
@@ -13,7 +13,7 @@ module CodeLoader
|
|
13
13
|
def self.call(xmldata, filepath)
|
14
14
|
data = read_codedata_from_xml(xmldata, File.basename(filepath))
|
15
15
|
code = Code.new(File.dirname(filepath), data[:path], data[:type])
|
16
|
-
code.features
|
16
|
+
code.features = data[:features]
|
17
17
|
code
|
18
18
|
end
|
19
19
|
|
@@ -31,7 +31,12 @@ module EmbeddedFile
|
|
31
31
|
return load_video_url(value, localdir)
|
32
32
|
end
|
33
33
|
|
34
|
-
{
|
34
|
+
{
|
35
|
+
text: "<pre>#{File.read(filepath)}</pre>",
|
36
|
+
file: :none,
|
37
|
+
type: :text,
|
38
|
+
url: value
|
39
|
+
}
|
35
40
|
end
|
36
41
|
|
37
42
|
def load_audio(value, localdir)
|
@@ -44,6 +49,7 @@ module EmbeddedFile
|
|
44
49
|
+ Base64.strict_encode64(File.open(filepath, "rb").read) \
|
45
50
|
+ "</file>"
|
46
51
|
output[:type] = :audio
|
52
|
+
output[:url] = value
|
47
53
|
output
|
48
54
|
end
|
49
55
|
|
@@ -51,7 +57,8 @@ module EmbeddedFile
|
|
51
57
|
{
|
52
58
|
text: "<audio src=\"#{value}\" controls></audio>",
|
53
59
|
file: :none,
|
54
|
-
type: :url
|
60
|
+
type: :url,
|
61
|
+
url: value
|
55
62
|
}
|
56
63
|
end
|
57
64
|
|
@@ -65,6 +72,7 @@ module EmbeddedFile
|
|
65
72
|
+ Base64.strict_encode64(File.open(filepath, "rb").read) \
|
66
73
|
+ "</file>"
|
67
74
|
output[:type] = :image
|
75
|
+
output[:url] = value
|
68
76
|
output
|
69
77
|
end
|
70
78
|
|
@@ -72,7 +80,8 @@ module EmbeddedFile
|
|
72
80
|
{
|
73
81
|
text: "<img src=\"#{value}\" alt=\"image\" width=\"400\" height=\"300\">",
|
74
82
|
file: :none,
|
75
|
-
type: :url
|
83
|
+
type: :url,
|
84
|
+
url: value
|
76
85
|
}
|
77
86
|
end
|
78
87
|
|
@@ -88,6 +97,7 @@ module EmbeddedFile
|
|
88
97
|
+ Base64.strict_encode64(File.open(filepath, "rb").read) \
|
89
98
|
+ "</file>"
|
90
99
|
output[:type] = :video
|
100
|
+
output[:url] = value
|
91
101
|
output
|
92
102
|
end
|
93
103
|
|
@@ -96,7 +106,8 @@ module EmbeddedFile
|
|
96
106
|
text: "<video controls width=\"400\" height=\"300\">" \
|
97
107
|
+ "<source src=\"#{value}\"/></video>",
|
98
108
|
file: :none,
|
99
|
-
type: :url
|
109
|
+
type: :url,
|
110
|
+
url: value
|
100
111
|
}
|
101
112
|
end
|
102
113
|
end
|
data/lib/asker/logger.rb
CHANGED
data/lib/asker/start.rb
CHANGED
@@ -2,7 +2,7 @@ require_relative "application"
|
|
2
2
|
require_relative "logger"
|
3
3
|
require_relative "displayer/concept_displayer"
|
4
4
|
require_relative "displayer/stats_displayer"
|
5
|
-
require_relative "exporter/
|
5
|
+
require_relative "exporter/export_action"
|
6
6
|
require_relative "loader/project_loader"
|
7
7
|
require_relative "loader/input_loader"
|
8
8
|
|
@@ -37,7 +37,7 @@ class Start
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def create_output(project, data)
|
40
|
-
|
40
|
+
ExportAction.new.call(data, project)
|
41
41
|
StatsDisplayer.show(data)
|
42
42
|
Logger.close
|
43
43
|
end
|
data/lib/asker/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asker-tool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Vargas Ruiz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: haml
|
@@ -146,21 +146,24 @@ files:
|
|
146
146
|
- lib/asker/data/table.rb
|
147
147
|
- lib/asker/data/template.rb
|
148
148
|
- lib/asker/data/world.rb
|
149
|
-
- lib/asker/deprecated/question_moodlexml_formatter.rb
|
150
149
|
- lib/asker/displayer/code_displayer.rb
|
151
150
|
- lib/asker/displayer/concept_ai_displayer.erb
|
152
151
|
- lib/asker/displayer/concept_ai_displayer.rb
|
153
152
|
- lib/asker/displayer/concept_displayer.rb
|
154
153
|
- lib/asker/displayer/problem_displayer.rb
|
155
154
|
- lib/asker/displayer/stats_displayer.rb
|
156
|
-
- lib/asker/exporter/
|
157
|
-
- lib/asker/exporter/
|
158
|
-
- lib/asker/exporter/
|
159
|
-
- lib/asker/exporter/
|
160
|
-
- lib/asker/exporter/
|
161
|
-
- lib/asker/exporter/
|
162
|
-
- lib/asker/exporter/
|
163
|
-
- lib/asker/exporter/
|
155
|
+
- lib/asker/exporter/doc/format_code2doc.rb
|
156
|
+
- lib/asker/exporter/doc/format_concept2doc.rb
|
157
|
+
- lib/asker/exporter/doc/format_problem2doc.rb
|
158
|
+
- lib/asker/exporter/export2doc.rb
|
159
|
+
- lib/asker/exporter/export2gift.rb
|
160
|
+
- lib/asker/exporter/export2moodle_xml.rb
|
161
|
+
- lib/asker/exporter/export2yaml.rb
|
162
|
+
- lib/asker/exporter/export_action.rb
|
163
|
+
- lib/asker/exporter/gift/export_code2gift.rb
|
164
|
+
- lib/asker/exporter/gift/export_concept2gift.rb
|
165
|
+
- lib/asker/exporter/gift/export_problem2gift.rb
|
166
|
+
- lib/asker/exporter/gift/question_gift_formatter.rb
|
164
167
|
- lib/asker/files/asker.ini
|
165
168
|
- lib/asker/files/example-code.haml
|
166
169
|
- lib/asker/files/example-concept.haml
|
@@ -195,7 +198,6 @@ files:
|
|
195
198
|
- lib/asker/files/language/sql/mistakes.yaml
|
196
199
|
- lib/asker/files/language/sql/templates.yaml
|
197
200
|
- lib/asker/formatter/code_string_formatter.rb
|
198
|
-
- lib/asker/formatter/concept_doc_formatter.rb
|
199
201
|
- lib/asker/formatter/concept_string_formatter.rb
|
200
202
|
- lib/asker/formatter/moodle/ddmatch.erb
|
201
203
|
- lib/asker/formatter/moodle/gapfill.erb
|
@@ -204,9 +206,8 @@ files:
|
|
204
206
|
- lib/asker/formatter/moodle/ordering.erb
|
205
207
|
- lib/asker/formatter/moodle/shortanswer.erb
|
206
208
|
- lib/asker/formatter/moodle/truefalse.erb
|
207
|
-
- lib/asker/formatter/
|
208
|
-
- lib/asker/formatter/
|
209
|
-
- lib/asker/formatter/question_moodle_formatter.rb
|
209
|
+
- lib/asker/formatter/question2hash.rb
|
210
|
+
- lib/asker/formatter/question2moodle_xml.rb
|
210
211
|
- lib/asker/formatter/rb2haml_formatter.rb
|
211
212
|
- lib/asker/lang/lang.rb
|
212
213
|
- lib/asker/lang/lang_factory.rb
|
@@ -1,69 +0,0 @@
|
|
1
|
-
# Transform Questions into Gift format
|
2
|
-
module QuestionMoodleXMLFormatter
|
3
|
-
def self.to_s(question)
|
4
|
-
@question = question
|
5
|
-
|
6
|
-
case @question.type
|
7
|
-
when :choice
|
8
|
-
s += choice_to_s(question)
|
9
|
-
when :boolean
|
10
|
-
when :match
|
11
|
-
when :short
|
12
|
-
end
|
13
|
-
s.flaten!
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.choice_to_s(question)
|
17
|
-
s = []
|
18
|
-
|
19
|
-
penalties = ["", "%-50%", "%-33.33333%", "%-25%", "%-20%"]
|
20
|
-
penalty = penalties[question.bads.size]
|
21
|
-
|
22
|
-
s << "<!-- question: #{question.name} -->"
|
23
|
-
s << '<question type="multichoice">'
|
24
|
-
s << " <name>"
|
25
|
-
s << " <text>#{question.name}</text>"
|
26
|
-
s << " </name>"
|
27
|
-
s << ' <questiontext format="html">'
|
28
|
-
s << " <text><![CDATA[#{question.text}]]></text>"
|
29
|
-
s << " </questiontext>"
|
30
|
-
s << ' <generalfeedback format="html">'
|
31
|
-
s << " <text>#{question.feedback}</text>"
|
32
|
-
s << " </generalfeedback>"
|
33
|
-
s << " <defaultgrade>1.0000000</defaultgrade>"
|
34
|
-
s << " <penalty>#{penalty}</penalty>"
|
35
|
-
s << " <hidden>0</hidden>"
|
36
|
-
s << " <single>true</single>"
|
37
|
-
s << " <shuffleanswers>#{question.shuffle?}</shuffleanswers>"
|
38
|
-
s << " <answernumbering>abc</answernumbering>"
|
39
|
-
s << ' <incorrectfeedback format="html">'
|
40
|
-
s << " <text>#{question.feedback}</text>"
|
41
|
-
s << " </incorrectfeedback>"
|
42
|
-
s << ' <answer fraction="100" format="html">'
|
43
|
-
s << " <text>#{question.good}</text>"
|
44
|
-
s << " </answer>"
|
45
|
-
s << ' <answer fraction="-25" format="html">'
|
46
|
-
s << " <text>#{question.bad[0]}</text>"
|
47
|
-
s << " </answer>"
|
48
|
-
s << " </question>"
|
49
|
-
s << ' <answer fraction="-25" format="html">'
|
50
|
-
s << " <text>#{question.bad[1]}</text>"
|
51
|
-
s << " </answer>"
|
52
|
-
s << " </question>"
|
53
|
-
s << ' <answer fraction="-25" format="html">'
|
54
|
-
s << " <text>#{question.bad[2]}</text>"
|
55
|
-
s << " </answer>"
|
56
|
-
s << " </question>"
|
57
|
-
s
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.sanitize(input = "")
|
61
|
-
output = input.dup
|
62
|
-
output.tr!("\n", " ")
|
63
|
-
output.tr!(":", ":")
|
64
|
-
output.tr!("=", "\\=")
|
65
|
-
# output.gsub!('{', "\\{")
|
66
|
-
# output.gsub!('}', "\\}")
|
67
|
-
output
|
68
|
-
end
|
69
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
require "yaml"
|
2
|
-
require_relative "../formatter/question_hash_formatter"
|
3
|
-
|
4
|
-
# Use to export data from ConceptIA to YAML format
|
5
|
-
module ConceptAIYAMLExporter
|
6
|
-
##
|
7
|
-
# Export array of ConceptAI objects from Project to YAML output file
|
8
|
-
# @param concepts_ai (Array)
|
9
|
-
# @param project (Project)
|
10
|
-
def self.export_all(concepts_ai, project)
|
11
|
-
questions = []
|
12
|
-
concepts_ai.each do |concept_ai|
|
13
|
-
questions += get_questions_from concept_ai
|
14
|
-
end
|
15
|
-
params = {lang: project.get(:lang),
|
16
|
-
projectname: project.get(:projectname)}
|
17
|
-
output = {params: params, questions: questions}
|
18
|
-
|
19
|
-
yamlfile = File.open(project.get(:yamlpath), "w")
|
20
|
-
yamlfile.write(output.to_yaml)
|
21
|
-
yamlfile.close
|
22
|
-
end
|
23
|
-
|
24
|
-
private_class_method def self.get_questions_from(concept_ai)
|
25
|
-
data = []
|
26
|
-
return data unless concept_ai.concept.process?
|
27
|
-
|
28
|
-
Application.instance.config["questions"]["stages"].each do |stage|
|
29
|
-
concept_ai.questions[stage].each do |question|
|
30
|
-
question.lang = concept_ai.concept.lang
|
31
|
-
data << QuestionHashFormatter.to_hash(question)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
data
|
35
|
-
end
|
36
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "../formatter/concept_doc_formatter"
|
4
|
-
require_relative "../version"
|
5
|
-
|
6
|
-
##
|
7
|
-
# Export Concept to Doc file
|
8
|
-
module ConceptDocExporter
|
9
|
-
##
|
10
|
-
# Export array of concepts to doc
|
11
|
-
def self.export_all(concepts, project)
|
12
|
-
file = File.new(project.get(:lessonpath), "w")
|
13
|
-
file.write("=" * 50 + "\n")
|
14
|
-
file.write("Created by : #{Asker::NAME} (version #{Asker::VERSION})\n")
|
15
|
-
file.write("File : #{project.get(:lessonname)}\n")
|
16
|
-
file.write("Time : #{Time.new}\n")
|
17
|
-
file.write("=" * 50 + "\n")
|
18
|
-
|
19
|
-
concepts.each do |concept|
|
20
|
-
file.write(ConceptDocFormatter.to_s(concept)) if concept.process
|
21
|
-
end
|
22
|
-
file.close
|
23
|
-
end
|
24
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
require_relative "concept_ai_yaml_exporter"
|
2
|
-
require_relative "concept_doc_exporter"
|
3
|
-
require_relative "data_gift_exporter"
|
4
|
-
require_relative "data_moodle_exporter"
|
5
|
-
|
6
|
-
##
|
7
|
-
# Export Output data files
|
8
|
-
# * YAML, Doc (txt), Gift (ConceptAI, Code) and Moodle XML (ConceptAI, Code)
|
9
|
-
module OutputFileExporter
|
10
|
-
def self.export(data, project)
|
11
|
-
config = Application.instance.config
|
12
|
-
|
13
|
-
ConceptAIYAMLExporter.export_all(data[:concepts_ai], project) if config["output"]["yaml"] == "yes"
|
14
|
-
ConceptDocExporter.export_all(data[:concepts], project) if config["output"]["doc"] == "yes"
|
15
|
-
DataGiftExporter.export_all(data, project) if config["output"]["gift"] == "yes"
|
16
|
-
DataMoodleExporter.call(data, project) if config["output"]["moodle"] == "yes"
|
17
|
-
end
|
18
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: false
|
2
|
-
|
3
|
-
require "rainbow"
|
4
|
-
require "terminal-table"
|
5
|
-
|
6
|
-
module ConceptDocFormatter
|
7
|
-
##
|
8
|
-
# Formatter Concept into Doc
|
9
|
-
# @param concept (Concept)
|
10
|
-
def self.to_s(concept)
|
11
|
-
out = ""
|
12
|
-
out << "\n#{Rainbow(concept.name).bg(:blue).bright}\n\n"
|
13
|
-
concept.texts.each { |i| out << "* #{i}\n" }
|
14
|
-
out << "\n"
|
15
|
-
concept.tables.each do |table|
|
16
|
-
out << table_to_s(table)
|
17
|
-
end
|
18
|
-
out
|
19
|
-
end
|
20
|
-
|
21
|
-
##
|
22
|
-
# Formatter Table to Doc
|
23
|
-
# @param table (Table)
|
24
|
-
# @return String
|
25
|
-
def self.table_to_s(table)
|
26
|
-
my_screen_table = Terminal::Table.new do |st|
|
27
|
-
st << table.fields
|
28
|
-
st << :separator
|
29
|
-
table.rows.each { |r| st.add_row r }
|
30
|
-
end
|
31
|
-
"#{my_screen_table}\n"
|
32
|
-
end
|
33
|
-
end
|