nested_array 2.4.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README-ru.md CHANGED
@@ -1,287 +1,548 @@
1
- # NestedArray
1
+ # nested_array
2
2
 
3
- Предназначен для преобразования в древовидную структуру плоских данных описанных
4
- по паттерну «Список смежности» (Adjacency List), то есть в нодах указа предок
5
- `parent_id`. Например:
3
+ 🎉 Мои поздравления! Вышла версия 3.0.
4
+
5
+ Гем `nested_array` позволяет преобразовать плоский массив данных древовидной
6
+ структуры во вложенный массив, а так же помогает отобразить деревья формируя
7
+ HTML вёрстку или псевдографику.
8
+
9
+ Древовидная структура должна быть описана по шаблону Списка смежности
10
+ (Adjacency List), то есть в каждом узле указан предок.
11
+
12
+ __Выбрать язык README.md__
13
+
14
+ - en [English](README.md)
15
+ - ru [Русский](README-ru.md)
16
+
17
+
18
+
19
+
20
+ ## <a id="Оглавление"></a>Оглавление
21
+ - [Установка](#1)
22
+ - [Использование](#2)
23
+ - [Преобразование данных методом `.to_nested`](#2.1)
24
+ - [Исходные данные – массив хэш](#2.1.1)
25
+ - [Исходные данные – массив ActiveRecord](#2.1.2)
26
+ - [Опции метода `.to_nested`](#2.1.3)
27
+ - [`root_id: id`](#2.1.3.1)
28
+ - [`branch_id: id`](#2.1.3.2)
29
+ - [Отображение древовидных структур](#2.2)
30
+ - [В виде многоуровневых списков](#2.2.1)
31
+ - [Маркированный и нумерованный списки `<ul>`, `<ol>`](#2.2.1.1)
32
+ - [Использование собственных шаблонов для отображения списка](#2.2.1.2)
33
+ - [Изменение шаблона в зависимости от данных узла](#2.2.1.3)
34
+ - [Расскрывающийся список на основе тега `<details></details>`](#2.2.1.4)
35
+ - [Формирование и вывод собственных шаблонов опираясь на изменение уровня узла `node.level`](#2.2.1.5)
36
+ - [В виде псевдографики](#2.2.2)
37
+ - [Добавление псевдографики перед именем модели методом `nested_to_options`](#2.2.2.1)
38
+ - [Тонкая псевдографика](#2.2.2.2)
39
+ - [Собственная псевдографика](#2.2.2.3)
40
+ - [Увеличение отступа в собственной псевдографике](#2.2.2.4)
41
+ - [В формах](#2.2.3)
42
+ - [С хелпером `form.select`](#2.2.3.1)
43
+ - [С хелперами `form.select` и `options_for_select`](#2.2.3.2)
44
+ - [Раскрывающийся список с переключателями `form.radio_button`](#2.2.3.3)
45
+
46
+
47
+
48
+
49
+ ## <a id="1"></a>Установка [↑](#Оглавление "К оглавлению")
50
+
51
+ 1. Добавте строку в файл _Gemfile_ вашего приложения:
6
52
 
7
53
  ```ruby
8
- [
9
- {id: 1, parent_id: nil, name: 'first', …},
10
- {id: 2, parent_id: 1, name: 'second', …},
11
- {id: 3, parent_id: 1, name: 'third', …}
12
- ]
13
- # ↓ ↓ ↓
14
- [
15
- {id: 1, parent_id: nil, name: 'first', children: [
16
- {id: 2, parent_id: 1, name: 'second', …},
17
- {id: 3, parent_id: 1, name: 'third', …}
18
- ], …}
19
- ]
54
+ # Работа с древовидными массивами
55
+ gem "nested_array", "~> 3.0"
20
56
  ```
21
57
 
58
+ И выполните `bundle install`.
22
59
 
60
+ 2. Если вы планируете использовать скромные CSS стили гема, добавте в
61
+ файл _app/assets/stylesheets/application.scss_:
23
62
 
63
+ ```css
64
+ /* Отображение древовидных массивов */
65
+ @import "nested_array";
66
+ ```
24
67
 
25
- ## Установка
26
68
 
27
- Добавте строку в _Gemfile_ вашего приложения:
28
69
 
29
- ```ruby
30
- # Версия не расширяет базовый класс Array методами гема. Для использования необходимо преобразовать данные к новому типу, см ниже.
31
70
 
32
- # Работа с древовидными массивами.
33
- gem 'nested_array', '~> 1.0.0'
71
+ ## <a id="2"></a>Использование [↑](#Оглавление "К оглавлению")
72
+
73
+ ### <a id="2.1"></a>Преобразование данных методом `.to_nested` [↑](#Оглавление "К оглавлению")
74
+
75
+ #### <a id="2.1.1"></a>Исходные данные – массив хэш [↑](#Оглавление "К оглавлению")
34
76
 
35
- # Версия с автоматическим расширением базового класса Array методами гема.
77
+ Допустим, есть массив хэш:
36
78
 
37
- # Работа с древовидными массивами.
38
- gem "nested_array", "~> 2.0.0"
79
+ ```rb
80
+ flat = [
81
+ {'id' => 3, 'parent_id' => nil},
82
+ {'id' => 2, 'parent_id' => 1},
83
+ {'id' => 1, 'parent_id' => nil}
84
+ ]
39
85
  ```
40
86
 
41
- И затем выполните `bundle install`.
87
+ Где каждый хэш это узел дерева, `id` — идентификатор узла,
88
+ `parent_id` — указатель на родительский узел.
42
89
 
43
- Или установите его как `gem install nested_array`
90
+ Необходимо преобразовать в массив в котором будут только корневые узлы
91
+ (`'parent_id' => nil`), а дочерние узлы помещены в поле
92
+ `children`.
44
93
 
94
+ ```rb
95
+ nested = flat.to_nested
96
+ puts nested.pretty_inspect
97
+ ```
45
98
 
99
+ Выведет:
46
100
 
101
+ ```
102
+ [#<OpenStruct id=3, parent_id=nil, level=0, origin={"id"=>3, "parent_id"=>nil}>,
103
+ #<OpenStruct id=1, parent_id=nil, level=0, children=[#<OpenStruct id=2, parent_id=1, level=1, origin={"id"=>2, "parent_id"=>1}>], origin={"id"=>1, "parent_id"=>nil}>]
104
+ ```
47
105
 
48
- ## Использование
106
+ В результате узлы представляют собой объекты `OpenStruct` у которых
107
+ исходные поля `id`, `parent_id` и дополнительные поля
108
+ `level`, `origin` и `children`.
49
109
 
50
- <a name="methods"></a>
51
- __Список методов__
110
+ В качестве исходных узлов могут быть и объекты ActiveRecord.
52
111
 
53
- * [to_nested](#to_nested) — преобразует плоскую структуру во вложенную;
54
- * [each_nested](#each_nested) — перебирает вложенную стуктуру;
55
- * [each_nested!](#each_nested) — перебирает вложенную стуктуру, предоставляя доступ к исходным данным;
56
- * [nested_to_html](#nested_to_html) — преобразует вложенную структуру в html вёрстку (многоуровневый список `<ul><li>…`);
57
- * [nested_to_options](#nested_to_options) — преобразует вложенную структуру в массив для формирования опций html-тега `<select>` с псевдографикой;
58
- * [nested_to_collection_select](#nested_to_collection_select) — преобразует вложенную структуру в плоскую но добавляет псевдографику в тектовое поле для формирования тэга `<select>`;
59
- * [concat_nested](#concat_nested) — скеивание вложенных структур, ноды склеиваются если путь к ним одинаков.
60
112
 
61
113
 
62
114
 
115
+ #### <a id="2.1.2"></a>Исходные данные – массив ActiveRecord [↑](#Оглавление "К оглавлению")
63
116
 
64
- <a name="to_nested"></a>
65
- ### to_nested [↑](#methods "К методам")
117
+ ```rb
118
+ catalogs = Catalog.all.to_a
119
+ nested = catalogs.to_nested
120
+ puts nested.pretty_inspect
121
+ ```
66
122
 
67
- Преобразует плоскую структуру во вложенную.
123
+ Выведет:
68
124
 
69
- ```ruby
70
- a = [{'id' => 1, 'parent_id' => nil}]
71
- a = NestedArray::Array.new a
72
- b = a.to_nested
125
+ ```
126
+ [
127
+ #<OpenStruct id=1, parent_id=nil, level=0, origin=#<Catalog id: 1, name: "Computer Components", parent_id: nil>, children=[
128
+ #<OpenStruct id=11, parent_id=1, level=1, origin=#<Catalog id: 11, name: "External Components", parent_id: 1>, children=[
129
+ #<OpenStruct id=111, parent_id=11, level=2, origin=#<Catalog id: 111, name: "Hard Drives", parent_id: 11>>,
130
+ #<OpenStruct id=112, parent_id=11, level=2, origin=#<Catalog id: 112, name: "Sound Cards", parent_id: 11>>,
131
+ #<OpenStruct id=113, parent_id=11, level=2, origin=#<Catalog id: 113, name: "KVM Switches", parent_id: 11>>,
132
+ #<OpenStruct id=114, parent_id=11, level=2, origin=#<Catalog id: 114, name: "Optical Drives", parent_id: 11>>
133
+ ]>,
134
+ #<OpenStruct id=12, parent_id=1, level=1, origin=#<Catalog id: 12, name: "Internal Components", parent_id: 1>>
135
+ ]>,
136
+ #<OpenStruct id=2, parent_id=nil, level=0, origin=#<Catalog id: 2, name: "Monitors", parent_id: nil>>,
137
+ #<OpenStruct id=3, parent_id=nil, level=0, origin=#<Catalog id: 3, name: "Servers", parent_id: nil>>,
138
+ #<OpenStruct id=4, parent_id=nil, level=0, origin=#<Catalog id: 4, name: "Networking Products", parent_id: nil>>
139
+ ]
73
140
  ```
74
141
 
75
- __Опции__
142
+ <sub>Метод `.to_nested` использует метод `object.serializable_hash`, чтобы получить список полей объекта.</sub>
76
143
 
77
- У каждой ноды вложенной структуры есть базовые свойства, такие как
78
- идентификатор, идентификатор предка и другие. Для доступа к этим данным
79
- используются ключи, которые можно настроить как в примере ниже. По умолчанию
80
- используются следующие __строковые__ (_чувствительны к string/symbol_) ключи:
81
144
 
82
- ```ruby
83
- b = a.to_nested({
84
- id: 'id', # указывает какое свойство ноды является идентификатором;
85
- parent_id: 'parent_id', # -//- предком;
86
- children: 'children', # -//- массивом потомков;
87
- level: 'level' # -//- дополнительным свойством с уровнем вложенности;
88
- root_id: nil # определяет что является корнем для построения дерева,
89
- # например, для построения ветви корнем корнем
90
- # является идентификатор одной из нод.
91
- })
145
+
146
+
147
+ #### <a id="2.1.3"></a>Опции метода `.to_nested` [↑](#Оглавление оглавлению")
148
+
149
+ ##### <a id="2.1.3.1"></a>`root_id: id` [↑](#Оглавление оглавлению")
150
+
151
+ `root_id: 1` взять потомков узла с `id` равным `1`.
152
+
153
+ ```erb
154
+ <% catalogs_of_1 = Catalog.all.to_a.to_nested(root_id: 1) %>
155
+ <ul>
156
+ <% catalogs_of_1.each_nested do |node, origin| %>
157
+ <%= node.before -%>
158
+ <%= origin.name -%> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
159
+ <%= node.after -%>
160
+ <% end %>
161
+ </ul>
92
162
  ```
93
163
 
94
- Дополнительные опции преобразования:
164
+ Выведет многоуровневый маркированный список потомков узла №1:
95
165
 
96
- ```ruby
97
- b = a.to_nested({
98
- hashed: false, # потомки могут храниться не в массиве а в хэше;
99
- add_level: false, # добавляет в ноду информацию о уровене вложенности ноды;
100
- })
166
+ ![Screenshot](doc/images/2.1.3.1.png)
167
+
168
+
169
+
170
+
171
+ ##### <a id="2.1.3.2"></a>`branch_id: id` [↑](#Оглавление "К оглавлению")
172
+
173
+ `branch_id: 1` — взять узел с `id` равным `1` и всех его потомков.
174
+
175
+ ```erb
176
+ <% catalogs_from_1 = Catalog.all.to_a.to_nested(branch_id: 1) %>
177
+ <ul>
178
+ <% catalogs_from_1.each_nested do |node, origin| %>
179
+ <%= node.before -%>
180
+ <%= origin.name -%> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
181
+ <%= node.after -%>
182
+ <% end %>
183
+ </ul>
101
184
  ```
102
185
 
186
+ Выведет узел №1 и его потомков:
103
187
 
188
+ ![Screenshot](doc/images/2.1.3.2.png)
104
189
 
105
190
 
106
- <a name="each_nested"></a>
107
- ### each_nested [↑](#methods "К методам")
191
+ ### <a id="2.2"></a>Отображение древовидных структур [↑](#Оглавление "К оглавлению")
108
192
 
109
- Перебирает вложенную стуктуру.
193
+ #### <a id="2.2.1"></a>В виде многоуровневых списков [↑](#Оглавление "К оглавлению")
110
194
 
111
- ```ruby
112
- nested.each_nested do |node, parents, level, is_last_children|
113
- puts node # > {'id' => ...}
114
- puts parents # > [{'id' => ...}]
115
- puts level # > 0
116
- puts is_last_children # > false
117
- end
195
+ ##### <a id="2.2.1.1"></a>Маркированный и нумерованный списки `<ul>`, `<ol>` [↑](#Оглавление "К оглавлению")
196
+
197
+ ```erb
198
+ <ul>
199
+ <% @catalogs.to_a.to_nested.each_nested do |node, origin| %>
200
+ <%= node.before %>
201
+ <%= link_to origin.name, origin %> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
202
+ <%= node.after %>
203
+ <% end %>
204
+ </ul>
205
+
206
+ <ol>
207
+ <% @catalogs.to_a.to_nested.each_nested ul: '<ol>', _ul: '</ol>' do |node, origin| %>
208
+ <%= node.before %>
209
+ <%= link_to origin.name, origin %> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
210
+ <%= node.after %>
211
+ <% end %>
212
+ </ol>
118
213
  ```
119
214
 
215
+ ![Screenshot](doc/images/2.2.1.1.png)
120
216
 
121
217
 
122
218
 
123
- <a name="nested_to_html"></a>
124
- ### nested_to_html [↑](#methods "К методам")
125
219
 
126
- Формирует _html_-код для вывода вложенных структур с использованием вложенных друг в друга списков `<ul>`.
220
+ ##### <a id="2.2.1.2"></a>Использование собственных шаблонов для отображения списка [↑](#Оглавление оглавлению")
127
221
 
128
- __Пример__
222
+ Вместо `<ul><li>`/`<ol><li>`
129
223
 
130
- ```ruby
131
- [
132
- {'id' => 1, 'parent_id' => nil, 'name' => 'first'},
133
- {'id' => 2, 'parent_id' => 1, 'name' => 'second'},
134
- {'id' => 3, 'parent_id' => 1, 'name' => 'third'}
135
- ].to_nested.nested_to_html do |node|
136
- node['name']
137
- end
224
+ ```erb
225
+ <% content_for :head do %>
226
+ <style>
227
+ /* Вертикальные отступы узла */
228
+ div.li { margin: .5em 0; }
229
+ /* Отступ уровней (children) */
230
+ div.ul { margin-left: 2em; }
231
+ </style>
232
+ <% end %>
233
+
234
+ <div class="ul">
235
+ <%# Переопределение открывающих и закрывающих тегов шаблонов. %>
236
+ <% @catalogs.to_a.to_nested.each_nested(
237
+ ul: '<div class="ul">',
238
+ _ul: '</div>',
239
+ li: '<div class="li">',
240
+ _li: '</div>'
241
+ ) do |node, origin| %>
242
+ <%= node.before -%>
243
+ <%= origin.name -%> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
244
+ <%= node.after -%>
245
+ <% end %>
246
+ </div>
138
247
  ```
139
248
 
140
- Вернёт
249
+ ![Screenshot](doc/images/2.2.1.2.png)
250
+
251
+
141
252
 
142
- ```html
143
- <li>first
144
- <ul>
145
- <li>second</li>
146
- <li>third</li>
147
- </ul>
148
- </li>
253
+
254
+
255
+ ##### <a id="2.2.1.3"></a>Изменение шаблона в зависимости от данных узла [↑](#Оглавление "К оглавлению")
256
+
257
+ Для изменения шаблонов вывода в зависимости от данных узла мы можем проверять
258
+ поля узла `node.li` и `node.ul`. Если поля не пустые, то вместо вывода их
259
+ содержимого подставлять собственный динамичный html.
260
+
261
+ Вывод имеющихся шаблонов узла (`node.li`, `node.ul` и `node._`):
262
+
263
+ ```erb
264
+ <ul>
265
+ <% @catalogs.to_a.to_nested.each_nested do |node, origin| %>
266
+ <%= node.li -%>
267
+ <%= origin.name -%> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
268
+ <%= node.ul -%>
269
+ <%= node._ -%>
270
+ <% end %>
271
+ </ul>
149
272
  ```
150
273
 
151
- __Расширенный пример__
274
+ ![Screenshot](doc/images/2.2.1.3-1.png)
152
275
 
153
- ```ruby
154
- .nested_to_html li: '<li class="my">', _ul: '<i></i></ul>' do |node, parents, level|
155
- block_options = {}
156
- block_options[:li] = '<li class="my current">' if node['id'] == 2
157
- [
158
- "id: #{node['id']}, #{node['name']}, parent name: #{parents[level]&.[]('name')}",
159
- block_options
160
- ]
161
- end
276
+ Замена шаблонов на динамический html:
277
+
278
+ ```erb
279
+ <% content_for :head do %>
280
+ <style>
281
+ li.level-0 {color: red;}
282
+ li.level-1 {color: green;}
283
+ li.level-2 {color: blue;}
284
+ li.has_children {font-weight: bold;}
285
+ ul.big {border: solid 1px gray;}
286
+ </style>
287
+ <% end %>
288
+
289
+ <ul>
290
+ <% @catalogs.to_a.to_nested.each_nested do |node, origin| %>
291
+ <li class="level-<%= node.level %> <%= 'has_children' if node.is_has_children %>">
292
+ <%= origin.name %> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
293
+ <% if node.ul.present? %>
294
+ <ul class="<%= 'big' if node.children.length > 2 %>">
295
+ <% end %>
296
+ <%= node._ -%>
297
+ <% end %>
298
+ </ul>
162
299
  ```
163
300
 
164
- __Опции__
301
+ ![Screenshot](doc/images/2.2.1.3-2.png)
165
302
 
166
- Все опции могут быть аргументами метода, и только некоторые опции влияют на результат через блок — на лету (последняя строка блока).
303
+ Стоит отметить, что поле `node.li` всегда присутствует в узле, в отличие от
304
+ `node.ul`.
167
305
 
168
- ```ruby
169
- tabulated: true,
170
- inline: false,
171
- tab: "\t",
172
- ul: '<ul>', # может задаваться блоком
173
- _ul: '</ul>',
174
- li: '<li>', # может задаваться блоком
175
- _li: '</li>',
306
+
307
+
308
+
309
+ ##### <a id="2.2.1.4"></a>Расскрывающийся список на основе тега `<details></details>` [↑](#Оглавление "К оглавлению")
310
+
311
+ ```erb
312
+ <ul class="nested_array-details">
313
+ <% @catalogs.to_a.to_nested.each_nested details: true do |node, origin| %>
314
+ <%= node.before %>
315
+ <%= origin.name %> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
316
+ <%= node.after %>
317
+ <% end %>
318
+ </ul>
176
319
  ```
177
320
 
321
+ ![Screenshot](doc/images/2.2.1.4-1.png)
178
322
 
323
+ По умолчанию подуровни скрыты, можно управлять отображением подуровней передавая
324
+ опцию в метод узла: `node.after(open: …)`:
179
325
 
326
+ ```erb
327
+ <ul class="nested_array-details">
328
+ <% @catalogs.to_a.to_nested.each_nested details: true do |node, origin| %>
329
+ <%= node.before %>
330
+ <%= origin.name %> <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
331
+ <%= node.after(open: node.is_has_children) %>
332
+ <% end %>
333
+ </ul>
334
+ ```
180
335
 
181
- <a name="nested_to_options"></a>
182
- ### nested_to_options [↑](#methods "К методам")
336
+ ![Screenshot](doc/images/2.2.1.4-2.png)
183
337
 
184
- Формирования опций для html-тега &lt;select&gt;
185
338
 
186
- Возвращает массив с псевдографикой, позволяющей вывести древовидную структуру.
187
339
 
188
- ```ruby
189
340
 
190
- [['option_text1', 'option_value1'],['option_text2', 'option_value2'],…]
341
+ ##### <a id="2.2.1.5"></a>Формирование и вывод собственных шаблонов опираясь на изменение уровня узла `node.level` [](#Оглавление "К оглавлению")
342
+
343
+ ```erb
344
+ <% content_for :head do %>
345
+ <style>
346
+ div.children {margin-left: 1em;}
347
+ div.node {position: relative;}
348
+ div.node::before {
349
+ position: absolute;
350
+ content: "";
351
+ width: 0px;
352
+ height: 0px;
353
+ border-top: 5px solid transparent;
354
+ border-bottom: 5px solid transparent;
355
+ border-left: 8.66px solid red;
356
+ left: -9px;
357
+ top: 3px;
358
+ }
359
+ </style>
360
+ <% end %>
361
+
362
+ <div class="children">
363
+ <% prev_level = nil %>
364
+ <% @catalogs.to_a.to_nested.each_nested do |node, origin| %>
365
+
366
+ <%# Уровень повысился? — открываем подуровень. %>
367
+ <% if prev_level.present? && prev_level < node.level %>
368
+ <div class="children">
369
+ <% end %>
370
+
371
+ <%# Уровень тот же? — предыдущий закрываем просто. %>
372
+ <% if prev_level.present? && prev_level == node.level %>
373
+ </div>
374
+ <% end %>
375
+
376
+ <%# Уровень понизился? - предыдущий закрываем сложно. %>
377
+ <% if prev_level.present? && prev_level > node.level %>
378
+ <% (prev_level - node.level).times do |t| %>
379
+ </div>
380
+ </div>
381
+ <% end %>
382
+ </div>
383
+ <% end %>
384
+
385
+ <%# Наш узел. %>
386
+ <div class="node">
387
+ <%= origin.name %>
388
+
389
+ <% prev_level = node.level %>
390
+ <% end %>
391
+
392
+ <%# Учёт предыдущего уровня при выходе из цикла (Уровень понизился). %>
393
+ <% if !prev_level.nil? %>
394
+ <% prev_level.times do |t| %>
395
+ </div>
396
+ </div>
397
+ <% end %>
398
+ </div>
399
+ <% end %>
400
+ </div>
191
401
  ```
192
402
 
193
- __Опции__
403
+ ![Screenshot](doc/images/2.2.1.5.png)
194
404
 
195
- ```ruby
196
- option_value: 'id', # Что брать в качестве значений при формировании опций селекта.
197
- option_text: 'name',
405
+
406
+
407
+
408
+ #### <a id="2.2.2"></a>В виде псевдографики [↑](#Оглавление "К оглавлению")
409
+
410
+ ##### <a id="2.2.2.1"></a>Добавление псевдографики перед именем модели методом `nested_to_options` [↑](#Оглавление "К оглавлению")
411
+
412
+ ```erb
413
+ <% options = @catalogs.to_a.to_nested.nested_to_options(:name, :id) %>
414
+ <pre><code><%= options.pluck(0).join($/) %>
415
+ </code></pre>
198
416
  ```
199
417
 
418
+ ![Screenshot](doc/images/2.2.2.1.png)
419
+
200
420
 
201
421
 
202
422
 
203
- <a name="nested_to_collection_select"></a>
204
- ### nested_to_collection_select [↑](#methods "К методам")
423
+ ##### <a id="2.2.2.2"></a>Тонкая псевдографика [↑](#Оглавление "К оглавлению")
205
424
 
206
- Преобразует вложенную структуру данных в плоскую, но добавляет в значение поля
207
- отвечающего за текстовое представление (:name) псевдографику древовидной
208
- структуры.
425
+ ```erb
426
+ <% options = @catalogs.to_a.to_nested.nested_to_options(:name, :id, thin_pseudographic: true) %>
427
+ <pre><code><%= options.pluck(0).join($/) %>
428
+ </code></pre>
429
+ ```
209
430
 
210
- Это позволяет вывести тэг select в сносном виде для использования с вложенными
211
- структурами.
431
+ ![Screenshot](doc/images/2.2.2.2.png)
212
432
 
213
- Пример с хелпером `collection_select`
214
433
 
215
- ```rb
216
- <%= form.collection_select :catalog_ids,
217
- Catalog.all.to_a.to_nested.nested_to_collection_select, :id, :name,
218
- {
219
- # prompt: true
220
- # include_blank: true
221
- },
222
- {
223
- multiple: true,
224
- size: 10
225
- }
226
- %>
434
+
435
+
436
+ ##### <a id="2.2.2.3"></a>Собственная певдографика [↑](#Оглавление "К оглавлению")
437
+
438
+ ```erb
439
+ <% options = @catalogs.to_a.to_nested.nested_to_options(:name, :id, pseudographics: %w(┬ ─ ❇ ├ └ &nbsp; │)) %>
440
+ <pre><code><%= options.pluck(0).join($/).html_safe %>
441
+ </code></pre>
227
442
  ```
228
443
 
229
- Пример с хелпером `select` в сочетании с `options_from_collection_for_select`
444
+ ![Screenshot](doc/images/2.2.2.3.png)
445
+
446
+
447
+
448
+
449
+ ##### <a id="2.2.2.4"></a>Увеличение отступа в собственной псевдографике [↑](#Оглавление "К оглавлению")
230
450
 
231
451
  ```erb
232
- <% catalogs = Catalog.all.to_a %>
233
- <%= form.select :catalog_ids,
234
- options_from_collection_for_select(
235
- catalogs.to_nested.nested_to_collection_select, :id, :name,
236
- disabled: catalogs.select{|x| x.hidden?}.pluck(:id),
237
- selected: form.object.catalog_ids
238
- ),
239
- {
240
- # prompt: true
241
- # include_blank: true
242
- },
243
- {
244
- multiple: true,
245
- size: 10
246
- }
247
- %>
452
+ <% options = @catalogs.to_a.to_nested.nested_to_options(:name, :id, pseudographics: ['─┬', '──', '─&nbsp;', '&nbsp;├', '&nbsp;└', '&nbsp;&nbsp;', '&nbsp;│']) %>
453
+ <pre><code><%= options.pluck(0).join($/).html_safe %>
454
+ </code></pre>
248
455
  ```
249
456
 
457
+ ![Screenshot](doc/images/2.2.2.4.png)
250
458
 
251
459
 
252
460
 
253
- <a name="concat_nested"></a>
254
- ### concat_nested [↑](#methods "К методам")
255
461
 
256
- Скеивание вложенных структур.
462
+ #### <a id="2.2.3"></a>В формах [↑](#Оглавление "К оглавлению")
257
463
 
258
- * Ноды склеиваются если путь к ним одинаков;
259
- * Путь определяется из сложения Текстов (конфигурируемо через :path_key);
464
+ #### <a id="2.2.3.1"></a>С хелпером `form.select` [↑](#Оглавление оглавлению")
260
465
 
261
- __Опции__
466
+ ```erb
467
+ <%= form_with(model: Catalog.find(11), url: root_path, method: :get) do |form| %>
468
+ <%= form.select :parent_id,
469
+ @catalogs.to_a.to_nested.nested_to_options(:name, :id),
470
+ {
471
+ include_blank: 'None'
472
+ },
473
+ {
474
+ multiple: false,
475
+ size: 11,
476
+ class: 'form-select form-select-sm nested_array-select'
477
+ }
478
+ %>
479
+ <% end %>
480
+ ```
262
481
 
263
- ```ruby
264
- path_separator: '-=path_separator=-',
265
- path_key: 'text',
482
+ ![Screenshot](doc/images/2.2.3.1.png)
483
+
484
+
485
+
486
+
487
+ #### <a id="2.2.3.2"></a>С хелперами `form.select` и `options_for_select` [↑](#Оглавление "К оглавлению")
488
+
489
+ ```erb
490
+ <%= form_with(model: Catalog.find(11), url: root_path, method: :get) do |form| %>
491
+ <%= form.select :parent_id,
492
+ options_for_select(
493
+ @catalogs.to_a.to_nested.nested_to_options(:name, :id).unshift(['None', '']),
494
+ selected: form.object.parent_id.to_s
495
+ ),
496
+ {
497
+ },
498
+ {
499
+ multiple: false,
500
+ size: 11,
501
+ class: 'nested_array-select'
502
+ }
503
+ %>
504
+ <% end %>
266
505
  ```
267
506
 
507
+ ![Screenshot](doc/images/2.2.3.2.png)
268
508
 
269
509
 
270
510
 
271
- ## Разработка
272
511
 
273
-
512
+ #### <a id="2.2.3.3"></a>Раскрывающийся список с переключателями `form.radio_button` [↑](#Оглавление "К оглавлению")
274
513
 
514
+ ```erb
515
+ <%= form_with(model: nil, url: root_path, method: :get) do |form| %>
516
+ <ul class="nested_array-details">
517
+ <% @catalogs.to_a.to_nested.each_nested details: true do |node, origin| %>
518
+ <%= node.before %>
519
+ <%= form.radio_button :parent_id, origin.id %>
520
+ <%= form.label :parent_id, origin.name, value: origin.id %>
521
+ <small>[<%= origin.id %>, <%= origin.parent_id || :nil %>, <%= node.level %>]</small>
522
+ <%= node.after(open: node.is_has_children) %>
523
+ <% end %>
524
+ </ul>
525
+ <% end %>
526
+ ```
275
527
 
528
+ ![Screenshot](doc/images/2.2.3.3.png)
276
529
 
277
530
 
278
- ## Содействие
279
531
 
280
-
281
532
 
533
+ ## Разработка
282
534
 
535
+ Для подключения локальной версии гема замените в строке подключения
536
+ (файл Gemfile) второй аргумент (версию) на опцию path:
283
537
 
538
+ ```rb
539
+ # Gemfile
540
+ # Работа с древовидными массивами
541
+ gem "nested_array", path: "../nested_array"
542
+ ```
543
+
544
+ Часто используемые команды
284
545
 
285
- ## Лицензия
546
+ ```sh
286
547
 
287
- В соответствии с условиями [лицензии MIT](https://opensource.org/licenses/MIT).
548
+ ```