| Name | Total Lines | Lines of Code | Total Coverage | Code Coverage |
|---|---|---|---|---|
| app/models/submission_file.rb | 214 | 157 | 64.02%
|
56.69%
|
Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.
1 class SubmissionFile < ActiveRecord::Base |
2 |
3 # Only allow alphanumeric characters, '.', '-', and '_' as |
4 # character set for submission files. |
5 FILENAME_SANITIZATION_REGEXP = Regexp.new('[^0-9a-zA-Z\.\-_]') |
6 # Character to be used as a replacement for all characters |
7 # matching the regular expression above |
8 SUBSTITUTION_CHAR = '_' |
9 |
10 belongs_to :submission |
11 has_many :annotations |
12 validates_associated :submission |
13 validates_presence_of :submission |
14 validates_presence_of :filename |
15 validates_presence_of :path |
16 |
17 validates_inclusion_of :is_converted, :in => [true, false] |
18 |
19 def get_file_type |
20 # This is where you can add more languages that SubmissionFile will |
21 # recognize. It will return the name of the language, which |
22 # SyntaxHighlighter can work with. |
23 case File.extname(filename) |
24 when ".sci" |
25 return "scilab" |
26 when ".java" |
27 return "java" |
28 when ".rb" |
29 return "ruby" |
30 when ".py" |
31 return "python" |
32 when ".js" |
33 return "javascript" |
34 when ".c" |
35 return "c" |
36 when ".scm" |
37 return "scheme" |
38 when ".ss" |
39 return "scheme" |
40 else |
41 return "unknown" |
42 end |
43 end |
44 |
45 def get_comment_syntax |
46 # This is where you can add more languages that SubmissionFile will |
47 # be able to insert comments into, for example when downloading annotations. |
48 # It will return a list, with the first element being the syntax to start a |
49 # comment and the second element being the syntax to end a comment. Use |
50 #the language's multiple line comment format. |
51 case File.extname(filename) |
52 when ".java", ".js", ".c" |
53 return ["/*", "*/"] |
54 when ".rb" |
55 return ["=begin\n", "\n=end"] |
56 when ".py" |
57 return ['"""', '"""'] |
58 when ".scm", ".ss" |
59 return ["#|","|#"] |
60 else |
61 return ["##","##"] |
62 end |
63 end |
64 |
65 def is_supported_image? |
66 #Here you can add more image types to support |
67 supported_formats = ['.jpeg', '.jpg', '.gif', '.png'] |
68 return supported_formats.include?(File.extname(filename)) |
69 end |
70 |
71 def is_pdf? |
72 return File.extname(filename) == '.pdf' |
73 end |
74 |
75 # Taken from http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/44936 |
76 def self.is_binary?(file_contents) |
77 return file_contents.size == 0 || |
78 file_contents.count("^ -~", "^\r\n") / file_contents.size > 0.3 || |
79 file_contents.count("\x00") > 0 |
80 end |
81 |
82 # Return an array representing the annotated areas of the submission file |
83 # |
84 # ===Returns: |
85 # |
86 # An array containing the extracted coordinates of all the annotations |
87 # associated with this file |
88 # |
89 # Return nil if this SubmissionFile is not a supported image. |
90 |
91 def get_annotation_grid |
92 return unless self.is_supported_image? || self.is_pdf? |
93 all_annotations = [] |
94 self.annotations.each do |annot| |
95 if annot.is_a?(ImageAnnotation) |
96 extracted_coords = annot.extract_coords |
97 return nil if extracted_coords.nil? |
98 all_annotations.push(extracted_coords) |
99 end |
100 end |
101 return all_annotations |
102 end |
103 |
104 def convert_pdf_to_jpg |
105 return unless MarkusConfigurator.markus_config_pdf_support && self.is_pdf? |
106 m_logger = MarkusLogger.instance |
107 storage_path = File.join(MarkusConfigurator.markus_config_pdf_storage, |
108 self.submission.grouping.group.repository_name, |
109 self.path) |
110 file_path = File.join(storage_path, self.filename.split('.')[0] + '.jpg') |
111 self.export_file(storage_path) |
112 # Remove any old copies of this image if they exist |
113 FileUtils.remove_file(file_path, true) if File.exists?(file_path) |
114 m_logger.log("Starting pdf conversion from #{File.join(storage_path, self.filename)} to #{file_path}") |
115 # ImageMagick can only save images with heights not exceeding 65500 pixels. |
116 # Larger images result in a conversion failure. |
117 begin |
118 # This is an ImageMagick command, see http://www.imagemagick.org/script/convert.php for documentation |
119 # For some reason, ImageMagick seemed to fail silently when not |
120 # redirecting the output to a log file. Let's redirect the output to |
121 # "something" |
122 `convert -limit memory #{MarkusConfigurator.markus_config_pdf_conv_memory_allowance} -limit map 0 -density 150 -resize 66% #{File.join(storage_path, self.filename)} -append #{file_path} >> #{File.join(RAILS_ROOT, "log", "export-pdf.log")}` |
123 # Sometimes, ImageMagick fails silently |
124 if File.exists?(file_path) |
125 m_logger.log("Successfully converted pdf file to jpg") |
126 else |
127 m_logger.log("Problem in PDF conversion") |
128 end |
129 rescue Exception => e |
130 m_logger.log("Pdf file couldn't be converted") |
131 end |
132 |
133 FileUtils.remove_file(File.join(storage_path, self.filename), true) |
134 self.is_converted = true |
135 self.save |
136 end |
137 |
138 # Return the contents of this SubmissionFile. Include annotations in the |
139 # file if include_annotations is true. |
140 def retrieve_file(include_annotations=false) |
141 student_group = submission.grouping.group |
142 repo = student_group.repo |
143 revision_number = submission.revision_number |
144 revision = repo.get_revision(revision_number) |
145 if revision.files_at_path(path)[filename].nil? |
146 raise I18n.t("results.could_not_find_file", |
147 :filename => filename, |
148 :repository_name => student_group.repository_name) |
149 end |
150 retrieved_file = repo.download_as_string(revision.files_at_path(path)[filename]) |
151 repo.close |
152 if include_annotations |
153 retrieved_file = add_annotations(retrieved_file) |
154 end |
155 return retrieved_file |
156 end |
157 |
158 # Export this file from the svn repository into storage_path |
159 # If a file of the same name as the one we are trying to export exists in |
160 # the given repository, it will be overwritten by the svn exports |
161 def export_file(storage_path) |
162 m_logger = MarkusLogger.instance |
163 m_logger.log("Exporting #{self.filename} from student repository") |
164 begin |
165 # Create the storage directories if they dont already exist |
166 FileUtils.makedirs(storage_path) |
167 # but deleted the file if it already exists |
168 if File.exists?(File.join(storage_path, self.filename)) |
169 FileUtils.rm(File.join(storage_path, self.filename)) |
170 end |
171 repo = submission.grouping.group.repo |
172 revision_number = submission.revision_number |
173 repo.export(File.join(storage_path, self.filename), |
174 File.join(self.path, self.filename), |
175 revision_number) |
176 end |
177 |
178 # Let's check the file exists befor claiming the file has been exported |
179 # properly |
180 if File.exists?(File.join(storage_path, self.filename)) |
181 m_logger.log("Successfuly exported #{self.filename} from student repository to #{File.join(storage_path, self.filename)}") |
182 else |
183 m_logger.log("Failed to export #{self.filename} from student |
184 repository") |
185 end |
186 end |
187 |
188 private |
189 |
190 def add_annotations(file_contents) |
191 comment_syntax = get_comment_syntax |
192 result = "" |
193 file_contents.split("\n").each_with_index do |contents, index| |
194 annotations.each do |annot| |
195 if index == annot.line_start.to_i - 1 |
196 text = AnnotationText.find(annot.annotation_text_id).content |
197 result = result.concat(I18n.t("graders.download.begin_annotation", |
198 :id => annot.annotation_number.to_s, |
199 :text => text, |
200 :comment_start => comment_syntax[0], |
201 :comment_end => comment_syntax[1]) + "\n") |
202 elsif index == annot.line_end.to_i |
203 result = result.concat(I18n.t("graders.download.end_annotation", |
204 :id => annot.annotation_number.to_s, |
205 :comment_start => comment_syntax[0], |
206 :comment_end => comment_syntax[1]) + "\n") |
207 end |
208 end |
209 result = result.concat(contents + "\n") |
210 end |
211 return result |
212 end |
213 end |
214 |
Generated on Tue Feb 07 00:07:36 -0500 2012 with rcov 0.9.10