module NestedArray::Nested class Error < StandardError end extend ActiveSupport::Concern included do |recipient| NESTED_OPTIONS ||= { # Имена полей для получения/записи информации, чувствительны к string/symbol id: 'id', parent_id: 'parent_id', children: 'children', level: 'level', # Параметры для преобразования в nested hashed: false, add_level: false, root_id: nil, # Параметры для преобразования в html tabulated: true, inline: false, tab: "\t", ul: '', li: '
  • ', _li: '
  • ', # Параматры для "склеивания" вложенных структур path_separator: '-=path_separator=-', path_key: 'text', # Настройки формирования массива для опций тега # с псевдографикой, позволяющей вывести древовидную структуру. # ``` # [['option_text1', 'option_value1'],['option_text2', 'option_value2'],…] # ``` def nested_to_options options={} options = NESTED_OPTIONS.merge options ret = [] last = [] each_nested do |node, parents, level, is_last| last[level+1] = is_last node_text = node[options[:option_text]] node_level = (1..level).map{|l| last[l] == true ? ' ' : '┃'}.join node_last = is_last ? '┗' : '┣' node_children = node[options[:children]].present? && node[options[:children]].length > 0 ? '┳' : '━' option_text = "#{node_level}#{node_last}#{node_children}╸#{node_text}" option_value = node[options[:option_value]] ret.push [option_text, option_value] end ret end # "Скеивание" вложенных структур # ноды склеиваются если путь к ним одинаков; # путь определяется из сложения Текстов (конфигурируемо через :path_key); def concat_nested tree=nil, options={} options = NESTED_OPTIONS.merge options return self if tree.nil? children_cache = {} tree.each_nested options do |node, parents, level| parent_path_names = parents.compact.map{|e| e[options[:path_key]]} parent_path = parent_path_names.join(options[:path_separator]) path = parent_path_names.push(node[options[:path_key]]).join(options[:path_separator]) element = node if !children_cache.keys.include? path if parent_path == '' array = self else array = children_cache[parent_path] end element[options[:children]] = [] array << element children_cache[parent_path] = array children_cache[path] = element[options[:children]] end end self end end