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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 35b3da8eb68307c23ab1a39ffe096c55bb826f27
4
+ data.tar.gz: 64366be7a67841d0f0c0fbc893e46835bf417f12
5
+ SHA512:
6
+ metadata.gz: 405374ce91c625deb5ad2f7eb3a1e3a0d9d518be315c960f32d92e858a0afe12224dcfbb0b4eb3951a40fde02f0973652d90b108c356881572c74a3be6ef2d58
7
+ data.tar.gz: cf0608091c08aaea0f5e099d4c1b439db05a2f8a2a4c3e3ed62efdb1f3444a22df0d798795213e2904417c960ed9cdda3e188fa1811ac5e7efd57b1fea774f07
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ _*
2
+ /Gemfile.lock
3
+ *.dot
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4.1
4
+ script: bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "https://rubygems.org"
2
+ gemspec
data/README.org ADDED
@@ -0,0 +1,471 @@
1
+ * Tree structure visualization function library
2
+
3
+ [[https://travis-ci.org/akicho8/tree_support.png]]
4
+
5
+ ** How to use in one line
6
+
7
+ Just pass the object that has the parent, children method to TreeSupport.tree
8
+
9
+ #+BEGIN_SRC ruby
10
+ require "tree_support"
11
+ puts TreeSupport.tree(TreeSupport.example)
12
+ # >> *root*
13
+ # >> ├─Battle
14
+ # >> │ ├─Attack
15
+ # >> │ │ ├─Shake the sword
16
+ # >> │ │ ├─Attack magic
17
+ # >> │ │ │ ├─Summoned Beast X
18
+ # >> │ │ │ └─Summoned Beast Y
19
+ # >> │ │ └─Repel sword in length
20
+ # >> │ └─Defense
21
+ # >> ├─Withdraw
22
+ # >> │ ├─To stop
23
+ # >> │ │ ├─Place a trap
24
+ # >> │ │ └─Shoot a bow and arrow
25
+ # >> │ └─To escape
26
+ # >> └─Break
27
+ # >> ├─Stop
28
+ # >> └─Recover
29
+ # >> ├─Recovery magic
30
+ # >> └─Drink recovery medicine
31
+ #+END_SRC
32
+
33
+ ** Detailed usage
34
+
35
+ *** Prepare a node class like this
36
+
37
+ #+BEGIN_SRC ruby
38
+ class Node
39
+ attr_accessor :name, :parent, :children
40
+
41
+ def initialize(name = nil, &block)
42
+ @name = name
43
+ @children = []
44
+ if block_given?
45
+ instance_eval(&block)
46
+ end
47
+ end
48
+
49
+ def add(*args, &block)
50
+ tap do
51
+ children << self.class.new(*args, &block).tap { |v| v.parent = self }
52
+ end
53
+ end
54
+ end
55
+ #+END_SRC
56
+
57
+ *** Create a tree
58
+
59
+ #+BEGIN_SRC ruby
60
+ root = Node.new("*root*") do
61
+ add "Battle" do
62
+ add "Attack" do
63
+ add "Shake the sword"
64
+ add "Attack magic" do
65
+ add "Summoned Beast X"
66
+ add "Summoned Beast Y"
67
+ end
68
+ add "Repel sword in length"
69
+ end
70
+ add "Defense"
71
+ end
72
+ add "Withdraw" do
73
+ add "To stop" do
74
+ add "Place a trap"
75
+ add "Shoot a bow and arrow"
76
+ end
77
+ add "To escape"
78
+ end
79
+ add "Break" do
80
+ add "Stop"
81
+ add "Recover" do
82
+ add "Recovery magic"
83
+ add "Drink recovery medicine"
84
+ end
85
+ end
86
+ end
87
+ #+END_SRC
88
+
89
+ *** Visualization
90
+
91
+ #+BEGIN_SRC ruby
92
+ puts TreeSupport.tree(root)
93
+ # >> *root*
94
+ # >> ├─Battle
95
+ # >> │ ├─Attack
96
+ # >> │ │ ├─Shake the sword
97
+ # >> │ │ ├─Attack magic
98
+ # >> │ │ │ ├─Summoned Beast X
99
+ # >> │ │ │ └─Summoned Beast Y
100
+ # >> │ │ └─Repel sword in length
101
+ # >> │ └─Defense
102
+ # >> ├─Withdraw
103
+ # >> │ ├─To stop
104
+ # >> │ │ ├─Place a trap
105
+ # >> │ │ └─Shoot a bow and arrow
106
+ # >> │ └─To escape
107
+ # >> └─Break
108
+ # >> ├─Stop
109
+ # >> └─Recover
110
+ # >> ├─Recovery magic
111
+ # >> └─Drink recovery medicine
112
+ #+END_SRC
113
+
114
+ *** Troublesome writing TreeSupport.tree
115
+
116
+ Include TreeSupport::Stringify
117
+
118
+ #+BEGIN_SRC ruby
119
+ Node.include(TreeSupport::Stringify)
120
+ puts root.to_s_tree
121
+ # >> *root*
122
+ # >> ├─Battle
123
+ # >> │ ├─Attack
124
+ # >> │ │ ├─Shake the sword
125
+ # >> │ │ ├─Attack magic
126
+ # >> │ │ │ ├─Summoned Beast X
127
+ # >> │ │ │ └─Summoned Beast Y
128
+ # >> │ │ └─Repel sword in length
129
+ # >> │ └─Defense
130
+ # >> ├─Withdraw
131
+ # >> │ ├─To stop
132
+ # >> │ │ ├─Place a trap
133
+ # >> │ │ └─Shoot a bow and arrow
134
+ # >> │ └─To escape
135
+ # >> └─Break
136
+ # >> ├─Stop
137
+ # >> └─Recover
138
+ # >> ├─Recovery magic
139
+ # >> └─Drink recovery medicine
140
+ #+END_SRC
141
+
142
+ *** How do I change the label of a node?
143
+
144
+ 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
145
+
146
+ *** How do I change labels without defining methods?
147
+
148
+ Add a block to tree
149
+
150
+ #+BEGIN_SRC ruby
151
+ puts TreeSupport.tree(root) { |node| node.object_id }
152
+ # >> 70308514816100
153
+ # >> ├─70308514815920
154
+ # >> │ ├─70308514815780
155
+ # >> │ │ ├─70308514815680
156
+ # >> │ │ ├─70308514815580
157
+ # >> │ │ │ ├─70308514815480
158
+ # >> │ │ │ └─70308514815420
159
+ # >> │ │ └─70308514815360
160
+ # >> │ └─70308514815300
161
+ # >> ├─70308514815220
162
+ # >> │ ├─70308514815080
163
+ # >> │ │ ├─70308514814980
164
+ # >> │ │ └─70308514814920
165
+ # >> │ └─70308514814860
166
+ # >> └─70308514814780
167
+ # >> ├─70308514814680
168
+ # >> └─70308514814580
169
+ # >> ├─70308514814480
170
+ # >> └─70308514814420
171
+ #+END_SRC
172
+
173
+ *** How to use methods that are common in tree structure?
174
+
175
+ The following methods become available in include of =TreeSupport::Treeable=
176
+
177
+ - each
178
+ - each_node
179
+ - descendants
180
+ - self_and_descendants
181
+ - ancestors
182
+ - root
183
+ - siblings
184
+ - self_and_siblings
185
+ - root?
186
+ - leaf?
187
+
188
+ *** How to convert to Gviz object?
189
+
190
+ #+BEGIN_SRC ruby
191
+ gv = TreeSupport.graphviz(root)
192
+ #+END_SRC
193
+
194
+ *** How to image it?
195
+
196
+ #+BEGIN_SRC ruby
197
+ gv.output("tree.png")
198
+ #+END_SRC
199
+
200
+ [[https://raw.github.com/akicho8/tree_support/master/images/tree.png]]
201
+
202
+ *** How do I change the color of a particular node?
203
+
204
+ Return the graphviz attribute as a hash in TreeSupport.graphviz block
205
+
206
+ #+BEGIN_SRC ruby
207
+ gv = TreeSupport.graphviz(root) do |node|
208
+ if node.name.include?("Attack")
209
+ {fillcolor: "lightblue", style: "filled"}
210
+ elsif node.name.include?("Recover")
211
+ {fillcolor: "lightpink", style: "filled"}
212
+ end
213
+ end
214
+ gv.output("tree_color.png")
215
+ #+END_SRC
216
+
217
+ [[https://raw.github.com/akicho8/tree_support/master/images/tree_color.png]]
218
+
219
+ *** How do I change the label of a particular node?
220
+
221
+ As with the above method, it returns a hash containing the label value
222
+
223
+ #+BEGIN_SRC ruby
224
+ gv = TreeSupport.graphviz(root) do |node|
225
+ {label: node.name.chars.first}
226
+ end
227
+ gv.output("tree_label.png")
228
+ #+END_SRC
229
+
230
+ [[https://raw.github.com/akicho8/tree_support/master/images/tree_label.png]]
231
+
232
+ *** How can I check the dot format of Graphviz?
233
+
234
+ #+BEGIN_SRC ruby
235
+ puts gv.to_dot
236
+ # >> digraph n70146110700700 {
237
+ # >> graph [charset = "UTF-8", rankdir = "LR"];
238
+ # >> n70146110700700 [label = "*root*"];
239
+ # >> n70146110700700 -> {n70146110698600; n70146110691220; n70146110689500;};
240
+ # >> n70146110698600 [label = "Battle"];
241
+ # >> n70146110698600 -> {n70146110698320; n70146110691720;};
242
+ # >> n70146110698320 [label = "Attack"];
243
+ # >> n70146110698320 -> {n70146110697900; n70146110697240; n70146110692060;};
244
+ # >> n70146110697900 [label = "Shake the sword"];
245
+ # >> n70146110697240 [label = "Attack magic"];
246
+ # >> n70146110697240 -> {n70146110695080; n70146110694480;};
247
+ # >> n70146110695080 [label = "Summoned Beast X"];
248
+ # >> n70146110694480 [label = "Summoned Beast Y"];
249
+ # >> n70146110692060 [label = "Repel sword in length"];
250
+ # >> n70146110691720 [label = "Defense"];
251
+ # >> n70146110691220 [label = "Withdraw"];
252
+ # >> n70146110691220 -> {n70146110690400; n70146110689620;};
253
+ # >> n70146110690400 [label = "To stop"];
254
+ # >> n70146110690400 -> {n70146110690220; n70146110689820;};
255
+ # >> n70146110690220 [label = "Place a trap"];
256
+ # >> n70146110689820 [label = "Shoot a bow and arrow"];
257
+ # >> n70146110689620 [label = "To escape"];
258
+ # >> n70146110689500 [label = "Break"];
259
+ # >> n70146110689500 -> {n70146110688500; n70146110687660;};
260
+ # >> n70146110688500 [label = "Stop"];
261
+ # >> n70146110687660 [label = "Recover"];
262
+ # >> n70146110687660 -> {n70146110686920; n70146110686220;};
263
+ # >> n70146110686920 [label = "Recovery magic"];
264
+ # >> n70146110686220 [label = "Drink recovery medicine"];
265
+ # >> }
266
+ #+END_SRC
267
+
268
+ *** How can I check the image conversion immediately when debugging?
269
+
270
+ #+BEGIN_SRC ruby
271
+ TreeSupport.graph_open(root)
272
+ #+END_SRC
273
+
274
+ Equivalent to the next shortcut
275
+
276
+ #+BEGIN_SRC ruby
277
+ TreeSupport.graphviz(root).output("_output.png")
278
+ `open _output.png`
279
+ #+END_SRC
280
+
281
+ *** Troublesome making node classes yourself
282
+
283
+ You can use =TreeSupport::Node= as it is.
284
+
285
+ #+BEGIN_SRC ruby
286
+ TreeSupport::Node.new("*root*") do
287
+ add "Battle" do
288
+ add "Attack" do
289
+ add "Shake the sword"
290
+ add "Attack magic" do
291
+ add "Summoned Beast X"
292
+ add "Summoned Beast Y"
293
+ end
294
+ end
295
+ end
296
+ end
297
+ #+END_SRC
298
+
299
+ *** Troublesome making trees
300
+
301
+ #+BEGIN_SRC ruby
302
+ TreeSupport.example
303
+ #+END_SRC
304
+
305
+ There is a simple sample tree
306
+
307
+ *** How to trace leaves?
308
+
309
+ If you include =TreeSupport::Treeable= you can use each_node
310
+
311
+ #+BEGIN_SRC ruby
312
+ root = TreeSupport.example
313
+ root.each_node.with_index { |n, i| p [i, n.name] }
314
+ # >> [0, "*root*"]
315
+ # >> [1, "Battle"]
316
+ # >> [2, "Attack"]
317
+ # >> [3, "Shake the sword"]
318
+ # >> [4, "Attack magic"]
319
+ # >> [5, "Summoned Beast X"]
320
+ # >> [6, "Summoned Beast Y"]
321
+ # >> [7, "Repel sword in length"]
322
+ # >> [8, "Defense"]
323
+ # >> [9, "Withdraw"]
324
+ # >> [10, "To stop"]
325
+ # >> [11, "Place a trap"]
326
+ # >> [12, "Shoot a bow and arrow"]
327
+ # >> [13, "To escape"]
328
+ # >> [14, "Break"]
329
+ # >> [15, "Stop"]
330
+ # >> [16, "Recover"]
331
+ # >> [17, "Recovery magic"]
332
+ # >> [18, "Drink recovery medicine"]
333
+ #+END_SRC
334
+
335
+ *** I do not want to display the root
336
+
337
+ #+BEGIN_SRC ruby
338
+ puts TreeSupport.tree(root, drop: 1)
339
+ # >> Battle
340
+ # >> ├─Attack
341
+ # >> │ ├─Shake the sword
342
+ # >> │ ├─Attack magic
343
+ # >> │ │ ├─Summoned Beast X
344
+ # >> │ │ └─Summoned Beast Y
345
+ # >> │ └─Repel sword in length
346
+ # >> └─Defense
347
+ # >> Withdraw
348
+ # >> ├─To stop
349
+ # >> │ ├─Place a trap
350
+ # >> │ └─Shoot a bow and arrow
351
+ # >> └─To escape
352
+ # >> Break
353
+ # >> ├─Stop
354
+ # >> └─Recover
355
+ # >> ├─Recovery magic
356
+ # >> └─Drink recovery medicine
357
+ #+END_SRC
358
+
359
+ *** Since the trees are too big, it is enough up to the depth 3
360
+
361
+ #+BEGIN_SRC ruby
362
+ puts TreeSupport.tree(root, take: 3)
363
+ # >> *root*
364
+ # >> ├─Battle
365
+ # >> │ ├─Attack
366
+ # >> │ └─Defense
367
+ # >> ├─Withdraw
368
+ # >> │ ├─To stop
369
+ # >> │ └─To escape
370
+ # >> └─Break
371
+ # >> ├─Stop
372
+ # >> └─Recover
373
+ #+END_SRC
374
+
375
+ *** When you combine both
376
+
377
+ #+BEGIN_SRC ruby
378
+ puts TreeSupport.tree(root, take: 3, drop: 1)
379
+ # >> Battle
380
+ # >> ├─Attack
381
+ # >> └─Defense
382
+ # >> Withdraw
383
+ # >> ├─To stop
384
+ # >> └─To escape
385
+ # >> Break
386
+ # >> ├─Stop
387
+ # >> └─Recover
388
+ #+END_SRC
389
+
390
+ *** Image version also has similar options
391
+
392
+ #+BEGIN_SRC ruby
393
+ gv = TreeSupport.graphviz(root, drop: 1)
394
+ gv.output("drop.png")
395
+ #+END_SRC
396
+
397
+ [[https://raw.github.com/akicho8/tree_support/master/images/drop.png]]
398
+
399
+ #+BEGIN_SRC ruby
400
+ gv = TreeSupport.graphviz(root, take: 3)
401
+ gv.output("take.png")
402
+ #+END_SRC
403
+
404
+ [[https://raw.github.com/akicho8/tree_support/master/images/take.png]]
405
+
406
+ #+BEGIN_SRC ruby
407
+ gv = TreeSupport.graphviz(root, take: 3, drop: 1)
408
+ gv.output("take_drop.png")
409
+ #+END_SRC
410
+
411
+ [[https://raw.github.com/akicho8/tree_support/master/images/take_drop.png]]
412
+
413
+ *** How to use acts_as_tree equivalent?
414
+
415
+ Migration
416
+
417
+ #+BEGIN_SRC ruby
418
+ create_table :nodes do |t|
419
+ t.belongs_to :parent
420
+ end
421
+ #+END_SRC
422
+
423
+ Model
424
+
425
+ #+BEGIN_SRC ruby
426
+ class Node < ActiveRecord::Base
427
+ ar_tree_model
428
+ end
429
+ #+END_SRC
430
+
431
+ Difference from https://github.com/amerine/acts_as_tree
432
+
433
+ - simple
434
+ - Safely delete all safe_destroy_all (accident with destroy_all in combination with acts_as_list)
435
+ - Node.roots is defined by scope
436
+ - Arguments are different. =:order => :id= if you want to do it =scope: -> { order(:id) }=. By doing this you can also pass the where condition.
437
+
438
+ *** How do I correspond to memory_record gem?
439
+
440
+ Just as with ordinary classes, we need parent and children methods
441
+
442
+ #+BEGIN_SRC ruby
443
+ class Foo
444
+ include MemoryRecord
445
+ static_record [
446
+ {key: :a, parent: nil},
447
+ {key: :b, parent: :a},
448
+ {key: :c, parent: :b},
449
+ ]
450
+
451
+ include TreeSupport::Treeable
452
+ include TreeSupport::Stringify
453
+
454
+ def parent
455
+ self.class[super]
456
+ end
457
+
458
+ def children
459
+ self.class.find_all { |e| e.parent == self }
460
+ end
461
+ end
462
+
463
+ puts Foo.find_all(&:root?).collect(&:to_s_tree)
464
+ # >> A
465
+ # >> └─B
466
+ # >> └─C
467
+ #+END_SRC
468
+
469
+ ** With concern
470
+
471
+ - Since Gviz extends the standard class, concerns about future interference when combined with Rails (Active Support) etc.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler"
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require "rspec/core/rake_task"
5
+ RSpec::Core::RakeTask.new
6
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ require "bundler/setup"
2
+ require "tree_support"
3
+ puts TreeSupport.tree(TreeSupport.example)
4
+ # >> *root*
5
+ # >> ├─Battle
6
+ # >> │ ├─Attack
7
+ # >> │ │ ├─Shake the sword
8
+ # >> │ │ ├─Attack magic
9
+ # >> │ │ │ ├─Summoned Beast X
10
+ # >> │ │ │ └─Summoned Beast Y
11
+ # >> │ │ └─Repel sword in length
12
+ # >> │ └─Defense
13
+ # >> ├─Withdraw
14
+ # >> │ ├─To stop
15
+ # >> │ │ ├─Place a trap
16
+ # >> │ │ └─Shoot a bow and arrow
17
+ # >> │ └─To escape
18
+ # >> └─Break
19
+ # >> ├─Stop
20
+ # >> └─Recover
21
+ # >> ├─Recovery magic
22
+ # >> └─Drink recovery medicine
@@ -0,0 +1,26 @@
1
+ #
2
+ # Built-in TreeSupport::Node can be used generically when you want to express a little tree structure
3
+ #
4
+ require "bundler/setup"
5
+ require "tree_support"
6
+
7
+ node = TreeSupport::Node.new("foo")
8
+ node.name # => "foo"
9
+
10
+ node = TreeSupport::Node.new(:foo)
11
+ node.key # => :foo
12
+
13
+ node = TreeSupport::Node.new(a: 1, b: 2)
14
+ node[:a] # => 1
15
+ node.to_h # => {:a=>1, :b=>2}
16
+
17
+ tree = TreeSupport::Node.new(:root) do
18
+ add :a do
19
+ add :b do
20
+ add :c
21
+ end
22
+ end
23
+ end
24
+
25
+ tree.each_node.find { |e| e.key == :root }.key # => :root
26
+ tree.each_node.find { |e| e.key == :b }.key # => :b
@@ -0,0 +1,6 @@
1
+ # Image conversion
2
+ #
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+ root = TreeSupport.example
6
+ TreeSupport.graphviz(root).output("_tree.png")
@@ -0,0 +1,98 @@
1
+ # Examples of homebrew nodes
2
+
3
+ require "bundler/setup"
4
+ require "tree_support"
5
+
6
+ class Node
7
+ attr_accessor :name, :parent, :children
8
+
9
+ def initialize(name = nil, &block)
10
+ @name = name
11
+ @children = []
12
+ if block_given?
13
+ instance_eval(&block)
14
+ end
15
+ end
16
+
17
+ # 木を簡単につくるため
18
+ def add(*args, &block)
19
+ tap do
20
+ children << self.class.new(*args, &block).tap do |v|
21
+ v.parent = self
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ root = Node.new("*root*") do
28
+ add "Battle" do
29
+ add "Attack" do
30
+ add "Shake the sword"
31
+ add "Attack magic" do
32
+ add "Summoned Beast X"
33
+ add "Summoned Beast Y"
34
+ end
35
+ add "Repel sword in length"
36
+ end
37
+ add "Defense"
38
+ end
39
+ add "Withdraw" do
40
+ add "To stop" do
41
+ add "Place a trap"
42
+ add "Shoot a bow and arrow"
43
+ end
44
+ add "To escape"
45
+ end
46
+ add "Break" do
47
+ add "Stop"
48
+ add "Recover" do
49
+ add "Recovery magic"
50
+ add "Drink recovery medicine"
51
+ end
52
+ end
53
+ end
54
+
55
+ # TreeSupport.tree に渡すオブジェクトは は parent.children と name に応答できさえすればいい
56
+ puts TreeSupport.tree(root)
57
+
58
+ # オブジェクトに文字列化するメソッドを入れるには?
59
+ Node.include(TreeSupport::Stringify)
60
+ puts root.to_s_tree
61
+ # >> *root*
62
+ # >> ├─Battle
63
+ # >> │ ├─Attack
64
+ # >> │ │ ├─Shake the sword
65
+ # >> │ │ ├─Attack magic
66
+ # >> │ │ │ ├─Summoned Beast X
67
+ # >> │ │ │ └─Summoned Beast Y
68
+ # >> │ │ └─Repel sword in length
69
+ # >> │ └─Defense
70
+ # >> ├─Withdraw
71
+ # >> │ ├─To stop
72
+ # >> │ │ ├─Place a trap
73
+ # >> │ │ └─Shoot a bow and arrow
74
+ # >> │ └─To escape
75
+ # >> └─Break
76
+ # >> ├─Stop
77
+ # >> └─Recover
78
+ # >> ├─Recovery magic
79
+ # >> └─Drink recovery medicine
80
+ # >> *root*
81
+ # >> ├─Battle
82
+ # >> │ ├─Attack
83
+ # >> │ │ ├─Shake the sword
84
+ # >> │ │ ├─Attack magic
85
+ # >> │ │ │ ├─Summoned Beast X
86
+ # >> │ │ │ └─Summoned Beast Y
87
+ # >> │ │ └─Repel sword in length
88
+ # >> │ └─Defense
89
+ # >> ├─Withdraw
90
+ # >> │ ├─To stop
91
+ # >> │ │ ├─Place a trap
92
+ # >> │ │ └─Shoot a bow and arrow
93
+ # >> │ └─To escape
94
+ # >> └─Break
95
+ # >> ├─Stop
96
+ # >> └─Recover
97
+ # >> ├─Recovery magic
98
+ # >> └─Drink recovery medicine