shnaider_carproj 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +10 -0
  3. data/Gemfile.lock +71 -0
  4. data/diagrams/add_owner.jpg +0 -0
  5. data/diagrams/delete_owner.jpg +0 -0
  6. data/diagrams/er.png +0 -0
  7. data/diagrams/owner.jpg +0 -0
  8. data/diagrams/owner.sai2 +0 -0
  9. data/diagrams/start.jpg +0 -0
  10. data/lib/car/controllers/publisher_input_form_controller_create.rb +44 -0
  11. data/lib/car/controllers/publisher_input_form_controller_edit.rb +52 -0
  12. data/lib/car/controllers/publisher_list_controller.rb +99 -0
  13. data/lib/car/tenant_db_data_source.rb +63 -0
  14. data/lib/car/ui/tenant_input_form.rb +69 -0
  15. data/lib/car/ui/tenant_list_view.rb +168 -0
  16. data/lib/controllers/tab_students_controller.rb +43 -0
  17. data/lib/data_sources/car_db_data_source.rb +43 -0
  18. data/lib/data_sources/db_client.rb +34 -0
  19. data/lib/db_config/carshering_config.yaml +5 -0
  20. data/lib/db_config/config.yaml +5 -0
  21. data/lib/db_config/migrations/create_db.sql +3 -0
  22. data/lib/db_config/migrations/create_tables.sql +29 -0
  23. data/lib/db_config/mock_data/mock_data.sql +55 -0
  24. data/lib/models/car.rb +31 -0
  25. data/lib/models/owner.rb +32 -0
  26. data/lib/models/student.rb +102 -0
  27. data/lib/models/student_base.rb +100 -0
  28. data/lib/models/student_short.rb +50 -0
  29. data/lib/models/tenant.rb +40 -0
  30. data/lib/owner/controllers/owner_input_form_controller_create.rb +44 -0
  31. data/lib/owner/controllers/owner_input_form_controller_edit.rb +53 -0
  32. data/lib/owner/controllers/owner_list_controller.rb +107 -0
  33. data/lib/owner/owner_db_data_source.rb +70 -0
  34. data/lib/owner/ui/owner_input_form.rb +69 -0
  35. data/lib/owner/ui/owner_list_view.rb +169 -0
  36. data/lib/repositories/adapters/db_source_adapter.rb +54 -0
  37. data/lib/repositories/adapters/file_source_adapter.rb +37 -0
  38. data/lib/repositories/containers/data_list.rb +74 -0
  39. data/lib/repositories/containers/data_list_student_short.rb +18 -0
  40. data/lib/repositories/containers/data_table.rb +35 -0
  41. data/lib/repositories/data_sources/db_data_source.rb +32 -0
  42. data/lib/repositories/data_sources/file_data_source.rb +75 -0
  43. data/lib/repositories/data_sources/transformers/data_transformer_base.rb +15 -0
  44. data/lib/repositories/data_sources/transformers/data_transformer_json.rb +16 -0
  45. data/lib/repositories/data_sources/transformers/data_transformer_yaml.rb +16 -0
  46. data/lib/repositories/student_repository.rb +32 -0
  47. data/lib/state_holders/list_state_notifier.rb +62 -0
  48. data/lib/tenant/controllers/tenant_input_form_controller_create.rb +44 -0
  49. data/lib/tenant/controllers/tenant_input_form_controller_edit.rb +53 -0
  50. data/lib/tenant/controllers/tenant_list_controller.rb +107 -0
  51. data/lib/tenant/tenant_db_data_source.rb +90 -0
  52. data/lib/tenant/ui/tenant_input_form.rb +69 -0
  53. data/lib/tenant/ui/tenant_list_view.rb +169 -0
  54. data/lib/views/main_window.rb +25 -0
  55. data/lib/views/tab_students.rb +148 -0
  56. data/requirements.docx +0 -0
  57. data/shnaider_carproj.gemspec +15 -0
  58. data/test/car_test.rb +33 -0
  59. data/test/logger.rb +27 -0
  60. data/test/main.rb +5 -0
  61. data/test/owner_test.rb +48 -0
  62. data/test/state_notifier_test.rb +80 -0
  63. data/test/tenant_test.rb +48 -0
  64. metadata +118 -0
@@ -0,0 +1,169 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'glimmer-dsl-libui'
4
+ require_relative '../controllers/tenant_list_controller'
5
+ require_relative 'tenant_input_form'
6
+
7
+ class TenantListView
8
+ include Glimmer
9
+
10
+ PAGE_SIZE = 20
11
+
12
+ def initialize
13
+ @controller = TenantListController.new(self)
14
+ @current_page = 1
15
+ @total_count = 0
16
+ end
17
+
18
+ def on_create
19
+ @controller.on_view_created
20
+ @controller.refresh_data(@current_page, PAGE_SIZE)
21
+ end
22
+
23
+ # Метод наблюдателя datalist
24
+ # def on_datalist_changed(new_table)
25
+ # arr = new_table.to_2d_array
26
+ # arr.map do |row|
27
+ # row[3] = [row[3][:value], contact_color(row[3][:type])] unless row[3].nil?
28
+ # end
29
+ # @table.model_array = arr
30
+ # end
31
+
32
+ def update(tenants)
33
+ @items = []
34
+
35
+ i = 0
36
+ item_num = 0
37
+ tenants.each do |tenant|
38
+ i += 1
39
+ item_num = ((@current_page - 1) * PAGE_SIZE) + i
40
+ @items << Struct.new(:№, :id, :имя_арендатора, :фамилия_арендатора, :номер_телефона).new(item_num, tenant.tenant_id, tenant.first_name, tenant.last_name, tenant.phone)
41
+ end
42
+
43
+ @table.model_array = @items
44
+ @page_label.text = "#{@current_page} / #{(@total_count / PAGE_SIZE.to_f).ceil}"
45
+ end
46
+
47
+ def update_count(new_cnt)
48
+ @total_count = new_cnt
49
+ @page_label.text = "#{@current_page} / #{(@total_count / PAGE_SIZE.to_f).ceil}"
50
+ end
51
+
52
+ def create
53
+
54
+ root_container = horizontal_box {
55
+ # Секция 1
56
+ vertical_box {
57
+ stretchy false
58
+
59
+ vertical_box {
60
+ stretchy false
61
+
62
+ label {
63
+ text 'Номер телефона'
64
+ }
65
+ combobox { |c|
66
+ items ['Не важно','Есть','Нет']
67
+ selected 0
68
+ on_selected do
69
+ @controller.filter_phone(@current_page, PAGE_SIZE, c.selected)
70
+ end
71
+ }
72
+
73
+ label {
74
+ text 'Сортировка'
75
+ }
76
+ combobox { |c|
77
+ items ['ID','Имя арендатора','Фамилия арендатора', 'Номер телефона']
78
+ selected 0
79
+ on_selected do
80
+ @controller.sort(@current_page, PAGE_SIZE, c.selected)
81
+ end
82
+ }
83
+ }
84
+
85
+
86
+ }
87
+
88
+ # Секция 2
89
+ vertical_box {
90
+ @table = refined_table(
91
+ table_editable: false,
92
+ filter: lambda do |row_hash, query|
93
+ utf8_query = query.force_encoding("utf-8")
94
+ row_hash['Имя арендатора'].include?(utf8_query)
95
+ end,
96
+ table_columns: {
97
+ '№' => :text,
98
+ 'ID' => :text,
99
+ 'Имя арендатора' => :text,
100
+ 'Фамилия арендатора' => :text,
101
+ 'Номер телефона' => :text,
102
+ },
103
+ per_page: PAGE_SIZE,
104
+
105
+ )
106
+
107
+ @pages = horizontal_box {
108
+ stretchy false
109
+
110
+ button("<") {
111
+ stretchy true
112
+
113
+ on_clicked do
114
+ @current_page = [@current_page - 1, 1].max
115
+ @controller.refresh_data(@current_page, PAGE_SIZE)
116
+ end
117
+
118
+ }
119
+ @page_label = label("...") { stretchy false }
120
+ button(">") {
121
+ stretchy true
122
+
123
+ on_clicked do
124
+ @current_page = [@current_page + 1, (@total_count / PAGE_SIZE.to_f).ceil].min
125
+ @controller.refresh_data(@current_page, PAGE_SIZE)
126
+ end
127
+ }
128
+ }
129
+ }
130
+
131
+ # Секция 3
132
+ vertical_box {
133
+ stretchy false
134
+
135
+ button('Добавить') {
136
+ stretchy false
137
+
138
+ on_clicked {
139
+ @controller.show_modal_add
140
+ }
141
+ }
142
+ button('Изменить') {
143
+ stretchy false
144
+
145
+ on_clicked {
146
+ @controller.show_modal_edit(@current_page, PAGE_SIZE, @table.selection) unless @table.selection.nil?
147
+ }
148
+ }
149
+ button('Удалить') {
150
+ stretchy false
151
+
152
+ on_clicked {
153
+ @controller.delete_selected(@current_page, PAGE_SIZE, @table.selection) unless @table.selection.nil?
154
+ @controller.refresh_data(@current_page, PAGE_SIZE)
155
+ }
156
+ }
157
+ button('Обновить') {
158
+ stretchy false
159
+
160
+ on_clicked {
161
+ @controller.refresh_data(@current_page, PAGE_SIZE)
162
+ }
163
+ }
164
+ }
165
+ }
166
+ on_create
167
+ root_container
168
+ end
169
+ end
@@ -0,0 +1,25 @@
1
+ require 'glimmer-dsl-libui'
2
+ require_relative 'tab_students'
3
+ require './owner/ui/owner_list_view'
4
+ require './tenant/ui/tenant_list_view'
5
+
6
+ class MainWindow
7
+ include Glimmer
8
+
9
+ def initialize
10
+ @view_tab_students = TabStudentsView.new
11
+ end
12
+
13
+ def create
14
+ window('Каршеринг', 1000, 600) {
15
+ tab {
16
+ tab_item('Владельцы') {
17
+ OwnerListView.new.create
18
+ }
19
+ tab_item('Арендаторы') {
20
+ TenantListView.new.create
21
+ }
22
+ }
23
+ }
24
+ end
25
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'glimmer-dsl-libui'
4
+ require './controllers/tab_students_controller'
5
+
6
+ class TabStudentsView
7
+ include Glimmer
8
+
9
+ ITEMS_PER_PAGE = 20
10
+
11
+ def initialize
12
+ @controller = TabStudentsController.new(self)
13
+ @current_page = 1
14
+ @total_count = 0
15
+ end
16
+
17
+ def on_create
18
+ @controller.on_view_created
19
+ @controller.refresh_data(@current_page, ITEMS_PER_PAGE)
20
+ end
21
+
22
+ # Метод наблюдателя datalist
23
+ def on_datalist_changed(new_table)
24
+ arr = new_table.to_2d_array
25
+ arr.map { |row| row[3] = [row[3][:value], contact_color(row[3][:type])] }
26
+ @table.model_array = arr
27
+ end
28
+
29
+ def update_student_count(new_cnt)
30
+ @total_count = new_cnt
31
+ @page_label.text = "#{@current_page} / #{(@total_count / ITEMS_PER_PAGE.to_f).ceil}"
32
+ end
33
+
34
+ def contact_color(type)
35
+ case type
36
+ when 'telegram'
37
+ '#00ADB5'
38
+ when 'email'
39
+ '#F08A5D'
40
+ when 'phone'
41
+ '#B83B5E'
42
+ else
43
+ '#000000'
44
+ end
45
+ end
46
+
47
+ def create
48
+ root_container = horizontal_box {
49
+ # Секция 1
50
+ vertical_box {
51
+ stretchy false
52
+
53
+ form {
54
+ stretchy false
55
+
56
+ @filter_last_name_initials = entry {
57
+ label 'Фамилия И. О.'
58
+ }
59
+
60
+ @filters = {}
61
+ fields = [[:git, 'Гит'], [:email, 'Почта'], [:phone, 'Телефон'], [:telegram, 'Телеграм']]
62
+
63
+ fields.each do |field|
64
+ @filters[field[0]] = {}
65
+
66
+ @filters[field[0]][:combobox] = combobox {
67
+ label "#{field[1]} имеется?"
68
+ items ['Не важно', 'Есть', 'Нет']
69
+ selected 0
70
+
71
+ on_selected do
72
+ if @filters[field[0]][:combobox].selected == 1
73
+ @filters[field[0]][:entry].read_only = false
74
+ else
75
+ @filters[field[0]][:entry].text = ''
76
+ @filters[field[0]][:entry].read_only = true
77
+ end
78
+ end
79
+ }
80
+
81
+ @filters[field[0]][:entry] = entry {
82
+ label field[1]
83
+ read_only true
84
+ }
85
+ end
86
+ }
87
+ }
88
+
89
+ # Секция 2
90
+ vertical_box {
91
+ @table = refined_table(
92
+ table_editable: false,
93
+ filter: lambda do |row_hash, query|
94
+ utf8_query = query.force_encoding("utf-8")
95
+ row_hash['Фамилия И. О'].include?(utf8_query)
96
+ end,
97
+ table_columns: {
98
+ '#' => :text,
99
+ 'Фамилия И. О' => :text,
100
+ 'Гит' => :text,
101
+ 'Контакт' => :text_color
102
+ }
103
+ )
104
+
105
+ @pages = horizontal_box {
106
+ stretchy false
107
+
108
+ button("<") {
109
+ stretchy true
110
+
111
+ on_clicked do
112
+ @current_page = [@current_page - 1, 1].max
113
+ @controller.refresh_data(@current_page, ITEMS_PER_PAGE)
114
+ end
115
+
116
+ }
117
+ @page_label = label("...") { stretchy false }
118
+ button(">") {
119
+ stretchy true
120
+
121
+ on_clicked do
122
+ @current_page = [@current_page + 1, (@total_count / ITEMS_PER_PAGE.to_f).ceil].min
123
+ @controller.refresh_data(@current_page, ITEMS_PER_PAGE)
124
+ end
125
+ }
126
+ }
127
+ }
128
+
129
+ # Секция 3
130
+ vertical_box {
131
+ stretchy false
132
+
133
+ button('Добавить') { stretchy false }
134
+ button('Изменить') { stretchy false }
135
+ button('Удалить') { stretchy false }
136
+ button('Обновить') {
137
+ stretchy false
138
+
139
+ on_clicked {
140
+ @controller.refresh_data(@current_page, ITEMS_PER_PAGE)
141
+ }
142
+ }
143
+ }
144
+ }
145
+ on_create
146
+ root_container
147
+ end
148
+ end
data/requirements.docx ADDED
Binary file
@@ -0,0 +1,15 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'shnaider_carproj'
3
+ spec.version = '0.1.0'
4
+ spec.authors = ['Shnaider']
5
+ spec.email = 'shnaideriya@yandex.ru'
6
+ spec.summary = 'Shnaider carshering app'
7
+ spec.description = 'Description Shnaider carshering app'
8
+ spec.homepage = 'https://github.com/bushmrz/ruby_individual_project'
9
+ spec.license = 'MIT'
10
+
11
+ spec.files = Dir.glob("**/*")
12
+ spec.require_paths = ['lib']
13
+
14
+ spec.add_dependency 'win32api'
15
+ end
data/test/car_test.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'minitest/autorun'
2
+ require './models/car'
3
+ class TestCar < Minitest::Test
4
+ def test_initialize_raises_error_with_null_car_id
5
+ assert Car.new(nil, 'model', 1, 1)
6
+ end
7
+
8
+ def test_initialize_raises_error_with_null_model
9
+ assert Car.new(1, nil, 1, 1)
10
+ end
11
+
12
+ def test_initialize_raises_error_with_null_owner_id
13
+ assert Car.new(1, 'model', nil, 1)
14
+ end
15
+
16
+ def test_initialize_raises_error_with_null_tenant_id
17
+ assert Car.new(1, 'model', 1, nil)
18
+ end
19
+
20
+ def test_initialize_raises_error_with_long_model
21
+ long_model = 'a' * 256
22
+ assert Car.new(1, long_model, 1, 1)
23
+ end
24
+
25
+ def test_car_attributes_are_set
26
+ car = Car.new(1, 'model', 2, 3)
27
+
28
+ assert_equal 1, car.car_id
29
+ assert_equal 'model', car.model
30
+ assert_equal 2, car.owner_id
31
+ assert_equal 3, car.tenant_id
32
+ end
33
+ end
data/test/logger.rb ADDED
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'logger'
4
+
5
+ ##
6
+ # Обертка для хранения объекта Logger
7
+
8
+ class LoggerHolder
9
+ private_class_method :new
10
+ @instance_mutex = Mutex.new
11
+
12
+ attr_reader :logger
13
+
14
+ def initialize
15
+ @logger = Logger.new(STDOUT)
16
+ end
17
+
18
+ def self.instance
19
+ return @instance.logger if @instance
20
+
21
+ @instance_mutex.synchronize do
22
+ @instance ||= new
23
+ end
24
+
25
+ @instance.logger
26
+ end
27
+ end
data/test/main.rb ADDED
@@ -0,0 +1,5 @@
1
+ require_relative 'logger'
2
+ require_relative 'lib/views/main_window'
3
+
4
+ LoggerHolder.instance.level = Logger::DEBUG
5
+ MainWindow.new.create.show
@@ -0,0 +1,48 @@
1
+ require 'minitest/autorun'
2
+ require './models/owner'
3
+ class TestOwner < Minitest::Test
4
+ def test_initialize_sets_attributes
5
+ owner = Owner.new(1, 'John', 'Doe', 'Smith')
6
+
7
+ assert_equal 1, owner.owner_id
8
+ assert_equal 'John', owner.first_name
9
+ assert_equal 'Doe', owner.last_name
10
+ assert_equal 'Smith', owner.father_name
11
+ end
12
+
13
+ def test_initialize_raises_error_if_owner_id_is_nil
14
+ assert
15
+ Owner.new(nil, 'John', 'Doe')
16
+ end
17
+
18
+ def test_initialize_raises_error_if_first_name_is_nil
19
+ assert
20
+ Owner.new(1, nil, 'Doe')
21
+ end
22
+
23
+ def test_initialize_raises_error_if_last_name_is_nil
24
+ assert
25
+ Owner.new(1, 'John', nil)
26
+ end
27
+
28
+ def test_initialize_raises_error_if_first_name_exceeds_50_characters
29
+ long_name = 'a' * 51
30
+ assert_raises
31
+ Owner.new(1, long_name, 'Doe')
32
+ end
33
+
34
+ def test_initialize_raises_error_if_last_name_exceeds_50_characters
35
+ long_name = 'a' * 51
36
+ assert
37
+ Owner.new(1, 'John', long_name)
38
+ end
39
+
40
+ def test_initialize_raises_error_if_father_name_exceeds_50_characters
41
+ long_name = 'a' * 51
42
+ assert Owner.new(1, 'John', 'Doe', long_name)
43
+ end
44
+
45
+ def test_initialize_raises_error_if_father_name_nil
46
+ assert Owner.new(1, 'John', 'Doe', nil)
47
+ end
48
+ end
@@ -0,0 +1,80 @@
1
+ require 'minitest/autorun'
2
+ require './lib/state_holders/list_state_notifier'
3
+ class TestListStateNotifier < Minitest::Test
4
+ def setup
5
+ @notifier = ListStateNotifier.new
6
+ end
7
+
8
+ def test_items_initialized_as_empty_array
9
+ assert_equal [], @notifier.items
10
+ end
11
+
12
+ def test_set_all_sets_items_and_notifies_listeners
13
+ listener = MiniTest::Mock.new
14
+ listener.expect(:update, nil, [[1, 2, 3]])
15
+ @notifier.add_listener(listener)
16
+
17
+ @notifier.set_all([1, 2, 3])
18
+
19
+ assert_equal [1, 2, 3], @notifier.items
20
+ listener.verify
21
+ end
22
+
23
+ def test_add_adds_item_and_notifies_listeners
24
+ listener = MiniTest::Mock.new
25
+ listener.expect(:update, nil, [@notifier.items])
26
+ @notifier.add_listener(listener)
27
+
28
+ @notifier.add(4)
29
+
30
+ assert_equal [4], @notifier.items
31
+ listener.verify
32
+ end
33
+
34
+ def test_get_returns_correct_item
35
+ @notifier.set_all([1, 2, 3])
36
+
37
+ assert_equal 2, @notifier.get(1)
38
+ end
39
+
40
+ def test_delete_removes_item_and_notifies_listeners
41
+ @notifier.set_all([1, 2, 3])
42
+ listener = MiniTest::Mock.new
43
+ listener.expect(:update, nil, [@notifier.items])
44
+ @notifier.add_listener(listener)
45
+
46
+ @notifier.delete(2)
47
+
48
+ assert_equal [1, 3], @notifier.items
49
+ listener.verify
50
+ end
51
+
52
+ def test_replace_replaces_item_and_notifies_listeners
53
+ @notifier.set_all([1, 2, 3])
54
+ listener = MiniTest::Mock.new
55
+ listener.expect(:update, nil, [@notifier.items])
56
+ @notifier.add_listener(listener)
57
+
58
+ @notifier.replace(2, 4)
59
+
60
+ assert_equal [1, 4, 3], @notifier.items
61
+ listener.verify
62
+ end
63
+
64
+ def test_add_listener_adds_listener
65
+ listener = MiniTest::Mock.new
66
+
67
+ @notifier.add_listener(listener)
68
+
69
+ assert_includes @notifier.instance_variable_get(:@listeners), listener
70
+ end
71
+
72
+ def test_delete_listener_removes_listener
73
+ listener = MiniTest::Mock.new
74
+ @notifier.add_listener(listener)
75
+
76
+ @notifier.delete_listener(listener)
77
+
78
+ refute_includes @notifier.instance_variable_get(:@listeners), listener
79
+ end
80
+ end
@@ -0,0 +1,48 @@
1
+ require 'minitest/autorun'
2
+ require './models/tenant'
3
+ class TestTenant < Minitest::Test
4
+ def test_initialize_sets_attributes
5
+ tenant = Tenant.new(1, 'John', 'Doe', '+79009009090')
6
+
7
+ assert_equal 1, tenant.tenant_id
8
+ assert_equal 'John', tenant.first_name
9
+ assert_equal 'Doe', tenant.last_name
10
+ assert_equal '+79009009090', tenant.phone
11
+ end
12
+
13
+ def test_initialize_raises_error_if_tenant_id_is_nil
14
+ assert
15
+ Tenant.new(nil, 'John', 'Doe')
16
+ end
17
+
18
+ def test_initialize_raises_error_if_first_name_is_nil
19
+ assert
20
+ Tenant.new(1, nil, 'Doe')
21
+ end
22
+
23
+ def test_initialize_raises_error_if_last_name_is_nil
24
+ assert
25
+ Tenant.new(1, 'John', nil)
26
+ end
27
+
28
+ def test_initialize_raises_error_if_first_name_exceeds_50_characters
29
+ long_name = 'a' * 51
30
+ assert_raises
31
+ Tenant.new(1, long_name, 'Doe')
32
+ end
33
+
34
+ def test_initialize_raises_error_if_last_name_exceeds_50_characters
35
+ long_name = 'a' * 51
36
+ assert
37
+ Tenant.new(1, 'John', long_name)
38
+ end
39
+
40
+ def test_initialize_raises_error_if_phone_uncorrect
41
+ phone_er = +78
42
+ assert Tenant.new(1, 'John', 'Doe', phone_er)
43
+ end
44
+
45
+ def test_initialize_raises_error_if_phone_nil
46
+ assert Tenant.new(1, 'John', 'Doe', nil)
47
+ end
48
+ end