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,116 @@
|
|
1
|
+
require "kconv"
|
2
|
+
require "active_support/concern"
|
3
|
+
require "active_support/core_ext/module/attribute_accessors" # mattr_accessor
|
4
|
+
|
5
|
+
module TreeSupport
|
6
|
+
mattr_accessor :name_methods
|
7
|
+
self.name_methods = [:to_s_tree_name, :name, :subject, :title]
|
8
|
+
|
9
|
+
def self.tree(*args, &block)
|
10
|
+
Inspector.tree(*args, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.node_name(object)
|
14
|
+
object.send(name_methods.find {|e| object.respond_to?(e)} || :to_s)
|
15
|
+
end
|
16
|
+
|
17
|
+
class Inspector
|
18
|
+
def self.tree(object, *args, &block)
|
19
|
+
new(*args, &block).tree(object)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(**options, &block)
|
23
|
+
@options = {
|
24
|
+
take: 256, # Up to depth N (for when the tree can not be displayed because it is huge)
|
25
|
+
drop: 0, # From the depth N (when set to 1 you can hide the route)
|
26
|
+
root_label: nil, # A valid alternative label for displaying the route
|
27
|
+
tab_space: 4, # Indent width from halfway
|
28
|
+
connect_char: "├",
|
29
|
+
tab_visible_char: "│",
|
30
|
+
edge_char: "└",
|
31
|
+
branch_char: "─",
|
32
|
+
debug: false,
|
33
|
+
}.merge(options)
|
34
|
+
|
35
|
+
@block = block
|
36
|
+
end
|
37
|
+
|
38
|
+
# 木構造の可視化
|
39
|
+
#
|
40
|
+
# 必要なメソッド
|
41
|
+
# parent.children
|
42
|
+
# name
|
43
|
+
#
|
44
|
+
def tree(object, **locals)
|
45
|
+
locals = {
|
46
|
+
depth: [],
|
47
|
+
}.merge(locals)
|
48
|
+
|
49
|
+
if locals[:depth].size > @options[:drop]
|
50
|
+
if object == object.parent.children.last
|
51
|
+
prefix_char = @options[:edge_char]
|
52
|
+
else
|
53
|
+
prefix_char = @options[:connect_char]
|
54
|
+
end
|
55
|
+
else
|
56
|
+
prefix_char = ""
|
57
|
+
end
|
58
|
+
|
59
|
+
indents = locals[:depth].each.with_index.collect {|e, i|
|
60
|
+
if i > @options[:drop]
|
61
|
+
tab = e ? @options[:tab_visible_char] : ""
|
62
|
+
tab.toeuc.ljust(@options[:tab_space]).toutf8
|
63
|
+
end
|
64
|
+
}.join
|
65
|
+
|
66
|
+
if @block
|
67
|
+
label = @block.call(object, locals)
|
68
|
+
else
|
69
|
+
if locals[:depth].empty? && @options[:root_label] # Change if there is root and alternative label
|
70
|
+
label = @options[:root_label]
|
71
|
+
else
|
72
|
+
label = TreeSupport.node_name(object)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
buffer = ""
|
77
|
+
branch_char = nil
|
78
|
+
|
79
|
+
if locals[:depth].size > @options[:drop]
|
80
|
+
branch_char = @options[:branch_char]
|
81
|
+
end
|
82
|
+
if locals[:depth].size < @options[:take]
|
83
|
+
if locals[:depth].size >= @options[:drop]
|
84
|
+
buffer = "#{indents}#{prefix_char}#{branch_char}#{label}#{@options[:debug] ? locals[:depth].inspect : ""}\n"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
flag = false
|
89
|
+
if object.parent
|
90
|
+
flag = (object != object.parent.children.last)
|
91
|
+
end
|
92
|
+
|
93
|
+
locals[:depth].push(flag)
|
94
|
+
if locals[:depth].size < @options[:take]
|
95
|
+
buffer << object.children.collect {|node| tree(node, locals)}.join
|
96
|
+
end
|
97
|
+
locals[:depth].pop
|
98
|
+
|
99
|
+
buffer
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
module Stringify
|
104
|
+
def to_s_tree(*args, &block)
|
105
|
+
Inspector.tree(self, *args, &block)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
if $0 == __FILE__
|
111
|
+
$LOAD_PATH << ".."
|
112
|
+
require "tree_support"
|
113
|
+
puts TreeSupport.example.to_s_tree(take: 0)
|
114
|
+
puts TreeSupport.example.to_s_tree(take: 1)
|
115
|
+
puts TreeSupport.example.to_s_tree(take: 2)
|
116
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation' # for Module#delegate.
|
2
|
+
|
3
|
+
module TreeSupport
|
4
|
+
# Simple node (because it is troublesome to bother to make it on the application side when only wooden structure information is wanted)
|
5
|
+
class Node
|
6
|
+
include Treeable
|
7
|
+
include Stringify
|
8
|
+
|
9
|
+
attr_accessor :attributes, :parent, :children
|
10
|
+
|
11
|
+
alias_method :name, :attributes
|
12
|
+
alias_method :key, :attributes
|
13
|
+
|
14
|
+
delegate :[], :[]=, :to_h, to: :attributes
|
15
|
+
|
16
|
+
def initialize(attributes = nil, &block)
|
17
|
+
@attributes = attributes
|
18
|
+
@children = []
|
19
|
+
if block_given?
|
20
|
+
instance_eval(&block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(*args, &block)
|
25
|
+
tap do
|
26
|
+
children << self.class.new(*args, &block).tap do |v|
|
27
|
+
v.parent = self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.example
|
34
|
+
Node.new("*root*") do
|
35
|
+
add "Battle" do
|
36
|
+
add "Attack" do
|
37
|
+
add "Shake the sword"
|
38
|
+
add "Attack magic" do
|
39
|
+
add "Summoned Beast X"
|
40
|
+
add "Summoned Beast Y"
|
41
|
+
end
|
42
|
+
add "Repel sword in length"
|
43
|
+
end
|
44
|
+
add "Defense"
|
45
|
+
end
|
46
|
+
add "Withdraw" do
|
47
|
+
add "To stop" do
|
48
|
+
add "Place a trap"
|
49
|
+
add "Shoot a bow and arrow"
|
50
|
+
end
|
51
|
+
add "To escape"
|
52
|
+
end
|
53
|
+
add "Break" do
|
54
|
+
add "Stop"
|
55
|
+
add "Recover" do
|
56
|
+
add "Recovery magic"
|
57
|
+
add "Drink recovery medicine"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Methods for easily making trees from data like CSV
|
64
|
+
class << self
|
65
|
+
# Array -> Tree
|
66
|
+
#
|
67
|
+
# records = [
|
68
|
+
# {key: :a, parent: nil},
|
69
|
+
# {key: :b, parent: :a},
|
70
|
+
# {key: :c, parent: :b},
|
71
|
+
# ]
|
72
|
+
#
|
73
|
+
# puts TreeSupport.records_to_tree(records).to_s_tree
|
74
|
+
# a
|
75
|
+
# └─b
|
76
|
+
# └─c
|
77
|
+
# └─d
|
78
|
+
#
|
79
|
+
# Be sure to have one route
|
80
|
+
#
|
81
|
+
def records_to_tree(records, key: :key, parent_key: :parent, root_key: nil)
|
82
|
+
# Once hashed
|
83
|
+
source_hash = records.inject({}) { |a, e| a.merge(e[key] => e) }
|
84
|
+
# The node also makes it a hash of only the node having the key
|
85
|
+
node_hash = records.inject({}) { |a, e| a.merge(e[key] => Node.new(e[key])) }
|
86
|
+
# Link nodes
|
87
|
+
node_hash.each_value do |node|
|
88
|
+
if parent = source_hash[node.key][parent_key]
|
89
|
+
parent_node = node_hash[parent]
|
90
|
+
node.parent = parent_node
|
91
|
+
parent_node.children << node
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# If the node whose parent was not set is the root (s)
|
96
|
+
roots = node_hash.each_value.find_all {|e| e.parent.nil? }
|
97
|
+
|
98
|
+
# Specify root_key when there are multiple routes and you are in trouble. Then create a new route and hang it.
|
99
|
+
if root_key
|
100
|
+
Node.new(root_key).tap do |root|
|
101
|
+
roots.each do |e|
|
102
|
+
e.parent = root
|
103
|
+
root.children << e
|
104
|
+
end
|
105
|
+
end
|
106
|
+
else
|
107
|
+
roots
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# Tree -> Array
|
112
|
+
#
|
113
|
+
# p TreeSupport.tree_to_records(tree)
|
114
|
+
# [
|
115
|
+
# {key: :a, parent: nil},
|
116
|
+
# {key: :b, parent: :a},
|
117
|
+
# {key: :c, parent: :b},
|
118
|
+
# ]
|
119
|
+
#
|
120
|
+
def tree_to_records(root, key: :key, parent_key: :parent)
|
121
|
+
root.each_node.collect {|e| {key => e.key, parent_key => e.parent&.key} }
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# Tree structure visualization library
|
2
|
+
#
|
3
|
+
# root = TreeSupport::Node.new("ROOT") do
|
4
|
+
# add "A" do
|
5
|
+
# add "B" do
|
6
|
+
# add "C"
|
7
|
+
# end
|
8
|
+
# end
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# puts TreeSupport.tree(root)
|
12
|
+
# > ROOT
|
13
|
+
# > └─A
|
14
|
+
# > └─B
|
15
|
+
# > └─C
|
16
|
+
|
17
|
+
require "tree_support/treeable"
|
18
|
+
require "tree_support/inspector"
|
19
|
+
require "tree_support/node"
|
20
|
+
require "tree_support/ar_tree_model" if defined?(ActiveRecord)
|
21
|
+
require "tree_support/railtie" if defined?(Rails)
|
22
|
+
|
23
|
+
# Do not put gviz when you do not use it to touch Object
|
24
|
+
begin
|
25
|
+
require "gviz"
|
26
|
+
require "tree_support/graphviz_builder"
|
27
|
+
rescue LoadError
|
28
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Definition of methods that are common in tree-structured interfaces
|
2
|
+
#
|
3
|
+
# All you need is parent and children methods
|
4
|
+
#
|
5
|
+
|
6
|
+
require "active_support/core_ext/module/concerning"
|
7
|
+
|
8
|
+
module TreeSupport
|
9
|
+
concern :Treeable do
|
10
|
+
def root
|
11
|
+
parent ? parent.root : self
|
12
|
+
end
|
13
|
+
|
14
|
+
def root?
|
15
|
+
!parent
|
16
|
+
end
|
17
|
+
|
18
|
+
def leaf?
|
19
|
+
children.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def each_node(&block)
|
23
|
+
return enum_for(__method__) unless block_given?
|
24
|
+
yield self
|
25
|
+
children.each { |e| e.each_node(&block) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def descendants
|
29
|
+
children.flat_map { |e| [e] + e.descendants }
|
30
|
+
end
|
31
|
+
|
32
|
+
def self_and_descendants
|
33
|
+
[self] + descendants
|
34
|
+
end
|
35
|
+
|
36
|
+
def ancestors
|
37
|
+
self_and_ancestors - [self]
|
38
|
+
end
|
39
|
+
|
40
|
+
def self_and_ancestors
|
41
|
+
[self] + (parent ? parent.self_and_ancestors : [])
|
42
|
+
end
|
43
|
+
|
44
|
+
def siblings
|
45
|
+
self_and_siblings - [self]
|
46
|
+
end
|
47
|
+
|
48
|
+
def self_and_siblings
|
49
|
+
parent ? parent.children : []
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/tree_support.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require "rails"
|
4
|
+
require "tree_support/ar_tree_model"
|
5
|
+
require "tree_support/railtie"
|
6
|
+
require "active_record"
|
7
|
+
|
8
|
+
Class.new(Rails::Application){config.eager_load = true}.initialize!
|
9
|
+
|
10
|
+
RSpec.describe "ArTreeModel" do
|
11
|
+
before do
|
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
|
+
ar_tree_model 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
|
+
@node = 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
|
+
end
|
65
|
+
|
66
|
+
it "roots" do
|
67
|
+
Node.roots.should == [@node]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "root" do
|
71
|
+
Node.root.should == @node
|
72
|
+
end
|
73
|
+
|
74
|
+
it "to_s_tree" do
|
75
|
+
@node.to_s_tree
|
76
|
+
end
|
77
|
+
|
78
|
+
it "safe_destroy_all" do
|
79
|
+
Node.safe_destroy_all
|
80
|
+
Node.count.should == 0
|
81
|
+
end
|
82
|
+
end
|
data/spec/node_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "Node" do
|
4
|
+
before do
|
5
|
+
@records = [
|
6
|
+
{key: :a0, parent: nil},
|
7
|
+
{key: :a1, parent: :a0},
|
8
|
+
{key: :a2, parent: :a1},
|
9
|
+
{key: :b0, parent: nil},
|
10
|
+
{key: :b1, parent: :b0},
|
11
|
+
{key: :b2, parent: :b1},
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
it "Array -> Tree(s)" do
|
16
|
+
TreeSupport.records_to_tree(@records).collect(&:to_s_tree).join.should == <<-EOT
|
17
|
+
a0
|
18
|
+
└─a1
|
19
|
+
└─a2
|
20
|
+
b0
|
21
|
+
└─b1
|
22
|
+
└─b2
|
23
|
+
EOT
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
it "Array -> Tree(1)" do
|
28
|
+
TreeSupport.records_to_tree(@records, root_key: :root).to_s_tree.should == <<-EOT
|
29
|
+
root
|
30
|
+
├─a0
|
31
|
+
│ └─a1
|
32
|
+
│ └─a2
|
33
|
+
└─b0
|
34
|
+
└─b1
|
35
|
+
└─b2
|
36
|
+
EOT
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Tree -> Array" do
|
40
|
+
root = TreeSupport.records_to_tree(@records, root_key: :root)
|
41
|
+
records = TreeSupport.tree_to_records(root)
|
42
|
+
records.should == [
|
43
|
+
{key: :root, parent: nil },
|
44
|
+
{key: :a0, parent: :root },
|
45
|
+
{key: :a1, parent: :a0 },
|
46
|
+
{key: :a2, parent: :a1 },
|
47
|
+
{key: :b0, parent: :root },
|
48
|
+
{key: :b1, parent: :b0 },
|
49
|
+
{key: :b2, parent: :b1 },
|
50
|
+
]
|
51
|
+
end
|
52
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "TreeSupport" do
|
4
|
+
it "tree" do
|
5
|
+
expected = <<-EOT
|
6
|
+
*root*
|
7
|
+
├─Battle
|
8
|
+
│ ├─Attack
|
9
|
+
│ │ ├─Shake the sword
|
10
|
+
│ │ ├─Attack magic
|
11
|
+
│ │ │ ├─Summoned Beast X
|
12
|
+
│ │ │ └─Summoned Beast Y
|
13
|
+
│ │ └─Repel sword in length
|
14
|
+
│ └─Defense
|
15
|
+
├─Withdraw
|
16
|
+
│ ├─To stop
|
17
|
+
│ │ ├─Place a trap
|
18
|
+
│ │ └─Shoot a bow and arrow
|
19
|
+
│ └─To escape
|
20
|
+
└─Break
|
21
|
+
├─Stop
|
22
|
+
└─Recover
|
23
|
+
├─Recovery magic
|
24
|
+
└─Drink recovery medicine
|
25
|
+
EOT
|
26
|
+
TreeSupport.example.to_s_tree.should == expected
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe "Treeable" do
|
4
|
+
before do
|
5
|
+
@root = TreeSupport::Node.new("*root*") do
|
6
|
+
add "a" do
|
7
|
+
add "a1"
|
8
|
+
add "a2" do
|
9
|
+
add "x"
|
10
|
+
end
|
11
|
+
add "a3"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
@a2 = @root.each_node.find {|e| e.name == "a2"}
|
15
|
+
@leaf = @root.each_node.find {|e| e.name == "x"}
|
16
|
+
end
|
17
|
+
|
18
|
+
it "root" do
|
19
|
+
@a2.root.name.should == "*root*"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "root?" do
|
23
|
+
@root.root?.should == true
|
24
|
+
@leaf.root?.should == false
|
25
|
+
end
|
26
|
+
|
27
|
+
it "leaf?" do
|
28
|
+
@root.leaf?.should == false
|
29
|
+
@leaf.leaf?.should == true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "each_node" do
|
33
|
+
@root.each_node.collect(&:name).should == ["*root*", "a", "a1", "a2", "x", "a3"]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "descendants" do
|
37
|
+
@root.descendants.collect(&:name).should == ["a", "a1", "a2", "x", "a3"]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "self_and_descendants" do
|
41
|
+
@root.self_and_descendants.collect(&:name).should == ["*root*", "a", "a1", "a2", "x", "a3"]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "ancestors" do
|
45
|
+
@a2.ancestors.collect(&:name).should == ["a", "*root*"]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "self_and_ancestors" do
|
49
|
+
@a2.self_and_ancestors.collect(&:name).should == ["a2", "a", "*root*"]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "siblings" do
|
53
|
+
@a2.siblings.collect(&:name).should == ["a1", "a3"]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "self_and_siblings" do
|
57
|
+
@a2.self_and_siblings.collect(&:name).should == ["a1", "a2", "a3"]
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tree_support/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "tree_support"
|
8
|
+
s.version = TreeSupport::VERSION
|
9
|
+
s.author = "akicho8"
|
10
|
+
s.email = "akicho8@gmail.com"
|
11
|
+
s.homepage = "https://github.com/akicho8/tree_support"
|
12
|
+
s.summary = "Tree structure visualization function library"
|
13
|
+
s.description = "Tree structure visualization function library"
|
14
|
+
s.platform = Gem::Platform::RUBY
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--charset=UTF-8", "--diagram", "--image-format=jpg"]
|
21
|
+
|
22
|
+
s.add_dependency "activesupport"
|
23
|
+
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
s.add_development_dependency "rspec"
|
26
|
+
s.add_development_dependency "rails"
|
27
|
+
s.add_development_dependency "activerecord"
|
28
|
+
s.add_development_dependency "sqlite3"
|
29
|
+
s.add_development_dependency "gviz"
|
30
|
+
end
|