nested_array 2.3.0 → 3.0.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.
data/README-ru.md CHANGED
@@ -1,236 +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>Использование [↑](#Оглавление "К оглавлению")
34
72
 
35
- # Версия с автоматическим расширением базового класса Array методами гема.
73
+ ### <a id="2.1"></a>Преобразование данных методом `.to_nested` [↑](#Оглавление оглавлению")
36
74
 
37
- # Работа с древовидными массивами.
38
- gem "nested_array", "~> 2.0.0"
75
+ #### <a id="2.1.1"></a>Исходные данные – массив хэш [↑](#Оглавление "К оглавлению")
76
+
77
+ Допустим, есть массив хэш:
78
+
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
- * [concat_nested](#concat_nested) — скеивание вложенных структур, ноды склеиваются если путь к ним одинаков.
59
112
 
60
113
 
61
114
 
115
+ #### <a id="2.1.2"></a>Исходные данные – массив ActiveRecord [↑](#Оглавление "К оглавлению")
62
116
 
63
- <a name="to_nested"></a>
64
- ### to_nested [↑](#methods "К методам")
117
+ ```rb
118
+ catalogs = Catalog.all.to_a
119
+ nested = catalogs.to_nested
120
+ puts nested.pretty_inspect
121
+ ```
65
122
 
66
- Преобразует плоскую структуру во вложенную.
123
+ Выведет:
67
124
 
68
- ```ruby
69
- a = [{'id' => 1, 'parent_id' => nil}]
70
- a = NestedArray::Array.new a
71
- 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
+ ]
72
140
  ```
73
141
 
74
- __Опции__
142
+ <sub>Метод `.to_nested` использует метод `object.serializable_hash`, чтобы получить список полей объекта.</sub>
75
143
 
76
- У каждой ноды вложенной структуры есть базовые свойства, такие как
77
- идентификатор, идентификатор предка и другие. Для доступа к этим данным
78
- используются ключи, которые можно настроить как в примере ниже. По умолчанию
79
- используются следующие __строковые__ (_чувствительны к string/symbol_) ключи:
80
144
 
81
- ```ruby
82
- b = a.to_nested({
83
- id: 'id', # указывает какое свойство ноды является идентификатором;
84
- parent_id: 'parent_id', # -//- предком;
85
- children: 'children', # -//- массивом потомков;
86
- level: 'level' # -//- дополнительным свойством с уровнем вложенности;
87
- root_id: nil # определяет что является корнем для построения дерева,
88
- # например, для построения ветви корнем корнем
89
- # является идентификатор одной из нод.
90
- })
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>
91
162
  ```
92
163
 
93
- Дополнительные опции преобразования:
164
+ Выведет многоуровневый маркированный список потомков узла №1:
94
165
 
95
- ```ruby
96
- b = a.to_nested({
97
- hashed: false, # потомки могут храниться не в массиве а в хэше;
98
- add_level: false, # добавляет в ноду информацию о уровене вложенности ноды;
99
- })
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>
100
184
  ```
101
185
 
186
+ Выведет узел №1 и его потомков:
102
187
 
188
+ ![Screenshot](doc/images/2.1.3.2.png)
103
189
 
104
190
 
105
- <a name="each_nested"></a>
106
- ### each_nested [↑](#methods "К методам")
191
+ ### <a id="2.2"></a>Отображение древовидных структур [↑](#Оглавление "К оглавлению")
107
192
 
108
- Перебирает вложенную стуктуру.
193
+ #### <a id="2.2.1"></a>В виде многоуровневых списков [↑](#Оглавление "К оглавлению")
109
194
 
110
- ```ruby
111
- nested.each_nested do |node, parents, level, is_last_children|
112
- puts node # > {'id' => ...}
113
- puts parents # > [{'id' => ...}]
114
- puts level # > 0
115
- puts is_last_children # > false
116
- 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>
117
213
  ```
118
214
 
215
+ ![Screenshot](doc/images/2.2.1.1.png)
119
216
 
120
217
 
121
218
 
122
- <a name="nested_to_html"></a>
123
- ### nested_to_html [↑](#methods "К методам")
124
219
 
125
- Формирует _html_-код для вывода вложенных структур с использованием вложенных друг в друга списков `<ul>`.
220
+ ##### <a id="2.2.1.2"></a>Использование собственных шаблонов для отображения списка [↑](#Оглавление оглавлению")
126
221
 
127
- __Пример__
222
+ Вместо `<ul><li>`/`<ol><li>`
128
223
 
129
- ```ruby
130
- [
131
- {'id' => 1, 'parent_id' => nil, 'name' => 'first'},
132
- {'id' => 2, 'parent_id' => 1, 'name' => 'second'},
133
- {'id' => 3, 'parent_id' => 1, 'name' => 'third'}
134
- ].to_nested.nested_to_html do |node|
135
- node['name']
136
- 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>
137
247
  ```
138
248
 
139
- Вернёт
249
+ ![Screenshot](doc/images/2.2.1.2.png)
250
+
140
251
 
141
- ```html
142
- <li>first
143
- <ul>
144
- <li>second</li>
145
- <li>third</li>
146
- </ul>
147
- </li>
252
+
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>
148
272
  ```
149
273
 
150
- __Расширенный пример__
274
+ ![Screenshot](doc/images/2.2.1.3-1.png)
275
+
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>
299
+ ```
151
300
 
152
- ```ruby
153
- .nested_to_html li: '<li class="my">', _ul: '<i></i></ul>' do |node, parents, level|
154
- block_options = {}
155
- block_options[:li] = '<li class="my current">' if node['id'] == 2
156
- [
157
- "id: #{node['id']}, #{node['name']}, parent name: #{parents[level]&.[]('name')}",
158
- block_options
159
- ]
160
- end
301
+ ![Screenshot](doc/images/2.2.1.3-2.png)
302
+
303
+ Стоит отметить, что поле `node.li` всегда присутствует в узле, в отличие от
304
+ `node.ul`.
305
+
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>
161
319
  ```
162
320
 
163
- __Опции__
321
+ ![Screenshot](doc/images/2.2.1.4-1.png)
164
322
 
165
- Все опции могут быть аргументами метода, и только некоторые опции влияют на результат через блок — на лету (последняя строка блока).
323
+ По умолчанию подуровни скрыты, можно управлять отображением подуровней передавая
324
+ опцию в метод узла: `node.after(open: …)`:
166
325
 
167
- ```ruby
168
- tabulated: true,
169
- inline: false,
170
- tab: "\t",
171
- ul: '<ul>', # может задаваться блоком
172
- _ul: '</ul>',
173
- li: '<li>', # может задаваться блоком
174
- _li: '</li>',
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>
175
334
  ```
176
335
 
336
+ ![Screenshot](doc/images/2.2.1.4-2.png)
337
+
338
+
339
+
340
+
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>
401
+ ```
177
402
 
403
+ ![Screenshot](doc/images/2.2.1.5.png)
178
404
 
179
405
 
180
- <a name="nested_to_options"></a>
181
- ### nested_to_options [↑](#methods "К методам")
182
406
 
183
- Формирования опций для html-тега &lt;select&gt;
184
407
 
185
- Возвращает массив с псевдографикой, позволяющей вывести древовидную структуру.
408
+ #### <a id="2.2.2"></a>В виде псевдографики [↑](#Оглавление оглавлению")
186
409
 
187
- ```ruby
410
+ ##### <a id="2.2.2.1"></a>Добавление псевдографики перед именем модели методом `nested_to_options` [↑](#Оглавление "К оглавлению")
188
411
 
189
- [['option_text1', 'option_value1'],['option_text2', 'option_value2'],…]
412
+ ```erb
413
+ <% options = @catalogs.to_a.to_nested.nested_to_options(:name, :id) %>
414
+ <pre><code><%= options.pluck(0).join($/) %>
415
+ </code></pre>
190
416
  ```
191
417
 
192
- __Опции__
418
+ ![Screenshot](doc/images/2.2.2.1.png)
193
419
 
194
- ```ruby
195
- option_value: 'id', # Что брать в качестве значений при формировании опций селекта.
196
- option_text: 'name',
420
+
421
+
422
+
423
+ ##### <a id="2.2.2.2"></a>Тонкая псевдографика [↑](#Оглавление "К оглавлению")
424
+
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>
197
429
  ```
198
430
 
431
+ ![Screenshot](doc/images/2.2.2.2.png)
199
432
 
200
433
 
201
434
 
202
- <a name="concat_nested"></a>
203
- ### concat_nested [↑](#methods "К методам")
204
435
 
205
- Скеивание вложенных структур.
436
+ ##### <a id="2.2.2.3"></a>Собственная певдографика [↑](#Оглавление "К оглавлению")
206
437
 
207
- * Ноды склеиваются если путь к ним одинаков;
208
- * Путь определяется из сложения Текстов (конфигурируемо через :path_key);
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>
442
+ ```
209
443
 
210
- __Опции__
444
+ ![Screenshot](doc/images/2.2.2.3.png)
211
445
 
212
- ```ruby
213
- path_separator: '-=path_separator=-',
214
- path_key: 'text',
446
+
447
+
448
+
449
+ ##### <a id="2.2.2.4"></a>Увеличение отступа в собственной псевдографике [↑](#Оглавление "К оглавлению")
450
+
451
+ ```erb
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>
215
455
  ```
216
456
 
457
+ ![Screenshot](doc/images/2.2.2.4.png)
458
+
459
+
460
+
461
+
462
+ #### <a id="2.2.3"></a>В формах [↑](#Оглавление "К оглавлению")
463
+
464
+ #### <a id="2.2.3.1"></a>С хелпером `form.select` [↑](#Оглавление "К оглавлению")
465
+
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
+ ```
481
+
482
+ ![Screenshot](doc/images/2.2.3.1.png)
217
483
 
218
484
 
219
485
 
220
- ## Разработка
221
486
 
222
-
487
+ #### <a id="2.2.3.2"></a>С хелперами `form.select` и `options_for_select` [↑](#Оглавление "К оглавлению")
223
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 %>
505
+ ```
506
+
507
+ ![Screenshot](doc/images/2.2.3.2.png)
508
+
509
+
510
+
511
+
512
+ #### <a id="2.2.3.3"></a>Раскрывающийся список с переключателями `form.radio_button` [↑](#Оглавление "К оглавлению")
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
+ ```
527
+
528
+ ![Screenshot](doc/images/2.2.3.3.png)
224
529
 
225
530
 
226
531
 
227
- ## Содействие
228
532
 
229
-
533
+ ## Разработка
230
534
 
535
+ Для подключения локальной версии гема замените в строке подключения
536
+ (файл Gemfile) второй аргумент (версию) на опцию path:
231
537
 
538
+ ```rb
539
+ # Gemfile
540
+ # Работа с древовидными массивами
541
+ gem "nested_array", path: "../nested_array"
542
+ ```
232
543
 
544
+ Часто используемые команды
233
545
 
234
- ## Лицензия
546
+ ```sh
235
547
 
236
- В соответствии с условиями [лицензии MIT](https://opensource.org/licenses/MIT).
548
+ ```