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,69 @@
|
|
1
|
+
|
2
|
+
require_relative '../../lang/lang_factory'
|
3
|
+
require_relative '../../ai/question'
|
4
|
+
require_relative 'base_code_ai'
|
5
|
+
|
6
|
+
class SQLCodeAI < BaseCodeAI
|
7
|
+
def initialize(data_object)
|
8
|
+
@data_object = data_object
|
9
|
+
@lines = data_object.lines
|
10
|
+
@lang = LangFactory.instance.get('sql')
|
11
|
+
@num = 0
|
12
|
+
@questions = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def make_comment_error
|
16
|
+
error_lines = []
|
17
|
+
questions = []
|
18
|
+
@lines.each_with_index do |line,index|
|
19
|
+
if line.include?('//')
|
20
|
+
lines = clone_array @lines
|
21
|
+
lines[index].sub!('//','').strip!
|
22
|
+
|
23
|
+
q = Question.new(:short)
|
24
|
+
q.name = "#{name}-#{num}-code1uncomment"
|
25
|
+
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
26
|
+
q.shorts << (index+1)
|
27
|
+
q.feedback = 'Comment symbol removed'
|
28
|
+
questions << q
|
29
|
+
elsif line.strip.size>0
|
30
|
+
lines = clone_array @lines
|
31
|
+
lines[index]='// ' + lines[index]
|
32
|
+
|
33
|
+
q = Question.new(:short)
|
34
|
+
q.name = "#{name}-#{num}-code1comment"
|
35
|
+
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
36
|
+
q.shorts << (index+1)
|
37
|
+
q.feedback = 'Comment symbol added'
|
38
|
+
questions << q
|
39
|
+
end
|
40
|
+
end
|
41
|
+
questions
|
42
|
+
end
|
43
|
+
|
44
|
+
def make_keyword_error
|
45
|
+
error_lines = []
|
46
|
+
questions = []
|
47
|
+
|
48
|
+
@lang.mistakes.each_pair do |key,values|
|
49
|
+
v = values.split(',')
|
50
|
+
v.each do |value|
|
51
|
+
@lines.each_with_index do |line,index|
|
52
|
+
error_lines << index if line.include?(key.to_s)
|
53
|
+
end
|
54
|
+
|
55
|
+
error_lines.each do |index|
|
56
|
+
lines = clone_array @lines
|
57
|
+
lines[index].sub!(key.to_s, value)
|
58
|
+
q = Question.new(:short)
|
59
|
+
q.name = "#{name}-#{num}-code1keyword"
|
60
|
+
q.text = @lang.text_for(:code1,lines_to_html(lines))
|
61
|
+
q.shorts << (index+1)
|
62
|
+
q.feedback = "Keyword error: '#{value}' must be '#{key}'"
|
63
|
+
questions << q
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
questions
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require_relative 'ai/code_ai_factory'
|
2
|
+
require_relative '../project'
|
3
|
+
require_relative '../formatter/code_string_formatter'
|
4
|
+
|
5
|
+
# Contains code data input
|
6
|
+
class Code
|
7
|
+
attr_reader :dirname, :filename, :type
|
8
|
+
attr_accessor :process, :features
|
9
|
+
attr_reader :lines, :questions
|
10
|
+
|
11
|
+
def initialize(dirname, filename, type)
|
12
|
+
@dirname = dirname
|
13
|
+
@filename = filename
|
14
|
+
@type = type
|
15
|
+
@filepath = File.join(@dirname, @filename)
|
16
|
+
@process = false
|
17
|
+
@features = []
|
18
|
+
@lines = load(@filepath)
|
19
|
+
@questions = []
|
20
|
+
@code_ai = CodeAIFactory.get(self)
|
21
|
+
end
|
22
|
+
|
23
|
+
def process?
|
24
|
+
@process
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_questions
|
28
|
+
return unless process?
|
29
|
+
@questions += @code_ai.make_questions
|
30
|
+
end
|
31
|
+
|
32
|
+
def lines_to_s(lines)
|
33
|
+
out = ''
|
34
|
+
lines.each_with_index do |line, index|
|
35
|
+
out << format("%2d| #{line}\n", (index + 1))
|
36
|
+
end
|
37
|
+
out
|
38
|
+
end
|
39
|
+
|
40
|
+
def debug
|
41
|
+
out = CodeStringFormatter.to_s(self)
|
42
|
+
p = Project.instance
|
43
|
+
p.verbose out
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def load(filepath)
|
49
|
+
return if filepath.nil?
|
50
|
+
content = File.read(filepath)
|
51
|
+
content.split("\n")
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
# Contain data information for every column
|
5
|
+
# Params:
|
6
|
+
# * +pRow+ - Parent row for this column
|
7
|
+
# * +index+ - Sequence order (Integer)
|
8
|
+
# * +xml_data+ - XML input data
|
9
|
+
class Column
|
10
|
+
attr_reader :row, :index, :id, :raw, :lang, :type, :simple
|
11
|
+
|
12
|
+
def initialize(row, index, xml_data)
|
13
|
+
@row = row
|
14
|
+
@index = index
|
15
|
+
@id = @row.id + '.' + @index.to_s
|
16
|
+
@raw = ''
|
17
|
+
@lang = @row.langs[@index]
|
18
|
+
@type = @row.types[@index]
|
19
|
+
@simple = { lang: true, type: true }
|
20
|
+
read_data_from_xml(xml_data)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_html
|
24
|
+
case @type
|
25
|
+
when 'text'
|
26
|
+
return @raw
|
27
|
+
when 'image_url'
|
28
|
+
return "<img src=\"#{raw}\" alt\=\"image\">"
|
29
|
+
when 'textfile_path'
|
30
|
+
return "<pre>#{raw}</pre>"
|
31
|
+
else
|
32
|
+
return "ERROR type #{@type}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def read_data_from_xml(xml_data)
|
39
|
+
raise '[ERROR] Column XML data with elements!' if xml_data.elements.count.positive?
|
40
|
+
|
41
|
+
@raw = xml_data.text.strip.to_s
|
42
|
+
|
43
|
+
# read attributes from XML input data
|
44
|
+
if xml_data.attributes['lang']
|
45
|
+
code = xml_data.attributes['lang'].strip
|
46
|
+
if code != @lang.code
|
47
|
+
@lang = LangFactory.instance.get(code)
|
48
|
+
@simple[:lang] = false
|
49
|
+
@row.simple_off(:lang)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
if xml_data.attributes['type']
|
54
|
+
type = xml_data.attributes['type'].strip
|
55
|
+
if type != @type.to_s
|
56
|
+
@type = type
|
57
|
+
@simple[:type] = false
|
58
|
+
@row.simple_off(:type)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rainbow'
|
4
|
+
require 'rexml/document'
|
5
|
+
|
6
|
+
require_relative '../project'
|
7
|
+
require_relative '../lang/lang_factory'
|
8
|
+
require_relative 'table'
|
9
|
+
require_relative 'data_field'
|
10
|
+
|
11
|
+
# Store Concept information
|
12
|
+
class Concept
|
13
|
+
attr_reader :id, :lang, :context
|
14
|
+
attr_reader :names, :type, :filename
|
15
|
+
attr_reader :data
|
16
|
+
attr_accessor :process
|
17
|
+
|
18
|
+
@@id = 0
|
19
|
+
|
20
|
+
def initialize(xml_data, filename, lang_code = 'en', context = [])
|
21
|
+
@@id += 1
|
22
|
+
@id = @@id
|
23
|
+
|
24
|
+
@filename = filename
|
25
|
+
@process = false
|
26
|
+
@lang = LangFactory.instance.get(lang_code)
|
27
|
+
|
28
|
+
if context.class == Array
|
29
|
+
@context = context
|
30
|
+
elsif context.nil?
|
31
|
+
@context = []
|
32
|
+
else
|
33
|
+
@context = context.split(',')
|
34
|
+
@context.collect!(&:strip)
|
35
|
+
end
|
36
|
+
@names = ['concept.' + @id.to_s]
|
37
|
+
@type = 'text'
|
38
|
+
|
39
|
+
@data = {}
|
40
|
+
@data[:tags] = []
|
41
|
+
@data[:texts] = []
|
42
|
+
@data[:images] = [] # TODO: By now, We'll treat images separated from texts
|
43
|
+
@data[:textfile_paths] = [] # TODO: By now, We'll treat this separated from texts
|
44
|
+
@data[:tables] = []
|
45
|
+
@data[:neighbors] = []
|
46
|
+
@data[:reference_to] = []
|
47
|
+
@data[:referenced_by] = []
|
48
|
+
|
49
|
+
read_data_from_xml(xml_data)
|
50
|
+
end
|
51
|
+
|
52
|
+
def name(option = :raw)
|
53
|
+
DataField.new(@names[0], @id, @type).get(option)
|
54
|
+
end
|
55
|
+
|
56
|
+
def text
|
57
|
+
@data[:texts][0] || '...'
|
58
|
+
end
|
59
|
+
|
60
|
+
def process?
|
61
|
+
@process
|
62
|
+
end
|
63
|
+
|
64
|
+
def try_adding_neighbor(other)
|
65
|
+
p = calculate_nearness_to_concept(other)
|
66
|
+
return if p.zero?
|
67
|
+
|
68
|
+
@data[:neighbors] << { concept: other, value: p }
|
69
|
+
# Sort neighbors list
|
70
|
+
@data[:neighbors].sort! { |a, b| a[:value] <=> b[:value] }
|
71
|
+
@data[:neighbors].reverse!
|
72
|
+
end
|
73
|
+
|
74
|
+
def calculate_nearness_to_concept(other)
|
75
|
+
weights = Project.instance.formula_weights
|
76
|
+
|
77
|
+
li_max1 = @context.count
|
78
|
+
li_max2 = @data[:tags].count
|
79
|
+
li_max3 = @data[:tables].count
|
80
|
+
|
81
|
+
lf_alike1 = lf_alike2 = lf_alike3 = 0.0
|
82
|
+
|
83
|
+
# check if exists this items from concept1 into concept2
|
84
|
+
@context.each { |i| lf_alike1 += 1.0 unless other.context.index(i).nil? }
|
85
|
+
@data[:tags].each { |i| lf_alike2 += 1.0 unless other.tags.index(i).nil? }
|
86
|
+
@data[:tables].each { |i| lf_alike3 += 1.0 unless other.tables.index(i).nil? }
|
87
|
+
|
88
|
+
lf_alike = (lf_alike1 * weights[0] + lf_alike2 * weights[1] + lf_alike3 * weights[2])
|
89
|
+
li_max = (li_max1 * weights[0] + li_max2 * weights[1] + li_max3 * weights[2])
|
90
|
+
(lf_alike * 100.0 / li_max)
|
91
|
+
end
|
92
|
+
|
93
|
+
def try_adding_references(other)
|
94
|
+
reference_to = 0
|
95
|
+
@data[:tags].each { |i| reference_to += 1 unless other.names.index(i.downcase).nil? }
|
96
|
+
@data[:texts].each do |t|
|
97
|
+
text = t.clone
|
98
|
+
text.split(' ').each do |word|
|
99
|
+
reference_to += 1 unless other.names.index(word.downcase).nil?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
if reference_to.positive?
|
103
|
+
@data[:reference_to] << other.name
|
104
|
+
other.data[:referenced_by] << name
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def method_missing(method)
|
109
|
+
@data[method]
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def read_data_from_xml(xml_data)
|
115
|
+
xml_data.elements.each do |i|
|
116
|
+
case i.name
|
117
|
+
when 'names'
|
118
|
+
process_names(i)
|
119
|
+
when 'tags'
|
120
|
+
process_tags(i)
|
121
|
+
when 'context'
|
122
|
+
# DEPRECATED: Don't use xml tag <context>
|
123
|
+
# instead define it as attibute of root xml tag
|
124
|
+
process_context(i)
|
125
|
+
when 'text'
|
126
|
+
# DEPRECATED: Use xml tag <def> instead of <text>
|
127
|
+
process_text(i)
|
128
|
+
when 'def'
|
129
|
+
process_def(i)
|
130
|
+
when 'table'
|
131
|
+
@data[:tables] << Table.new(self, i)
|
132
|
+
else
|
133
|
+
text = " [ERROR] <#{i.name}> unkown XML attribute for concept #{name}"
|
134
|
+
msg = Rainbow(text).color(:red)
|
135
|
+
Project.instance.verbose msg
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def process_names(value)
|
141
|
+
@names = []
|
142
|
+
j = value.text.split(',')
|
143
|
+
j.each { |k| @names << k.strip }
|
144
|
+
@type = value.attributes['type'].strip if value.attributes['type']
|
145
|
+
end
|
146
|
+
|
147
|
+
def process_tags(value)
|
148
|
+
raise '[Error] tags label empty!' if value.text.nil? || value.text.size.zero?
|
149
|
+
@data[:tags] = value.text.split(',')
|
150
|
+
@data[:tags].collect!(&:strip)
|
151
|
+
end
|
152
|
+
|
153
|
+
def process_context(value)
|
154
|
+
msg = ' │ ' + Rainbow(' [DEPRECATED] Concept ').yellow
|
155
|
+
msg += Rainbow(name).yellow.bright
|
156
|
+
msg += Rainbow(' move <context> tag info to <map>.').yellow
|
157
|
+
Project.instance.verbose msg
|
158
|
+
@context = value.text.split(',')
|
159
|
+
@context.collect!(&:strip)
|
160
|
+
end
|
161
|
+
|
162
|
+
def process_text(value)
|
163
|
+
msg = ' │ ' + Rainbow(' [DEPRECATED] Concept ').yellow
|
164
|
+
msg += Rainbow(name).yellow.bright
|
165
|
+
msg += Rainbow(' replace <text> tag by <def>.').yellow
|
166
|
+
Project.instance.verbose msg
|
167
|
+
@data[:texts] << value.text.strip
|
168
|
+
end
|
169
|
+
|
170
|
+
def process_def(value)
|
171
|
+
case value.attributes['type']
|
172
|
+
when 'image'
|
173
|
+
msg = "[DEBUG] Concept#read_xml: image #{Rainbow(value.text).bright}"
|
174
|
+
Project.instance.verbose Rainbow(msg).yellow
|
175
|
+
when 'image_url'
|
176
|
+
@data[:images] << value.text.strip
|
177
|
+
when 'textfile_path'
|
178
|
+
@data[:textfile_paths] << value.text.strip
|
179
|
+
else
|
180
|
+
@data[:texts] << value.text.strip
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Contain data information for every field
|
4
|
+
# Params:
|
5
|
+
# * +data+ - Data (Text). This is the field content
|
6
|
+
# * +id+ - Identifier (Integer)
|
7
|
+
# * +type+ - May be "text", "textfile_path", "textfile_url" or "image_url"
|
8
|
+
class DataField
|
9
|
+
attr_reader :id, :type
|
10
|
+
|
11
|
+
def initialize(data, id, type)
|
12
|
+
@data = data
|
13
|
+
@id = id.to_i # TODO: revise where it comes from? Is it unique value?
|
14
|
+
@type = type.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def get(option = :raw)
|
18
|
+
case @type
|
19
|
+
when :text
|
20
|
+
return get_text(option)
|
21
|
+
when :textfile_path
|
22
|
+
return get_textfile_path(option)
|
23
|
+
when :textfile_url
|
24
|
+
return get_textfile_url(option)
|
25
|
+
when :image_url
|
26
|
+
return get_image_url(option)
|
27
|
+
end
|
28
|
+
raise ".get: data=#{@data}, type=#{@type}, option=#{option}"
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def get_text(option)
|
34
|
+
return to_screen(@data) if option == :screen
|
35
|
+
|
36
|
+
@data
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_textfile_path(option)
|
40
|
+
case option
|
41
|
+
when :raw
|
42
|
+
return @data
|
43
|
+
when :id
|
44
|
+
return "textfile_path.#{@id}"
|
45
|
+
when :decorated
|
46
|
+
content = File.new(@data).read
|
47
|
+
return "<pre>\n#{content}</pre>"
|
48
|
+
when :screen
|
49
|
+
return to_screen(@data)
|
50
|
+
end
|
51
|
+
raise ".get_textfile_path: data=#{@data}, type=#{@type}, option=#{option}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def get_textfile_url(option)
|
55
|
+
case option
|
56
|
+
when :raw
|
57
|
+
return @data
|
58
|
+
when :id
|
59
|
+
return "textfile_url.#{@id}"
|
60
|
+
when :decorated
|
61
|
+
return "<a href=\"#{@data}\">Textfile URL</a>"
|
62
|
+
when :screen
|
63
|
+
return to_screen(@data)
|
64
|
+
end
|
65
|
+
raise ".get_textfile_url: data=#{@data}, type=#{@type}, option=#{option}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_image_url(option)
|
69
|
+
case option
|
70
|
+
when :raw
|
71
|
+
return @data
|
72
|
+
when :id
|
73
|
+
return "image_url.#{@id}"
|
74
|
+
when :decorated
|
75
|
+
return "<img src=\"#{@data}\" alt=\"image\">"
|
76
|
+
when :screen
|
77
|
+
return to_screen(@data)
|
78
|
+
end
|
79
|
+
raise ".get_image_url: data=#{@data}, type=#{@type}, option=#{option}"
|
80
|
+
end
|
81
|
+
|
82
|
+
def to_screen(text)
|
83
|
+
return text[0, 7] + '...' + text[-15, 15] if text.size > 25
|
84
|
+
|
85
|
+
text
|
86
|
+
end
|
87
|
+
end
|