acts_as_associate_tree 0.0.1

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.
@@ -0,0 +1,193 @@
1
+ ##
2
+ # Module
3
+ # ActsAsAssociateTree
4
+ #
5
+ # Used for generating tree-like data
6
+ #
7
+ # Interface: generate_tree_nodes
8
+ #
9
+ # Suppose you have a class like this
10
+ #
11
+ # class Foo
12
+ # attr_reader :i
13
+ # def initialize(i)
14
+ # @i = i
15
+ # end
16
+ #
17
+ # def items
18
+ # foo_items = []
19
+ # i.times do |i|
20
+ # foo_items.push Foo.new("Item" + i.to_s)
21
+ # end
22
+ # foo_items
23
+ # end
24
+ #
25
+ # class << self
26
+ # def all
27
+ # all_foos = []
28
+ # 2.times do |i|
29
+ # all_foos.push Foo.new(i + 1)
30
+ # end
31
+ # all_foos
32
+ # end
33
+ # end
34
+ # end
35
+ #
36
+ # generate_tree_nodes do
37
+ # nodes { Foo.all }
38
+ # node_attrs { { :text => i } } # invoke this block by the instance_eval
39
+ # # method of each element in nodes
40
+ # children {
41
+ # nodes { items }
42
+ # node_attrs { { :text => i } } # using nodes#element.instance_eval to run this block
43
+ # }
44
+ # end
45
+ #
46
+ # it will return a array like bellow:
47
+ #
48
+ # [{
49
+ # :text=>1,
50
+ # :children=>[{
51
+ # :text=>"Item0",
52
+ # :leaf=>true
53
+ # }]
54
+ # }, {
55
+ # :text=>2,
56
+ # :children=>[{
57
+ # :text=>"Item0",
58
+ # :leaf=>true
59
+ # }, {
60
+ # :text=>"Item1",
61
+ # :leaf=>true
62
+ # }]
63
+ # }]
64
+ #
65
+ # include this module in your controller or model or any of your classes
66
+ # used to generating tree-like datas, you will get a instance function
67
+ # *generate_tree_nodes*, then you could use it this way.
68
+ #
69
+ # class Parent < ActiveRecord::Base
70
+ # has_many :children
71
+ # end
72
+ #
73
+ # class Child < ActiveRecord::Base
74
+ # belongs_to :parent
75
+ # end
76
+ #
77
+ # 其数据如下:
78
+ #
79
+ # # Parent.all
80
+ # # +-------+---------+
81
+ # # | id | name |
82
+ # # +-------+---------+
83
+ # # | 1 | xx1 |
84
+ # # | 2 | xx2 |
85
+ # # | 3 | xx3 |
86
+ # # | 4 | xx4 |
87
+ # # | 5 | xx5 |
88
+ # # +-------+---------+
89
+ #
90
+ # # Child.all
91
+ # # +-------+--------------+--------+
92
+ # # | id | parent_id | name |
93
+ # # +-------+--------------+--------+
94
+ # # | 1 | 1 | xx0 |
95
+ # # | 2 | 1 | xx1 |
96
+ # # | 3 | 1 | xx2 |
97
+ # # | 4 | 2 | xx0 |
98
+ # # | 5 | 2 | xx1 |
99
+ # # +-------+--------------+--------+
100
+ #
101
+ # class ParentController < ApplicationController
102
+ # include ActsAsAssociateTree
103
+ #
104
+ # # GET /parent/index_tree.json
105
+ # def index_tree
106
+ # special_tag = 'special_tag'
107
+ # render :josn => generate_tree_nodes {
108
+ # # 一个树可以有不同的结点集
109
+ # add_set {
110
+ # nodes { Parent.all } # 结点的数据,block的执行结果需返回一个数组
111
+ # node_attrs { { :name => name } } # 结点属性,block执行结果需返回一个Hash实例,block 中可以执行任何一个 Parent 实例能执行的方法
112
+ # children {
113
+ # nodes { children } # 在子结点中可以执行任何一个 Parent 实例能执行的方法
114
+ # node_attrs { { :name => name, :special => id == 1 ? special_tag : 'nothing' } } # 每一个 block 中都能访问闭包变量,如 special_tag
115
+ # }
116
+ # # 可以添加多个子节点
117
+ # children {
118
+ # nodes { [1, 2, 3, 4, 5] }
119
+ # node_attrs { { :name => self } }
120
+ # }
121
+ # }
122
+ # # 其他结点集
123
+ # add_set {
124
+ # set_attrs { { :text => 'i am a tree nodes set' } } # 可以添加结点集描述
125
+ # nodes { %w(act_as_associate_tree is so powerful) }
126
+ # node_attrs { { :text => self } }
127
+ # }
128
+ # }
129
+ # end
130
+ # end
131
+ #
132
+ # *index_tree* 方法会返回如下形式的数据
133
+ #
134
+ # [{:name=>"xx1",
135
+ # :children=>
136
+ # [{:name=>"xx0", :special=>"special_tag", :leaf=>true},
137
+ # {:name=>"xx1", :special=>"nothing", :leaf=>true},
138
+ # {:name=>"xx2", :special=>"nothing", :leaf=>true},
139
+ # {:name=>1, :leaf=>true},
140
+ # {:name=>2, :leaf=>true},
141
+ # {:name=>3, :leaf=>true},
142
+ # {:name=>4, :leaf=>true},
143
+ # {:name=>5, :leaf=>true}]},
144
+ # {:name=>"xx2",
145
+ # :children=>
146
+ # [{:name=>"xx0", :special=>"nothing", :leaf=>true},
147
+ # {:name=>"xx1", :special=>"nothing", :leaf=>true},
148
+ # {:name=>1, :leaf=>true},
149
+ # {:name=>2, :leaf=>true},
150
+ # {:name=>3, :leaf=>true},
151
+ # {:name=>4, :leaf=>true},
152
+ # {:name=>5, :leaf=>true}]},
153
+ # {:name=>"xx3",
154
+ # :children=>
155
+ # [{:name=>1, :leaf=>true},
156
+ # {:name=>2, :leaf=>true},
157
+ # {:name=>3, :leaf=>true},
158
+ # {:name=>4, :leaf=>true},
159
+ # {:name=>5, :leaf=>true}]},
160
+ # {:name=>"xx4",
161
+ # :children=>
162
+ # [{:name=>1, :leaf=>true},
163
+ # {:name=>2, :leaf=>true},
164
+ # {:name=>3, :leaf=>true},
165
+ # {:name=>4, :leaf=>true},
166
+ # {:name=>5, :leaf=>true}]},
167
+ # {:name=>"xx5",
168
+ # :children=>
169
+ # [{:name=>1, :leaf=>true},
170
+ # {:name=>2, :leaf=>true},
171
+ # {:name=>3, :leaf=>true},
172
+ # {:name=>4, :leaf=>true},
173
+ # {:name=>5, :leaf=>true}]},
174
+ # {:text=>"i am a tree nodes set",
175
+ # :children=>
176
+ # [{:text=>"act_as_associate_tree", :leaf=>true},
177
+ # {:text=>"is", :leaf=>true},
178
+ # {:text=>"so", :leaf=>true},
179
+ # {:text=>"powerful", :leaf=>true}]}]
180
+ #
181
+ require_relative 'acts_as_associate_tree/node_set.rb'
182
+ require_relative 'acts_as_associate_tree/set_tree.rb'
183
+
184
+ module ActsAsAssociateTree
185
+ class ConfigurationError < Exception; end
186
+
187
+ ##
188
+ # act_as_associate_tree 的统一接口,传入结点构造器后,产生结点
189
+ def generate_tree_nodes &block
190
+ (SetTree.new.instance_eval &block).expand
191
+ end
192
+ module_function :generate_tree_nodes
193
+ end
@@ -0,0 +1,107 @@
1
+ module ActsAsAssociateTree
2
+ class NodeSet
3
+ attr_reader :children_sets, :nodes_block, :node_attrs_block, :set_block, :set_attrs_block
4
+ attr_reader :set_symbol, :expandable, :mother_tree, :parent_set # for 'symbol' feature
5
+ def initialize(mother_tree, parent_set = nil, &block)
6
+ @children_sets = []
7
+ @set_symbol = ''
8
+ @mother_tree = mother_tree
9
+ @expandable = true
10
+ @parent_set = parent_set
11
+
12
+ self.instance_eval &block
13
+ end
14
+
15
+ # with symbol setting, you would be able to generate only a part of a tree instead of a whole one
16
+ def symbol(sym)
17
+ raise ConfigurationError.new('symbol Must be a SYMBOL') unless sym.kind_of? Symbol
18
+ @set_symbol = sym
19
+ return if mother_tree.expanding_symbol == :all
20
+ @expandable = false
21
+ enable_expanding if mother_tree.expanding_symbol == @set_symbol
22
+ end
23
+
24
+ # resymbolize
25
+ # def resymbol
26
+ # symbol set_symbol
27
+ # end
28
+
29
+ def enable_expanding
30
+ @expandable = true
31
+ parent_set.enable_expanding unless parent_set.nil?
32
+ end
33
+
34
+ ##
35
+ # 树集的属性
36
+ # block 的执行结果需返回一个 hash
37
+ def set_attrs(&block)
38
+ @set_attrs_block = block
39
+ end
40
+
41
+ ##
42
+ # 节点集合
43
+ def nodes(&block)
44
+ @nodes_block = block
45
+ end
46
+
47
+ ##
48
+ # 节点属性
49
+ # block 的执行结果需返回一个 hash
50
+ def node_attrs(&block)
51
+ @node_attrs_block = block
52
+ end
53
+
54
+ ##
55
+ # 子节点属性
56
+ def children(&block)
57
+ @children_sets << NodeSet.new(mother_tree, self, &block)
58
+ end
59
+
60
+ def expandable?
61
+ expandable
62
+ end
63
+
64
+ ##
65
+ # 展开树集
66
+ def expand(parent_scope = Object)
67
+ return [] unless expandable?
68
+ nodes = parent_scope.instance_eval &nodes_block
69
+ # Expand child set of each node
70
+ expanded_set = nodes.map do |node|
71
+ node_attrs = generate_node_attrs(node)
72
+ expand_node_children_set(node, node_attrs)
73
+ end
74
+ # Wrap a set around the expaned set
75
+ expanded_set = set_up_set_attributes(parent_scope, expanded_set) unless set_attrs_block.nil?
76
+
77
+ expanded_set
78
+ end
79
+
80
+ private
81
+ def generate_node_attrs(node)
82
+ attrs = node.instance_eval &node_attrs_block
83
+ raise ConfigurationError.new("Node attributes isn't a HASH INSTANCE") unless attrs.kind_of?(Hash)
84
+ attrs
85
+ end
86
+
87
+ def expand_node_children_set(node, node_attrs)
88
+ node_attrs[:children] = []
89
+ children_sets.each do |children_set|
90
+ node_attrs[:children] += children_set.expand(node)
91
+ end
92
+ if node_attrs[:children].empty?
93
+ node_attrs.delete(:children)
94
+ node_attrs[:leaf] = true
95
+ end
96
+
97
+ node_attrs
98
+ end
99
+
100
+ def set_up_set_attributes(parent_scope, expanded_set)
101
+ set_attrs = parent_scope.instance_eval &set_attrs_block
102
+ raise ConfigurationError.new("Set attributes isn't a HASH INSTANCE") unless set_attrs.kind_of?(Hash)
103
+ set_attrs[:children] = expanded_set
104
+ [set_attrs]
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,47 @@
1
+ module ActsAsAssociateTree
2
+ class SetTree
3
+ attr_reader :root
4
+ def initialize
5
+ @node_sets = []
6
+ @expanding_symbol = :all
7
+ end
8
+
9
+ ##
10
+ # 添加根节点,如果不需要根节点,可以不添加,节点类型需为一个哈希
11
+ def enroot(root)
12
+ raise ConfigurationError.new("Root configuration should be a HASH INSTANCE") unless root.kind_of?(Hash)
13
+ @root = root
14
+ end
15
+
16
+ # expanding_symbol = :all || :set_symbol
17
+ def expanding_symbol(type = nil)
18
+ return @expanding_symbol if type.nil?
19
+ raise ConfigurationError.new('expanding_symbol Must be a SYMBOL') unless type.kind_of? Symbol
20
+ @expanding_symbol = type
21
+ end
22
+
23
+ ##
24
+ # 添加一个新的节点集
25
+ def add_set(&set_block)
26
+ @node_sets << NodeSet.new(self, &set_block)
27
+ self
28
+ end
29
+
30
+ ##
31
+ # 展开所有的节点集
32
+ def expand
33
+ # Expand all node sets
34
+ expanded_node_sets = []
35
+ @node_sets.each do |node_set|
36
+ expanded_node_sets += node_set.expand
37
+ end
38
+ # set up root attributes
39
+ unless @root.nil?
40
+ @root[:children] = expanded_node_sets
41
+ expanded_node_sets = @root
42
+ end
43
+
44
+ expanded_node_sets
45
+ end
46
+ end
47
+ end
metadata ADDED
@@ -0,0 +1,47 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acts_as_associate_tree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Justin_lu
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-13 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: organize a tree data
15
+ email: gdjyluxiaoyong@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/acts_as_associate_tree.rb
21
+ - lib/acts_as_associate_tree/node_set.rb
22
+ - lib/acts_as_associate_tree/set_tree.rb
23
+ homepage: http://rubygems.org/gems/acts_as_associate_tree
24
+ licenses: []
25
+ post_install_message:
26
+ rdoc_options: []
27
+ require_paths:
28
+ - lib
29
+ required_ruby_version: !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ required_rubygems_version: !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ! '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ requirements: []
42
+ rubyforge_project:
43
+ rubygems_version: 1.8.24
44
+ signing_key:
45
+ specification_version: 3
46
+ summary: tree data
47
+ test_files: []