asker-tool 2.7.2 → 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/ai/problem/customizer.rb +36 -0
- data/lib/asker/ai/problem/problem_ai.rb +9 -239
- data/lib/asker/ai/problem/stage_answers.rb +104 -0
- data/lib/asker/ai/problem/stage_base.rb +34 -0
- data/lib/asker/ai/problem/stage_steps.rb +121 -0
- data/lib/asker/application.rb +1 -0
- data/lib/asker/check_input/check_haml_data.rb +2 -2
- data/lib/asker/cli.rb +2 -0
- data/lib/asker/data/concept.rb +5 -5
- data/lib/asker/data/problem.rb +10 -2
- data/lib/asker/data/project_data.rb +3 -2
- data/lib/asker/displayer/code_displayer.rb +2 -2
- data/lib/asker/displayer/concept_ai_displayer.rb +5 -3
- data/lib/asker/displayer/concept_displayer.rb +2 -2
- data/lib/asker/displayer/problem_displayer.rb +14 -7
- data/lib/asker/displayer/stats_displayer.rb +3 -3
- 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/concept_string_formatter.rb +0 -1
- 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 +114 -0
- data/lib/asker/loader/embedded_file/type.rb +51 -0
- data/lib/asker/loader/problem_loader.rb +2 -0
- data/lib/asker/logger.rb +1 -1
- data/lib/asker/start.rb +3 -3
- data/lib/asker/version.rb +1 -1
- metadata +22 -16
- 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
- data/lib/asker/loader/embedded_file.rb +0 -133
@@ -11,7 +11,8 @@ class ProjectData
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def reset
|
14
|
-
@default = {inputbasedir: FileUtils.pwd,
|
14
|
+
# @default = {inputbasedir: FileUtils.pwd,
|
15
|
+
@default = {inputbasedir: Dir.pwd,
|
15
16
|
stages: {d: true, b: true, f: true, i: true, s: true, t: true},
|
16
17
|
threshold: 0.5,
|
17
18
|
outputdir: "output",
|
@@ -44,7 +45,7 @@ class ProjectData
|
|
44
45
|
@param[:logname] = "#{@param[:projectname]}.log"
|
45
46
|
@param[:outputname] = "#{@param[:projectname]}-gift.txt"
|
46
47
|
@param[:lessonname] = "#{@param[:projectname]}.txt"
|
47
|
-
@param[:yamlname] = "#{@param[:projectname]}
|
48
|
+
@param[:yamlname] = "#{@param[:projectname]}.yaml"
|
48
49
|
@param[:moodlename] = "#{@param[:projectname]}-moodle.xml"
|
49
50
|
|
50
51
|
outputdir = get(:outputdir)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require "terminal-table"
|
2
2
|
require_relative "../logger"
|
3
3
|
|
4
|
-
|
4
|
+
class CodeDisplayer
|
5
5
|
##
|
6
6
|
# Show all "code" data on screen
|
7
7
|
# @param codes (Array) List of "code" data
|
8
|
-
def
|
8
|
+
def call(codes)
|
9
9
|
return if codes.nil? || codes.size.zero?
|
10
10
|
|
11
11
|
total_c = total_q = total_e = 0
|
@@ -10,7 +10,7 @@ class ConceptAIDisplayer
|
|
10
10
|
##
|
11
11
|
# Display ConceptAI stat on screen
|
12
12
|
# @param concepts_ai (Array)
|
13
|
-
def
|
13
|
+
def call(concepts_ai)
|
14
14
|
stages = Application.instance.config["questions"]["stages"]
|
15
15
|
# Create table HEAD
|
16
16
|
screen_table = Terminal::Table.new do |st|
|
@@ -80,7 +80,9 @@ class ConceptAIDisplayer
|
|
80
80
|
Logger.info "#{screen_table}\n"
|
81
81
|
end
|
82
82
|
|
83
|
-
|
83
|
+
private
|
84
|
+
|
85
|
+
def export_excluded_questions(screen_table, concepts_ai)
|
84
86
|
# Create table BODY
|
85
87
|
total = {}
|
86
88
|
total[:q] = total[:c] = 0
|
@@ -114,7 +116,7 @@ class ConceptAIDisplayer
|
|
114
116
|
total[:ss], total[:st]]
|
115
117
|
end
|
116
118
|
|
117
|
-
|
119
|
+
def export_notes
|
118
120
|
exclude_questions = Application.instance.config["questions"]["exclude"].to_s
|
119
121
|
renderer = ERB.new(File.read(File.join(File.dirname(__FILE__), "concept_ai_displayer.erb")))
|
120
122
|
Logger.info Rainbow(renderer.result(binding)).white
|
@@ -2,11 +2,11 @@ require_relative "../application"
|
|
2
2
|
require_relative "../formatter/concept_string_formatter"
|
3
3
|
require_relative "../logger"
|
4
4
|
|
5
|
-
|
5
|
+
class ConceptDisplayer
|
6
6
|
##
|
7
7
|
# Show concepts on screen
|
8
8
|
# @param concepts (Array) List of concept data
|
9
|
-
def
|
9
|
+
def call(concepts)
|
10
10
|
return if concepts.nil? || concepts.size.zero?
|
11
11
|
|
12
12
|
show_mode = Application.instance.config["global"]["show_mode"]
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require "terminal-table"
|
2
2
|
require_relative "../logger"
|
3
3
|
|
4
|
-
|
4
|
+
class ProblemDisplayer
|
5
5
|
##
|
6
6
|
# Show all "problem" data on screen
|
7
7
|
# @param problems (Array) List of "problems" data
|
8
|
-
def
|
8
|
+
def call(problems)
|
9
9
|
return if problems.nil? || problems.size.zero?
|
10
10
|
|
11
|
-
total_p = total_q = total_e = 0
|
11
|
+
total_p = total_q = total_e = total_a = total_s = 0
|
12
12
|
my_screen_table = Terminal::Table.new do |st|
|
13
|
-
st << %w[Problem Desc Questions Entries xFactor]
|
13
|
+
st << %w[Problem Desc Questions Entries xFactor a s]
|
14
14
|
st << :separator
|
15
15
|
end
|
16
16
|
|
@@ -23,14 +23,19 @@ module ProblemDisplayer
|
|
23
23
|
e += 1 if !ask[:answer].nil?
|
24
24
|
end
|
25
25
|
|
26
|
+
desc = Rainbow(problem.desc[0, 24]).green
|
26
27
|
q = problem.questions.size
|
27
28
|
factor = "Unknown"
|
28
29
|
factor = (q.to_f / e).round(2).to_s unless e.zero?
|
29
|
-
|
30
|
-
|
30
|
+
a = problem.stats[:answer]
|
31
|
+
s = problem.stats[:steps]
|
32
|
+
|
33
|
+
my_screen_table.add_row [problem.name, desc, q, e, factor, a, s]
|
31
34
|
total_p += 1
|
32
35
|
total_q += q
|
33
36
|
total_e += e
|
37
|
+
total_a += a
|
38
|
+
total_s += s
|
34
39
|
end
|
35
40
|
return unless total_p.positive?
|
36
41
|
|
@@ -38,7 +43,9 @@ module ProblemDisplayer
|
|
38
43
|
my_screen_table.add_row [Rainbow("TOTAL = #{total_p}").bright, "",
|
39
44
|
Rainbow(total_q.to_s).bright,
|
40
45
|
Rainbow(total_e.to_s).bright,
|
41
|
-
Rainbow((total_q / total_e.to_f).round(2)).bright
|
46
|
+
Rainbow((total_q / total_e.to_f).round(2)).bright,
|
47
|
+
Rainbow(total_a.to_s).bright,
|
48
|
+
Rainbow(total_s.to_s).bright]
|
42
49
|
Logger.verboseln Rainbow("\n[INFO] Showing PROBLEMs statistics").white
|
43
50
|
Logger.verboseln my_screen_table.to_s
|
44
51
|
end
|
@@ -10,8 +10,8 @@ module StatsDisplayer
|
|
10
10
|
def self.show(data)
|
11
11
|
return unless Application.instance.config["global"]["show_mode"]
|
12
12
|
|
13
|
-
ConceptAIDisplayer.
|
14
|
-
CodeDisplayer.
|
15
|
-
ProblemDisplayer.
|
13
|
+
ConceptAIDisplayer.new.call(data[:concepts_ai])
|
14
|
+
CodeDisplayer.new.call(data[:codes_ai])
|
15
|
+
ProblemDisplayer.new.call(data[:problems])
|
16
16
|
end
|
17
17
|
end
|
@@ -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
|
|