asker-tool 2.7.1 → 2.8.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 -213
- 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 +136 -0
- data/lib/asker/check_input.rb +15 -10
- data/lib/asker/cli.rb +2 -0
- data/lib/asker/data/concept.rb +3 -3
- data/lib/asker/data/problem.rb +10 -2
- data/lib/asker/data/project_data.rb +2 -1
- 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/files/language/ca/templates.yaml +1 -0
- data/lib/asker/files/language/du/templates.yaml +1 -0
- data/lib/asker/files/language/en/templates.yaml +1 -0
- data/lib/asker/files/language/es/templates.yaml +1 -0
- data/lib/asker/files/language/fr/templates.yaml +1 -0
- data/lib/asker/formatter/concept_string_formatter.rb +0 -1
- data/lib/asker/loader/content_loader.rb +10 -8
- data/lib/asker/loader/embedded_file/loader.rb +103 -0
- data/lib/asker/loader/embedded_file/type.rb +51 -0
- data/lib/asker/loader/file_loader.rb +2 -1
- data/lib/asker/loader/problem_loader.rb +2 -0
- data/lib/asker/logger.rb +7 -3
- data/lib/asker/start.rb +2 -2
- data/lib/asker/version.rb +1 -1
- metadata +8 -3
- data/lib/asker/loader/embedded_file.rb +0 -133
data/lib/asker/check_input.rb
CHANGED
@@ -2,34 +2,39 @@ require_relative "check_input/check_haml_data"
|
|
2
2
|
require_relative "logger"
|
3
3
|
|
4
4
|
class CheckInput
|
5
|
+
attr_accessor :verbose
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@verbose = true
|
9
|
+
end
|
10
|
+
|
5
11
|
def check(filepath)
|
6
|
-
@filepath = filepath
|
7
12
|
# Check HAML file syntax
|
8
|
-
exist = check_file_exist
|
13
|
+
exist = check_file_exist(filepath)
|
9
14
|
return false unless exist
|
10
|
-
check_file_content
|
15
|
+
check_file_content(filepath)
|
11
16
|
end
|
12
17
|
|
13
18
|
private
|
14
19
|
|
15
|
-
def check_file_exist
|
16
|
-
if
|
20
|
+
def check_file_exist(filepath)
|
21
|
+
if filepath.nil?
|
17
22
|
Logger.error "CheckInput: Unknown filename"
|
18
23
|
exit 1
|
19
24
|
end
|
20
|
-
unless File.exist?
|
21
|
-
Logger.error "CheckInput: File not found! (#{
|
25
|
+
unless File.exist? filepath
|
26
|
+
Logger.error "CheckInput: File not found! (#{filepath})"
|
22
27
|
exit 1
|
23
28
|
end
|
24
|
-
unless File.extname(
|
29
|
+
unless File.extname(filepath) == ".haml"
|
25
30
|
Logger.error "CheckInput: Check works with HAML files!"
|
26
31
|
exit 1
|
27
32
|
end
|
28
33
|
true
|
29
34
|
end
|
30
35
|
|
31
|
-
def check_file_content
|
32
|
-
data = CheckHamlData.new(
|
36
|
+
def check_file_content(filepath)
|
37
|
+
data = CheckHamlData.new(filepath)
|
33
38
|
data.check
|
34
39
|
data.show_errors if @verbose
|
35
40
|
data.ok?
|
data/lib/asker/cli.rb
CHANGED
@@ -45,6 +45,7 @@ class CLI < Thor
|
|
45
45
|
end
|
46
46
|
|
47
47
|
map ["--check"] => "check"
|
48
|
+
option :color, type: :boolean
|
48
49
|
desc "check FILEPATH", "Check HAML input file syntax"
|
49
50
|
long_desc <<-LONGDESC
|
50
51
|
|
@@ -64,6 +65,7 @@ class CLI < Thor
|
|
64
65
|
end
|
65
66
|
|
66
67
|
map ["f", "-f", "--file"] => "file"
|
68
|
+
option :color, type: :boolean
|
67
69
|
desc "[file] FILEPATH", "Build output files, from HAML/XML input file."
|
68
70
|
long_desc <<-LONGDESC
|
69
71
|
|
data/lib/asker/data/concept.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "rexml/document"
|
2
2
|
|
3
3
|
require_relative "../lang/lang_factory"
|
4
|
-
require_relative "../loader/embedded_file"
|
4
|
+
require_relative "../loader/embedded_file/loader"
|
5
5
|
require_relative "../logger"
|
6
6
|
require_relative "table"
|
7
7
|
require_relative "data_field"
|
@@ -173,10 +173,10 @@ class Concept
|
|
173
173
|
case value.attributes["type"]
|
174
174
|
when "image_url"
|
175
175
|
# Link with remote image
|
176
|
-
@data[:images] << EmbeddedFile.
|
176
|
+
@data[:images] << EmbeddedFile::Loader.new.call(value.text.strip, File.dirname(@filename))
|
177
177
|
when "file"
|
178
178
|
# Load local images and text files
|
179
|
-
@data[:images] << EmbeddedFile.
|
179
|
+
@data[:images] << EmbeddedFile::Loader.new.call(value.text.strip, File.dirname(@filename))
|
180
180
|
when nil
|
181
181
|
if value.text.nil?
|
182
182
|
Logger.warn "Concept: def/text empty!"
|
data/lib/asker/data/problem.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative "../logger"
|
2
|
+
require_relative "../lang/lang_factory"
|
2
3
|
|
3
4
|
class Problem
|
4
5
|
attr_accessor :lang
|
@@ -10,12 +11,13 @@ class Problem
|
|
10
11
|
attr_accessor :descs
|
11
12
|
attr_accessor :asks
|
12
13
|
attr_accessor :questions
|
14
|
+
attr_accessor :stats
|
13
15
|
|
14
16
|
@@id = 0
|
15
17
|
def initialize
|
16
18
|
@@id += 1
|
17
19
|
@id = @@id
|
18
|
-
@lang =
|
20
|
+
@lang = LangFactory.instance.get("en")
|
19
21
|
@context = nil
|
20
22
|
@process = false
|
21
23
|
@filename = "?"
|
@@ -24,6 +26,7 @@ class Problem
|
|
24
26
|
@descs = []
|
25
27
|
@asks = []
|
26
28
|
@questions = []
|
29
|
+
@stats = { answer: 0, steps: 0}
|
27
30
|
end
|
28
31
|
|
29
32
|
def self.from(values)
|
@@ -46,7 +49,8 @@ class Problem
|
|
46
49
|
end
|
47
50
|
|
48
51
|
def name
|
49
|
-
"problem
|
52
|
+
firstword = @descs[0]&.strip&.split(" ")&.first&.downcase || "problem"
|
53
|
+
"#{firstword}#{@id}"
|
50
54
|
end
|
51
55
|
|
52
56
|
def validate
|
@@ -59,6 +63,8 @@ class Problem
|
|
59
63
|
private
|
60
64
|
|
61
65
|
def validate_varnames
|
66
|
+
return if @varnames.nil?
|
67
|
+
|
62
68
|
if !@varnames.size.zero? && @cases.size.zero?
|
63
69
|
Logger.warn "Problem: No problem/varnames defined with no problem/case"
|
64
70
|
end
|
@@ -75,6 +81,8 @@ class Problem
|
|
75
81
|
end
|
76
82
|
|
77
83
|
def validate_cases
|
84
|
+
return if @cases.nil?
|
85
|
+
|
78
86
|
@cases.each do |acase|
|
79
87
|
if acase.size != @varnames.size
|
80
88
|
Logger.error "Problem: problem/cases size not equal to problem/varnames size"
|
@@ -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",
|
@@ -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
|
@@ -33,3 +33,4 @@
|
|
33
33
|
:ps4: 'Canvia el pas <%=text1%> pel pas <%=text2%>'
|
34
34
|
:ps5: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Resposta:</b ></p><pre><%=text3%></pre><br/><i>(Col·loca cada pas en la seva posició correcta dins de la seqüència)</i>'
|
35
35
|
:ps6: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><br/><i>(Posa cada pas en la posició correcta dins de la seqüència)</i>'
|
36
|
+
:ps7: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Resposta:</b ></p><pre><%=text3%></pre><br/><i>(Nota: Cada símbol ? representa una lletra/símbol, i cada * represent una o diverses paraules.)</i >'
|
@@ -33,3 +33,4 @@
|
|
33
33
|
:ps4: 'Ändere Schritt <%=text1%> in Schritt <%=text2%>'
|
34
34
|
:ps5: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><p><b>Antwort:</b ></p><pre><%=text3%></pre><br/><i>(Platzieren Sie jeden Schritt an der richtigen Position innerhalb der Sequenz)</i>'
|
35
35
|
:ps6: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><br/><i>(Platzieren Sie jeden Schritt an der richtigen Position innerhalb der Sequenz)</i>'
|
36
|
+
:ps7: '<p><%=text1%></p><p><b>Frage:</b> <%=text2%></p><p><b>Antwort:</b ></p><pre><%=text3%></pre><br/><i>(Hinweis: Jedes ? steht für einen Buchstaben/ein Symbol und jedes * steht für ein oder mehrere Wörter.)</i > '
|
@@ -33,3 +33,4 @@
|
|
33
33
|
:ps4: 'Change step <%=text1%> by step <%=text2%>'
|
34
34
|
:ps5: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><p><b>Answer:</b></p><pre><%=text3%></pre><br/><i>(Place each step in its correct position within the sequence)</i>'
|
35
35
|
:ps6: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><br/><i>(Place each step in its correct position within the sequence)</i>'
|
36
|
+
:ps7: '<p><%=text1%></p><p><b>Question:</b> <%=text2%></p><p><b>Answer:</b ></p><pre><%=text3%></pre><br/><i>(Note: Each ? represents a letter/symbol, and each * represents one or more words.)</i>'
|
@@ -33,3 +33,4 @@
|
|
33
33
|
:ps4: 'Cambia el paso <%=text1%> por el paso <%=text2%>'
|
34
34
|
:ps5: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Respuesta:</b></p><pre><%=text3%></pre><br/><i>(Coloca cada paso en su posición correcta dentro de la secuencia)</i>'
|
35
35
|
:ps6: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><br/><i>(Coloca cada paso en su posición correcta dentro de la secuencia)</i>'
|
36
|
+
:ps7: '<p><%=text1%></p><p><b>Pregunta:</b> <%=text2%></p><p><b>Respuesta:</b></p><pre><%=text3%></pre><br/><i>(Nota: Cada símbolo ? representa una letra/símbolo, y cada * represent una o varias palabras.)</i>'
|
@@ -33,3 +33,4 @@
|
|
33
33
|
:ps4: "Changer l'étape <%=text1%> en étape <%=text2%>"
|
34
34
|
:ps5 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><p><b>Réponse :</b ></p><pre><%=text3%></pre><br/><i>(Placez chaque étape dans sa position correcte dans la séquence)</i>"
|
35
35
|
:ps6 : "<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><br/><i>(Placez chaque étape dans sa position correcte dans la séquence)</i>"
|
36
|
+
:ps7 : '<p><%=text1%></p><p><b>Question :</b> <%=text2%></p><p><b>Réponse :</b ></p><pre><%=text3%></pre><br/><i>(Remarque : chaque ? représente une lettre/un symbole, et chaque * représente un ou plusieurs mots.)</i > '
|
@@ -6,12 +6,12 @@ require_relative "../data/project_data"
|
|
6
6
|
require_relative "../lang/lang_factory"
|
7
7
|
require_relative "../logger"
|
8
8
|
|
9
|
-
|
9
|
+
class ContentLoader
|
10
10
|
##
|
11
11
|
# Load XML content into Asker data objects
|
12
12
|
# @param filepath (String) File path
|
13
13
|
# @param content (String) XML plane text content
|
14
|
-
def
|
14
|
+
def call(filepath, content)
|
15
15
|
begin
|
16
16
|
xmlcontent = REXML::Document.new(content)
|
17
17
|
rescue REXML::ParseException
|
@@ -39,7 +39,9 @@ module ContentLoader
|
|
39
39
|
{concepts: concepts, codes: codes, problems: problems}
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
private
|
43
|
+
|
44
|
+
def read_lang_attribute(xmldata)
|
43
45
|
begin
|
44
46
|
lang_code = xmldata.root.attributes["lang"]
|
45
47
|
rescue itself
|
@@ -49,7 +51,7 @@ module ContentLoader
|
|
49
51
|
LangFactory.instance.get(lang_code)
|
50
52
|
end
|
51
53
|
|
52
|
-
|
54
|
+
def read_context_attribute(xmldata)
|
53
55
|
begin
|
54
56
|
context = xmldata.root.attributes["context"].split(",")
|
55
57
|
context.collect!(&:strip)
|
@@ -60,7 +62,7 @@ module ContentLoader
|
|
60
62
|
context
|
61
63
|
end
|
62
64
|
|
63
|
-
|
65
|
+
def read_concept(xmldata, filepath, lang, context)
|
64
66
|
project = ProjectData.instance
|
65
67
|
concept = Concept.new(xmldata, filepath, lang, context)
|
66
68
|
cond = [File.basename(filepath), :default].include? project.get(:process_file)
|
@@ -68,7 +70,7 @@ module ContentLoader
|
|
68
70
|
concept
|
69
71
|
end
|
70
72
|
|
71
|
-
|
73
|
+
def read_code(xmldata, filepath)
|
72
74
|
project = ProjectData.instance
|
73
75
|
code = CodeLoader.call(xmldata, filepath)
|
74
76
|
cond = [File.basename(filepath), :default].include? project.get(:process_file)
|
@@ -76,7 +78,7 @@ module ContentLoader
|
|
76
78
|
code
|
77
79
|
end
|
78
80
|
|
79
|
-
|
81
|
+
def read_problem(xmldata, filepath, lang, context)
|
80
82
|
project = ProjectData.instance
|
81
83
|
problem = ProblemLoader.new(lang, context).call(xmldata, filepath)
|
82
84
|
cond = [File.basename(filepath), :default].include? project.get(:process_file)
|
@@ -84,7 +86,7 @@ module ContentLoader
|
|
84
86
|
problem
|
85
87
|
end
|
86
88
|
|
87
|
-
|
89
|
+
def raise_error_with(filepath, content)
|
88
90
|
Logger.error "ContentLoader: Format error (#{filepath})"
|
89
91
|
Logger.error " : Revise output file (ouput/error.xml)"
|
90
92
|
f = File.open("output/error.xml", "w")
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require "base64"
|
2
|
+
require_relative "../../logger"
|
3
|
+
require_relative "type"
|
4
|
+
|
5
|
+
module EmbeddedFile
|
6
|
+
# Methods to load embedded files defined into asker input data file
|
7
|
+
# Examples:
|
8
|
+
# def line with :type = :image_url used to link external file as https://..."
|
9
|
+
# def line with :type = :file used to load local file as image.png or file.txt"
|
10
|
+
class Loader
|
11
|
+
##
|
12
|
+
# @param value (String)
|
13
|
+
# @param localdir (String) Input file base folder
|
14
|
+
# @return Hash
|
15
|
+
def call(value, localdir)
|
16
|
+
filepath = File.join(localdir, value)
|
17
|
+
type = EmbebbedFile::Type.new.for(value, localdir)
|
18
|
+
|
19
|
+
case type
|
20
|
+
when :image
|
21
|
+
return load_image(value, localdir)
|
22
|
+
when :image_url
|
23
|
+
return load_image_url(value, localdir)
|
24
|
+
when :audio
|
25
|
+
return load_audio(value, localdir)
|
26
|
+
when :audio_url
|
27
|
+
return load_audio_url(value, localdir)
|
28
|
+
when :video
|
29
|
+
return load_video(value, localdir)
|
30
|
+
when :video_url
|
31
|
+
return load_video_url(value, localdir)
|
32
|
+
end
|
33
|
+
|
34
|
+
{text: "<pre>#{File.read(filepath)}</pre>", file: :none, type: :text}
|
35
|
+
end
|
36
|
+
|
37
|
+
def load_audio(value, localdir)
|
38
|
+
filepath = File.join(localdir, value)
|
39
|
+
output = {}
|
40
|
+
output[:text] = '<audio controls><source src="@@PLUGINFILE@@/' + File.basename(filepath) \
|
41
|
+
+ '">Your browser does not support the audio tag.</audio>'
|
42
|
+
output[:file] = '<file name="' + File.basename(filepath) \
|
43
|
+
+ '" path="/" encoding="base64">' \
|
44
|
+
+ Base64.strict_encode64(File.open(filepath, "rb").read) \
|
45
|
+
+ "</file>"
|
46
|
+
output[:type] = :audio
|
47
|
+
output
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_audio_url(value, localdir)
|
51
|
+
{
|
52
|
+
text: "<audio src=\"#{value}\" controls></audio>",
|
53
|
+
file: :none,
|
54
|
+
type: :url
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def load_image(value, localdir)
|
59
|
+
filepath = File.join(localdir, value)
|
60
|
+
output = {}
|
61
|
+
output[:text] = '<img src="@@PLUGINFILE@@/' + File.basename(filepath) \
|
62
|
+
+ '" alt="imagen" class="img-responsive atto_image_button_text-bottom">'
|
63
|
+
output[:file] = '<file name="' + File.basename(filepath) \
|
64
|
+
+ '" path="/" encoding="base64">' \
|
65
|
+
+ Base64.strict_encode64(File.open(filepath, "rb").read) \
|
66
|
+
+ "</file>"
|
67
|
+
output[:type] = :image
|
68
|
+
output
|
69
|
+
end
|
70
|
+
|
71
|
+
def load_image_url(value, localdir)
|
72
|
+
{
|
73
|
+
text: "<img src=\"#{value}\" alt=\"image\" width=\"400\" height=\"300\">",
|
74
|
+
file: :none,
|
75
|
+
type: :url
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
def load_video(value, localdir)
|
80
|
+
filepath = File.join(localdir, value)
|
81
|
+
output = {}
|
82
|
+
output[:text] = '<video controls><source src="@@PLUGINFILE@@/' \
|
83
|
+
+ File.basename(filepath) \
|
84
|
+
+ '"/>Your browser does not support the video tag.</video>'
|
85
|
+
output[:file] = '<file name="' \
|
86
|
+
+ File.basename(filepath) \
|
87
|
+
+ '" path="/" encoding="base64">' \
|
88
|
+
+ Base64.strict_encode64(File.open(filepath, "rb").read) \
|
89
|
+
+ "</file>"
|
90
|
+
output[:type] = :video
|
91
|
+
output
|
92
|
+
end
|
93
|
+
|
94
|
+
def load_video_url(value, localdir)
|
95
|
+
{
|
96
|
+
text: "<video controls width=\"400\" height=\"300\">" \
|
97
|
+
+ "<source src=\"#{value}\"/></video>",
|
98
|
+
file: :none,
|
99
|
+
type: :url
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
module EmbebbedFile
|
3
|
+
class Type
|
4
|
+
def for(value, localdir)
|
5
|
+
if is_url? value
|
6
|
+
return :image_url if is_image? value
|
7
|
+
return :audio_url if is_audio? value
|
8
|
+
return :video_url if is_video? value
|
9
|
+
|
10
|
+
Logger.error "EmbebbedFile::Type.for: Unknown URL type (#{value})"
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
filepath = File.join(localdir, value)
|
15
|
+
unless File.exist?(filepath)
|
16
|
+
Logger.error "EmbeddedFile::Type.for: File does not exist (#{filepath})"
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
return :image if is_image? value
|
21
|
+
return :audio if is_audio? value
|
22
|
+
return :video if is_video? value
|
23
|
+
|
24
|
+
:text
|
25
|
+
end
|
26
|
+
|
27
|
+
def is_audio?(filename)
|
28
|
+
extens = [".mp3", ".ogg", ".wav"]
|
29
|
+
extens.each { |ext| return true if filename.downcase.end_with?(ext) }
|
30
|
+
false
|
31
|
+
end
|
32
|
+
|
33
|
+
def is_image?(filename)
|
34
|
+
extens = [".jpg", ".jpeg", ".png"]
|
35
|
+
extens.each { |ext| return true if filename.downcase.end_with?(ext) }
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_video?(filename)
|
40
|
+
extens = [".mp4", ".ogv"]
|
41
|
+
extens.each { |ext| return true if filename.downcase.end_with?(ext) }
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def is_url?(value)
|
46
|
+
return true if value.start_with?("https://", "http://")
|
47
|
+
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -7,6 +7,7 @@ require_relative "../logger"
|
|
7
7
|
# return { concepts: [], codes: [] }
|
8
8
|
module FileLoader
|
9
9
|
def self.call(filename)
|
10
|
+
Logger.debug "==> Loading #{filename}"
|
10
11
|
if File.extname(filename).casecmp(".haml").zero?
|
11
12
|
file_content = HamlLoader.load filename
|
12
13
|
elsif File.extname(filename).casecmp(".xml").zero?
|
@@ -15,6 +16,6 @@ module FileLoader
|
|
15
16
|
Logger.error "FileLoader: HAML or XML required (#{filename})"
|
16
17
|
exit 1
|
17
18
|
end
|
18
|
-
ContentLoader.call(filename, file_content)
|
19
|
+
ContentLoader.new.call(filename, file_content)
|
19
20
|
end
|
20
21
|
end
|
data/lib/asker/logger.rb
CHANGED
@@ -1,14 +1,18 @@
|
|
1
|
-
require "singleton"
|
2
1
|
require_relative "version"
|
3
2
|
|
4
3
|
class Logger
|
5
|
-
include Singleton
|
6
4
|
@verbose = true
|
7
5
|
|
8
|
-
def set_verbose(value)
|
6
|
+
def self.set_verbose(value)
|
9
7
|
@verbose = (value == "yes")
|
10
8
|
end
|
11
9
|
|
10
|
+
def self.debug(msg)
|
11
|
+
msg = Rainbow("#{msg}").white
|
12
|
+
puts msg if @verbose
|
13
|
+
@logfile&.write(msg)
|
14
|
+
end
|
15
|
+
|
12
16
|
def self.info(msg)
|
13
17
|
puts msg if @verbose
|
14
18
|
@logfile&.write(msg)
|
data/lib/asker/start.rb
CHANGED
@@ -9,7 +9,7 @@ require_relative "loader/input_loader"
|
|
9
9
|
class Start
|
10
10
|
def call(filepath)
|
11
11
|
project_data, data = load_input(filepath)
|
12
|
-
ConceptDisplayer.
|
12
|
+
ConceptDisplayer.new.call(data[:concepts])
|
13
13
|
create_output(project_data, data)
|
14
14
|
end
|
15
15
|
|
@@ -19,7 +19,7 @@ class Start
|
|
19
19
|
init_project_data
|
20
20
|
project_data = ProjectLoader.load(args)
|
21
21
|
Logger.create(project_data.get(:logpath))
|
22
|
-
Logger.
|
22
|
+
Logger.set_verbose(Application.instance.config["global"]["verbose"])
|
23
23
|
|
24
24
|
inputdirs = project_data.get(:inputdirs).split(",")
|
25
25
|
internet = Application.instance.config["global"]["internet"] == "yes"
|
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.8.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-07-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: haml
|
@@ -117,7 +117,11 @@ files:
|
|
117
117
|
- lib/asker/ai/code/ruby_code_ai.rb
|
118
118
|
- lib/asker/ai/code/sql_code_ai.rb
|
119
119
|
- lib/asker/ai/concept_ai.rb
|
120
|
+
- lib/asker/ai/problem/customizer.rb
|
120
121
|
- lib/asker/ai/problem/problem_ai.rb
|
122
|
+
- lib/asker/ai/problem/stage_answers.rb
|
123
|
+
- lib/asker/ai/problem/stage_base.rb
|
124
|
+
- lib/asker/ai/problem/stage_steps.rb
|
121
125
|
- lib/asker/ai/question.rb
|
122
126
|
- lib/asker/ai/stages/base_stage.rb
|
123
127
|
- lib/asker/ai/stages/main.rb
|
@@ -210,7 +214,8 @@ files:
|
|
210
214
|
- lib/asker/loader/code_loader.rb
|
211
215
|
- lib/asker/loader/content_loader.rb
|
212
216
|
- lib/asker/loader/directory_loader.rb
|
213
|
-
- lib/asker/loader/embedded_file.rb
|
217
|
+
- lib/asker/loader/embedded_file/loader.rb
|
218
|
+
- lib/asker/loader/embedded_file/type.rb
|
214
219
|
- lib/asker/loader/file_loader.rb
|
215
220
|
- lib/asker/loader/haml_loader.rb
|
216
221
|
- lib/asker/loader/image_url_loader.rb
|