tree_support 0.1.0

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.
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