tmis 0.1.3
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.
- checksums.yaml +7 -0
- data/COPYING +674 -0
- data/README.md +44 -0
- data/Rakefile +64 -0
- data/bin/tmis +4 -0
- data/lib/tmis/engine/database.rb +58 -0
- data/lib/tmis/engine/export/timetable_exporter.rb +366 -0
- data/lib/tmis/engine/import/abstract_spreadsheet.rb +53 -0
- data/lib/tmis/engine/import/spreadsheet_roo.rb +136 -0
- data/lib/tmis/engine/import/timetable_manager.rb +110 -0
- data/lib/tmis/engine/import/timetable_reader.rb +79 -0
- data/lib/tmis/engine/mailer/mailer.rb +51 -0
- data/lib/tmis/engine/migrations/10_create_speciality_subjects.rb +17 -0
- data/lib/tmis/engine/migrations/11_create_emails.rb +10 -0
- data/lib/tmis/engine/migrations/12_add_indexes.rb +32 -0
- data/lib/tmis/engine/migrations/1_create_groups.rb +11 -0
- data/lib/tmis/engine/migrations/2_create_subgroups.rb +10 -0
- data/lib/tmis/engine/migrations/3_create_subjects.rb +11 -0
- data/lib/tmis/engine/migrations/4_create_cabinets.rb +12 -0
- data/lib/tmis/engine/migrations/5_create_lecturers.rb +14 -0
- data/lib/tmis/engine/migrations/6_create_studies.rb +15 -0
- data/lib/tmis/engine/migrations/7_create_courses.rb +9 -0
- data/lib/tmis/engine/migrations/8_create_specialities.rb +9 -0
- data/lib/tmis/engine/migrations/9_create_semesters.rb +10 -0
- data/lib/tmis/engine/models/cabinet.rb +18 -0
- data/lib/tmis/engine/models/course.rb +11 -0
- data/lib/tmis/engine/models/email.rb +19 -0
- data/lib/tmis/engine/models/group.rb +31 -0
- data/lib/tmis/engine/models/lecturer.rb +45 -0
- data/lib/tmis/engine/models/semester.rb +4 -0
- data/lib/tmis/engine/models/speciality.rb +3 -0
- data/lib/tmis/engine/models/speciality_subject.rb +6 -0
- data/lib/tmis/engine/models/study.rb +56 -0
- data/lib/tmis/engine/models/subgroup.rb +21 -0
- data/lib/tmis/engine/models/subject.rb +19 -0
- data/lib/tmis/engine/verificator.rb +96 -0
- data/lib/tmis/interface/forms/about.rb +24 -0
- data/lib/tmis/interface/forms/console.rb +28 -0
- data/lib/tmis/interface/forms/debug_console.rb +32 -0
- data/lib/tmis/interface/forms/edit_study.rb +110 -0
- data/lib/tmis/interface/forms/expand_changes.rb +128 -0
- data/lib/tmis/interface/forms/export_general_timetable.rb +68 -0
- data/lib/tmis/interface/forms/export_group_timetable.rb +158 -0
- data/lib/tmis/interface/forms/export_lecturer_timetable.rb +171 -0
- data/lib/tmis/interface/forms/find.rb +71 -0
- data/lib/tmis/interface/forms/import.rb +36 -0
- data/lib/tmis/interface/forms/settings.rb +125 -0
- data/lib/tmis/interface/forms/ui_about.rb +88 -0
- data/lib/tmis/interface/forms/ui_console.rb +68 -0
- data/lib/tmis/interface/forms/ui_debug_console.rb +82 -0
- data/lib/tmis/interface/forms/ui_edit_study.rb +202 -0
- data/lib/tmis/interface/forms/ui_expand_changes.rb +134 -0
- data/lib/tmis/interface/forms/ui_export_general_timetable.rb +142 -0
- data/lib/tmis/interface/forms/ui_export_group_timetable.rb +160 -0
- data/lib/tmis/interface/forms/ui_export_lecturer_timetable.rb +160 -0
- data/lib/tmis/interface/forms/ui_find.rb +77 -0
- data/lib/tmis/interface/forms/ui_import.rb +134 -0
- data/lib/tmis/interface/forms/ui_settings.rb +417 -0
- data/lib/tmis/interface/mainwindow.rb +933 -0
- data/lib/tmis/interface/models/cabinet_table_model.rb +133 -0
- data/lib/tmis/interface/models/course_table_model.rb +87 -0
- data/lib/tmis/interface/models/group_table_model.rb +190 -0
- data/lib/tmis/interface/models/lecturer_table_model.rb +111 -0
- data/lib/tmis/interface/models/semester_table_model.rb +137 -0
- data/lib/tmis/interface/models/speciality_subject_table_model.rb +288 -0
- data/lib/tmis/interface/models/speciality_table_model.rb +87 -0
- data/lib/tmis/interface/models/study_table_model.rb +323 -0
- data/lib/tmis/interface/models/subgroup_table_model.rb +136 -0
- data/lib/tmis/interface/models/subject_table_model.rb +90 -0
- data/lib/tmis/interface/ui_mainwindow.rb +928 -0
- data/lib/tmis.rb +45 -0
- data/spec/config.rb +49 -0
- data/spec/database_spec.rb +18 -0
- data/spec/export/timetable_exporter_mocks.rb +20 -0
- data/spec/export/timetable_exporter_spec.rb +34 -0
- data/spec/factories/factories.rb +65 -0
- data/spec/import/test_data/raspisanie_2013.csv +104 -0
- data/spec/import/timetable_importer_mocks.rb +6 -0
- data/spec/import/timetable_manager_spec.rb +16 -0
- data/spec/import/timetable_reader_spec.rb +111 -0
- data/spec/import/timetable_roo_spec.rb +48 -0
- data/spec/mailer/mailer_spec.rb +37 -0
- data/spec/mainwindow_spec.rb +18 -0
- data/spec/models/cabinet_spec.rb +33 -0
- data/spec/models/course_spec.rb +26 -0
- data/spec/models/group_spec.rb +33 -0
- data/spec/models/lecturer_spec.rb +38 -0
- data/spec/models/semester_spec.rb +26 -0
- data/spec/models/speciality_spec.rb +26 -0
- data/spec/models/speciality_subject_spec.rb +9 -0
- data/spec/models/study_spec.rb +9 -0
- data/spec/models/subgroup_spec.rb +26 -0
- data/spec/models/subject_spec.rb +39 -0
- metadata +290 -0
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Timetable Management Information System
|
2
|
+
|
3
|
+
Информационная система управления расписанием, предназначенная для учебных заведений среднего профессионального образования.
|
4
|
+
|
5
|
+
Возможности:
|
6
|
+
* Импорт и экспорт расписания в распространенные форматы;
|
7
|
+
* Экспорт расписания для преподавателей и групп на основе общего;
|
8
|
+
* Рассылка по электронной почте;
|
9
|
+
* Отображение расписания в табличной форме по дням и группам;
|
10
|
+
* Удобство редактирования засчёт ассоциирования предметов, преподавателей и кабинетов;
|
11
|
+
* Отслеживание ошибок;
|
12
|
+
* Хранение расписания за любой период;
|
13
|
+
* Работа с базой данных, как с простым файлом;
|
14
|
+
* Широкие возможности настройки;
|
15
|
+
* Кроссплатформенность.
|
16
|
+
|
17
|
+
Запланированы:
|
18
|
+
* Интерактивная справка;
|
19
|
+
* Веб-интерфейс;
|
20
|
+
* Генерация расписания;
|
21
|
+
* Оптимизация расписания.
|
22
|
+
|
23
|
+
Для получения дополнительной информации воспользуйтесь [вики проекта](https://github.com/Noein/TMIS/wiki).
|
24
|
+
|
25
|
+
Copyright © 2012 Милешкин Владислав <noein93@gmail.com>
|
26
|
+
|
27
|
+
TMIS является свободным программным обеспечением и распространяется на условиях GNU GPLv3. Текст лицензии можно найти в файле COPYING, а также по ссылке: [www.gnu.org/licenses/gpl](http://www.gnu.org/licenses/gpl).
|
28
|
+
|
29
|
+
## Скриншоты
|
30
|
+
| [](http://i.imgur.com/lG7gdit.png) | [](http://i.imgur.com/YjFu5ok.png) |
|
31
|
+
| ----------------------------------------------------------------------------- |----------------------------------------------------------------------------------|
|
32
|
+
| [](http://i.imgur.com/qGHDB9L.png) | [](http://i.imgur.com/OmSapi0.png) |
|
33
|
+
| [](http://i.imgur.com/9N8GGQn.png) | [](http://i.imgur.com/JUKmxzA.png) |
|
34
|
+
| [](http://i.imgur.com/OJS5v2v.png) | [](http://i.imgur.com/pOBbGDg.png) |
|
35
|
+
| [](http://i.imgur.com/cf43WDC.png) | |
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
## Сообщения об ошибках
|
44
|
+
Для сообщений об ошибках вы можете использовать баг-трекер на github или связаться с автором по почте.
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'rake/testtask'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
|
4
|
+
def rbuic4(arg)
|
5
|
+
puts "rbuic4 #{arg}"
|
6
|
+
%x[rbuic4 #{arg}]
|
7
|
+
end
|
8
|
+
|
9
|
+
def compile_form(path)
|
10
|
+
path = "lib/tmis/" + path
|
11
|
+
path[/([a-z_0-9\/]+\/)([a-z_0-9\.]+)/i]
|
12
|
+
dirs, file = $1, $2
|
13
|
+
rbuic4(path << ' -o ' << dirs << 'ui_' << file.sub('.ui', '.rb'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove_form(path)
|
17
|
+
rm ("lib/tmis/" + path)
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Run tests"
|
21
|
+
|
22
|
+
#Rake::TestTask.new do |t|
|
23
|
+
# t.libs << 'test'
|
24
|
+
# t.libs << 'lib/tmis'
|
25
|
+
#end
|
26
|
+
|
27
|
+
task :test => [:compile, :spec]
|
28
|
+
task :default => [:test]
|
29
|
+
|
30
|
+
task :spec do
|
31
|
+
puts %x[rspec]
|
32
|
+
end
|
33
|
+
|
34
|
+
#RSpec::Core::RakeTask.new(:spec)
|
35
|
+
|
36
|
+
task :compile do
|
37
|
+
compile_form 'interface/mainwindow.ui'
|
38
|
+
compile_form 'interface/forms/settings.ui'
|
39
|
+
compile_form 'interface/forms/import.ui'
|
40
|
+
compile_form 'interface/forms/export_general_timetable.ui'
|
41
|
+
compile_form 'interface/forms/export_lecturer_timetable.ui'
|
42
|
+
compile_form 'interface/forms/export_group_timetable.ui'
|
43
|
+
compile_form 'interface/forms/edit_study.ui'
|
44
|
+
compile_form 'interface/forms/console.ui'
|
45
|
+
compile_form 'interface/forms/about.ui'
|
46
|
+
compile_form 'interface/forms/expand_changes.ui'
|
47
|
+
compile_form 'interface/forms/find.ui'
|
48
|
+
compile_form 'interface/forms/debug_console.ui'
|
49
|
+
end
|
50
|
+
|
51
|
+
task :clean do
|
52
|
+
remove_form 'interface/ui_mainwindow.rb'
|
53
|
+
remove_form 'interface/forms/ui_settings.rb'
|
54
|
+
remove_form 'interface/forms/ui_import.rb'
|
55
|
+
remove_form 'interface/forms/ui_export_general_timetable.rb'
|
56
|
+
remove_form 'interface/forms/ui_export_lecturer_timetable.rb'
|
57
|
+
remove_form 'interface/forms/ui_export_group_timetable.rb'
|
58
|
+
remove_form 'interface/forms/ui_edit_study.rb'
|
59
|
+
remove_form 'interface/forms/ui_console.rb'
|
60
|
+
remove_form 'interface/forms/ui_about.rb'
|
61
|
+
remove_form 'interface/forms/ui_expand_changes.rb'
|
62
|
+
remove_form 'interface/forms/ui_find.rb'
|
63
|
+
remove_form 'interface/forms/ui_debug_console.rb'
|
64
|
+
end
|
data/bin/tmis
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
# Copyright (C) 2013 Vladislav Mileshkin
|
4
|
+
#
|
5
|
+
# This file is part of TMIS.
|
6
|
+
#
|
7
|
+
# TMIS is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# TMIS is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with TMIS. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
20
|
+
require 'active_record'
|
21
|
+
require 'singleton'
|
22
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
23
|
+
class Database
|
24
|
+
include Singleton
|
25
|
+
|
26
|
+
attr_reader :path
|
27
|
+
|
28
|
+
def connect_to(path)
|
29
|
+
@path = path
|
30
|
+
if ActiveRecord::Base.connected?
|
31
|
+
ActiveRecord::Base.remove_connection
|
32
|
+
connect path
|
33
|
+
else
|
34
|
+
connect path
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def connected?
|
40
|
+
ActiveRecord::Base.connected?
|
41
|
+
end
|
42
|
+
|
43
|
+
def disconnect
|
44
|
+
ActiveRecord::Base.remove_connection; self
|
45
|
+
end
|
46
|
+
|
47
|
+
def transaction(&block)
|
48
|
+
ActiveRecord::Base.transaction(&block); self
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def connect(path)
|
53
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: path)
|
54
|
+
ActiveRecord::Base.timestamped_migrations = false
|
55
|
+
ActiveRecord::Migrator.up (File.dirname(__FILE__) << '/migrations')
|
56
|
+
self
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,366 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require 'contracts'
|
4
|
+
require 'spreadsheet'
|
5
|
+
require 'benchmark'
|
6
|
+
require_relative '../import/abstract_spreadsheet'
|
7
|
+
require_relative '../models/lecturer'
|
8
|
+
require_relative '../models/group'
|
9
|
+
require_relative '../models/study'
|
10
|
+
#include Contracts
|
11
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
12
|
+
class AbstractTimetableExportStratagy
|
13
|
+
#Contract Or[Range,Array] => Any
|
14
|
+
def initialize(dates)
|
15
|
+
raise NotImplementedError
|
16
|
+
end
|
17
|
+
|
18
|
+
#Contract None => Or[Range,Array]
|
19
|
+
def rows
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
#Contract None => Or[Range,Array]
|
24
|
+
def columns
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
#Contract Any => Any
|
29
|
+
def row_value(row_entity)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
#Contract Any => Any
|
34
|
+
def column_value(col_entity)
|
35
|
+
raise NotImplementedError
|
36
|
+
end
|
37
|
+
|
38
|
+
#Contract Any, Any => ArrayOf[Study]
|
39
|
+
def studies(row_entity, col_entity)
|
40
|
+
raise NotImplementedError
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class TimetableExporter
|
45
|
+
#Contract IsA[AbstractSpreadsheet], IsA[AbstractTimetableExportStratagy] => Any
|
46
|
+
def initialize(table, stratagy)
|
47
|
+
@table = table
|
48
|
+
@stratagy = stratagy
|
49
|
+
end
|
50
|
+
|
51
|
+
#Contract None => IsA[AbstractSpreadsheet]
|
52
|
+
def export
|
53
|
+
rows_export
|
54
|
+
@table
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def rows_export
|
59
|
+
rows.each do |entity, rows|
|
60
|
+
rows_format(rows)
|
61
|
+
@table[rows[0] + 1, 1] = @stratagy.row_value(entity)
|
62
|
+
(1..6).each do |row|
|
63
|
+
pair_format(rows, row)
|
64
|
+
@table[(rows[0] - 1) + row * 2, 2] = "#{row} пара"
|
65
|
+
end
|
66
|
+
columns_export(entity, rows)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def columns_export(row_ent, rows)
|
71
|
+
columns.each do |ent, cols|
|
72
|
+
columns_format(rows, cols)
|
73
|
+
@table[rows[0], cols[0]] = @stratagy.column_value(ent)
|
74
|
+
export_studies(@stratagy.studies(row_ent, ent), rows, cols)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
#Contract ArrayOf[Study], [Pos, Pos], [Pos, Pos] => Any
|
79
|
+
def export_studies(studies, rows, cols)
|
80
|
+
prepare_studies(studies).each do |number, studies|
|
81
|
+
if studies.size == 1
|
82
|
+
@table.merge(real_row(rows, number), cols[0], real_row(rows, number) + 1, cols[0])
|
83
|
+
@table.merge(real_row(rows, number), cols[1], real_row(rows, number) + 1, cols[1])
|
84
|
+
end
|
85
|
+
studies.each_with_index do |study, i|
|
86
|
+
@table[real_row(rows, number) + i, cols[0]] = study.to_s
|
87
|
+
@table[real_row(rows, number) + i, cols[1]] = study.cabinet.title
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def rows
|
93
|
+
@stratagy.rows.zip((1..(13 * @stratagy.rows.to_a.size)).each_slice(13).map{ |i| [i.first, i.last] })
|
94
|
+
end
|
95
|
+
|
96
|
+
def columns
|
97
|
+
@stratagy.columns.zip((3..(@stratagy.columns.to_a.size * 2) + (3 - 1)).each_slice(2))
|
98
|
+
end
|
99
|
+
|
100
|
+
#Contract ArrayOf[Study] => ({ Pos => ArrayOf[Study] })
|
101
|
+
def prepare_studies(studies)
|
102
|
+
studies.sort_by(&:number).group_by(&:number)
|
103
|
+
end
|
104
|
+
|
105
|
+
#Contract ArrayOf[Pos], Pos => Pos
|
106
|
+
def real_row(rows, number)
|
107
|
+
(rows[0] - 1) + (number * 2)
|
108
|
+
end
|
109
|
+
|
110
|
+
def rows_format(rows)
|
111
|
+
@table.merge(rows[0] + 1, 1, rows[1], 1)
|
112
|
+
format = Spreadsheet::Format.new
|
113
|
+
format.rotation = 90
|
114
|
+
format.horizontal_align = :center
|
115
|
+
format.vertical_align = :middle
|
116
|
+
format.top = :medium
|
117
|
+
format.bottom = :medium
|
118
|
+
format.right = :medium
|
119
|
+
format.left = :medium
|
120
|
+
@table.format(rows[0] + 1, 1, format)
|
121
|
+
end
|
122
|
+
|
123
|
+
def pair_format(rows, row)
|
124
|
+
@table.row((rows[0] - 1) + row * 2).height = 30
|
125
|
+
@table.row(rows[0] + row * 2).height = 30
|
126
|
+
@table.merge((rows[0] - 1) + row * 2, 2, rows[0] + row * 2, 2)
|
127
|
+
end
|
128
|
+
|
129
|
+
def columns_format(rows, cols)
|
130
|
+
@table.column(cols[0]).width = 25
|
131
|
+
@table.merge(rows[0], cols[0], rows[0], cols[1])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
class GeneralTimetableExportStratagy < AbstractTimetableExportStratagy
|
136
|
+
#Contract Or[Range,Array] => Any
|
137
|
+
def initialize(dates)
|
138
|
+
@dates = dates
|
139
|
+
end
|
140
|
+
|
141
|
+
#Contract None => Or[Range,Array]
|
142
|
+
def rows
|
143
|
+
@dates
|
144
|
+
end
|
145
|
+
|
146
|
+
#Contract None => Or[Range,Array]
|
147
|
+
def columns
|
148
|
+
Group.all.sort_by(&:title_for_sort)
|
149
|
+
end
|
150
|
+
|
151
|
+
#Contract Any => Any
|
152
|
+
def row_value(date)
|
153
|
+
date.strftime('%A')
|
154
|
+
end
|
155
|
+
|
156
|
+
#Contract Any => Any
|
157
|
+
def column_value(group)
|
158
|
+
group.title
|
159
|
+
end
|
160
|
+
|
161
|
+
#Contract Any, Any => ArrayOf[Study]
|
162
|
+
def studies(date, group)
|
163
|
+
Study.of_group_and_its_subgroups(group).where(date: date).to_a
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class LecturerTimetableExportStratagy < AbstractTimetableExportStratagy
|
168
|
+
#Contract Or[Range,Array], Lecturer => Any
|
169
|
+
def initialize(dates, lecturer)
|
170
|
+
@dates = dates
|
171
|
+
@lecturer = lecturer
|
172
|
+
end
|
173
|
+
|
174
|
+
#Contract None => Or[Range,Array]
|
175
|
+
def rows
|
176
|
+
@dates
|
177
|
+
end
|
178
|
+
|
179
|
+
# TODO Изменить контракты
|
180
|
+
#Contract None => RespondTo[:zip]
|
181
|
+
def columns
|
182
|
+
Group.where(id: @lecturer.studies.where(date: @dates, groupable_type: 'Group').select(:groupable_id))
|
183
|
+
end
|
184
|
+
|
185
|
+
#Contract Any => Any
|
186
|
+
def row_value(date)
|
187
|
+
date.strftime('%A')
|
188
|
+
end
|
189
|
+
|
190
|
+
#Contract Any => Any
|
191
|
+
def column_value(group)
|
192
|
+
group.title
|
193
|
+
end
|
194
|
+
|
195
|
+
#Contract Any, Any => ArrayOf[Study]
|
196
|
+
def studies(date, group)
|
197
|
+
Study.of_group_and_its_subgroups(group).where(date: date, lecturer_id: @lecturer).to_a
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
class TimetableExporter2
|
202
|
+
#Contract IsA[AbstractSpreadsheet], IsA[AbstractTimetableExportStratagy] => Any
|
203
|
+
def initialize(table, stratagy)
|
204
|
+
@table = table
|
205
|
+
@stratagy = stratagy
|
206
|
+
end
|
207
|
+
|
208
|
+
#Contract None => IsA[AbstractSpreadsheet]
|
209
|
+
def export
|
210
|
+
rows_export
|
211
|
+
@table
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
def rows_export
|
216
|
+
rows.each do |entity, rows|
|
217
|
+
rows_format(rows)
|
218
|
+
@table[rows[0] + 1, 1] = @stratagy.row_value(entity)
|
219
|
+
(1..6).each do |row|
|
220
|
+
pair_format(rows, row)
|
221
|
+
@table[(rows[0] - 1) + row * 2, 2] = "#{row} пара"
|
222
|
+
end
|
223
|
+
columns_export(entity, rows)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def columns_export(row_ent, rows)
|
228
|
+
columns.each do |ent, cols|
|
229
|
+
columns_format(rows, cols)
|
230
|
+
@table[rows[0], cols[0]] = @stratagy.column_value(ent)
|
231
|
+
export_studies(@stratagy.studies(row_ent, ent), rows, cols)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
#Contract ArrayOf[Study], [Pos, Pos], [Pos, Pos] => Any
|
236
|
+
def export_studies(studies, rows, cols)
|
237
|
+
prepare_studies(studies).each do |number, studies|
|
238
|
+
@table.merge(real_row(rows, number), cols[0], real_row(rows, number) + 1, cols[0])
|
239
|
+
@table.merge(real_row(rows, number), cols[1], real_row(rows, number) + 1, cols[1])
|
240
|
+
studies.each_with_index do |study, i|
|
241
|
+
@table[real_row(rows, number) + i, cols[0]] =
|
242
|
+
"#{study.subject.title}\n#{study.groupable.get_group.title} " +
|
243
|
+
(study.groupable.subgroup? ? "(#{study.groupable.number}п)" : '')
|
244
|
+
@table[real_row(rows, number) + i, cols[1]] = study.cabinet.title
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def rows
|
250
|
+
@stratagy.rows.zip((1..(7 * @stratagy.rows.to_a.size)).each_slice(7).map{ |i| [i.first, i.last] })
|
251
|
+
end
|
252
|
+
|
253
|
+
def columns
|
254
|
+
@stratagy.columns.zip((3..(@stratagy.columns.to_a.size * 2) + (3 - 1)).each_slice(2))
|
255
|
+
end
|
256
|
+
|
257
|
+
#Contract ArrayOf[Study] => ({ Pos => ArrayOf[Study] })
|
258
|
+
def prepare_studies(studies)
|
259
|
+
studies.sort_by(&:number).group_by(&:number)
|
260
|
+
end
|
261
|
+
|
262
|
+
#Contract ArrayOf[Pos], Pos => Pos
|
263
|
+
def real_row(rows, number)
|
264
|
+
(rows[0] - 1) + (number * 2)
|
265
|
+
end
|
266
|
+
|
267
|
+
def rows_format(rows)
|
268
|
+
@table.merge(rows[0] + 1, 1, rows[1], 1)
|
269
|
+
format = Spreadsheet::Format.new
|
270
|
+
format.rotation = 90
|
271
|
+
format.horizontal_align = :center
|
272
|
+
format.vertical_align = :middle
|
273
|
+
format.top = :medium
|
274
|
+
format.bottom = :medium
|
275
|
+
format.right = :medium
|
276
|
+
format.left = :medium
|
277
|
+
@table.format(rows[0] + 1, 1, format)
|
278
|
+
end
|
279
|
+
|
280
|
+
def pair_format(rows, row)
|
281
|
+
@table.row((rows[0] - 1) + row * 2).height = 30
|
282
|
+
@table.row(rows[0] + row * 2).height = 30
|
283
|
+
@table.merge((rows[0] - 1) + row * 2, 2, rows[0] + row * 2, 2)
|
284
|
+
end
|
285
|
+
|
286
|
+
def columns_format(rows, cols)
|
287
|
+
@table.column(cols[0]).width = 25
|
288
|
+
@table.merge(rows[0], cols[0], rows[0], cols[1])
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
class LecturerTimetableExportStratagy2 < AbstractTimetableExportStratagy
|
293
|
+
#Contract Or[Range,Array], Lecturer => Any
|
294
|
+
def initialize(dates, lecturer)
|
295
|
+
@dates = dates
|
296
|
+
@lecturer = lecturer
|
297
|
+
end
|
298
|
+
|
299
|
+
#Contract None => Or[Range,Array]
|
300
|
+
def rows
|
301
|
+
['']
|
302
|
+
end
|
303
|
+
|
304
|
+
# TODO Изменить контракты
|
305
|
+
#Contract None => RespondTo[:zip]
|
306
|
+
def columns
|
307
|
+
@dates
|
308
|
+
end
|
309
|
+
|
310
|
+
#Contract Any => Any
|
311
|
+
def row_value(none)
|
312
|
+
""
|
313
|
+
end
|
314
|
+
|
315
|
+
#Contract Any => Any
|
316
|
+
def column_value(date)
|
317
|
+
date.strftime('%A')
|
318
|
+
end
|
319
|
+
|
320
|
+
#Contract Any, Any => ArrayOf[Study]
|
321
|
+
def studies(none, date)
|
322
|
+
Study.find_by_sql("select studies.* "+
|
323
|
+
"from studies "+
|
324
|
+
"join groups on groups.id = studies.groupable_id and studies.groupable_type = 'Group' "+
|
325
|
+
"where date = '#{date.to_s}' and lecturer_id = #{@lecturer.id} "+
|
326
|
+
"union "+
|
327
|
+
"select studies.* "+
|
328
|
+
"from studies "+
|
329
|
+
"join subgroups on subgroups.id = studies.groupable_id and studies.groupable_type = 'Subgroup' "+
|
330
|
+
"where date = '#{date.to_s}' and lecturer_id = #{@lecturer.id}")
|
331
|
+
#Study.of_group_and_its_subgroups(group).where(date: date, lecturer_id: @lecturer).to_a
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
class GroupTimetableExportStratagy < AbstractTimetableExportStratagy
|
336
|
+
#Contract Or[Range,Array], Group => Any
|
337
|
+
def initialize(dates, group)
|
338
|
+
@dates = dates
|
339
|
+
@group = group
|
340
|
+
end
|
341
|
+
|
342
|
+
#Contract None => Or[Range,Array]
|
343
|
+
def rows
|
344
|
+
['']
|
345
|
+
end
|
346
|
+
|
347
|
+
#Contract None => RespondTo[:zip]
|
348
|
+
def columns
|
349
|
+
@dates
|
350
|
+
end
|
351
|
+
|
352
|
+
#Contract Any => Any
|
353
|
+
def row_value(none)
|
354
|
+
""
|
355
|
+
end
|
356
|
+
|
357
|
+
#Contract Any => Any
|
358
|
+
def column_value(date)
|
359
|
+
date.strftime('%A')
|
360
|
+
end
|
361
|
+
|
362
|
+
#Contract Any, Any => ArrayOf[Study]
|
363
|
+
def studies(none, date)
|
364
|
+
Study.of_group_and_its_subgroups(@group).where(date: date).to_a
|
365
|
+
end
|
366
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# coding: UTF-8
|
2
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
3
|
+
require 'contracts'
|
4
|
+
#include Contracts
|
5
|
+
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
6
|
+
class AbstractSpreadsheet
|
7
|
+
#Contract String => Any
|
8
|
+
def initialize(filepath)
|
9
|
+
raise NotImplementedError
|
10
|
+
end
|
11
|
+
|
12
|
+
#Contract None => Pos
|
13
|
+
def last_row
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
#Contract None => Pos
|
18
|
+
def last_column
|
19
|
+
raise NotImplementedError
|
20
|
+
end
|
21
|
+
|
22
|
+
#Contract Not[Neg] => Any
|
23
|
+
def sheet(n)
|
24
|
+
raise NotImplementedError
|
25
|
+
end
|
26
|
+
|
27
|
+
#Contract Pos => Any
|
28
|
+
def row(n)
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
#Contract Pos => Any
|
33
|
+
def column(n)
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
#Contract Pos, Pos => Any
|
38
|
+
def [](r, c)
|
39
|
+
raise NotImplementedError
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module WritableSpreadsheet
|
44
|
+
#Contract Pos, Pos, Any => Any
|
45
|
+
def []=(r, c, obj)
|
46
|
+
raise NotImplementedError
|
47
|
+
end
|
48
|
+
|
49
|
+
#Contract None => Any
|
50
|
+
def save
|
51
|
+
raise NotImplementedError
|
52
|
+
end
|
53
|
+
end
|