nested_array 2.4.0 → 3.0.1

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,287 +1,557 @@
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
- })
92
- ```
93
145
 
94
- Дополнительные опции преобразования:
95
146
 
96
- ```ruby
97
- b = a.to_nested({
98
- hashed: false, # потомки могут храниться не в массиве а в хэше;
99
- add_level: false, # добавляет в ноду информацию о уровене вложенности ноды;
100
- })
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>
101
162
  ```
102
163
 
164
+ Выведет многоуровневый маркированный список потомков узла №1:
103
165
 
166
+ ![Screenshot](doc/images/2.1.3.1.png)
104
167
 
105
168
 
106
- <a name="each_nested"></a>
107
- ### each_nested [↑](#methods "К методам")
108
169
 
109
- Перебирает вложенную стуктуру.
110
170
 
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
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>
118
184
  ```
119
185
 
186
+ Выведет узел №1 и его потомков:
120
187
 
188
+ ![Screenshot](doc/images/2.1.3.2.png)
121
189
 
122
190
 
123
- <a name="nested_to_html"></a>
124
- ### nested_to_html [↑](#methods "К методам")
191
+ ### <a id="2.2"></a>Отображение древовидных структур [↑](#Оглавление "К оглавлению")
125
192
 
126
- Формирует _html_-код для вывода вложенных структур с использованием вложенных друг в друга списков `<ul>`.
193
+ #### <a id="2.2.1"></a>В виде многоуровневых списков [↑](#Оглавление оглавлению")
127
194
 
128
- __Пример__
195
+ ##### <a id="2.2.1.1"></a>Маркированный и нумерованный списки `<ul>`, `<ol>` [↑](#Оглавление "К оглавлению")
129
196
 
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
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>
138
213
  ```
139
214
 
140
- Вернёт
215
+ ![Screenshot](doc/images/2.2.1.1.png)
216
+
217
+
141
218
 
142
- ```html
143
- <li>first
144
- <ul>
145
- <li>second</li>
146
- <li>third</li>
147
- </ul>
148
- </li>
219
+
220
+ ##### <a id="2.2.1.2"></a>Использование собственных шаблонов для отображения списка [↑](#Оглавление "К оглавлению")
221
+
222
+ Вместо `<ul><li>`/`<ol><li>`
223
+
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>
149
247
  ```
150
248
 
151
- __Расширенный пример__
249
+ ![Screenshot](doc/images/2.2.1.2.png)
152
250
 
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
251
+
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>
162
272
  ```
163
273
 
164
- __Опции__
274
+ ![Screenshot](doc/images/2.2.1.3-1.png)
165
275
 
166
- Все опции могут быть аргументами метода, и только некоторые опции влияют на результат через блок — на лету (последняя строка блока).
276
+ Замена шаблонов на динамический html:
167
277
 
168
- ```ruby
169
- tabulated: true,
170
- inline: false,
171
- tab: "\t",
172
- ul: '<ul>', # может задаваться блоком
173
- _ul: '</ul>',
174
- li: '<li>', # может задаваться блоком
175
- _li: '</li>',
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>
176
299
  ```
177
300
 
301
+ ![Screenshot](doc/images/2.2.1.3-2.png)
178
302
 
303
+ Стоит отметить, что поле `node.li` всегда присутствует в узле, в отличие от
304
+ `node.ul`.
179
305
 
180
306
 
181
- <a name="nested_to_options"></a>
182
- ### nested_to_options [↑](#methods "К методам")
183
307
 
184
- Формирования опций для html-тега &lt;select&gt;
185
308
 
186
- Возвращает массив с псевдографикой, позволяющей вывести древовидную структуру.
309
+ ##### <a id="2.2.1.4"></a>Расскрывающийся список на основе тега `<details></details>` [↑](#Оглавление "К оглавлению")
187
310
 
188
- ```ruby
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>
319
+ ```
189
320
 
190
- [['option_text1', 'option_value1'],['option_text2', 'option_value2'],…]
321
+ ![Screenshot](doc/images/2.2.1.4-1.png)
322
+
323
+ По умолчанию подуровни скрыты, можно управлять отображением подуровней передавая
324
+ опцию в метод узла: `node.after(open: …)`:
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>
191
334
  ```
192
335
 
193
- __Опции__
336
+ ![Screenshot](doc/images/2.2.1.4-2.png)
194
337
 
195
- ```ruby
196
- option_value: 'id', # Что брать в качестве значений при формировании опций селекта.
197
- option_text: 'name',
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>
198
401
  ```
199
402
 
403
+ ![Screenshot](doc/images/2.2.1.5.png)
404
+
200
405
 
201
406
 
202
407
 
203
- <a name="nested_to_collection_select"></a>
204
- ### nested_to_collection_select [↑](#methods "К методам")
408
+ #### <a id="2.2.2"></a>В виде псевдографики [↑](#Оглавление "К оглавлению")
205
409
 
206
- Преобразует вложенную структуру данных в плоскую, но добавляет в значение поля
207
- отвечающего за текстовое представление (:name) псевдографику древовидной
208
- структуры.
410
+ ##### <a id="2.2.2.1"></a>Добавление псевдографики перед именем модели методом `nested_to_options` [↑](#Оглавление "К оглавлению")
209
411
 
210
- Это позволяет вывести тэг select в сносном виде для использования с вложенными
211
- структурами.
412
+ ```erb
413
+ <% options = @catalogs.to_a.to_nested.nested_to_options(:name, :id) %>
414
+ <pre><code><%= options.pluck(0).join($/) %>
415
+ </code></pre>
416
+ ```
212
417
 
213
- Пример с хелпером `collection_select`
418
+ ![Screenshot](doc/images/2.2.2.1.png)
214
419
 
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
- %>
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>
227
429
  ```
228
430
 
229
- Пример с хелпером `select` в сочетании с `options_from_collection_for_select`
431
+ ![Screenshot](doc/images/2.2.2.2.png)
432
+
433
+
434
+
435
+
436
+ ##### <a id="2.2.2.3"></a>Собственная певдографика [↑](#Оглавление "К оглавлению")
230
437
 
231
438
  ```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
- %>
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>
248
442
  ```
249
443
 
444
+ ![Screenshot](doc/images/2.2.2.3.png)
445
+
446
+
250
447
 
251
448
 
449
+ ##### <a id="2.2.2.4"></a>Увеличение отступа в собственной псевдографике [↑](#Оглавление "К оглавлению")
252
450
 
253
- <a name="concat_nested"></a>
254
- ### concat_nested [↑](#methods методам")
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>
455
+ ```
255
456
 
256
- Скеивание вложенных структур.
457
+ ![Screenshot](doc/images/2.2.2.4.png)
257
458
 
258
- * Ноды склеиваются если путь к ним одинаков;
259
- * Путь определяется из сложения Текстов (конфигурируемо через :path_key);
260
459
 
261
- __Опции__
262
460
 
263
- ```ruby
264
- path_separator: '-=path_separator=-',
265
- path_key: 'text',
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 %>
266
480
  ```
267
481
 
482
+ ![Screenshot](doc/images/2.2.3.1.png)
268
483
 
269
484
 
270
485
 
271
- ## Разработка
272
486
 
273
-
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 %>
505
+ ```
506
+
507
+ ![Screenshot](doc/images/2.2.3.2.png)
508
+
509
+
274
510
 
275
511
 
512
+ #### <a id="2.2.3.3"></a>Раскрывающийся список с переключателями `form.radio_button` [↑](#Оглавление "К оглавлению")
276
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
+ ```
277
527
 
278
- ## Содействие
528
+ ![Screenshot](doc/images/2.2.3.3.png)
279
529
 
280
-
281
530
 
282
531
 
283
532
 
533
+ ## Разработка
284
534
 
285
- ## Лицензия
535
+ Часто используемые команды
536
+
537
+ ```sh
538
+ # rspec управляет загружаемыми гемами, поэтому сам rspec запускается НЕ `bundle
539
+ # exec rspec`, а просто `rspec` или `./bin/rspec`.
540
+ rspec ./spec/lib/nested_array_spec.rb
541
+ rspec ./spec/lib/nested_array/nested_spec.rb
542
+ rspec # Прогон тестов
543
+ subl lib/nested_array/version.rb # Обновление версии
544
+ bundle exec yard doc # Обновление документации в doc/_index.html
545
+ git … # Git-фиксация в origin/master и тег
546
+ gem build # Сборка гема
547
+ gem push ./nested_array-… # Публикация гема
548
+ ```
286
549
 
287
- В соответствии с условиями [лицензии MIT](https://opensource.org/licenses/MIT).
550
+ Для подключения локальной версии гема в rails замените в строке подключения
551
+ (файл Gemfile) второй аргумент (версию) на опцию path:
552
+
553
+ ```rb
554
+ # Gemfile
555
+ # Работа с древовидными массивами
556
+ gem "nested_array", path: "../nested_array"
557
+ ```