tree_support 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +2 -0
  6. data/README.org +471 -0
  7. data/Rakefile +6 -0
  8. data/examples/0100_simple.rb +22 -0
  9. data/examples/0110_embeded_node_class.rb +26 -0
  10. data/examples/0120_graphiz_output_image.rb +6 -0
  11. data/examples/0130_node_class_example.rb +98 -0
  12. data/examples/0140_active_record.rb +81 -0
  13. data/examples/0150_acts_as_tree.rb +101 -0
  14. data/examples/0160_acts_as_tree_and_list.rb +133 -0
  15. data/examples/0170_node_class.rb +28 -0
  16. data/examples/0180_replace_to_active_record_tree.rb +120 -0
  17. data/examples/0190_generate_ruby_code.rb +68 -0
  18. data/examples/0200_ar_tree_model.rb +82 -0
  19. data/examples/0201_safe_destroy_all.rb +55 -0
  20. data/examples/0210_take_drop.rb +40 -0
  21. data/examples/0220_it_will_not_be_strange_to_tojson.rb +27 -0
  22. data/examples/0230_list_to_tree.rb +68 -0
  23. data/examples/0240_memory_record.rb +34 -0
  24. data/examples/Gemfile +12 -0
  25. data/examples/Gemfile.lock +137 -0
  26. data/examples/demo.rb +126 -0
  27. data/images/drop.png +0 -0
  28. data/images/take.png +0 -0
  29. data/images/take_drop.png +0 -0
  30. data/images/tree.png +0 -0
  31. data/images/tree_color.png +0 -0
  32. data/images/tree_label.png +0 -0
  33. data/lib/tree_support/ar_tree_model.rb +74 -0
  34. data/lib/tree_support/graphviz_builder.rb +78 -0
  35. data/lib/tree_support/inspector.rb +116 -0
  36. data/lib/tree_support/node.rb +124 -0
  37. data/lib/tree_support/railtie.rb +9 -0
  38. data/lib/tree_support/tree_support.rb +28 -0
  39. data/lib/tree_support/treeable.rb +52 -0
  40. data/lib/tree_support/version.rb +3 -0
  41. data/lib/tree_support.rb +2 -0
  42. data/spec/ar_tree_model_spec.rb +82 -0
  43. data/spec/node_spec.rb +52 -0
  44. data/spec/spec_helper.rb +8 -0
  45. data/spec/tree_support_spec.rb +28 -0
  46. data/spec/treeable_spec.rb +59 -0
  47. data/tree_support.gemspec +30 -0
  48. metadata +196 -0
@@ -0,0 +1,81 @@
1
+ # Visualization of tree structure using only ActiveRecord
2
+ #
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+ require "active_record"
6
+ require "pp"
7
+
8
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
9
+ ActiveRecord::Migration.verbose = false
10
+
11
+ ActiveRecord::Schema.define do
12
+ create_table :nodes do |t|
13
+ t.belongs_to :parent
14
+ t.string :name
15
+ end
16
+ end
17
+
18
+ class Node < ActiveRecord::Base
19
+ belongs_to :parent, class_name: name, foreign_key: "parent_id"
20
+ has_many :children, -> { order(:id) }, class_name: name, foreign_key: "parent_id"
21
+
22
+ def add(name, &block)
23
+ tap do
24
+ child = children.create!(name: name)
25
+ if block_given?
26
+ child.instance_eval(&block)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ root = Node.create!(name: "*root*").tap do |n|
33
+ n.instance_eval do
34
+ add "Battle" do
35
+ add "Attack" do
36
+ add "Shake the sword"
37
+ add "Attack magic" do
38
+ add "Summoned Beast X"
39
+ add "Summoned Beast Y"
40
+ end
41
+ add "Repel sword in length"
42
+ end
43
+ add "Defense"
44
+ end
45
+ add "Withdraw" do
46
+ add "To stop" do
47
+ add "Place a trap"
48
+ add "Shoot a bow and arrow"
49
+ end
50
+ add "To escape"
51
+ end
52
+ add "Break" do
53
+ add "Stop"
54
+ add "Recover" do
55
+ add "Recovery magic"
56
+ add "Drink recovery medicine"
57
+ end
58
+ end
59
+ end
60
+ end
61
+
62
+ puts TreeSupport.tree(root)
63
+ # >> *root*
64
+ # >> ├─Battle
65
+ # >> │ ├─Attack
66
+ # >> │ │ ├─Shake the sword
67
+ # >> │ │ ├─Attack magic
68
+ # >> │ │ │ ├─Summoned Beast X
69
+ # >> │ │ │ └─Summoned Beast Y
70
+ # >> │ │ └─Repel sword in length
71
+ # >> │ └─Defense
72
+ # >> ├─Withdraw
73
+ # >> │ ├─To stop
74
+ # >> │ │ ├─Place a trap
75
+ # >> │ │ └─Shoot a bow and arrow
76
+ # >> │ └─To escape
77
+ # >> └─Break
78
+ # >> ├─Stop
79
+ # >> └─Recover
80
+ # >> ├─Recovery magic
81
+ # >> └─Drink recovery medicine
@@ -0,0 +1,101 @@
1
+ # Example using acts_as_tree
2
+ #
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+ require "active_record"
6
+
7
+ begin
8
+ require "acts_as_tree"
9
+ ActiveRecord::Base.include(ActsAsTree)
10
+ end
11
+
12
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
13
+ ActiveRecord::Migration.verbose = false
14
+
15
+ ActiveRecord::Schema.define do
16
+ create_table :nodes do |t|
17
+ t.belongs_to :parent
18
+ t.string :name
19
+ end
20
+ end
21
+
22
+ class Node < ActiveRecord::Base
23
+ acts_as_tree order: "name"
24
+
25
+ def add(name, &block)
26
+ tap do
27
+ child = children.create!(name: name)
28
+ if block_given?
29
+ child.instance_eval(&block)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ _root = Node.create!(name: "*root*").tap do |n|
36
+ n.instance_eval do
37
+ add "Battle" do
38
+ add "Attack" do
39
+ add "Shake the sword"
40
+ add "Attack magic" do
41
+ add "Summoned Beast X"
42
+ add "Summoned Beast Y"
43
+ end
44
+ add "Repel sword in length"
45
+ end
46
+ add "Defense"
47
+ end
48
+ add "Withdraw" do
49
+ add "To stop" do
50
+ add "Place a trap"
51
+ add "Shoot a bow and arrow"
52
+ end
53
+ add "To escape"
54
+ end
55
+ add "Break" do
56
+ add "Stop"
57
+ add "Recover" do
58
+ add "Recovery magic"
59
+ add "Drink recovery medicine"
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ Node.extend(ActsAsTree::TreeView)
66
+ Node.tree_view(:name)
67
+
68
+ # puts TreeSupport.tree(root)
69
+ # ~> from -:8:in `<main>'
70
+ # ~> from -:8:in `require'
71
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree.rb:322:in `<top (required)>'
72
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree.rb:322:in `require'
73
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree/active_record/acts/tree.rb:1:in `<top (required)>'
74
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree/active_record/acts/tree.rb:1:in `require'
75
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activesupport-5.0.0/lib/active_support/core_ext/hash/transform_values.rb:11: warning: method redefined; discarding old transform_values
76
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activesupport-5.0.0/lib/active_support/core_ext/hash/transform_values.rb:23: warning: method redefined; discarding old transform_values!
77
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
78
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
79
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
80
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
81
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/arel-7.1.0/lib/arel/nodes/casted.rb:14: warning: instance variable @class not initialized
82
+ # >> root
83
+ # >> |_ *root*
84
+ # >> | |_ Battle
85
+ # >> | |_ Attack
86
+ # >> | |_ Attack magic
87
+ # >> | |_ Summoned Beast X
88
+ # >> | |_ Summoned Beast Y
89
+ # >> | |_ Repel sword in length
90
+ # >> | |_ Shake the sword
91
+ # >> | |_ Defense
92
+ # >> | |_ Break
93
+ # >> | |_ Recover
94
+ # >> | |_ Drink recovery medicine
95
+ # >> | |_ Recovery magic
96
+ # >> | |_ Stop
97
+ # >> | |_ Withdraw
98
+ # >> | |_ To escape
99
+ # >> | |_ To stop
100
+ # >> | |_ Place a trap
101
+ # >> | |_ Shoot a bow and arrow
@@ -0,0 +1,133 @@
1
+ # Example of holding sibling's order in acts_as_list with acts_as_tree
2
+ #
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+ require "active_record"
6
+
7
+ begin
8
+ require "acts_as_tree"
9
+ ActiveRecord::Base.include(ActsAsTree)
10
+ end
11
+
12
+ begin
13
+ require "acts_as_list"
14
+ ActiveRecord::Base.include(ActiveRecord::Acts::List)
15
+ end
16
+
17
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
18
+ ActiveRecord::Migration.verbose = false
19
+
20
+ ActiveRecord::Schema.define do
21
+ create_table :nodes do |t|
22
+ t.belongs_to :parent
23
+ t.string :name
24
+ t.integer :position
25
+ end
26
+ end
27
+
28
+ class Node < ActiveRecord::Base
29
+ acts_as_tree order: "position"
30
+ acts_as_list scope: :parent
31
+
32
+ def add(name, &block)
33
+ tap do
34
+ child = children.create!(name: name)
35
+ if block_given?
36
+ child.instance_eval(&block)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ root = Node.create!(name: "*root*").tap do |n|
43
+ n.instance_eval do
44
+ add "Battle" do
45
+ add "Attack" do
46
+ add "Shake the sword"
47
+ add "Attack magic" do
48
+ add "Summoned Beast X"
49
+ add "Summoned Beast Y"
50
+ end
51
+ add "Repel sword in length"
52
+ end
53
+ add "Defense"
54
+ end
55
+ add "Withdraw" do
56
+ add "To stop" do
57
+ add "Place a trap"
58
+ add "Shoot a bow and arrow"
59
+ end
60
+ add "To escape"
61
+ end
62
+ add "Break" do
63
+ add "Stop"
64
+ add "Recover" do
65
+ add "Recovery magic"
66
+ add "Drink recovery medicine"
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ # Node.extend(ArTreeModel::TreeView)
73
+ # Node.tree_view(:name)
74
+
75
+ puts TreeSupport.tree(root) {|e| "#{e.name}(#{e.position})"}
76
+
77
+ # acts_as_tree + acts_as_list は destroy_all で事故る
78
+ Node.destroy_all rescue $! # => #<ActiveRecord::RecordNotFound: Couldn't find Node with 'id'=2>
79
+ # ~> from -:8:in `<main>'
80
+ # ~> from -:8:in `require'
81
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree.rb:322:in `<top (required)>'
82
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree.rb:322:in `require'
83
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree/active_record/acts/tree.rb:1:in `<top (required)>'
84
+ # ~> from /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/acts_as_tree-2.4.0/lib/acts_as_tree/active_record/acts/tree.rb:1:in `require'
85
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activesupport-5.0.0/lib/active_support/core_ext/hash/transform_values.rb:11: warning: method redefined; discarding old transform_values
86
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activesupport-5.0.0/lib/active_support/core_ext/hash/transform_values.rb:23: warning: method redefined; discarding old transform_values!
87
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
88
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
89
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
90
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/concurrent-ruby-1.0.2/lib/concurrent/map.rb:230: warning: constant ::Fixnum is deprecated
91
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/arel-7.1.0/lib/arel/nodes/casted.rb:14: warning: instance variable @class not initialized
92
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
93
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
94
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
95
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
96
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
97
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
98
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
99
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
100
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
101
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
102
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
103
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
104
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
105
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
106
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
107
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
108
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
109
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
110
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/activerecord-5.0.0/lib/active_record/sanitization.rb:163: warning: too many arguments for format string
111
+ # ~> /usr/local/var/rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/arel-7.1.0/lib/arel/nodes/casted.rb:14: warning: instance variable @class not initialized
112
+ # ~> !XMP1512801308_58182_9031![1] => ActiveRecord::RecordNotFound #<ActiveRecord::RecordNotFound: Couldn't find Node with 'id'=2>
113
+ # ~> root
114
+ # ~> _xmp_1512801308_58182_55846
115
+ # >> *root*(1)
116
+ # >> ├─Battle(1)
117
+ # >> │ ├─Attack(1)
118
+ # >> │ │ ├─Shake the sword(1)
119
+ # >> │ │ ├─Attack magic(2)
120
+ # >> │ │ │ ├─Summoned Beast X(1)
121
+ # >> │ │ │ └─Summoned Beast Y(2)
122
+ # >> │ │ └─Repel sword in length(3)
123
+ # >> │ └─Defense(2)
124
+ # >> ├─Withdraw(2)
125
+ # >> │ ├─To stop(1)
126
+ # >> │ │ ├─Place a trap(1)
127
+ # >> │ │ └─Shoot a bow and arrow(2)
128
+ # >> │ └─To escape(2)
129
+ # >> └─Break(3)
130
+ # >> ├─Stop(1)
131
+ # >> └─Recover(2)
132
+ # >> ├─Recovery magic(1)
133
+ # >> └─Drink recovery medicine(2)
@@ -0,0 +1,28 @@
1
+ # each_node can be used if Treeable module is included
2
+ #
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+
6
+ root = TreeSupport.example
7
+ root.class.ancestors # => [TreeSupport::Node, TreeSupport::Stringify, TreeSupport::Treeable, Object, Kernel, BasicObject]
8
+ root.each_node.with_index { |n, i| p [i, n.name] }
9
+
10
+ # >> [0, "*root*"]
11
+ # >> [1, "Battle"]
12
+ # >> [2, "Attack"]
13
+ # >> [3, "Shake the sword"]
14
+ # >> [4, "Attack magic"]
15
+ # >> [5, "Summoned Beast X"]
16
+ # >> [6, "Summoned Beast Y"]
17
+ # >> [7, "Repel sword in length"]
18
+ # >> [8, "Defense"]
19
+ # >> [9, "Withdraw"]
20
+ # >> [10, "To stop"]
21
+ # >> [11, "Place a trap"]
22
+ # >> [12, "Shoot a bow and arrow"]
23
+ # >> [13, "To escape"]
24
+ # >> [14, "Break"]
25
+ # >> [15, "Stop"]
26
+ # >> [16, "Recover"]
27
+ # >> [17, "Recovery magic"]
28
+ # >> [18, "Drink recovery medicine"]
@@ -0,0 +1,120 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # Idiom replacing TreeSupport::Node's tree with ActiveRecord's tree
4
+ #
5
+ require "bundler/setup"
6
+ require "tree_support"
7
+ require "active_record"
8
+
9
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
10
+ ActiveRecord::Migration.verbose = false
11
+
12
+ ActiveRecord::Schema.define do
13
+ create_table :nodes do |t|
14
+ t.belongs_to :parent
15
+ t.string :name
16
+ end
17
+ end
18
+
19
+ class Node < ActiveRecord::Base
20
+ belongs_to :parent, class_name: name, foreign_key: :parent_id
21
+ has_many :children, class_name: name, foreign_key: :parent_id
22
+ end
23
+
24
+ # METHOD 1. It is simple but unique key equivalent becomes essential
25
+ Node.destroy_all
26
+ TreeSupport.example.each_node do |node|
27
+ obj = Node.find_or_initialize_by(name: node.name) # I'm doing find_or to update
28
+ if node.parent
29
+ obj.parent = Node.find_by(name: node.parent.name) # It is difficult to draw here without a unique key
30
+ else
31
+ obj.parent = nil
32
+ end
33
+ obj.save!
34
+ end
35
+ root = Node.find_by(name: TreeSupport.example.name)
36
+ puts TreeSupport.tree(root)
37
+
38
+ # METHOD 2. Improve method 1 by making sure that parents are always present when children are made
39
+ Node.destroy_all
40
+ stock = {}
41
+ TreeSupport.example.each_node do |node|
42
+ obj = Node.find_or_initialize_by(name: node.name)
43
+ if node.parent
44
+ obj.parent = stock[node.parent]
45
+ else
46
+ obj.parent = nil
47
+ end
48
+ obj.save!
49
+ stock[node] = obj
50
+ end
51
+ root = Node.find_by(name: TreeSupport.example.name)
52
+ puts TreeSupport.tree(root)
53
+
54
+ # Method 3. Unnecessary to use a unique key when recursive. However, it is a bit that create! Is two places. Update is difficult (?)
55
+ Node.destroy_all
56
+ def create_recursion(root, node)
57
+ sub = root.children.create!(name: node.name)
58
+ node.children.each {|node| create_recursion(sub, node) }
59
+ end
60
+ root = Node.create!(name: TreeSupport.example.name)
61
+ TreeSupport.example.children.each {|node| create_recursion(root, node)}
62
+ puts TreeSupport.tree(root)
63
+
64
+ # >> *root*
65
+ # >> ├─Battle
66
+ # >> │ ├─Attack
67
+ # >> │ │ ├─Shake the sword
68
+ # >> │ │ ├─Attack magic
69
+ # >> │ │ │ ├─Summoned Beast X
70
+ # >> │ │ │ └─Summoned Beast Y
71
+ # >> │ │ └─Repel sword in length
72
+ # >> │ └─Defense
73
+ # >> ├─Withdraw
74
+ # >> │ ├─To stop
75
+ # >> │ │ ├─Place a trap
76
+ # >> │ │ └─Shoot a bow and arrow
77
+ # >> │ └─To escape
78
+ # >> └─Break
79
+ # >> ├─Stop
80
+ # >> └─Recover
81
+ # >> ├─Recovery magic
82
+ # >> └─Drink recovery medicine
83
+ # >> *root*
84
+ # >> ├─Battle
85
+ # >> │ ├─Attack
86
+ # >> │ │ ├─Shake the sword
87
+ # >> │ │ ├─Attack magic
88
+ # >> │ │ │ ├─Summoned Beast X
89
+ # >> │ │ │ └─Summoned Beast Y
90
+ # >> │ │ └─Repel sword in length
91
+ # >> │ └─Defense
92
+ # >> ├─Withdraw
93
+ # >> │ ├─To stop
94
+ # >> │ │ ├─Place a trap
95
+ # >> │ │ └─Shoot a bow and arrow
96
+ # >> │ └─To escape
97
+ # >> └─Break
98
+ # >> ├─Stop
99
+ # >> └─Recover
100
+ # >> ├─Recovery magic
101
+ # >> └─Drink recovery medicine
102
+ # >> *root*
103
+ # >> ├─Battle
104
+ # >> │ ├─Attack
105
+ # >> │ │ ├─Shake the sword
106
+ # >> │ │ ├─Attack magic
107
+ # >> │ │ │ ├─Summoned Beast X
108
+ # >> │ │ │ └─Summoned Beast Y
109
+ # >> │ │ └─Repel sword in length
110
+ # >> │ └─Defense
111
+ # >> ├─Withdraw
112
+ # >> │ ├─To stop
113
+ # >> │ │ ├─Place a trap
114
+ # >> │ │ └─Shoot a bow and arrow
115
+ # >> │ └─To escape
116
+ # >> └─Break
117
+ # >> ├─Stop
118
+ # >> └─Recover
119
+ # >> ├─Recovery magic
120
+ # >> └─Drink recovery medicine
@@ -0,0 +1,68 @@
1
+ # Generating original code from tree of TreeSupport::Node Rough
2
+
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+
6
+ def generate(node)
7
+ s = ""
8
+ if node.parent
9
+ s << "add #{node.name.inspect}"
10
+ else
11
+ s << "TreeSupport::Node.new(#{node.name.inspect})"
12
+ end
13
+ unless node.children.empty?
14
+ s << [" do\n", node.children.collect {|node| generate(node) }.join, "end"].join
15
+ end
16
+ s << "\n"
17
+ end
18
+
19
+ code = generate(TreeSupport.example)
20
+ puts code
21
+
22
+ puts TreeSupport.tree(eval(code))
23
+ # >> TreeSupport::Node.new("*root*") do
24
+ # >> add "Battle" do
25
+ # >> add "Attack" do
26
+ # >> add "Shake the sword"
27
+ # >> add "Attack magic" do
28
+ # >> add "Summoned Beast X"
29
+ # >> add "Summoned Beast Y"
30
+ # >> end
31
+ # >> add "Repel sword in length"
32
+ # >> end
33
+ # >> add "Defense"
34
+ # >> end
35
+ # >> add "Withdraw" do
36
+ # >> add "To stop" do
37
+ # >> add "Place a trap"
38
+ # >> add "Shoot a bow and arrow"
39
+ # >> end
40
+ # >> add "To escape"
41
+ # >> end
42
+ # >> add "Break" do
43
+ # >> add "Stop"
44
+ # >> add "Recover" do
45
+ # >> add "Recovery magic"
46
+ # >> add "Drink recovery medicine"
47
+ # >> end
48
+ # >> end
49
+ # >> end
50
+ # >> *root*
51
+ # >> ├─Battle
52
+ # >> │ ├─Attack
53
+ # >> │ │ ├─Shake the sword
54
+ # >> │ │ ├─Attack magic
55
+ # >> │ │ │ ├─Summoned Beast X
56
+ # >> │ │ │ └─Summoned Beast Y
57
+ # >> │ │ └─Repel sword in length
58
+ # >> │ └─Defense
59
+ # >> ├─Withdraw
60
+ # >> │ ├─To stop
61
+ # >> │ │ ├─Place a trap
62
+ # >> │ │ └─Shoot a bow and arrow
63
+ # >> │ └─To escape
64
+ # >> └─Break
65
+ # >> ├─Stop
66
+ # >> └─Recover
67
+ # >> ├─Recovery magic
68
+ # >> └─Drink recovery medicine
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # An example using TreeSupport::ArTreeModel of alternate library of acts_as_tree
4
+ #
5
+ require "bundler/setup"
6
+
7
+ require "rails"
8
+ require "active_record"
9
+ require "tree_support"
10
+
11
+ Class.new(Rails::Application) { config.eager_load = false }.initialize! # Activate ar_tree_model
12
+
13
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
14
+ ActiveRecord::Migration.verbose = false
15
+
16
+ ActiveRecord::Schema.define do
17
+ create_table :nodes do |t|
18
+ t.belongs_to :parent
19
+ t.string :name
20
+ end
21
+ end
22
+
23
+ class Node < ActiveRecord::Base
24
+ ar_tree_model scope: -> { order(:name).where.not(name: "Break") }
25
+
26
+ def add(name, &block)
27
+ tap do
28
+ child = children.create!(name: name)
29
+ if block_given?
30
+ child.instance_eval(&block)
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ Node.create!(name: "*root*").tap do |n|
37
+ n.instance_eval do
38
+ add "Battle" do
39
+ add "Attack" do
40
+ add "Shake the sword"
41
+ add "Attack magic" do
42
+ add "Summoned Beast X"
43
+ add "Summoned Beast Y"
44
+ end
45
+ add "Repel sword in length"
46
+ end
47
+ add "Defense"
48
+ end
49
+ add "Withdraw" do
50
+ add "To stop" do
51
+ add "Place a trap"
52
+ add "Shoot a bow and arrow"
53
+ end
54
+ add "To escape"
55
+ end
56
+ add "Break" do
57
+ add "Stop"
58
+ add "Recover" do
59
+ add "Recovery magic"
60
+ add "Drink recovery medicine"
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ puts Node.root.to_s_tree
67
+ Node.destroy_all # Because it does not use acts_as_list, it can be erased
68
+
69
+ # >> *root*
70
+ # >> ├─Battle
71
+ # >> │ ├─Attack
72
+ # >> │ │ ├─Attack magic
73
+ # >> │ │ │ ├─Summoned Beast X
74
+ # >> │ │ │ └─Summoned Beast Y
75
+ # >> │ │ ├─Repel sword in length
76
+ # >> │ │ └─Shake the sword
77
+ # >> │ └─Defense
78
+ # >> └─Withdraw
79
+ # >> ├─To escape
80
+ # >> └─To stop
81
+ # >> ├─Place a trap
82
+ # >> └─Shoot a bow and arrow
@@ -0,0 +1,55 @@
1
+ # An example requiring safe_destroy_all (since acts_as_list is behind, you can roll it with destroy_all)
2
+
3
+ require "bundler/setup"
4
+
5
+ require "rails"
6
+ require "active_record"
7
+ require "tree_support"
8
+
9
+ begin
10
+ require "acts_as_list"
11
+ ActiveRecord::Base.include(ActiveRecord::Acts::List)
12
+ end
13
+
14
+ Class.new(Rails::Application) { config.eager_load = false }.initialize! # Activate ar_tree_model
15
+
16
+ ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
17
+ ActiveRecord::Migration.verbose = false
18
+
19
+ ActiveRecord::Schema.define do
20
+ create_table :nodes do |t|
21
+ t.belongs_to :parent
22
+ t.string :name
23
+ t.integer :position
24
+ end
25
+ end
26
+
27
+ class Node < ActiveRecord::Base
28
+ ar_tree_model
29
+ acts_as_list scope: :parent
30
+
31
+ def add(name, &block)
32
+ tap do
33
+ child = children.create!(name: name)
34
+ if block_given?
35
+ child.instance_eval(&block)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ Node.create!(name: "*root*").tap do |n|
42
+ n.instance_eval do
43
+ add "Battle" do
44
+ add "Attack"
45
+ end
46
+ end
47
+ end
48
+
49
+ puts Node.root.to_s_tree
50
+ Node.destroy_all rescue $! # => #<ActiveRecord::RecordNotFound: Couldn't find Node with 'id'=2>
51
+ Node.safe_destroy_all
52
+ Node.count # => 0
53
+ # >> *root*
54
+ # >> └─Battle
55
+ # >> └─Attack