asker-tool 2.1.2
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 +7 -0
- data/LICENSE +674 -0
- data/README.md +53 -0
- data/bin/asker +4 -0
- data/docs/changelog/v2.1.md +99 -0
- data/docs/commands.md +15 -0
- data/docs/contributions.md +18 -0
- data/docs/history.md +40 -0
- data/docs/idea.md +44 -0
- data/docs/inputs/README.md +39 -0
- data/docs/inputs/code.md +69 -0
- data/docs/inputs/concepts.md +142 -0
- data/docs/inputs/jedi.md +68 -0
- data/docs/inputs/tables.md +112 -0
- data/docs/inputs/templates.md +87 -0
- data/docs/install/README.md +38 -0
- data/docs/install/manual.md +26 -0
- data/docs/install/scripts.md +26 -0
- data/docs/revise/asker-file.md +41 -0
- data/docs/revise/buenas-practicas/01-convocatoria.md +30 -0
- data/docs/revise/buenas-practicas/02-formulario.md +35 -0
- data/docs/revise/buenas-practicas/03-descripcion.md +63 -0
- data/docs/revise/buenas-practicas/04-resultados.md +17 -0
- data/docs/revise/buenas-practicas/05-reproducir.md +10 -0
- data/docs/revise/ejemplos/01/README.md +27 -0
- data/docs/revise/ejemplos/02/README.md +31 -0
- data/docs/revise/ejemplos/03/README.md +31 -0
- data/docs/revise/ejemplos/04/README.md +37 -0
- data/docs/revise/ejemplos/05/README.md +25 -0
- data/docs/revise/ejemplos/06/README.md +43 -0
- data/docs/revise/ejemplos/README.md +11 -0
- data/docs/revise/projects.md +74 -0
- data/lib/asker.rb +103 -0
- data/lib/asker/ai/ai.rb +70 -0
- data/lib/asker/ai/ai_calculate.rb +55 -0
- data/lib/asker/ai/concept_ai.rb +49 -0
- data/lib/asker/ai/question.rb +58 -0
- data/lib/asker/ai/stages/base_stage.rb +16 -0
- data/lib/asker/ai/stages/main.rb +8 -0
- data/lib/asker/ai/stages/stage_b.rb +87 -0
- data/lib/asker/ai/stages/stage_d.rb +160 -0
- data/lib/asker/ai/stages/stage_f.rb +156 -0
- data/lib/asker/ai/stages/stage_i.rb +140 -0
- data/lib/asker/ai/stages/stage_s.rb +52 -0
- data/lib/asker/ai/stages/stage_t.rb +170 -0
- data/lib/asker/application.rb +30 -0
- data/lib/asker/checker.rb +356 -0
- data/lib/asker/cli.rb +85 -0
- data/lib/asker/code/ai/base_code_ai.rb +48 -0
- data/lib/asker/code/ai/code_ai_factory.rb +26 -0
- data/lib/asker/code/ai/javascript_code_ai.rb +167 -0
- data/lib/asker/code/ai/python_code_ai.rb +167 -0
- data/lib/asker/code/ai/ruby_code_ai.rb +169 -0
- data/lib/asker/code/ai/sql_code_ai.rb +69 -0
- data/lib/asker/code/code.rb +53 -0
- data/lib/asker/data/column.rb +62 -0
- data/lib/asker/data/concept.rb +183 -0
- data/lib/asker/data/data_field.rb +87 -0
- data/lib/asker/data/row.rb +93 -0
- data/lib/asker/data/table.rb +96 -0
- data/lib/asker/data/template.rb +65 -0
- data/lib/asker/data/world.rb +53 -0
- data/lib/asker/exporter/code_gift_exporter.rb +35 -0
- data/lib/asker/exporter/code_screen_exporter.rb +45 -0
- data/lib/asker/exporter/concept_ai_gift_exporter.rb +33 -0
- data/lib/asker/exporter/concept_ai_screen_exporter.rb +115 -0
- data/lib/asker/exporter/concept_ai_yaml_exporter.rb +33 -0
- data/lib/asker/exporter/concept_doc_exporter.rb +21 -0
- data/lib/asker/exporter/concept_screen_exporter.rb +25 -0
- data/lib/asker/exporter/main.rb +9 -0
- data/lib/asker/files/config.ini +40 -0
- data/lib/asker/formatter/code_string_formatter.rb +16 -0
- data/lib/asker/formatter/concept_doc_formatter.rb +37 -0
- data/lib/asker/formatter/concept_string_formatter.rb +66 -0
- data/lib/asker/formatter/question_gift_formatter.rb +65 -0
- data/lib/asker/formatter/question_hash_formatter.rb +40 -0
- data/lib/asker/formatter/question_moodlexml_formatter.rb +71 -0
- data/lib/asker/formatter/rb2haml_formatter.rb +26 -0
- data/lib/asker/lang/lang.rb +42 -0
- data/lib/asker/lang/lang_factory.rb +19 -0
- data/lib/asker/lang/text_actions.rb +150 -0
- data/lib/asker/loader/code_loader.rb +53 -0
- data/lib/asker/loader/content_loader.rb +101 -0
- data/lib/asker/loader/directory_loader.rb +58 -0
- data/lib/asker/loader/file_loader.rb +33 -0
- data/lib/asker/loader/image_url_loader.rb +61 -0
- data/lib/asker/loader/input_loader.rb +24 -0
- data/lib/asker/loader/project_loader.rb +71 -0
- data/lib/asker/logger.rb +21 -0
- data/lib/asker/project.rb +170 -0
- metadata +261 -0
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
require 'yaml'
|
5
|
+
require_relative 'text_actions'
|
6
|
+
|
7
|
+
# Lang#lang
|
8
|
+
class Lang
|
9
|
+
include TextActions
|
10
|
+
|
11
|
+
attr_reader :code, :mistakes
|
12
|
+
|
13
|
+
def initialize(code = 'en')
|
14
|
+
@code = code.to_s
|
15
|
+
load_files
|
16
|
+
end
|
17
|
+
|
18
|
+
def lang
|
19
|
+
@code
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def load_files
|
25
|
+
dirbase = File.dirname(__FILE__)
|
26
|
+
filename = File.join(dirbase, 'locales', @code, 'templates.yaml')
|
27
|
+
begin
|
28
|
+
@templates = YAML.load(File.new(filename))
|
29
|
+
rescue StandardError => e
|
30
|
+
p = Project.instance
|
31
|
+
p.vervose "[ERROR] lang.initialize(): Reading YAML file <#{filename}>"
|
32
|
+
p.vervose "[ADVISE] Revise apostrophe into string without \\ char\n"
|
33
|
+
raise e
|
34
|
+
end
|
35
|
+
filename = File.join(dirbase, 'locales', @code, 'connectors.yaml')
|
36
|
+
@connectors = YAML.load(File.new(filename))
|
37
|
+
|
38
|
+
filename = File.join(dirbase, 'locales', @code, 'mistakes.yaml')
|
39
|
+
@mistakes = YAML.load(File.new(filename))
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
require_relative 'lang'
|
5
|
+
require_relative '../project'
|
6
|
+
|
7
|
+
# LangFactory#get
|
8
|
+
class LangFactory
|
9
|
+
include Singleton
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@langs = {}
|
13
|
+
Project.instance.locales.each { |i| @langs[i] = Lang.new(i) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(locale)
|
17
|
+
@langs[locale]
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module TextActions
|
4
|
+
|
5
|
+
def text_for(pOption, pText1="",pText2="",pText3="",pText4="",pText5="",pText6="",pText7="")
|
6
|
+
text1=pText1
|
7
|
+
text2=pText2
|
8
|
+
text3=pText3
|
9
|
+
text4=pText4
|
10
|
+
text5=pText5
|
11
|
+
text6=pText6
|
12
|
+
text7=pText7
|
13
|
+
|
14
|
+
# TODO: check if exists pOption before use it
|
15
|
+
renderer = ERB.new(@templates[pOption])
|
16
|
+
output = renderer.result(binding)
|
17
|
+
return output
|
18
|
+
end
|
19
|
+
|
20
|
+
def text_filter_connectors(pText, pFilter)
|
21
|
+
input_lines = pText.split(".")
|
22
|
+
output_lines = []
|
23
|
+
output_words = []
|
24
|
+
input_lines.each_with_index do |line, rowindex|
|
25
|
+
row=[]
|
26
|
+
line.split(' ').each_with_index do |word, colindex|
|
27
|
+
flag = @connectors.include? word.downcase
|
28
|
+
|
29
|
+
# if <word> is a conector and <pFilter>==true Then Choose this <word>
|
30
|
+
# if <word> isn't a conector and <pFilter>==true and <word>.length>1 Then Choose this <word>
|
31
|
+
if (flag and pFilter) || (!flag and !pFilter and word.length>1)
|
32
|
+
output_words << {:word => word,
|
33
|
+
:row => rowindex,
|
34
|
+
:col => colindex }
|
35
|
+
row << (output_words.size-1)
|
36
|
+
else
|
37
|
+
row << word
|
38
|
+
end
|
39
|
+
end
|
40
|
+
row << '.'
|
41
|
+
output_lines << row
|
42
|
+
end
|
43
|
+
|
44
|
+
indexes = []
|
45
|
+
exclude = ['[', ']', '(', ')', "\"" ]
|
46
|
+
output_words.each_with_index do |item, index|
|
47
|
+
flag = true
|
48
|
+
exclude.each { |e| flag = false if (item[:word].include?(e)) }
|
49
|
+
indexes << index if flag
|
50
|
+
end
|
51
|
+
|
52
|
+
result={ :lines => output_lines, :words => output_words, :indexes => indexes }
|
53
|
+
return result
|
54
|
+
end
|
55
|
+
|
56
|
+
def text_with_connectors(text)
|
57
|
+
text_filter_connectors(text, false)
|
58
|
+
end
|
59
|
+
|
60
|
+
def text_without_connectors(text)
|
61
|
+
text_filter_connectors(text, true)
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_text_from_filtered(pStruct, pIndexes)
|
65
|
+
lines = pStruct[:lines]
|
66
|
+
lIndexes = pIndexes.sort
|
67
|
+
counter = 1
|
68
|
+
lText = ''
|
69
|
+
|
70
|
+
lines.each do |line|
|
71
|
+
line.each do |value|
|
72
|
+
if value.class == String
|
73
|
+
lText += (' ' + value)
|
74
|
+
elsif value == value.to_i
|
75
|
+
# INFO: ruby 2.4 unifies Fixnum and Bignum into Integer
|
76
|
+
# Avoid using deprecated classes.
|
77
|
+
if lIndexes.include? value
|
78
|
+
lText += " [#{counter.to_s}]"
|
79
|
+
counter += 1
|
80
|
+
else
|
81
|
+
lword = pStruct[:words][value][:word]
|
82
|
+
lText += (' ' + lword)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
lText.gsub!(' .', '.')
|
88
|
+
lText.gsub!(' ,', ',')
|
89
|
+
lText = lText[1, lText.size] if lText[0] == ' '
|
90
|
+
lText
|
91
|
+
end
|
92
|
+
|
93
|
+
def count_words(pInputText)
|
94
|
+
return 0 if pInputText.nil?
|
95
|
+
|
96
|
+
t = pInputText.clone
|
97
|
+
t.gsub!("\n"," ")
|
98
|
+
t.gsub!("/"," ")
|
99
|
+
#t.gsub!("-"," ")
|
100
|
+
t.gsub!("."," ")
|
101
|
+
t.gsub!(","," ")
|
102
|
+
t.gsub!(" "," ")
|
103
|
+
t.gsub!(" "," ")
|
104
|
+
t.split(" ").count
|
105
|
+
end
|
106
|
+
|
107
|
+
def do_mistake_to(pText = '')
|
108
|
+
lText = pText.dup
|
109
|
+
keys = @mistakes.keys
|
110
|
+
|
111
|
+
# Try to do mistake with one item from the key list
|
112
|
+
keys.shuffle!
|
113
|
+
keys.each do |key|
|
114
|
+
if lText.include? key.to_s
|
115
|
+
values = @mistakes[key].split(',')
|
116
|
+
values.shuffle!
|
117
|
+
lText = lText.sub(key.to_s,values[0].to_s)
|
118
|
+
return lText
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Force mistake by swapping letters
|
123
|
+
if lText.size > 1
|
124
|
+
i = rand(lText.size - 2)
|
125
|
+
aux = lText[i]
|
126
|
+
lText[i] = lText[i + 1]
|
127
|
+
lText[i + 1] = aux
|
128
|
+
end
|
129
|
+
return lText if lText != pText
|
130
|
+
|
131
|
+
lText + 's'
|
132
|
+
end
|
133
|
+
|
134
|
+
def hide_text(input_text)
|
135
|
+
input = input_text.clone
|
136
|
+
if count_words(input) < 2 && input.size < 10
|
137
|
+
output = '[*]'
|
138
|
+
else
|
139
|
+
output = ''
|
140
|
+
input.each_char do |char|
|
141
|
+
if ' !|"@#$%&/()=?¿¡+*(){}[],.-_<>'.include? char
|
142
|
+
output += char
|
143
|
+
else
|
144
|
+
output += '?'
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
output
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
require 'rexml/document'
|
5
|
+
require_relative '../logger'
|
6
|
+
require_relative '../code/code'
|
7
|
+
|
8
|
+
# Read XML info about Code input data
|
9
|
+
module CodeLoader
|
10
|
+
##
|
11
|
+
# Load XML data about Code object
|
12
|
+
# @param xmldata (XML Object)
|
13
|
+
# @param filepath (String)
|
14
|
+
# @return Code object
|
15
|
+
def self.load(xmldata, filepath)
|
16
|
+
data = read_codedata_from_xml(xmldata, File.basename(filepath))
|
17
|
+
code = Code.new(File.dirname(filepath), data[:path], data[:type])
|
18
|
+
code.features << data[:features]
|
19
|
+
code
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Read Code data from XML content
|
24
|
+
# @param xmldata (XML Object)
|
25
|
+
# @param filename (String) File name that contains data
|
26
|
+
# @return Code object
|
27
|
+
def self.read_codedata_from_xml(xmldata, filename)
|
28
|
+
data = { path: '?', type: '?', features: [] }
|
29
|
+
xmldata.elements.each do |i|
|
30
|
+
data[:path] = i.text if i.name == 'path'
|
31
|
+
data[:type] = i.text.to_sym if i.name == 'type'
|
32
|
+
data[:features] << read_features(i, filename) if i.name == 'features'
|
33
|
+
end
|
34
|
+
data
|
35
|
+
end
|
36
|
+
|
37
|
+
##
|
38
|
+
# Read features data from XML input
|
39
|
+
# @param xmldata (XML object)
|
40
|
+
# @return Array with features (Strings)
|
41
|
+
def self.read_features(xmldata, filename)
|
42
|
+
features = []
|
43
|
+
xmldata.elements.each do |i|
|
44
|
+
if i.name == 'row'
|
45
|
+
features << i.text
|
46
|
+
else
|
47
|
+
msg = Rainbow("[ERROR] features/#{i.name} from #{filename}").color(:red)
|
48
|
+
Logger.verbose msg
|
49
|
+
end
|
50
|
+
end
|
51
|
+
features
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
require 'rexml/document'
|
5
|
+
require_relative '../data/concept'
|
6
|
+
require_relative 'code_loader'
|
7
|
+
require_relative '../logger'
|
8
|
+
require_relative '../project'
|
9
|
+
|
10
|
+
# Define methods that load data from XML contents
|
11
|
+
module ContentLoader
|
12
|
+
##
|
13
|
+
# Load XML content into Asker data objects
|
14
|
+
# @param filepath (String) File path
|
15
|
+
# @param content (String) XML plane text content
|
16
|
+
def self.load(filepath, content)
|
17
|
+
concepts = []
|
18
|
+
codes = []
|
19
|
+
begin
|
20
|
+
xmlcontent = REXML::Document.new(content)
|
21
|
+
rescue REXML::ParseException
|
22
|
+
raise_error_with(filepath, content)
|
23
|
+
end
|
24
|
+
lang = read_lang_attribute(xmlcontent)
|
25
|
+
context = read_context_attribute(xmlcontent)
|
26
|
+
|
27
|
+
xmlcontent.root.elements.each do |xmldata|
|
28
|
+
case xmldata.name
|
29
|
+
when 'concept'
|
30
|
+
concepts << read_concept(xmldata, filepath, lang, context)
|
31
|
+
when 'code'
|
32
|
+
codes << read_code(xmldata, filepath)
|
33
|
+
else
|
34
|
+
Logger.verboseln Rainbow("[ERROR] Unkown tag <#{xmldata.name}>").red
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
{ concepts: concepts, codes: codes }
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Read lang attr from input XML data
|
43
|
+
# @param xmldata (XML Object)
|
44
|
+
def self.read_lang_attribute(xmldata)
|
45
|
+
begin
|
46
|
+
lang = xmldata.root.attributes['lang']
|
47
|
+
rescue StandardError
|
48
|
+
lang = Project.instance.lang
|
49
|
+
end
|
50
|
+
lang
|
51
|
+
end
|
52
|
+
|
53
|
+
##
|
54
|
+
# Read context attr from input XML data
|
55
|
+
# @param xmldata (XML Object)
|
56
|
+
def self.read_context_attribute(xmldata)
|
57
|
+
begin
|
58
|
+
context = xmldata.root.attributes['context']
|
59
|
+
rescue StandardError
|
60
|
+
context = 'unknown'
|
61
|
+
end
|
62
|
+
context
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Read concept from input XML data
|
67
|
+
# @param xmldata (XML Object)
|
68
|
+
# @param filepath (String)
|
69
|
+
# @param lang
|
70
|
+
# @param context
|
71
|
+
def self.read_concept(xmldata, filepath, lang, context)
|
72
|
+
project = Project.instance
|
73
|
+
c = Concept.new(xmldata, filepath, lang, context)
|
74
|
+
if [ File.basename(filepath), :default ].include? project.process_file
|
75
|
+
c.process = true
|
76
|
+
end
|
77
|
+
c
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Read code from input XML data
|
82
|
+
# @param xmldata (XML Object)
|
83
|
+
# @param filepath (String)
|
84
|
+
def self.read_code(xmldata, filepath)
|
85
|
+
project = Project.instance
|
86
|
+
c = CodeLoader.load(xmldata, filepath)
|
87
|
+
if [ File.basename(filepath), :default ].include? project.process_file
|
88
|
+
c.process = true
|
89
|
+
end
|
90
|
+
c
|
91
|
+
end
|
92
|
+
|
93
|
+
def self.raise_error_with(filepath, content)
|
94
|
+
msg = Rainbow("[ERROR] ContentLoader: Format error in #{filepath}").red.bright
|
95
|
+
Logger.verbose msg
|
96
|
+
f = File.open('output/error.xml', 'w')
|
97
|
+
f.write(content)
|
98
|
+
f.close
|
99
|
+
raise msg
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'file_loader'
|
4
|
+
require_relative '../logger'
|
5
|
+
|
6
|
+
# Load input data from one directory
|
7
|
+
module DirectoryLoader
|
8
|
+
##
|
9
|
+
# Load input data from directory
|
10
|
+
# @param dirname (String) Directory name
|
11
|
+
def self.load(dirname)
|
12
|
+
DirectoryLoader.check_dir(dirname)
|
13
|
+
files = (Dir.new(dirname).entries - ['.', '..']).sort
|
14
|
+
# Accept only HAML or XML files
|
15
|
+
accepted = files.select { |f| %w[.xml .haml].include? File.extname(f) }
|
16
|
+
Logger.verbose " * Input directory = #{Rainbow(dirname).bright}"
|
17
|
+
DirectoryLoader.load_files(accepted, dirname)
|
18
|
+
end
|
19
|
+
|
20
|
+
##
|
21
|
+
# Check directory
|
22
|
+
# @param dirname (String) Directory name
|
23
|
+
def self.check_dir(dirname)
|
24
|
+
return if Dir.exist? dirname
|
25
|
+
|
26
|
+
msg = Rainbow("[ERROR] #{dirname} directory dosn't exist!").color(:red)
|
27
|
+
Logger.verboseln msg
|
28
|
+
raise msg
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# Load accepted files from dirname directory
|
33
|
+
# @param filenames (Array) File name list
|
34
|
+
# @param dirname (String) Base directory
|
35
|
+
def self.load_files(filenames, dirname)
|
36
|
+
output = { concepts: [], codes: [] }
|
37
|
+
filenames.each do |filename|
|
38
|
+
filepath = File.join(dirname, filename)
|
39
|
+
data = DirectoryLoader.load_file(filepath, filename == filenames.last)
|
40
|
+
output[:concepts] += data[:concepts]
|
41
|
+
output[:codes] += data[:codes]
|
42
|
+
end
|
43
|
+
output
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Load one input file
|
48
|
+
# @param filepath (String) Path to input file
|
49
|
+
# @param last (Boolean) True if it is the last filename
|
50
|
+
def self.load_file(filepath, last = false)
|
51
|
+
if last
|
52
|
+
Logger.verbose " └── Input file = #{Rainbow(filepath).bright}"
|
53
|
+
else
|
54
|
+
Logger.verbose " ├── Input file = #{Rainbow(filepath).bright}"
|
55
|
+
end
|
56
|
+
FileLoader.load(filepath)
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'haml'
|
4
|
+
require_relative 'content_loader'
|
5
|
+
require_relative '../logger'
|
6
|
+
|
7
|
+
# Methods that load a filename and return list of concepts
|
8
|
+
module FileLoader
|
9
|
+
##
|
10
|
+
# Load asker data from file
|
11
|
+
# @param filename (String) File name to be load
|
12
|
+
def self.load(filename)
|
13
|
+
if File.extname(filename).casecmp('.haml').zero?
|
14
|
+
file_content = load_haml filename
|
15
|
+
elsif File.extname(filename).casecmp('.xml').zero?
|
16
|
+
file_content = File.read(filename)
|
17
|
+
else
|
18
|
+
msg = "[ERROR] FileLoader: Format error #{filename}"
|
19
|
+
Logger.verbose msg
|
20
|
+
raise msg
|
21
|
+
end
|
22
|
+
ContentLoader.load(filename, file_content)
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Load HAML file name
|
27
|
+
# @param filename (String) HAML file name
|
28
|
+
def self.load_haml(filename)
|
29
|
+
template = File.read(filename)
|
30
|
+
haml_engine = Haml::Engine.new(template)
|
31
|
+
haml_engine.render
|
32
|
+
end
|
33
|
+
end
|