reviser 0.0.1.1.pre.beta → 0.0.2.rc1

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +18 -0
  3. data/README.md +46 -0
  4. data/ext/valgrind.rb +21 -18
  5. data/ext/web_validators.rb +132 -0
  6. data/lang/HTML.yml +2 -14
  7. data/lib/component.rb +41 -39
  8. data/lib/components/archiver.rb +105 -101
  9. data/lib/components/checker.rb +46 -52
  10. data/lib/components/extractors.rb +121 -120
  11. data/lib/components/generator.rb +40 -37
  12. data/lib/components/generators.rb +113 -109
  13. data/lib/components/organiser.rb +165 -153
  14. data/lib/config.rb +53 -35
  15. data/lib/criteria/code_analysis.rb +54 -0
  16. data/lib/criteria/compilation.rb +42 -0
  17. data/lib/criteria/execution.rb +78 -0
  18. data/lib/exec.rb +109 -94
  19. data/lib/helpers/criteria.rb +152 -154
  20. data/lib/helpers/git.rb +23 -21
  21. data/lib/helpers/project.rb +198 -19
  22. data/lib/helpers/system.rb +50 -39
  23. data/lib/loggers/logger.rb +39 -30
  24. data/lib/loggers/modes.rb +118 -54
  25. data/lib/reviser.rb +63 -41
  26. data/res/css/style_logs.css +166 -0
  27. data/res/css/web_validators/css-base.css +733 -0
  28. data/res/css/web_validators/css-results.css +257 -0
  29. data/res/css/web_validators/html-base.css +746 -0
  30. data/res/css/web_validators/html-results.css +489 -0
  31. data/res/labys/labfich11.txt +19 -0
  32. data/res/labys/test.txt +3 -0
  33. data/res/labys/yoda.txt +19 -0
  34. data/res/scss/style_logs.scss +134 -0
  35. data/type/JavaProject.yml +18 -0
  36. data/type/Pendu.yml +22 -0
  37. data/type/Web.yml +23 -0
  38. metadata +144 -10
  39. data/ext/html_validator.rb +0 -21
  40. data/lib/helpers/code_analysis.rb +0 -64
  41. data/lib/helpers/compilation.rb +0 -40
  42. data/lib/helpers/execution.rb +0 -83
  43. data/lib/project.rb +0 -155
@@ -1,130 +1,134 @@
1
-
2
- # Module containing all methods for writing results.
3
- #
4
- # Convention over configuration !
5
- #
6
- # To add a new format, you need maybe to install a gem.
7
- # Find a gem which supports a specified format on rubygems.org.
8
- # Add the line "gem <gem>" in the Gemfile and execute "bundle install"
9
- #
10
- # Now, you can write the method corresponding to the format.
11
- # The name of the method corresponds to the format.
12
- # For example, if you want to generate a word file (.doc), the name of the method will be: "doc"
13
- # Don't forget to require the gem: "require <gem>" at the beginning of the method !
14
- # the header of method looks like the following block:
15
- #
16
- # def <format> (ext = '<format>')
17
- # require <gem>
18
- # ...
19
- # end
20
- #
21
- # To write results, you have to go through in the data instance variable.
22
- # data is a [Hash]:
23
- # - key: The person's name.
24
- # - value: Results of analysis
25
- #
26
- # Each value of data is also a [Hash]:
27
- # - key: the name of criterion checked.
28
- # - value: The result of criterion.
29
- #
30
- #
31
- # @author Renan Strauss
32
- # @author Yann Prono
33
- #
34
- module Components
35
- module Generators
36
-
37
- # Generates the CSV file
38
- def csv(ext = '.csv')
39
- require 'csv'
40
- CSV.open(out(ext), 'wb') do |f|
41
- # Criterias as columns
42
- f << (criterias).unshift('projet')
43
-
44
- # Values for each project as rows
45
- @data.keys.each do |proj|
46
- f << @data[proj].values.unshift(proj)
1
+ module Reviser
2
+ module Components
3
+
4
+ # Module containing all methods for writing results.
5
+ #
6
+ # Convention over configuration !
7
+ #
8
+ # To add a new format, you need maybe to install a gem.
9
+ # Find a gem which supports a specified format on rubygems.org.
10
+ # Add the line "gem <gem>" in the Gemfile and execute "bundle install"
11
+ #
12
+ # Now, you can write the method corresponding to the format.
13
+ # The name of the method corresponds to the format.
14
+ # For example, if you want to generate a word file (.doc), the name of the method will be: "doc"
15
+ # Don't forget to require the gem: "require <gem>" at the beginning of the method !
16
+ # the header of method looks like the following block:
17
+ #
18
+ # def <format> (ext = '<format>') require <gem> ... end
19
+ #
20
+ # To write results, you have to go through in the data instance variable.
21
+ # data is a [Hash]:
22
+ #
23
+ # - key: The person's name.
24
+ # - value: Results of analysis
25
+ #
26
+ # Each value of data is also a [Hash]:
27
+ #
28
+ # - key: the name of criterion checked.
29
+ # - value: The result of criterion.
30
+ #
31
+ #
32
+ # @author Renan Strauss
33
+ # @author Yann Prono
34
+ #
35
+ module Generators
36
+
37
+ # Generates the CSV file
38
+ def csv(ext = '.csv')
39
+ require 'csv'
40
+ CSV.open(out(ext), 'wb') do |f|
41
+ # Criterias as columns
42
+ f << (criterias).unshift('projet')
43
+
44
+ # Values for each project as rows
45
+ @data.keys.each do |proj|
46
+ f << @data[proj].values.unshift(proj)
47
+ end
47
48
  end
48
49
  end
49
- end
50
50
 
51
- # Generates a Excel file
52
- def xls(ext = '.xls')
53
- require 'spreadsheet'
54
- Spreadsheet.client_encoding = 'UTF-8'
55
- book = Spreadsheet::Workbook.new
56
- sheet = book.create_worksheet :name => 'Results'
51
+ # Generates a Excel file
52
+ def xls(ext = '.xls')
53
+ require 'spreadsheet'
54
+ Spreadsheet.client_encoding = 'UTF-8'
55
+ book = Spreadsheet::Workbook.new
56
+ sheet = book.create_worksheet :name => 'Results'
57
57
 
58
- # header
59
- format = Spreadsheet::Format.new :weight => :bold, :size => 14 ,
60
- :horizontal_align => :center
58
+ # header
59
+ format = Spreadsheet::Format.new :weight => :bold, :size => 14 ,
60
+ :horizontal_align => :center
61
61
 
62
- (criterias.unshift('Projets')).each_with_index do |crit, i|
63
- sheet[0,i] = crit
64
- sheet.column(i).width = (crit.size * format.font.size/10) + 5
65
- end
66
- sheet.row(0).default_format = format
67
- sheet.row(0).height = 18
62
+ (criterias.unshift('Projets')).each_with_index do |crit, i|
63
+ sheet[0,i] = crit
64
+ sheet.column(i).width = (crit.size * format.font.size/10) + 5
65
+ end
66
+ sheet.row(0).default_format = format
67
+ sheet.row(0).height = 18
68
68
 
69
- # Values for each project as rows
70
- @data.keys.each_with_index do |proj, i|
71
- sheet.insert_row(i+1,@data[proj].values.unshift(proj))
72
- end
69
+ # Values for each project as rows
70
+ @data.keys.each_with_index do |proj, i|
71
+ sheet.insert_row(i+1,@data[proj].values.unshift(proj))
72
+ end
73
73
 
74
- book.write out(ext)
75
- end
74
+ book.write out(ext)
75
+ end
76
76
 
77
- # Generates an HTML file
78
- def html(ext = '.html')
79
- out = '<!DOCTYPE html><html><head>'
80
- out += '<meta charset= "UTF-8">'
81
- out += "<link rel=\"stylesheet\" href=\"#{Cfg[:res_dir]}/css/component.css\" />"
82
- out += "<link rel=\"stylesheet\" href=\"#{Cfg[:res_dir]}/css/normalize.css\" />"
83
- out += '<script src="res/js/component.css"></script>'
84
- out += '<title>Results</title>'
85
- out += "</head>\n<body><table><thead>"
86
- out += ' <tr>'
87
-
88
- criterias.unshift('Projet').each { |crit| out += "<th>#{crit}</th>" }
89
-
90
- out += '</tr></thead><tbody>'
91
- # Values for each project as rows
92
- @data.keys.each do |proj|
93
- out += "<tr><th>#{proj}</th>"
94
- @data[proj].each do |k, v|
95
- if k.to_s[/(compilation|execution)/]
96
- out += '<td class="console">'
97
- else
98
- out += '<td>'
99
- end
77
+ # Generates an HTML file
78
+ def html(ext = '.html')
79
+ out = '<!DOCTYPE html><html><head>'
80
+ out += '<meta charset= "UTF-8">'
81
+ out += "<link rel=\"stylesheet\" href=\"#{Cfg[:res_dir]}/css/component.css\" />"
82
+ out += "<link rel=\"stylesheet\" href=\"#{Cfg[:res_dir]}/css/normalize.css\" />"
83
+ out += '<script src="res/js/component.css"></script>'
84
+ out += '<title>Results</title>'
85
+ out += "</head>\n<body><table><thead>"
86
+ out += ' <tr>'
87
+
88
+ criterias.unshift('Projet').each { |crit| out += "<th>#{crit}</th>" }
89
+
90
+ out += '</tr></thead><tbody>'
91
+ # Values for each project as rows
92
+ @data.keys.each do |proj|
93
+ out += "<tr><th>#{proj}</th>"
94
+ @data[proj].each do |k, v|
95
+ if k.to_s[/(compilation|execution)/]
96
+ out += '<td class="console">'
97
+ else
98
+ out += '<td>'
99
+ end
100
100
 
101
- # If file, generate a link, else do nothing !
102
- out += file?(v) && "<pre><a href=\"#{v.gsub(' ','%20')}\" target=\"_blank\">#{v}</a></pre></td>" ||"<pre>#{v}</pre></td>"
101
+ # If file, generate a link, else do nothing !
102
+ out += file?(v) && "<pre><a href=\"#{v.gsub(' ','%20')}\" target=\"_blank\">#{v}</a></pre></td>" ||"<pre>#{v}</pre></td>"
103
103
 
104
+ end
105
+ out += '</tr>'
104
106
  end
105
- out += '</tr>'
106
- end
107
107
 
108
- out += '</tbody></table>'
108
+ out += '</tbody></table>'
109
109
 
110
- out += '<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>'
111
- out += '<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.min.js"></script>'
112
- #out += "<script src=\"#{Cfg[:res_dir]}/js/jquery.stickyheader.js\"></script>"
110
+ out += '<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>'
111
+ out += '<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery-throttle-debounce/1.1/jquery.ba-throttle-debounce.min.js"></script>'
112
+ #out += "<script src=\"#{Cfg[:res_dir]}/js/jquery.stickyheader.js\"></script>"
113
113
 
114
- out += '</body></html>'
114
+ out += '</body></html>'
115
115
 
116
- File.open(out(ext), 'w') { |f| f.write(out) }
117
- end
116
+ File.open(out(ext), 'w') { |f| f.write(out) }
117
+ end
118
118
 
119
- private
119
+ private
120
120
 
121
- def out(ext)
122
- Cfg[:out] + ext
123
- end
121
+ def out(ext)
122
+ Cfg[:out] + ext
123
+ end
124
124
 
125
- def file? path
126
- File.exist? path.to_s
127
- end
125
+ # Checks if result is a existing file.
126
+ # @param path [String] of possible file
127
+ # @return [Boolean] True if the path is a real file.
128
+ def file? path
129
+ File.exist? path.to_s
130
+ end
128
131
 
132
+ end
129
133
  end
130
134
  end
@@ -1,181 +1,193 @@
1
1
  require 'fileutils'
2
2
  require_relative '../helpers/git'
3
- require_relative '../project'
4
-
5
-
6
- module Components
7
-
8
- # Class which organizes all directories to simplify projects' analysis.
9
- # Organiser renames projects folders and organises the whole of projects
10
- # in order to have a structured folder (files at the root of folder)
11
- # During this step, a git repository will be created, with an initial commit.
12
- #
13
- # @author Yann Prono
14
- # @author Renan Strauss
15
- #
16
- class Organiser < Component
17
-
18
- # Include all tools
19
- include Helpers::Git
20
- include Project
21
-
22
- # All entries to ignore during sort and organization
23
- $rejected_entries = ['.', '..', '__MACOSX']
24
-
25
- # initialize tool.
26
- # Organiser has to :
27
- # - get all students
28
- # - get all groups (classes)
29
- # - get all teams (binoms)
30
- # - get all unknown soldiers ...
31
- def initialize(data)
32
- raise ArgumentError if data == nil || !data.respond_to?('each')
33
-
34
- super data
35
-
36
- @directory = Cfg[:dest]
37
- @path = @directory
38
- @git = nil
39
- @students = []
40
- @binoms = []
41
- @groups = []
42
- @unknown = []
43
-
44
- # How many patterns are in the pseudo-regex?
45
- @count_patterns = {}
46
- end
3
+ require_relative '../helpers/project'
47
4
 
48
- # Rename directories more clearly.
49
- # @param entry [String] path of the entry to rename.
50
- def rename(entry)
51
- name = format entry
52
- if name != nil
53
- if name != entry
54
- new_path = File.join(@directory, name)
55
- FileUtils.mkdir_p new_path.split(File.basename(new_path))[0]
56
- FileUtils.mv(File.join(@directory, entry), new_path, :force => true)
57
-
58
- @logger.h2 Logger::INFO, "renaming #{File.basename(entry)} to #{File.basename(name)}"
5
+
6
+ module Reviser
7
+ module Components
8
+
9
+ # Class which organizes all directories to simplify projects' analysis.
10
+ # Organiser renames projects folders and organises the whole of projects
11
+ # in order to have a structured folder (files at the root of folder)
12
+ # During this step, a git repository will be created, with an initial commit.
13
+ #
14
+ # The other important task of Organiser is to detect all students, all binoms and all groups,
15
+ # thank to the directory name.
16
+ #
17
+ # @author Yann Prono
18
+ # @author Renan Strauss
19
+ #
20
+ class Organiser < Component
21
+
22
+ # Include all tools
23
+ include Helpers::Git
24
+ include Helpers::Project::Naming
25
+
26
+ # All entries to ignore during sort and organization
27
+ $rejected_entries = ['.', '..', '__MACOSX']
28
+
29
+ # initializes tool.
30
+ # The initialization will prepare all to
31
+ # crate a git repo, save all detected students as well someone who
32
+ # doesn't respect convention ...
33
+ Organiser
34
+ def initialize(data)
35
+ raise ArgumentError if data == nil || !data.respond_to?('each')
36
+
37
+ super data
38
+
39
+ @directory = Cfg[:dest]
40
+ @path = @directory
41
+ @git = nil
42
+ @students = []
43
+ @binoms = []
44
+ @projects_per_group = {}
45
+ @unknown = []
46
+ @results = []
47
+
48
+ # How many patterns are in the pseudo-regex?
49
+ @count_patterns = {}
50
+ end
51
+
52
+ # Renames directories more clearly.
53
+ # @param entry [String] path of the entry to rename.
54
+ def rename(entry)
55
+ name = format entry
56
+ if name != nil
57
+ if name != entry
58
+ new_path = File.join(@directory, name)
59
+ FileUtils.mkdir_p(new_path.split(File.basename(new_path))[0])
60
+ FileUtils.mv(File.join(@directory, entry), new_path, :force => true)
61
+
62
+ @logger.h2 Logger::INFO, "renaming #{File.basename(entry)} to #{File.basename(name)}"
63
+ else
64
+ @logger.h2 Logger::INFO, "#{entry} has not been renamed}, already formatted"
65
+ end
59
66
  else
60
- @logger.h2 Logger::INFO, "#{entry} has not been renamed}, already formatted"
67
+ @logger.h2 Logger::ERROR, "Can't rename #{File.basename(entry)} - Datas not found in name"
61
68
  end
62
- else
63
- @logger.h2 Logger::ERROR, "Can't rename #{File.basename(entry)} - Datas not found in name"
69
+ name
64
70
  end
65
- end
66
71
 
67
- # Method which moves project's directories in order to
68
- # have the same hierarchy for all project.
69
- # @param entry [String] path of the entry to structure.
70
- def structure(entry)
71
- chdir entry
72
- @logger.h2 Logger::INFO, "#{entry} => #{@path}"
73
- level = 0
74
- @logger.h2 Logger::INFO, "Files in #{@path}"
75
- @logger.h3 Logger::INFO, "#{all}"
76
-
77
- @logger.h2 Logger::INFO, "Dirs in #{@path}"
78
- @logger.h3 Logger::INFO, "#{directories}"
79
- # directory to delete if the project directory is not structured
80
- rm = directories.first
81
-
82
- # Loop to find the core of project
83
- #
84
- # Basically running through
85
- # each level of directories
86
- # while there are only directories
87
- # in the current directory
88
- #
89
- while all == directories
90
- level += 1
91
- @logger.h2 Logger::DEBUG, "Level += 1\nPath = #{@path}"
92
- chdir directories.first
93
- @logger.h2 Logger::DEBUG, "New path = #{@path}"
94
- end
72
+ # Method which moves project's directories in order to
73
+ # have the same hierarchy for all project.
74
+ # @param entry [String] path of the entry to structure.
75
+ def structure(entry)
76
+ chdir entry
77
+ @logger.h2 Logger::INFO, "#{entry} => #{@path}"
78
+ level = 0
79
+ @logger.h2 Logger::INFO, "Files in #{@path}"
80
+ @logger.h3 Logger::INFO, "#{all}"
81
+
82
+ @logger.h2 Logger::INFO, "Dirs in #{@path}"
83
+ @logger.h3 Logger::INFO, "#{directories}"
84
+ # directory to delete if the project directory is not structured
85
+ rm = directories.first
86
+
87
+ # Loop to find the core of project
88
+ #
89
+ # Basically running through
90
+ # each level of directories
91
+ # while there are only directories
92
+ # in the current directory
93
+ #
94
+ while all == directories
95
+ level += 1
96
+ @logger.h2 Logger::DEBUG, "Level += 1\nPath = #{@path}"
97
+ chdir directories.first
98
+ @logger.h2 Logger::DEBUG, "New path = #{@path}"
99
+ end
95
100
 
96
- # If the core of project is not at the root of directory ...
97
- if level >= 1
98
- Dir.glob(File.join(@path,'*')).each do |file|
99
- FileUtils.mv(file,File.join(@directory, entry))
101
+ # If the core of project is not at the root of directory ...
102
+ if level >= 1
103
+ Dir.glob(File.join(@path,'*')).each do |file|
104
+ FileUtils.mv(file,File.join(@directory, entry))
105
+ end
106
+ @logger.h2 Logger::INFO, "Structuring #{File.join(@path)}"
107
+ @logger.h2 Logger::INFO, "Removing #{File.join(@directory, entry, rm)}"
108
+ FileUtils.rm_rf(File.join(@directory, entry, rm))
100
109
  end
101
- @logger.h2 Logger::INFO, "Structuring #{File.join(@path)}"
102
- @logger.h2 Logger::INFO, "Removing #{File.join(@directory, entry, rm)}"
103
- FileUtils.rm_rf(File.join(@directory, entry, rm))
104
- end
105
110
 
106
- @path = @directory
107
- end
111
+ @path = @directory
112
+ end
108
113
 
109
- # Initialize a git repo.
110
- # @param entry [String] Directory to process.
111
- def git(entry)
112
- Dir.chdir File.join(@directory, entry) do
113
- git_init
114
- git_add
115
- git_commit
114
+ # Initializes a git repo.
115
+ # @param entry [String] Directory to process.
116
+ def git(entry)
117
+ Dir.chdir File.join(@directory, entry) do
118
+ git_init
119
+ git_add
120
+ git_commit
121
+ end
116
122
  end
117
- end
118
123
 
119
124
 
120
- # Method which run the organiser.
121
- # It will apply all importants methods of this class for each project.
122
- def run
123
- @data.each do |entry|
124
- @logger.h1 Logger::INFO, "Work on #{entry}"
125
- @logger.h1 Logger::INFO, "Structure project"
126
- structure entry
125
+ # Method which runs the organiser.
126
+ # It will apply all importants methods of this class for each project.
127
+ def run
128
+ @data.each do |entry|
129
+
130
+ @logger.h1 Logger::INFO, "Work on #{entry}"
131
+ @logger.h1 Logger::INFO, "Structure project"
132
+ structure entry
127
133
 
128
- @logger.h1 Logger::INFO, "Initializing git repo"
129
- git entry
134
+ @logger.h1 Logger::INFO, "Initializing git repo"
135
+ git entry
130
136
 
131
- @logger.h1 Logger::INFO, "Renaming directory"
132
- rename entry
133
- @logger.newline
134
- end
137
+ @logger.h1 Logger::INFO, "Renaming directory"
138
+ new_path = rename entry
139
+ @logger.newline
140
+ @results << new_path
141
+ end
135
142
 
136
- @logger.h1 Logger::INFO, "#{@groups.size} group#{'s' if @groups.size > 1} have been detected"
137
- @logger.h1 Logger::INFO, "#{@students.size} student#{'s' if @students.size > 1} have been detected"
138
- @logger.h1 Logger::INFO, "#{@binoms.size} binom#{'s' if @binoms.size > 1} have been detected"
143
+ @logger.h1 Logger::INFO, "#{@projects_per_group.keys.size} group#{'s' if @projects_per_group.keys.size > 1} have been detected"
144
+ @logger.h1 Logger::INFO, "#{@students.size} student#{'s' if @students.size > 1} have been detected"
145
+ @logger.h1 Logger::INFO, "#{@binoms.size} binom#{'s' if @binoms.size > 1} have been detected"
139
146
 
140
- log_resume(@groups, Logger::INFO, "Groups:")
141
- log_resume(@students, Logger::INFO, "Students:")
142
- log_resume(@binoms, Logger::INFO, "Binoms:")
147
+ formalized = []
148
+ @projects_per_group.each { |k,v| formalized << "#{k.to_s}: #{v} project#{'s' if v > 1}" }
149
+ log_resume(formalized, Logger::INFO, "Groups:")
150
+ log_resume(@students, Logger::INFO, "Students:")
151
+ log_resume(@binoms, Logger::INFO, "Binoms:")
143
152
 
144
- log_resume(@unknown, Logger::ERROR, "\n#{@unknown.size} projects didn't matched with regex")
145
- end
153
+ log_resume(@unknown, Logger::ERROR, "\n#{@unknown.size} projects didn't matched with regex")
154
+
155
+ @results
156
+ end
146
157
 
147
- private
148
- #
149
- # Take attention : these accessors
150
- # are meant to be used by structure
151
- # only ! Because @path is initialized
152
- # for that, and used only in this def
153
- #
154
- def all
155
- Dir.entries(@path) - $rejected_entries
156
- end
158
+ private
159
+ #
160
+ # Take attention : these accessors
161
+ # are meant to be used by structure
162
+ # only ! Because @path is initialized
163
+ # for that, and used only in this def
164
+ #
165
+ def all
166
+ Dir.entries(@path) - $rejected_entries
167
+ end
157
168
 
158
- def directories
159
- all.select { |e| File.directory? File.join(@path, e) }
160
- end
169
+ def directories
170
+ all.select { |e| File.directory? File.join(@path, e) }
171
+ end
161
172
 
162
- def chdir(dir)
163
- base = @path
164
- @path = File.join(base, dir)
165
- end
173
+ def chdir(dir)
174
+ base = @path
175
+ @path = File.join(base, dir)
176
+ end
166
177
 
167
178
 
168
- # Shortuct for logs ...
169
- # @param data [Array] to loop.
170
- # @param severity [Integer] Severity of the log.
171
- # @param message [String] Message to log before writing data..
172
- def log_resume(data ,severity, message)
173
- unless data.empty?
174
- @logger.newline
175
- @logger.h1 severity, message
176
- data.each {|d| @logger.h2 severity, "#{d}" }
179
+ # Shortcut for logs ...
180
+ # @param data [Array] to loop.
181
+ # @param severity [Integer] Severity of the log.
182
+ # @param message [String] Message to log before writing data.
183
+ def log_resume(data ,severity, message)
184
+ unless data.empty?
185
+ @logger.newline
186
+ @logger.h1 severity, message
187
+ data.each {|d| @logger.h2 severity, "#{d}" }
188
+ end
177
189
  end
190
+
178
191
  end
179
-
180
192
  end
181
193
  end