Description:
added language identification using file extension git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@363 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r166:7417e965c968 - - 4 files changed: 57 inserted, 7 deleted

@@ -0,0 +1,23
1 + class AddCommonExtToLanguages < ActiveRecord::Migration
2 + def self.up
3 + # language.common_ext is a comma-separated list of common file
4 + # extensions.
5 + add_column :languages, :common_ext, :string
6 +
7 + # updating table information
8 + Language.reset_column_information
9 + common_ext = {
10 + 'c' => 'c',
11 + 'cpp' => 'cpp,cc',
12 + 'pas' => 'pas'
13 + }
14 + Language.find(:all).each do |lang|
15 + lang.common_ext = common_ext[lang.name]
16 + lang.save
17 + end
18 + end
19 +
20 + def self.down
21 + remove_column :languages, :common_ext
22 + end
23 + end
@@ -1,2 +1,24
1 1 class Language < ActiveRecord::Base
2 +
3 + @@languages_by_ext = {}
4 +
5 + def self.cache_ext_hash
6 + @@languages_by_ext = {}
7 + Language.find(:all).each do |language|
8 + language.common_ext.split(',').each do |ext|
9 + @@languages_by_ext[ext] = language
2 10 end
11 + end
12 + end
13 +
14 + def self.find_by_extension(ext)
15 + if @@languages_by_ext.length == 0
16 + Language.cache_ext_hash
17 + end
18 + if @@languages_by_ext.has_key? ext
19 + return @@languages_by_ext[ext]
20 + else
21 + return nil
22 + end
23 + end
24 + end
@@ -1,148 +1,152
1 1 class Submission < ActiveRecord::Base
2 2
3 3 belongs_to :language
4 4 belongs_to :problem
5 5 belongs_to :user
6 6
7 7 before_validation :assign_problem
8 8 before_validation :assign_language
9 9
10 10 validates_presence_of :source
11 11 validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
12 12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
13 13 validate :must_have_valid_problem
14 14 validate :must_specify_language
15 15
16 16 before_save :assign_latest_number_if_new_recond
17 17
18 18 def self.find_last_by_user_and_problem(user_id, problem_id)
19 19 last_sub = find(:first,
20 20 :conditions => {:user_id => user_id,
21 21 :problem_id => problem_id},
22 22 :order => 'number DESC')
23 23 return last_sub
24 24 end
25 25
26 26 def self.find_all_last_by_problem(problem_id)
27 27 # need to put in SQL command, maybe there's a better way
28 28 Submission.find_by_sql("SELECT * FROM submissions " +
29 29 "WHERE id = " +
30 30 "(SELECT MAX(id) FROM submissions AS subs " +
31 31 "WHERE subs.user_id = submissions.user_id AND " +
32 32 "problem_id = " + problem_id.to_s + " " +
33 33 "GROUP BY user_id) " +
34 34 "ORDER BY user_id")
35 35 end
36 36
37 37 def self.find_last_for_all_available_problems(user_id)
38 38 submissions = Array.new
39 39 problems = Problem.find_available_problems
40 40 problems.each do |problem|
41 41 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
42 42 submissions << sub if sub!=nil
43 43 end
44 44 submissions
45 45 end
46 46
47 47 def self.find_by_user_problem_number(user_id, problem_id, number)
48 48 Submission.find(:first,
49 49 :conditions => {
50 50 :user_id => user_id,
51 51 :problem_id => problem_id,
52 52 :number => number
53 53 })
54 54 end
55 55
56 56 def self.find_all_by_user_problem(user_id, problem_id)
57 57 Submission.find(:all,
58 58 :conditions => {
59 59 :user_id => user_id,
60 60 :problem_id => problem_id,
61 61 })
62 62 end
63 63
64 64 protected
65 65
66 66 def self.find_option_in_source(option, source)
67 67 if source==nil
68 68 return nil
69 69 end
70 70 i = 0
71 71 source.each_line do |s|
72 72 if s =~ option
73 73 words = s.split
74 74 return words[1]
75 75 end
76 76 i = i + 1
77 77 if i==10
78 78 return nil
79 79 end
80 80 end
81 81 return nil
82 82 end
83 83
84 - def self.find_language_in_source(source)
84 + def self.find_language_in_source(source, source_filename="")
85 85 langopt = find_option_in_source(/^LANG:/,source)
86 - if language = Language.find_by_name(langopt)
87 - return language
88 - elsif language = Language.find_by_pretty_name(langopt)
89 - return language
86 + if langopt
87 + return (Language.find_by_name(langopt) ||
88 + Language.find_by_pretty_name(langopt))
89 + else
90 + if source_filename
91 + return Language.find_by_extension(source_filename.split('.').last)
90 92 else
91 93 return nil
92 94 end
93 95 end
96 + end
94 97
95 98 def self.find_problem_in_source(source)
96 99 prob_opt = find_option_in_source(/^TASK:/,source)
97 100 if problem = Problem.find_by_name(prob_opt)
98 101 return problem
99 102 else
100 103 return nil
101 104 end
102 105 end
103 106
104 107 def assign_problem
105 108 if self.problem_id!=-1
106 109 begin
107 110 self.problem = Problem.find(self.problem_id)
108 111 rescue ActiveRecord::RecordNotFound
109 112 self.problem = nil
110 113 end
111 114 else
112 115 self.problem = Submission.find_problem_in_source(self.source)
113 116 end
114 117 end
115 118
116 119 def assign_language
117 - self.language = Submission.find_language_in_source(self.source)
120 + self.language = Submission.find_language_in_source(self.source,
121 + self.source_filename)
118 122 end
119 123
120 124 # validation codes
121 125 def must_specify_language
122 126 return if self.source==nil
123 127
124 128 # for output_only tasks
125 129 return if self.problem!=nil and self.problem.output_only
126 130
127 131 if self.language==nil
128 132 errors.add('source',"must specify programming language") unless self.language!=nil
129 133 end
130 134 end
131 135
132 136 def must_have_valid_problem
133 137 return if self.source==nil
134 138 if self.problem==nil
135 139 errors.add('problem',"must be specified.")
136 140 elsif (!self.problem.available) and (self.new_record?)
137 141 errors.add('problem',"must be valid.")
138 142 end
139 143 end
140 144
141 145 # callbacks
142 146 def assign_latest_number_if_new_recond
143 147 return if !self.new_record?
144 148 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
145 149 self.number = (latest==nil) ? 1 : latest.number + 1;
146 150 end
147 151
148 152 end
@@ -1,157 +1,158
1 1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 3 # then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 6 # to create the application database on another system, you should be using db:schema:load, not running
7 7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11
12 - ActiveRecord::Schema.define(:version => 20090206145016) do
12 + ActiveRecord::Schema.define(:version => 20090416235658) do
13 13
14 14 create_table "announcements", :force => true do |t|
15 15 t.string "author"
16 16 t.text "body"
17 17 t.boolean "published"
18 18 t.datetime "created_at"
19 19 t.datetime "updated_at"
20 20 t.boolean "frontpage", :default => false
21 21 t.boolean "contest_only", :default => false
22 22 end
23 23
24 24 create_table "configurations", :force => true do |t|
25 25 t.string "key"
26 26 t.string "value_type"
27 27 t.string "value"
28 28 t.datetime "created_at"
29 29 t.datetime "updated_at"
30 30 end
31 31
32 32 create_table "countries", :force => true do |t|
33 33 t.string "name"
34 34 t.datetime "created_at"
35 35 t.datetime "updated_at"
36 36 end
37 37
38 38 create_table "descriptions", :force => true do |t|
39 39 t.text "body"
40 40 t.boolean "markdowned"
41 41 t.datetime "created_at"
42 42 t.datetime "updated_at"
43 43 end
44 44
45 45 create_table "grader_processes", :force => true do |t|
46 46 t.string "host", :limit => 20
47 47 t.integer "pid"
48 48 t.string "mode"
49 49 t.boolean "active"
50 50 t.datetime "created_at"
51 51 t.datetime "updated_at"
52 52 t.integer "task_id"
53 53 t.string "task_type"
54 54 end
55 55
56 56 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
57 57
58 58 create_table "languages", :force => true do |t|
59 59 t.string "name", :limit => 10
60 60 t.string "pretty_name"
61 61 t.string "ext", :limit => 10
62 + t.string "common_ext"
62 63 end
63 64
64 65 create_table "messages", :force => true do |t|
65 66 t.integer "sender_id"
66 67 t.integer "receiver_id"
67 68 t.integer "replying_message_id"
68 69 t.text "body"
69 70 t.boolean "replied"
70 71 t.datetime "created_at"
71 72 t.datetime "updated_at"
72 73 end
73 74
74 75 create_table "problems", :force => true do |t|
75 76 t.string "name", :limit => 30
76 77 t.string "full_name"
77 78 t.integer "full_score"
78 79 t.date "date_added"
79 80 t.boolean "available"
80 81 t.string "url"
81 82 t.integer "description_id"
82 83 t.boolean "test_allowed"
83 84 t.boolean "output_only"
84 85 end
85 86
86 87 create_table "rights", :force => true do |t|
87 88 t.string "name"
88 89 t.string "controller"
89 90 t.string "action"
90 91 end
91 92
92 93 create_table "rights_roles", :id => false, :force => true do |t|
93 94 t.integer "right_id"
94 95 t.integer "role_id"
95 96 end
96 97
97 98 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
98 99
99 100 create_table "roles", :force => true do |t|
100 101 t.string "name"
101 102 end
102 103
103 104 create_table "roles_users", :id => false, :force => true do |t|
104 105 t.integer "role_id"
105 106 t.integer "user_id"
106 107 end
107 108
108 109 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
109 110
110 111 create_table "sessions", :force => true do |t|
111 112 t.string "session_id"
112 113 t.text "data"
113 114 t.datetime "updated_at"
114 115 end
115 116
116 117 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
117 118 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
118 119
119 120 create_table "sites", :force => true do |t|
120 121 t.string "name"
121 122 t.boolean "started"
122 123 t.datetime "start_time"
123 124 t.datetime "created_at"
124 125 t.datetime "updated_at"
125 126 t.integer "country_id"
126 127 t.string "password"
127 128 end
128 129
129 130 create_table "submissions", :force => true do |t|
130 131 t.integer "user_id"
131 132 t.integer "problem_id"
132 133 t.integer "language_id"
133 134 t.text "source"
134 135 t.binary "binary"
135 136 t.datetime "submitted_at"
136 137 t.datetime "compiled_at"
137 138 t.text "compiler_message"
138 139 t.datetime "graded_at"
139 140 t.integer "points"
140 141 t.text "grader_comment"
141 142 t.integer "number"
142 143 t.string "source_filename"
143 144 end
144 145
145 146 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
146 147 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
147 148
148 149 create_table "tasks", :force => true do |t|
149 150 t.integer "submission_id"
150 151 t.datetime "created_at"
151 152 t.integer "status"
152 153 t.datetime "updated_at"
153 154 end
154 155
155 156 create_table "test_requests", :force => true do |t|
156 157 t.integer "user_id"
157 158 t.integer "problem_id"
You need to be logged in to leave comments. Login now