Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

tree_support

Package Overview
Dependencies
Maintainers
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tree_support

  • 0.1.9
  • Rubygems
  • Socket score

Version published
Maintainers
1
Created
Source
  • Tree structure visualization function library

    [[https://travis-ci.org/akicho8/tree_support.png]]

** Installation

Install as a standalone gem

#+BEGIN_SRC shell $ gem install tree_support #+END_SRC

Or install within application using Gemfile

#+BEGIN_SRC shell $ bundle add tree_support $ bundle install #+END_SRC

** How to use in one line

Just pass the object that has the parent, children method to =TreeSupport.tree=

#+BEGIN_SRC ruby require "tree_support" puts TreeSupport.tree(TreeSupport.example)

>> root

>> ├─Battle

>> │ ├─Attack

>> │ │ ├─Shake the sword

>> │ │ ├─Attack magic

>> │ │ │ ├─Summoned Beast X

>> │ │ │ └─Summoned Beast Y

>> │ │ └─Repel sword in length

>> │ └─Defense

>> ├─Withdraw

>> │ ├─To stop

>> │ │ ├─Place a trap

>> │ │ └─Shoot a bow and arrow

>> │ └─To escape

>> └─Break

>> ├─Stop

>> └─Recover

>> ├─Recovery magic

>> └─Drink recovery medicine

#+END_SRC

** Detailed usage

*** Prepare a node class like this

#+BEGIN_SRC ruby class Node attr_accessor :name, :parent, :children

def initialize(name = nil, &block) @name = name @children = [] if block_given? instance_eval(&block) end end

def add(*args, &block) tap do children << self.class.new(*args, &block).tap { |v| v.parent = self } end end end #+END_SRC

*** Create a tree

#+BEGIN_SRC ruby root = Node.new("root") do add "Battle" do add "Attack" do add "Shake the sword" add "Attack magic" do add "Summoned Beast X" add "Summoned Beast Y" end add "Repel sword in length" end add "Defense" end add "Withdraw" do add "To stop" do add "Place a trap" add "Shoot a bow and arrow" end add "To escape" end add "Break" do add "Stop" add "Recover" do add "Recovery magic" add "Drink recovery medicine" end end end #+END_SRC

*** Visualization

#+BEGIN_SRC ruby puts TreeSupport.tree(root)

>> root

>> ├─Battle

>> │ ├─Attack

>> │ │ ├─Shake the sword

>> │ │ ├─Attack magic

>> │ │ │ ├─Summoned Beast X

>> │ │ │ └─Summoned Beast Y

>> │ │ └─Repel sword in length

>> │ └─Defense

>> ├─Withdraw

>> │ ├─To stop

>> │ │ ├─Place a trap

>> │ │ └─Shoot a bow and arrow

>> │ └─To escape

>> └─Break

>> ├─Stop

>> └─Recover

>> ├─Recovery magic

>> └─Drink recovery medicine

#+END_SRC

*** Troublesome writing TreeSupport.tree

=include TreeSupport::Stringify=

#+BEGIN_SRC ruby Node.include(TreeSupport::Stringify) puts root.to_s_tree

>> root

>> ├─Battle

>> │ ├─Attack

>> │ │ ├─Shake the sword

>> │ │ ├─Attack magic

>> │ │ │ ├─Summoned Beast X

>> │ │ │ └─Summoned Beast Y

>> │ │ └─Repel sword in length

>> │ └─Defense

>> ├─Withdraw

>> │ ├─To stop

>> │ │ ├─Place a trap

>> │ │ └─Shoot a bow and arrow

>> │ └─To escape

>> └─Break

>> ├─Stop

>> └─Recover

>> ├─Recovery magic

>> └─Drink recovery medicine

#+END_SRC

*** How do I change the label of a node?

We look for =to_s_tree_name=, =name=, =subject=, =title=, =to_s= defined by =TreeSupport.name_methods= in that order, so we define the method by considering the priority

*** How do I change labels without defining methods?

Add a block to tree

#+BEGIN_SRC ruby puts TreeSupport.tree(root) { |node| node.object_id }

>> 70308514816100

>> ├─70308514815920

>> │ ├─70308514815780

>> │ │ ├─70308514815680

>> │ │ ├─70308514815580

>> │ │ │ ├─70308514815480

>> │ │ │ └─70308514815420

>> │ │ └─70308514815360

>> │ └─70308514815300

>> ├─70308514815220

>> │ ├─70308514815080

>> │ │ ├─70308514814980

>> │ │ └─70308514814920

>> │ └─70308514814860

>> └─70308514814780

>> ├─70308514814680

>> └─70308514814580

>> ├─70308514814480

>> └─70308514814420

#+END_SRC

*** How to use methods that are common in tree structure?

The following methods become available in include of =TreeSupport::Treeable=
  • root
  • root?
  • leaf?
  • each
  • each_node
  • descendants
  • self_and_descendants
  • ancestors
  • self_and_ancestors
  • siblings
  • self_and_siblings

*** How to convert to Gviz object?

#+BEGIN_SRC ruby gv = TreeSupport.graphviz(root) #+END_SRC

*** How to image it?

#+BEGIN_SRC ruby gv.output("tree.png") #+END_SRC

[[https://raw.github.com/akicho8/tree_support/master/images/tree.png]]

*** How do I change the color of a particular node?

Return the graphviz attribute as a hash in TreeSupport.graphviz block

#+BEGIN_SRC ruby gv = TreeSupport.graphviz(root) do |node| if node.name.include?("Attack") {fillcolor: "lightblue", style: "filled"} elsif node.name.include?("Recover") {fillcolor: "lightpink", style: "filled"} end end gv.output("tree_color.png") #+END_SRC

[[https://raw.github.com/akicho8/tree_support/master/images/tree_color.png]]

*** How do I change the label of a particular node?

As with the above method, it returns a hash containing the label value

#+BEGIN_SRC ruby gv = TreeSupport.graphviz(root) do |node| {label: node.name.chars.first} end gv.output("tree_label.png") #+END_SRC

[[https://raw.github.com/akicho8/tree_support/master/images/tree_label.png]]

*** How can I check the dot format of Graphviz?

#+BEGIN_SRC ruby puts gv.to_dot

>> digraph n70146110700700 {

>> graph [charset = "UTF-8", rankdir = "LR"];

>> n70146110700700 [label = "root"];

>> n70146110700700 -> {n70146110698600; n70146110691220; n70146110689500;};

>> n70146110698600 [label = "Battle"];

>> n70146110698600 -> {n70146110698320; n70146110691720;};

>> n70146110698320 [label = "Attack"];

>> n70146110698320 -> {n70146110697900; n70146110697240; n70146110692060;};

>> n70146110697900 [label = "Shake the sword"];

>> n70146110697240 [label = "Attack magic"];

>> n70146110697240 -> {n70146110695080; n70146110694480;};

>> n70146110695080 [label = "Summoned Beast X"];

>> n70146110694480 [label = "Summoned Beast Y"];

>> n70146110692060 [label = "Repel sword in length"];

>> n70146110691720 [label = "Defense"];

>> n70146110691220 [label = "Withdraw"];

>> n70146110691220 -> {n70146110690400; n70146110689620;};

>> n70146110690400 [label = "To stop"];

>> n70146110690400 -> {n70146110690220; n70146110689820;};

>> n70146110690220 [label = "Place a trap"];

>> n70146110689820 [label = "Shoot a bow and arrow"];

>> n70146110689620 [label = "To escape"];

>> n70146110689500 [label = "Break"];

>> n70146110689500 -> {n70146110688500; n70146110687660;};

>> n70146110688500 [label = "Stop"];

>> n70146110687660 [label = "Recover"];

>> n70146110687660 -> {n70146110686920; n70146110686220;};

>> n70146110686920 [label = "Recovery magic"];

>> n70146110686220 [label = "Drink recovery medicine"];

>> }

#+END_SRC

*** How can I check the image conversion immediately when debugging?

#+BEGIN_SRC ruby TreeSupport.graph_open(root) #+END_SRC

Equivalent to the next shortcut

#+BEGIN_SRC ruby TreeSupport.graphviz(root).output("_output.png") open _output.png #+END_SRC

*** Troublesome making node classes yourself

You can use =TreeSupport::Node= as it is.

#+BEGIN_SRC ruby TreeSupport::Node.new("root") do add "Battle" do add "Attack" do add "Shake the sword" add "Attack magic" do add "Summoned Beast X" add "Summoned Beast Y" end end end end #+END_SRC

*** Troublesome making trees

#+BEGIN_SRC ruby TreeSupport.example #+END_SRC

There is a simple sample tree

*** How to trace leaves?

If you include =TreeSupport::Treeable= you can use each_node

#+BEGIN_SRC ruby root = TreeSupport.example root.each_node.with_index { |n, i| p [i, n.name] }

>> [0, "root"]

>> [1, "Battle"]

>> [2, "Attack"]

>> [3, "Shake the sword"]

>> [4, "Attack magic"]

>> [5, "Summoned Beast X"]

>> [6, "Summoned Beast Y"]

>> [7, "Repel sword in length"]

>> [8, "Defense"]

>> [9, "Withdraw"]

>> [10, "To stop"]

>> [11, "Place a trap"]

>> [12, "Shoot a bow and arrow"]

>> [13, "To escape"]

>> [14, "Break"]

>> [15, "Stop"]

>> [16, "Recover"]

>> [17, "Recovery magic"]

>> [18, "Drink recovery medicine"]

#+END_SRC

*** I do not want to display the root

#+BEGIN_SRC ruby puts TreeSupport.tree(root, drop: 1)

>> Battle

>> ├─Attack

>> │ ├─Shake the sword

>> │ ├─Attack magic

>> │ │ ├─Summoned Beast X

>> │ │ └─Summoned Beast Y

>> │ └─Repel sword in length

>> └─Defense

>> Withdraw

>> ├─To stop

>> │ ├─Place a trap

>> │ └─Shoot a bow and arrow

>> └─To escape

>> Break

>> ├─Stop

>> └─Recover

>> ├─Recovery magic

>> └─Drink recovery medicine

#+END_SRC

*** Since the trees are too big, it is enough up to the depth 3

#+BEGIN_SRC ruby puts TreeSupport.tree(root, take: 3)

>> root

>> ├─Battle

>> │ ├─Attack

>> │ └─Defense

>> ├─Withdraw

>> │ ├─To stop

>> │ └─To escape

>> └─Break

>> ├─Stop

>> └─Recover

#+END_SRC

*** When you combine both

#+BEGIN_SRC ruby puts TreeSupport.tree(root, take: 3, drop: 1)

>> Battle

>> ├─Attack

>> └─Defense

>> Withdraw

>> ├─To stop

>> └─To escape

>> Break

>> ├─Stop

>> └─Recover

#+END_SRC

*** Image version also has similar options

#+BEGIN_SRC ruby gv = TreeSupport.graphviz(root, drop: 1) gv.output("drop.png") #+END_SRC

[[https://raw.github.com/akicho8/tree_support/master/images/drop.png]]

#+BEGIN_SRC ruby gv = TreeSupport.graphviz(root, take: 3) gv.output("take.png") #+END_SRC

[[https://raw.github.com/akicho8/tree_support/master/images/take.png]]

#+BEGIN_SRC ruby gv = TreeSupport.graphviz(root, take: 3, drop: 1) gv.output("take_drop.png") #+END_SRC

[[https://raw.github.com/akicho8/tree_support/master/images/take_drop.png]]

*** Methods for easily making trees from data like CSV

Conversion from Array to Tree

#+BEGIN_SRC ruby require "tree_support"

records = [ {key: :a, parent: nil}, {key: :b, parent: :a}, {key: :c, parent: :b}, ]

When the first node is regarded as a parent

puts TreeSupport.records_to_tree(records).first.to_s_tree

>> a

>> └─b

>> └─c

When you make a parent parenting the whole

puts TreeSupport.records_to_tree(records, root_key: :root).to_s_tree

>> root

>> └─a

>> └─b

>> └─c

#+END_SRC

Conversion from Tree to Array

#+BEGIN_SRC ruby tree = TreeSupport.records_to_tree(records) pp TreeSupport.tree_to_records(tree.first)

>> [

>> {:key=>:a, :parent=>nil},

>> {:key=>:b, :parent=>:a},

>> {:key=>:c, :parent=>:b},

>> ]

#+END_SRC

*** How to use acts_as_tree equivalent?

Migration

#+BEGIN_SRC ruby create_table :nodes do |t| t.belongs_to :parent end #+END_SRC

Model

#+BEGIN_SRC ruby class Node < ActiveRecord::Base ar_tree_model end #+END_SRC

Difference from https://github.com/amerine/acts_as_tree

- simple
- Safely delete all safe_destroy_all (accident with destroy_all in combination with acts_as_list)
- Node.roots is defined by scope
- Arguments are different. =:order => :id= if you want to do it =scope: -> { order(:id) }=. By doing this you can also pass the where condition.

*** How do I correspond to memory_record gem?

Just as with ordinary classes, we need parent and children methods

#+BEGIN_SRC ruby class TreeModel include MemoryRecord memory_record [ {key: :a, parent: nil}, {key: :b, parent: :a}, {key: :c, parent: :b}, ]

include TreeSupport::Treeable include TreeSupport::Stringify

def parent self.class[super] end

def children self.class.find_all { |e| e.parent == self } end end

puts TreeModel.find_all(&:root?).collect(&:to_s_tree)

>> A

>> └─B

>> └─C

#+END_SRC

** With concern

  • Since Gviz extends the standard class, concerns about future interference when combined with Rails (Active Support) etc.

FAQs

Package last updated on 21 Mar 2020

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc