Files
ubicloud/lib/option_tree_generator.rb
Burak Yucesoy 34d6702d1d Introduce OptionTreeGenerator
To simplify the creation of dependency trees for options, we are introducing a
new class; OptionTreeGenerator. It provides a very simple interface. You can
call add_option to add a new option and if you specify a parent, it will be
added as a child option of that parent. At the end, you can call serialize,
which returns 2 useful constructs; a dependency tree with all possible options
and paths from parents to reach specified option node, both are used in the
frontend to render the form.
2024-12-09 06:30:01 +01:00

62 lines
1.6 KiB
Ruby

# frozen_string_literal: true
class OptionTreeGenerator
def initialize
@options = []
@parents = {}
end
def add_option(name:, values: nil, parent: nil, &check)
@options << {name:, values:, parent:, check:}
end
def build_subtree(option, path)
return unless option[:values]
subtree = {}
Array(option[:values]).each do |value|
next if option[:check] && !option[:check].call(*path, value)
child_options = @options.select { |opt| opt[:parent] == option[:name] }
subtree[value] = child_options.map do |child_option|
@parents[child_option[:name]] = @parents[option[:name]] + [option[:name]]
[child_option[:name], build_subtree(child_option, path + [value])]
end.to_h
end
subtree
end
def serialize
option_tree = {}
@options.each do |option|
if option[:parent].nil?
@parents[option[:name]] = []
option_tree[option[:name]] = build_subtree(option, [])
end
end
[option_tree, @parents]
end
def self.generate_allowed_options(name, option_tree, parents)
allowed_options = []
traverse = lambda do |tree, path_to_follow, current_path|
if path_to_follow.empty?
allowed_options << current_path
else
current_node = path_to_follow.first
tree[current_node].keys.each do |option|
new_path = current_path.dup
new_path[path_to_follow.first] = option
traverse.call(tree[path_to_follow.first][option], path_to_follow[1..], new_path)
end
end
end
traverse.call(option_tree, parents[name] + [name], {})
allowed_options
end
end