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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +2 -0
- data/README.org +471 -0
- data/Rakefile +6 -0
- data/examples/0100_simple.rb +22 -0
- data/examples/0110_embeded_node_class.rb +26 -0
- data/examples/0120_graphiz_output_image.rb +6 -0
- data/examples/0130_node_class_example.rb +98 -0
- data/examples/0140_active_record.rb +81 -0
- data/examples/0150_acts_as_tree.rb +101 -0
- data/examples/0160_acts_as_tree_and_list.rb +133 -0
- data/examples/0170_node_class.rb +28 -0
- data/examples/0180_replace_to_active_record_tree.rb +120 -0
- data/examples/0190_generate_ruby_code.rb +68 -0
- data/examples/0200_ar_tree_model.rb +82 -0
- data/examples/0201_safe_destroy_all.rb +55 -0
- data/examples/0210_take_drop.rb +40 -0
- data/examples/0220_it_will_not_be_strange_to_tojson.rb +27 -0
- data/examples/0230_list_to_tree.rb +68 -0
- data/examples/0240_memory_record.rb +34 -0
- data/examples/Gemfile +12 -0
- data/examples/Gemfile.lock +137 -0
- data/examples/demo.rb +126 -0
- data/images/drop.png +0 -0
- data/images/take.png +0 -0
- data/images/take_drop.png +0 -0
- data/images/tree.png +0 -0
- data/images/tree_color.png +0 -0
- data/images/tree_label.png +0 -0
- data/lib/tree_support/ar_tree_model.rb +74 -0
- data/lib/tree_support/graphviz_builder.rb +78 -0
- data/lib/tree_support/inspector.rb +116 -0
- data/lib/tree_support/node.rb +124 -0
- data/lib/tree_support/railtie.rb +9 -0
- data/lib/tree_support/tree_support.rb +28 -0
- data/lib/tree_support/treeable.rb +52 -0
- data/lib/tree_support/version.rb +3 -0
- data/lib/tree_support.rb +2 -0
- data/spec/ar_tree_model_spec.rb +82 -0
- data/spec/node_spec.rb +52 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/tree_support_spec.rb +28 -0
- data/spec/treeable_spec.rb +59 -0
- data/tree_support.gemspec +30 -0
- 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
|