asker-tool 2.1.7 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/{LICENSE.txt → LICENSE} +0 -0
  3. data/README.md +14 -15
  4. data/bin/asker +1 -1
  5. data/lib/asker/ai/ai.rb +6 -3
  6. data/lib/asker/ai/ai_calculate.rb +20 -6
  7. data/lib/asker/ai/concept_ai.rb +12 -3
  8. data/lib/asker/ai/question.rb +28 -6
  9. data/lib/asker/ai/stages/base_stage.rb +45 -6
  10. data/lib/asker/ai/stages/stage_b.rb +90 -49
  11. data/lib/asker/ai/stages/stage_d.rb +69 -90
  12. data/lib/asker/ai/stages/stage_f.rb +47 -38
  13. data/lib/asker/ai/stages/stage_i.rb +79 -92
  14. data/lib/asker/ai/stages/stage_s.rb +41 -36
  15. data/lib/asker/ai/stages/stage_t.rb +114 -73
  16. data/lib/asker/application.rb +7 -16
  17. data/lib/asker/check_input/check_haml_data.rb +264 -0
  18. data/lib/asker/check_input/check_table.rb +104 -0
  19. data/lib/asker/check_input.rb +51 -0
  20. data/lib/asker/cli.rb +47 -44
  21. data/lib/asker/data/code.rb +5 -16
  22. data/lib/asker/data/concept.rb +71 -24
  23. data/lib/asker/data/project_data.rb +63 -0
  24. data/lib/asker/data/table.rb +2 -0
  25. data/lib/asker/data/template.rb +3 -1
  26. data/lib/asker/data/world.rb +8 -16
  27. data/lib/asker/displayer/code_displayer.rb +7 -0
  28. data/lib/asker/displayer/concept_ai_displayer.erb +10 -0
  29. data/lib/asker/displayer/concept_ai_displayer.rb +24 -22
  30. data/lib/asker/displayer/concept_displayer.rb +9 -4
  31. data/lib/asker/displayer/stats_displayer.rb +8 -0
  32. data/lib/asker/exporter/concept_ai_gift_exporter.rb +7 -11
  33. data/lib/asker/exporter/concept_ai_moodle_exporter.rb +45 -0
  34. data/lib/asker/exporter/concept_ai_yaml_exporter.rb +6 -3
  35. data/lib/asker/exporter/concept_doc_exporter.rb +12 -2
  36. data/lib/asker/exporter/data_gift_exporter.rb +31 -0
  37. data/lib/asker/exporter/output_file_exporter.rb +9 -6
  38. data/lib/asker/files/{config.ini → asker.ini} +14 -4
  39. data/lib/asker/files/language/du/connectors.yaml +81 -0
  40. data/lib/asker/files/language/du/mistakes.yaml +82 -0
  41. data/lib/asker/files/language/du/templates.yaml +28 -49
  42. data/lib/asker/files/language/en/templates.yaml +19 -19
  43. data/lib/asker/files/language/es/mistakes.yaml +9 -7
  44. data/lib/asker/files/language/es/templates.yaml +19 -19
  45. data/lib/asker/files/language/fr/connectors.yaml +68 -84
  46. data/lib/asker/files/language/fr/templates.yaml +22 -22
  47. data/lib/asker/formatter/concept_doc_formatter.rb +0 -4
  48. data/lib/asker/formatter/concept_string_formatter.rb +7 -4
  49. data/lib/asker/formatter/moodle/matching.erb +38 -0
  50. data/lib/asker/formatter/moodle/multichoice.erb +49 -0
  51. data/lib/asker/formatter/moodle/shortanswer.erb +30 -0
  52. data/lib/asker/formatter/moodle/truefalse.erb +47 -0
  53. data/lib/asker/formatter/question_gift_formatter.rb +21 -19
  54. data/lib/asker/formatter/question_moodle_formatter.rb +27 -0
  55. data/lib/asker/lang/lang_factory.rb +7 -1
  56. data/lib/asker/loader/code_loader.rb +1 -1
  57. data/lib/asker/loader/content_loader.rb +12 -14
  58. data/lib/asker/loader/directory_loader.rb +1 -8
  59. data/lib/asker/loader/embedded_file.rb +42 -0
  60. data/lib/asker/loader/file_loader.rb +1 -6
  61. data/lib/asker/loader/haml_loader.rb +9 -5
  62. data/lib/asker/loader/image_url_loader.rb +8 -9
  63. data/lib/asker/loader/input_loader.rb +5 -6
  64. data/lib/asker/loader/project_loader.rb +18 -10
  65. data/lib/asker/logger.rb +36 -9
  66. data/lib/asker/skeleton.rb +3 -2
  67. data/lib/asker/version.rb +9 -0
  68. data/lib/asker.rb +72 -43
  69. metadata +60 -18
  70. data/lib/asker/checker.rb +0 -455
  71. data/lib/asker/project.rb +0 -146
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative 'file_loader'
4
- require_relative '../logger'
5
4
 
6
5
  # Load input data from one directory
7
6
  module DirectoryLoader
@@ -13,7 +12,6 @@ module DirectoryLoader
13
12
  files = (Dir.new(dirname).entries - ['.', '..']).sort
14
13
  # Accept only HAML or XML files
15
14
  accepted = files.select { |f| %w[.xml .haml].include? File.extname(f) }
16
- Logger.verbose " * Input directory = #{Rainbow(dirname).bright}"
17
15
  DirectoryLoader.load_files(accepted, dirname)
18
16
  end
19
17
 
@@ -24,7 +22,7 @@ module DirectoryLoader
24
22
  return if Dir.exist? dirname
25
23
 
26
24
  msg = Rainbow("[ERROR] #{dirname} directory dosn't exist!").color(:red)
27
- Logger.verboseln msg
25
+ puts msg
28
26
  raise msg
29
27
  end
30
28
 
@@ -48,11 +46,6 @@ module DirectoryLoader
48
46
  # @param filepath (String) Path to input file
49
47
  # @param last (Boolean) True if it is the last filename
50
48
  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
49
  FileLoader.load(filepath)
57
50
  end
58
51
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'base64'
4
+
5
+ # Methods to load embedded files defined into asker input data file
6
+ # Example:
7
+ # * def line with :type = :image_url used to link external file as https://..."
8
+ # * def line with :type = :file used to load local file as image.png or file.txt"
9
+ module EmbeddedFile
10
+ ##
11
+ # @param value (String)
12
+ # @param localdir (String) Input file base folder
13
+ # @return Hash
14
+ # rubocop:disable Metrics/MethodLength
15
+ # rubocop:disable Metrics/AbcSize
16
+ def self.load(value, localdir)
17
+ # When filename is an URL
18
+ if value.start_with?('https://') || value.start_with?('http://')
19
+ return { text: "<img src=\"#{value}\" alt=\"image\" width=\"400\" height=\"300\">", file: :none }
20
+ end
21
+
22
+ filepath = File.join(localdir, value)
23
+ unless File.exist?(filepath)
24
+ # When filename is unkown!
25
+ Logger.verbose Rainbow("[ERROR] Unknown file! #{filepath}").red.bright
26
+ exit 1
27
+ end
28
+ # When filename is PNG, JPG o JPEG
29
+ if ['.png', '.jpg', '.jpeg'].include? File.extname(filepath)
30
+ # converts image into base64 strings
31
+ text = '<img src="@@PLUGINFILE@@/' + File.basename(filepath) \
32
+ + '" alt="imagen" class="img-responsive atto_image_button_text-bottom">'
33
+ data = '<file name="' + File.basename(filepath) + '" path="/" encoding="base64">' \
34
+ + Base64.strict_encode64(File.open(filepath, 'rb').read) + '</file>'
35
+ return { text: text, file: data }
36
+ end
37
+ # Suposse that filename is TXT file
38
+ return { text: "<pre>#{File.read(filepath)}</pre>", file: :none } if File.exist?(filepath)
39
+ end
40
+ # rubocop:enable Metrics/MethodLength
41
+ # rubocop:enable Metrics/AbcSize
42
+ end
@@ -2,21 +2,16 @@
2
2
 
3
3
  require_relative 'content_loader'
4
4
  require_relative 'haml_loader'
5
- require_relative '../logger'
6
5
 
7
6
  # Methods that load a filename and return list of concepts
8
7
  module FileLoader
9
- ##
10
- # Load asker data from file
11
- # @param filename (String) File name to be load
12
8
  def self.load(filename)
13
9
  if File.extname(filename).casecmp('.haml').zero?
14
10
  file_content = HamlLoader.load filename
15
11
  elsif File.extname(filename).casecmp('.xml').zero?
16
12
  file_content = File.read(filename)
17
13
  else
18
- msg = "[ERROR] FileLoader: Format error #{filename}"
19
- Logger.verbose msg
14
+ puts "[ERROR] FileLoader: Format error #{filename}"
20
15
  raise msg
21
16
  end
22
17
  ContentLoader.load(filename, file_content)
@@ -4,12 +4,16 @@ require 'haml'
4
4
 
5
5
  # HAML file loader
6
6
  module HamlLoader
7
- ##
8
- # Load HAML file name
9
- # @param filename (String) HAML file name
10
7
  def self.load(filename)
11
8
  template = File.read(filename)
12
- haml_engine = Haml::Engine.new(template)
13
- haml_engine.render
9
+ begin
10
+ haml_engine = Haml::Engine.new(template)
11
+ return haml_engine.render
12
+ rescue StandardError => e
13
+ puts "[ERROR] HamlLoader: Can't load <#{filename}> file!"
14
+ puts " => #{e}"
15
+ exit 0
16
+ end
14
17
  end
18
+
15
19
  end
@@ -1,8 +1,6 @@
1
1
 
2
2
  require 'net/http'
3
3
  require 'uri'
4
- require_relative '../application'
5
- require_relative '../logger'
6
4
 
7
5
  # Search URL images on Internet
8
6
  # Methods:
@@ -36,20 +34,21 @@ module ImageUrlLoader
36
34
  end
37
35
  end
38
36
  rescue
39
- Logger.verboseln '[ERROR] ImageUrlLoader'
40
- Logger.verboseln " => #{search_url}"
41
- Logger.verboseln ' => Check Internet connections'
42
- Logger.verboseln ' => Ensure URL is well formed'
37
+ puts '[ERROR] ImageUrlLoader'
38
+ puts " => #{search_url}"
39
+ puts ' => Check Internet connections'
40
+ puts ' => Ensure URL is well formed'
43
41
  end
44
42
  image_urls
45
43
  end
46
44
 
47
45
  def self.sanitize_string(input)
46
+ text = input.dup
48
47
  r = [ ['á', 'a'], ['é', 'e'], ['í', 'i'], ['ó', 'o'], ['ú', 'u'], ['ñ', 'n'], ['Á', 'A'], ['É', 'E'], ['Í', 'I'], ['Ó', 'O'], ['Ú', 'U'], ['Ñ', 'N']]
49
- r.each { |item| input.gsub!(item[0], item[1]) }
48
+ r.each { |item| text.gsub!(item[0], item[1]) }
50
49
  r = ['-', '_', ',', '"']
51
- r.each { |item| input.gsub!(item, ' ') }
52
- input.split(' ')
50
+ r.each { |item| text.gsub!(item, ' ') }
51
+ text.split(' ')
53
52
  end
54
53
 
55
54
  def self.sanitize_array(input)
@@ -3,30 +3,29 @@
3
3
  require_relative 'directory_loader'
4
4
  require_relative '../ai/concept_ai'
5
5
  require_relative '../data/world'
6
- require_relative '../logger'
7
6
 
8
7
  # Load DATA defined into our Project
9
8
  module InputLoader
10
9
  ##
11
10
  # Load input data from every input directory
12
11
  # @param inputdirs (Array)
13
- def self.load(inputdirs)
12
+ def self.load(inputdirs, internet = true)
14
13
  data = { concepts: [], codes: [], world: nil,
15
14
  concepts_ai: [], codes_ai: [] }
16
- Logger.verbose "\n[INFO] Loading input data"
15
+ #Logger.verboseln "\n[INFO] Loading input data"
17
16
  inputdirs.each do |dirname|
18
17
  temp = DirectoryLoader.load(dirname)
19
18
  data[:concepts] += temp[:concepts]
20
19
  data[:codes] += temp[:codes]
21
20
  end
22
- create_questions(data)
21
+ create_questions(data, internet)
23
22
  end
24
23
 
25
- private_class_method def self.create_questions(data)
24
+ private_class_method def self.create_questions(data, internet)
26
25
  # Create World data
27
26
  # * Calculate concept neighbours
28
27
  # * TO-DO: Calculate code neighbours
29
- data[:world] = World.new(data[:concepts])
28
+ data[:world] = World.new(data[:concepts], internet)
30
29
  # Create ConceptAI data (ConceptAI = concept + questions)
31
30
  data[:concepts].each do |concept|
32
31
  data[:concepts_ai] << ConceptAI.new(concept, data[:world])
@@ -1,8 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yaml'
4
- require_relative '../project'
5
- require_relative '../logger'
4
+ require_relative '../data/project_data'
6
5
 
7
6
  # Load params into Project class using arg input
8
7
  # * load
@@ -14,22 +13,26 @@ module ProjectLoader
14
13
  ##
15
14
  # Load project from args
16
15
  # @param args (String or Hash)
16
+ # rubocop:disable Metrics/MethodLength
17
17
  def self.load(args)
18
- project = Project.instance
18
+ project = ProjectData.instance
19
19
 
20
20
  if args.class == Hash
21
21
  project.param.merge!(args)
22
+ project.open
22
23
  return project
23
24
  elsif args.class == String
24
25
  ProjectLoader.load_from_string(args)
26
+ project.open
25
27
  return project
26
28
  end
27
29
 
28
30
  msg = '[ERROR] ProjectLoader:'
29
31
  msg += "Configuration params format is <#{pArgs.class}>!"
30
- Logger.verbose Rainbow(msg).red
32
+ puts Rainbow(msg).red
31
33
  raise msg
32
34
  end
35
+ # rubocop:enable Metrics/MethodLength
33
36
 
34
37
  ##
35
38
  # Load project from filepath. Options:
@@ -37,11 +40,13 @@ module ProjectLoader
37
40
  # * XML filepath
38
41
  # * YAML filepath
39
42
  # @param filepath (String)
43
+ # rubocop:disable Metrics/MethodLength
44
+ # rubocop:disable Metrics/AbcSize
40
45
  def self.load_from_string(filepath)
41
- project = Project.instance
46
+ project = ProjectData.instance
42
47
  unless File.exist?(filepath)
43
48
  msg = Rainbow("[ERROR] #{filepath} not found!").red.bright
44
- Logger.verbose msg
49
+ puts msg
45
50
  exit 1
46
51
  end
47
52
 
@@ -51,24 +56,27 @@ module ProjectLoader
51
56
  return project
52
57
  elsif File.extname(filepath) == '.yaml'
53
58
  return load_from_yaml(filepath)
54
- else
55
- error_loading(filepath)
56
59
  end
60
+ error_loading(filepath)
57
61
  end
62
+ # rubocop:enable Metrics/MethodLength
63
+ # rubocop:enable Metrics/AbcSize
58
64
 
65
+ # rubocop:disable Security/YAMLLoad
59
66
  def self.load_from_yaml(arg)
60
- project = Project.instance
67
+ project = ProjectData.instance
61
68
  project.param.merge!(YAML.load(File.open(arg)))
62
69
  project.set(:configfilename, arg)
63
70
  project.set(:projectdir, File.dirname(arg))
64
71
  project
65
72
  end
73
+ # rubocop:enable Security/YAMLLoad
66
74
 
67
75
  ##
68
76
  # Error found and exit application.
69
77
  def self.error_loading(arg)
70
78
  msg = Rainbow("[ERROR] Loading... #{arg}").red.bright
71
- Logger.verbose msg
79
+ puts msg
72
80
  exit 1
73
81
  end
74
82
  end
data/lib/asker/logger.rb CHANGED
@@ -1,20 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'application'
4
- require_relative 'project'
3
+ require 'singleton'
4
+ require_relative 'version'
5
5
 
6
6
  # Display and log project messages
7
- module Logger
8
- ##
9
- # Display and log text
7
+ class Logger
8
+ include Singleton
9
+ @attr_verbose = 'yes'
10
+
11
+ def set_verbose(value)
12
+ @attr_verbose = value
13
+ end
14
+
10
15
  def self.verbose(msg)
11
- puts msg if Application.instance.config['global']['verbose'] == 'yes'
12
- Project.instance.get(:logfile)&.write("#{msg}\n")
16
+ print msg if @attr_verbose == 'yes'
17
+ @logfile&.write(msg)
13
18
  end
14
19
 
15
- ##
16
- # Display and log text line
17
20
  def self.verboseln(msg)
18
21
  verbose(msg + "\n")
19
22
  end
23
+
24
+ def log(msg)
25
+ verbose(msg)
26
+ end
27
+
28
+ def logln(msg)
29
+ verboseln(msg)
30
+ end
31
+ ##
32
+ # Create or reset logfile
33
+ def self.create(logpath, logname)
34
+ @logfile = File.open(logpath, 'w')
35
+ @logfile.write('=' * 50 + "\n")
36
+ @logfile.write("Created by : #{Version::NAME}")
37
+ @logfile.write(" (version #{Version::VERSION})\n")
38
+ @logfile.write("File : #{logname}\n")
39
+ @logfile.write("Time : #{Time.new}\n")
40
+ @logfile.write("Author : David Vargas Ruiz\n")
41
+ @logfile.write('=' * 50 + "\n\n")
42
+ end
43
+
44
+ def self.close
45
+ @logfile.close
46
+ end
20
47
  end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'fileutils'
4
4
  require 'rainbow'
5
+ require_relative 'version'
5
6
 
6
7
  # Skeleton: create skeleton for asker input files
7
8
  # * create
@@ -33,8 +34,8 @@ module Skeleton
33
34
  # Create default configuration files
34
35
  def self.create_configuration
35
36
  puts "\n[INFO] Creating configuration files"
36
- src = File.join(File.dirname(__FILE__), 'files', 'config.ini')
37
- dst = File.join('config.ini')
37
+ src = File.join(File.dirname(__FILE__), 'files', Version::CONFIGFILE)
38
+ dst = File.join(Version::CONFIGFILE)
38
39
  copyfile(src, dst)
39
40
  end
40
41
 
@@ -0,0 +1,9 @@
1
+
2
+ # Global parameters
3
+ module Version
4
+ VERSION = '2.2.3'
5
+ NAME = 'asker'
6
+ GEM = 'asker-tool'
7
+ CONFIGFILE = 'asker.ini'
8
+ HOMEPAGE = "https://github.com/teuton-software/#{NAME}/tree/v2.2"
9
+ end
data/lib/asker.rb CHANGED
@@ -2,71 +2,100 @@
2
2
 
3
3
  require 'rainbow'
4
4
 
5
+ require_relative 'asker/skeleton'
6
+ require_relative 'asker/check_input'
7
+
5
8
  require_relative 'asker/displayer/concept_displayer'
6
9
  require_relative 'asker/displayer/stats_displayer'
7
10
  require_relative 'asker/exporter/output_file_exporter'
8
- require_relative 'asker/loader/project_loader'
9
- require_relative 'asker/loader/input_loader'
10
- require_relative 'asker/checker'
11
11
  require_relative 'asker/logger'
12
- require_relative 'asker/skeleton'
13
12
 
14
- ##
15
- # Asker main class
13
+ require_relative 'asker/loader/project_loader'
14
+ require_relative 'asker/loader/input_loader'
16
15
  class Asker
17
- ##
18
- # Create asker input demo files
19
- # @param dirpath (String)
20
- def self.create_input(dirpath)
21
- Skeleton.create_input(dirpath)
16
+ def self.init
17
+ Skeleton.create_configuration
22
18
  end
23
19
 
24
- ##
25
- # Create asker configuration files
26
- def self.create_configuration
27
- Skeleton.create_configuration
20
+ def self.new_input(dirpath)
21
+ Skeleton.create_input(dirpath)
28
22
  end
29
23
 
30
- ##
31
- # Checking input file syntax
32
- # @param filepath (String)
33
24
  def self.check(filepath)
34
- Checker.check(filepath)
25
+ CheckInput.new.file(filepath).check
35
26
  end
36
27
 
37
- ##
38
- # Start working
39
- # @param filepath (String) HAML or XML filepath
40
28
  def self.start(filepath)
41
- project, data = load_input(filepath)
29
+ project_data, data = load_input(filepath)
42
30
  ConceptDisplayer.show(data[:concepts])
43
- create_output(project, data)
31
+ create_output(project_data, data)
44
32
  end
45
33
 
46
- ##
47
- # Load input data
48
- # @param args (Hash)
49
34
  private_class_method def self.load_input(args)
50
- project = ProjectLoader.load(args)
51
- project.open # Open output files
52
- data = InputLoader.load(project.get(:inputdirs).split(','))
53
- [project, data]
35
+ init_project_data
36
+ project_data = ProjectLoader.load(args)
37
+ init_logger(project_data)
38
+
39
+ inputdirs = project_data.get(:inputdirs).split(',')
40
+ internet = Application.instance.config['global']['internet'] == 'yes'
41
+ data = InputLoader.load(inputdirs, internet)
42
+ [project_data, data]
43
+ end
44
+
45
+ private_class_method def self.init_project_data()
46
+ project_data = ProjectData.instance
47
+ outputdir = Application.instance.config['output']['folder']
48
+ project_data.set(:outputdir, outputdir)
49
+
50
+ formula_weights = Application.instance.config['ai']['formula_weights']
51
+ project_data.set(:weights, formula_weights)
52
+ end
53
+
54
+ private_class_method def self.init_logger(project_data)
55
+ # Create log file where to save log messages
56
+ Logger.create(project_data.get(:logpath),
57
+ project_data.get(:logname))
58
+ Logger.instance.set_verbose(Application.instance.config['verbose'])
59
+ Logger.verboseln '[INFO] Project open'
60
+ Logger.verboseln ' ├── inputdirs = ' + Rainbow(project_data.get(:inputdirs)).bright
61
+ Logger.verboseln ' └── process_file = ' + Rainbow(project_data.get(:process_file)).bright
54
62
  end
55
63
 
56
- ##
57
- # Create output files: Gift, YAML, TXT Doc
58
- # rubocop:disable Metrics/AbcSize
59
64
  private_class_method def self.create_output(project, data)
60
- Logger.verbose "\n[INFO] Creating output files"
61
- Logger.verbose ' ├── Gift questions file => ' +
62
- Rainbow(project.get(:outputpath)).bright
63
- Logger.verbose ' ├── YAML questions file => ' +
64
- Rainbow(project.get(:yamlpath)).bright
65
- Logger.verbose ' └── Lesson file => ' +
66
- Rainbow(project.get(:lessonpath)).bright
65
+ Logger.verboseln "\n[INFO] Creating output files"
66
+ m = ' ├── Gift questions file => '
67
+ m += if Application.instance.config['output']['gift'] == 'yes'
68
+ Rainbow(project.get(:outputpath)).bright
69
+ else
70
+ "#{project.get(:outputpath)} (No)"
71
+ end
72
+ Logger.verboseln m
73
+
74
+ m = ' ├── Lesson file => '
75
+ m += if Application.instance.config['output']['doc'] == 'yes'
76
+ Rainbow(project.get(:lessonpath)).bright
77
+ else
78
+ "#{project.get(:lessonpath)} (No)"
79
+ end
80
+ Logger.verboseln m
81
+
82
+ m = ' ├── YAML questions file => '
83
+ m += if Application.instance.config['output']['yaml'] == 'yes'
84
+ Rainbow(project.get(:yamlpath)).bright
85
+ else
86
+ "#{project.get(:yamlpath)} (No)"
87
+ end
88
+ Logger.verboseln m
89
+
90
+ m = ' └── Moodle XML file => '
91
+ m += if Application.instance.config['output']['moodle'] == 'yes'
92
+ Rainbow(project.get(:moodlepath)).bright
93
+ else
94
+ "#{project.get(:moodlepath)} (No)"
95
+ end
96
+ Logger.verboseln m
67
97
  OutputFileExporter.export(data, project)
68
98
  StatsDisplayer.show(data)
69
- project.close # Logger use Project.get(:logfile) until the end
99
+ Logger.close
70
100
  end
71
- # rubocop:enable Metrics/AbcSize
72
101
  end