shnaider_carproj 0.1.0

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 (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