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.
Files changed (94) hide show
  1. checksums.yaml +7 -0
  2. data/COPYING +674 -0
  3. data/README.md +44 -0
  4. data/Rakefile +64 -0
  5. data/bin/tmis +4 -0
  6. data/lib/tmis/engine/database.rb +58 -0
  7. data/lib/tmis/engine/export/timetable_exporter.rb +366 -0
  8. data/lib/tmis/engine/import/abstract_spreadsheet.rb +53 -0
  9. data/lib/tmis/engine/import/spreadsheet_roo.rb +136 -0
  10. data/lib/tmis/engine/import/timetable_manager.rb +110 -0
  11. data/lib/tmis/engine/import/timetable_reader.rb +79 -0
  12. data/lib/tmis/engine/mailer/mailer.rb +51 -0
  13. data/lib/tmis/engine/migrations/10_create_speciality_subjects.rb +17 -0
  14. data/lib/tmis/engine/migrations/11_create_emails.rb +10 -0
  15. data/lib/tmis/engine/migrations/12_add_indexes.rb +32 -0
  16. data/lib/tmis/engine/migrations/1_create_groups.rb +11 -0
  17. data/lib/tmis/engine/migrations/2_create_subgroups.rb +10 -0
  18. data/lib/tmis/engine/migrations/3_create_subjects.rb +11 -0
  19. data/lib/tmis/engine/migrations/4_create_cabinets.rb +12 -0
  20. data/lib/tmis/engine/migrations/5_create_lecturers.rb +14 -0
  21. data/lib/tmis/engine/migrations/6_create_studies.rb +15 -0
  22. data/lib/tmis/engine/migrations/7_create_courses.rb +9 -0
  23. data/lib/tmis/engine/migrations/8_create_specialities.rb +9 -0
  24. data/lib/tmis/engine/migrations/9_create_semesters.rb +10 -0
  25. data/lib/tmis/engine/models/cabinet.rb +18 -0
  26. data/lib/tmis/engine/models/course.rb +11 -0
  27. data/lib/tmis/engine/models/email.rb +19 -0
  28. data/lib/tmis/engine/models/group.rb +31 -0
  29. data/lib/tmis/engine/models/lecturer.rb +45 -0
  30. data/lib/tmis/engine/models/semester.rb +4 -0
  31. data/lib/tmis/engine/models/speciality.rb +3 -0
  32. data/lib/tmis/engine/models/speciality_subject.rb +6 -0
  33. data/lib/tmis/engine/models/study.rb +56 -0
  34. data/lib/tmis/engine/models/subgroup.rb +21 -0
  35. data/lib/tmis/engine/models/subject.rb +19 -0
  36. data/lib/tmis/engine/verificator.rb +96 -0
  37. data/lib/tmis/interface/forms/about.rb +24 -0
  38. data/lib/tmis/interface/forms/console.rb +28 -0
  39. data/lib/tmis/interface/forms/debug_console.rb +32 -0
  40. data/lib/tmis/interface/forms/edit_study.rb +110 -0
  41. data/lib/tmis/interface/forms/expand_changes.rb +128 -0
  42. data/lib/tmis/interface/forms/export_general_timetable.rb +68 -0
  43. data/lib/tmis/interface/forms/export_group_timetable.rb +158 -0
  44. data/lib/tmis/interface/forms/export_lecturer_timetable.rb +171 -0
  45. data/lib/tmis/interface/forms/find.rb +71 -0
  46. data/lib/tmis/interface/forms/import.rb +36 -0
  47. data/lib/tmis/interface/forms/settings.rb +125 -0
  48. data/lib/tmis/interface/forms/ui_about.rb +88 -0
  49. data/lib/tmis/interface/forms/ui_console.rb +68 -0
  50. data/lib/tmis/interface/forms/ui_debug_console.rb +82 -0
  51. data/lib/tmis/interface/forms/ui_edit_study.rb +202 -0
  52. data/lib/tmis/interface/forms/ui_expand_changes.rb +134 -0
  53. data/lib/tmis/interface/forms/ui_export_general_timetable.rb +142 -0
  54. data/lib/tmis/interface/forms/ui_export_group_timetable.rb +160 -0
  55. data/lib/tmis/interface/forms/ui_export_lecturer_timetable.rb +160 -0
  56. data/lib/tmis/interface/forms/ui_find.rb +77 -0
  57. data/lib/tmis/interface/forms/ui_import.rb +134 -0
  58. data/lib/tmis/interface/forms/ui_settings.rb +417 -0
  59. data/lib/tmis/interface/mainwindow.rb +933 -0
  60. data/lib/tmis/interface/models/cabinet_table_model.rb +133 -0
  61. data/lib/tmis/interface/models/course_table_model.rb +87 -0
  62. data/lib/tmis/interface/models/group_table_model.rb +190 -0
  63. data/lib/tmis/interface/models/lecturer_table_model.rb +111 -0
  64. data/lib/tmis/interface/models/semester_table_model.rb +137 -0
  65. data/lib/tmis/interface/models/speciality_subject_table_model.rb +288 -0
  66. data/lib/tmis/interface/models/speciality_table_model.rb +87 -0
  67. data/lib/tmis/interface/models/study_table_model.rb +323 -0
  68. data/lib/tmis/interface/models/subgroup_table_model.rb +136 -0
  69. data/lib/tmis/interface/models/subject_table_model.rb +90 -0
  70. data/lib/tmis/interface/ui_mainwindow.rb +928 -0
  71. data/lib/tmis.rb +45 -0
  72. data/spec/config.rb +49 -0
  73. data/spec/database_spec.rb +18 -0
  74. data/spec/export/timetable_exporter_mocks.rb +20 -0
  75. data/spec/export/timetable_exporter_spec.rb +34 -0
  76. data/spec/factories/factories.rb +65 -0
  77. data/spec/import/test_data/raspisanie_2013.csv +104 -0
  78. data/spec/import/timetable_importer_mocks.rb +6 -0
  79. data/spec/import/timetable_manager_spec.rb +16 -0
  80. data/spec/import/timetable_reader_spec.rb +111 -0
  81. data/spec/import/timetable_roo_spec.rb +48 -0
  82. data/spec/mailer/mailer_spec.rb +37 -0
  83. data/spec/mainwindow_spec.rb +18 -0
  84. data/spec/models/cabinet_spec.rb +33 -0
  85. data/spec/models/course_spec.rb +26 -0
  86. data/spec/models/group_spec.rb +33 -0
  87. data/spec/models/lecturer_spec.rb +38 -0
  88. data/spec/models/semester_spec.rb +26 -0
  89. data/spec/models/speciality_spec.rb +26 -0
  90. data/spec/models/speciality_subject_spec.rb +9 -0
  91. data/spec/models/study_spec.rb +9 -0
  92. data/spec/models/subgroup_spec.rb +26 -0
  93. data/spec/models/subject_spec.rb +39 -0
  94. 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
+ | [![Main](http://i.imgur.com/ZbSEbbn.png)](http://i.imgur.com/lG7gdit.png) | [![DragAndDrop](http://i.imgur.com/6aHY7L1.png)](http://i.imgur.com/YjFu5ok.png) |
31
+ | ----------------------------------------------------------------------------- |----------------------------------------------------------------------------------|
32
+ | [![Edit](http://i.imgur.com/JVsMNi2.png)](http://i.imgur.com/qGHDB9L.png) | [![Table](http://i.imgur.com/8z1E9Fz.png)](http://i.imgur.com/OmSapi0.png) |
33
+ | [![Coloring](http://i.imgur.com/yTOfexh.png)](http://i.imgur.com/9N8GGQn.png) | [![Coloring2](http://i.imgur.com/eb9j3Cu.png)](http://i.imgur.com/JUKmxzA.png) |
34
+ | [![Expand](http://i.imgur.com/gWi1ErD.png)](http://i.imgur.com/OJS5v2v.png) | [![Settings](http://i.imgur.com/1efXwqm.png)](http://i.imgur.com/pOBbGDg.png) |
35
+ | [![Export](http://i.imgur.com/k4afo9v.png)](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,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tmis'
4
+ TMIS.run
@@ -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