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