diff --git a/tutor/app/assets/javascripts/solutions.js.coffee b/tutor/app/assets/javascripts/solutions.js.coffee index d1f32efd..addad684 100644 --- a/tutor/app/assets/javascripts/solutions.js.coffee +++ b/tutor/app/assets/javascripts/solutions.js.coffee @@ -277,6 +277,11 @@ debug_console = -> # Author: Rami Khalil + Khaled Helmy @jump_state = (state_number) -> highlight_line variables[state_number]['line'] + if state_number isnt 0 + clear_console() + $("#output_section").html variables[state_number]["stream"] + if variables[state_number]["exception"] + runtime_error variables[state_number]["exception"] update_memory_contents state_number # [View Variables - Story 3.7] diff --git a/tutor/app/assets/stylesheets/application.css b/tutor/app/assets/stylesheets/application.css index 2288e797..a3d0bb9a 100644 --- a/tutor/app/assets/stylesheets/application.css +++ b/tutor/app/assets/stylesheets/application.css @@ -11,6 +11,7 @@ *= require_self *= require_tree . */ += require posts .side-left { height:700px; diff --git a/tutor/app/assets/stylesheets/posts.css.scss b/tutor/app/assets/stylesheets/posts.css.scss index 1a7e1539..bec73e3c 100644 --- a/tutor/app/assets/stylesheets/posts.css.scss +++ b/tutor/app/assets/stylesheets/posts.css.scss @@ -1,3 +1,8 @@ -// Place all the styles related to the posts controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ +.greyLine { + border-bottom: 1px solid #D0D0D0; +} + +.reply { + padding-left:30px; + border-bottom: 1px solid #D0D0D0; +} \ No newline at end of file diff --git a/tutor/app/controllers/posts_controller.rb b/tutor/app/controllers/posts_controller.rb index afb13e76..345a576b 100644 --- a/tutor/app/controllers/posts_controller.rb +++ b/tutor/app/controllers/posts_controller.rb @@ -53,7 +53,9 @@ def destroy # Author: Ahmed Atef def show @post = Post.find(params[:id]) - @replies = @post.replies.order("created_at desc") + @post.views_count = @post.views_count + 1 + @post.save + @replies = @post.replies.order("created_at asc") end # [Add Post - Story 1.13] diff --git a/tutor/app/models/debugger.rb b/tutor/app/models/debugger.rb index 23fa4028..a430ab1e 100644 --- a/tutor/app/models/debugger.rb +++ b/tutor/app/models/debugger.rb @@ -62,21 +62,22 @@ def input(input) # Authors: Mussab ElDash + Rami Khalil def start(class_name, input) $all = [] + source_path = "#{Rails.root.to_s}/#{Solution::JAVA_PATH}" Dir.chdir(Solution::CLASS_PATH){ begin - $input, $output, $error, $wait_thread = Open3.popen3("jdb", class_name, *input) + $input, $output, $error, $wait_thread = Open3.popen3("jdb", + "-sourcepath", source_path, class_name, *input) buffer_until_ready input "stop in #{class_name}.main" buffer_until_ready input "run" - num = get_line + nums = get_line locals = get_variables - hash = {:line => num, :locals => locals} - $all << hash + nums[:locals] = locals + $all << nums debug rescue => e unless e.message === 'Exited' - p e.message return false end end @@ -84,7 +85,6 @@ def start(class_name, input) begin Process.kill("TERM", $wait_thread.pid) rescue => e - p e.message end return $all end @@ -99,10 +99,14 @@ def debug while counter < 100 && !$input.closed? do begin input "step" - num = get_line - locals = get_variables - hash = {:line => num, :locals => locals} - $all << hash + nums = get_line + locals = [] + begin + locals = get_variables + rescue => e + end + nums[:locals] = locals + $all << nums counter += 1 rescue => e $input.close @@ -118,24 +122,83 @@ def debug # Author: Mussab ElDash def get_line out_stream = buffer_until_complete - list_of_lines = out_stream.split(/\n+/) - before_last_line = list_of_lines[-2] - /, line=\d+/ =~ before_last_line - before_last_regex_capture = $& - /\d+/ =~ before_last_regex_capture - before_last_regex_capture = $& - last_line = list_of_lines[-2] - /^\d+/=~ last_line - last_regex_capture = $& - if last_regex_capture - return last_regex_capture.to_i - elsif before_last_regex_capture - return before_last_regex_capture.to_i + exceptions = has_exception out_stream + stream = get_stream out_stream + /,\sline=\d+/ =~ out_stream + line_first = $& + begin + input "list" + out_stream = buffer_until_complete + /\n\d+\s=>/ =~ out_stream + line_second = $& + rescue => e + end + if line_first + line_first = line_first[7..-1] + exceptions[:line] = line_first.to_i + if $all[-1] + exceptions[:stream] = "#{$all[-1][:stream]}#{stream}" + else + exceptions[:stream] = "" + end + return exceptions + elsif line_second + line_second = line_second[0..-4] + exceptions[:line] = line_second.to_i + return exceptions else raise 'Exited' end end + # [Debugger: Debug - Story 3.6] + # Checks if there is a runtime error thrown + # Parameters: + # line: The line to be checked if it has a runtime error + # Returns: A hash of the exception and its explanation if exists + # Author: Mussab ElDash + def get_stream(line) + /^>\s.+\n/ =~ line + stream = $& + if stream + stream = stream[2..-1] + p stream + return stream + end + return "" + end + + # [Debugger: Debug - Story 3.6] + # Checks if there is a runtime error thrown + # Parameters: + # line: The line to be checked if it has a runtime error + # Returns: A hash of the exception and its explanation if exists + # Author: Mussab ElDash + def has_exception(line) + /Exception occurred: / =~ line + if $& + exception = get_exception + return {:status => false, :exception => Executer.get_runtime_explaination(exception)} + end + return {:status => true} + end + + # [Debugger: Debug - Story 3.6] + # Checks if there is a runtime error thrown + # Parameters: + # line: The line to be checked if it has a runtime error + # Returns: A hash of the exception and its explanation if exists + # Author: Mussab ElDash + def get_exception + input "step" + out_stream = buffer_until_complete + ragex_first = /[[:space:]]+at\s[[:alnum:]]+\.main\([[:alnum:]]+\.java:\d+\)/m + regex_second = /[[:space:]]+The application exited\n*/ + regex = /#{ragex_first}#{regex_second}/ + out_stream = out_stream.sub(regex, "") + return out_stream + end + # [Debugger: Debug - Story 3.6] # Create a java file and start debugging # Parameters: @@ -153,7 +216,7 @@ def self.debug(student_id, problem_id, code, input) return {:success => false, data: compile_status} end debugger = Debugger.new - class_name = solution.class_file_name + class_name = solution.file_name debugging = debugger.start(class_name, input.split(" ")) java_file = solution.java_file_name true, true class_file = solution.class_file_name true, true diff --git a/tutor/app/models/executer.rb b/tutor/app/models/executer.rb index ad5512e6..ce21e6c9 100644 --- a/tutor/app/models/executer.rb +++ b/tutor/app/models/executer.rb @@ -87,18 +87,41 @@ def self.remove_class_name(file_name, error, sub_name) # A hash [error, explanation], where error is the runtime error and explanation # is a custom message to explain the error # Author: Ahmed Akram + def self.get_runtime_error(file_name, sub_name) + execute_res = remove_class_name(file_name, execute_res, sub_name) + return get_runtime_explaination(execute_res) + end + + # [Debugger: Debug - Story 3.6] + # Returns a message explaining what this error is + # Parameters: + # exception: The exception to be explained + # Returns: The Explanation of the exception given + # Author: Mussab ElDash + def self.get_runtime_explaination(exception) + if exception.include?("/ by zero") || exception.include?("ArithmeticException") + message = "Division by Zero results in infinity, " + + "which computers can not understand. Be careful !" + return {errors: exception, explanation: message} + else + message = "To be set Runtime Error!" + return {errors: exception, explanation: message} + end + end + + # [Compiler: Test - Story 3.15] + # Returns the runtime error and a message + # Parameters: + # file_name: The submitted file name + # sub_name: The name to replace the class name + # Returns: A hash [error, explanation], where error is the runtime error and explanation + # is a custom message to explain the error + # Author: Ahmed Akram def self.get_runtime_error file_name = @solution.file_name sub_name = 'CoolSoft' @execute_res = remove_class_name(file_name, @execute_res, sub_name) - if @execute_res.include?("/ by zero") - message = "Division by Zero results in infinity, "\ - "which computers can not understand. Be careful !" - return msg = {errors: @execute_res, explanation: message} - else - message = "To be set Runtime Error!" - return msg = {errors: @execute_res, explanation: message} - end + return get_runtime_explaination @execute_res end # [Compiler: Test - Story 3.15] @@ -112,4 +135,4 @@ def self.get_output return {success: true, message: @execute_res} end -end \ No newline at end of file +end diff --git a/tutor/app/models/post.rb b/tutor/app/models/post.rb index 844360c1..c66e387b 100644 --- a/tutor/app/models/post.rb +++ b/tutor/app/models/post.rb @@ -17,6 +17,12 @@ class Post < ActiveRecord::Base #Methods + def most_recent_reply + reply = Reply.first(:order => 'created_at DESC', + :conditions => ['post_id = ?', self.id]) + return reply + end + # [Advanced Search - Story 1.23] # search for posts # Parameters: hash of search options @@ -44,4 +50,5 @@ def self.search(params) end end end + end diff --git a/tutor/app/views/discussion_boards/show.html.erb b/tutor/app/views/discussion_boards/show.html.erb index 9688d8b1..7becd032 100644 --- a/tutor/app/views/discussion_boards/show.html.erb +++ b/tutor/app/views/discussion_boards/show.html.erb @@ -1,30 +1,71 @@ -
<%= link_to post.title, :controller => 'posts', :action=> 'show', - :id => post.id,:method => :get, class: "btn btn-success" %> - | - <%= post.views_count %> -|||||
Post | +Replies | +Post Owner | +Last Reply | +Created | +Views | +
+ <%= link_to post.title, :controller => 'posts', :action=> 'show', + :id => post.id,:method => :get, class: + "btn btn-success" %>+ |
+
+ <%= post.replies.count %> + |
+
+ <%= post.owner.name %>'s post + |
+ + <% if post.most_recent_reply %> + <%= distance_of_time_in_words_to_now post.most_recent + _reply.created_at %> ago by + <% if post.most_recent_reply.owner_type == "Lecturer" %> + <%= link_to post.most_recent_reply.owner.name, + "/lecturers/{post.most_recent_reply.owner_id}" %> + <% end %> + <% if post.most_recent_reply.owner_type == "Student" %> + <%= link_to post.most_recent_reply.owner.name, + "/students/{post.most_recent_reply.owner_id}" %> + <% end %> + <% if post.most_recent_reply.owner_type == "TeachingAssistant" %> + <%= link_to post.most_recent_reply.owner.name, + "/teachingassistants/{post.most_recent_reply.owner_id}" %> + <% end %> + <% else %> + No replies + <% end %> + | +
+ <%=distance_of_time_in_words_to_now post.created_at %> ago
+ + |
+
+ <%= post.views_count %> + |
+
<%= @post.owner.name %>
+<%= @post.content %>
+<%= distance_of_time_in_words_to_now @post. + created_at %> ago
+<%= reply.content %>
<%= distance_of_time_in_words_to_now reply. + created_at %> ago
+<%= flash[:alert] %>
Time spent: 0:00 @@ -68,6 +67,7 @@