acts_as_dag 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d531050423c7ca9be51544e54596e0310b96b2c
4
+ data.tar.gz: a0ec98ace714701dec05881502ffa834646d9fab
5
+ SHA512:
6
+ metadata.gz: c618e157390becaede12d0065b237945852cb3d64f5e4400933c10748e64a32bb80b1ecddc7245545b8dacea0c52d996ad74206440001c371f114ec821c55e64
7
+ data.tar.gz: 59fb1e46422ff35ec92c13b3877be868ce044ce4c50011b3a55f992877bd4965c109076937eb92e5effbf9717803145f872a99d2495e4659c21773c2c19ea66a
@@ -75,7 +75,7 @@ module ActsAsDAG
75
75
  after_create :initialize_descendants
76
76
 
77
77
  extend ActsAsDAG::ClassMethods
78
- include ActsAsDAG::InstanceMethods
78
+ include ActsAsDAG::InstanceMethods
79
79
  end
80
80
  end
81
81
 
@@ -88,7 +88,7 @@ module ActsAsDAG
88
88
  # Can pass a list of categories and only those will be reorganized
89
89
  def reorganize(categories_to_reorganize = self.all)
90
90
  return if categories_to_reorganize.empty?
91
-
91
+
92
92
  reset_hierarchy(categories_to_reorganize)
93
93
 
94
94
  word_count_groups = categories_to_reorganize.group_by{|category| ActsAsDAG::HelperMethods.word_count(category)}.sort
@@ -101,16 +101,16 @@ module ActsAsDAG
101
101
 
102
102
  # Try drop each category into each root
103
103
  categories.sort_by(&:name).each do |category|
104
- start = Time.now
105
- suitable_parent = false
106
- roots_categories.each do |root|
107
- suitable_parent = true if ActsAsDAG::HelperMethods.plinko(root, category)
108
- end
109
- unless suitable_parent
110
- ActiveRecord::Base.logger.info { "Plinko couldn't find a suitable parent for #{category.name}" }
111
- categories_with_no_parents << category
104
+ ActiveRecord::Base.benchmark "Analyze #{category.name}" do
105
+ suitable_parent = false
106
+ roots_categories.each do |root|
107
+ suitable_parent = true if ActsAsDAG::HelperMethods.plinko(root, category)
108
+ end
109
+ unless suitable_parent
110
+ ActiveRecord::Base.logger.info { "Plinko couldn't find a suitable parent for #{category.name}" }
111
+ categories_with_no_parents << category
112
+ end
112
113
  end
113
- puts "took #{Time.now - start} to analyze #{category.name}"
114
114
  end
115
115
 
116
116
  # Add all categories from this group without suitable parents to the roots
@@ -136,7 +136,7 @@ module ActsAsDAG
136
136
  category.send :initialize_links
137
137
  category.send :initialize_descendants
138
138
  end
139
- end
139
+ end
140
140
  end
141
141
 
142
142
  module InstanceMethods
@@ -145,6 +145,13 @@ module ActsAsDAG
145
145
  self.class.roots.exists? self
146
146
  end
147
147
 
148
+ def make_root
149
+ ancestor_links.delete_all
150
+ parent_links.delete_all
151
+ send :initialize_links
152
+ send :initialize_descendants
153
+ end
154
+
148
155
  # Adds a category as a parent of this category (self)
149
156
  def add_parent(parent)
150
157
  ActsAsDAG::HelperMethods.link(parent, self)
@@ -207,7 +214,7 @@ module ActsAsDAG
207
214
  def self.plinko(current, other)
208
215
  # ActiveRecord::Base.logger.info { "Plinkoing '#{other.name}' into '#{current.name}'..." }
209
216
  if should_descend_from?(current, other)
210
- # Find the descendants of the current category that +other+ should descend from
217
+ # Find the descendants of the current category that +other+ should descend from
211
218
  descendants_other_should_descend_from = current.descendants.select{|descendant| should_descend_from?(descendant, other) }
212
219
  # Of those, find the categories with the most number of matching words and make +other+ their child
213
220
  # We find all suitable candidates to provide support for categories whose names are permutations of each other
@@ -219,7 +226,7 @@ module ActsAsDAG
219
226
  other.add_parent(new_parent)
220
227
 
221
228
  # We've just affected the associations in ways we can not possibly imagine, so let's clear the association cache
222
- current.clear_association_cache
229
+ current.clear_association_cache
223
230
  end
224
231
  return true
225
232
  end
@@ -235,8 +242,8 @@ module ActsAsDAG
235
242
  unless plinko(current, category)
236
243
  end
237
244
  end
238
- end
239
- end
245
+ end
246
+ end
240
247
 
241
248
  # Returns the portion of this category's name that is not present in any of it's parents
242
249
  def self.unique_name_portion(current)
@@ -331,7 +338,7 @@ module ActsAsDAG
331
338
  # A F
332
339
  # / \ /
333
340
  # B C
334
- # |
341
+ # |
335
342
  # | D
336
343
  # \ /
337
344
  # E
@@ -350,7 +357,7 @@ module ActsAsDAG
350
357
 
351
358
  # Create a descendant link to iteself, then iterate through all children
352
359
  # We add this node to the ancestor array we received
353
- # Then we create a descendant link between it and all nodes in the array we were passed (nodes traversed between it and all its ancestors affected by the unlinking).
360
+ # Then we create a descendant link between it and all nodes in the array we were passed (nodes traversed between it and all its ancestors affected by the unlinking).
354
361
  # Then iterate to all children of the current node passing the ancestor array along
355
362
  def self.rebuild_descendant_links(current, ancestors = [])
356
363
  indent = Array.new(ancestors.size, " ").join
@@ -392,4 +399,4 @@ module ActsAsDAG
392
399
 
393
400
  validates_presence_of :ancestor_id, :descendant_id
394
401
  end
395
- end
402
+ end
@@ -5,7 +5,7 @@ describe 'acts_as_dag' do
5
5
  before(:each) do
6
6
  @klass.destroy_all # Because we're using sqlite3 and it doesn't support transactional specs (afaik)
7
7
  end
8
-
8
+
9
9
  describe "and" do
10
10
  before(:each) do
11
11
  @grandpa = @klass.create(:name => 'grandpa')
@@ -81,7 +81,7 @@ describe 'acts_as_dag' do
81
81
 
82
82
  @grandpa.descendants.should == [@grandpa, @dad, @child]
83
83
  end
84
-
84
+
85
85
  it "should be able to test descent" do
86
86
  @dad.add_child(@child)
87
87
  @grandpa.add_child(@dad)
@@ -95,13 +95,40 @@ describe 'acts_as_dag' do
95
95
  it "should be a root node immediately after saving" do
96
96
  @grandpa.parents.should be_empty
97
97
  @grandpa.root?.should be_true
98
- end
98
+ end
99
99
 
100
100
  it "should be a child if it has a parent" do
101
101
  @grandpa.add_child(@dad)
102
102
  @grandpa.add_child(@mom)
103
103
  @klass.children.order(:id).should == [@dad, @mom]
104
- end
104
+ end
105
+ end
106
+
107
+ context "when a record hierarchy exists" do
108
+ before(:each) do
109
+ @grandma = @klass.create(:name => 'grandma')
110
+ @mom = @klass.create(:name => 'mom')
111
+ @brother = @klass.create(:name => 'brother')
112
+
113
+ @grandma.add_child(@mom)
114
+ @mom.add_child(@brother)
115
+ end
116
+
117
+ it "destroying a record should delete the associated hierarchy-tracking records " do
118
+ @mom.destroy
119
+ @mom.descendant_links.should be_empty
120
+ @mom.ancestor_links.should be_empty
121
+ @mom.parent_links.should be_empty
122
+ @mom.child_links.should be_empty
123
+ end
124
+
125
+ it "make_root should make the record a root, but maintain it's children" do
126
+ @mom.make_root
127
+
128
+ @mom.should be_root
129
+ @mom.parents.should be_empty
130
+ @mom.children.should be_present
131
+ end
105
132
  end
106
133
 
107
134
  describe "reorganization" do
@@ -110,7 +137,7 @@ describe 'acts_as_dag' do
110
137
  @totem_pole = @klass.create(:name => "totem pole")
111
138
  @big_totem_pole = @klass.create(:name => "big totem pole")
112
139
  @big_model_totem_pole = @klass.create(:name => "big model totem pole")
113
- @big_red_model_totem_pole = @klass.create(:name => "big red model totem pole")
140
+ @big_red_model_totem_pole = @klass.create(:name => "big red model totem pole")
114
141
  end
115
142
 
116
143
  it "should reinitialize links and descendants after resetting the hierarchy" do
@@ -121,18 +148,18 @@ describe 'acts_as_dag' do
121
148
  @big_totem_pole.descendants.should == [@big_totem_pole]
122
149
  end
123
150
 
124
- it "should be able to determine whether one category is an ancestor of the other by inspecting the name" do
151
+ it "should be able to determine whether one category is an ancestor of the other by inspecting the name" do
125
152
  ActsAsDAG::HelperMethods.should_descend_from?(@totem_pole, @big_totem_pole).should be_true
126
153
  ActsAsDAG::HelperMethods.should_descend_from?(@big_totem_pole, @totem_pole).should be_false
127
154
  end
128
155
 
129
- it "should be able to determine the number of matching words in two categories names" do
156
+ it "should be able to determine the number of matching words in two categories names" do
130
157
  ActsAsDAG::HelperMethods.matching_word_count(@totem_pole, @big_totem_pole).should == 2
131
158
  end
132
159
 
133
160
  it "should arrange the categories correctly when not passed any arguments" do
134
161
  @klass.reorganize
135
-
162
+
136
163
  @totem.children.should == [@totem_pole]
137
164
  @totem_pole.children.should == [@big_totem_pole]
138
165
  @big_totem_pole.children.should == [@big_model_totem_pole]
@@ -141,7 +168,7 @@ describe 'acts_as_dag' do
141
168
 
142
169
  it "should arrange the categories correctly when passed a set of nodes to reorganize" do
143
170
  @klass.reorganize [@totem, @totem_pole, @big_totem_pole, @big_model_totem_pole, @big_red_model_totem_pole]
144
-
171
+
145
172
  @totem.reload.children.should == [@totem_pole]
146
173
  @totem_pole.reload.children.should == [@big_totem_pole]
147
174
  @big_totem_pole.reload.children.should == [@big_model_totem_pole]
@@ -158,7 +185,7 @@ describe 'acts_as_dag' do
158
185
  @big_totem_pole.children.should == [@big_model_totem_pole]
159
186
  @big_model_totem_pole.reload.children.should == [@big_red_model_totem_pole]
160
187
  end
161
-
188
+
162
189
  it "should still work when there are categories that are permutations of each other" do
163
190
  @big_totem_pole_model = @klass.create(:name => "big totem pole model")
164
191
 
@@ -169,7 +196,7 @@ describe 'acts_as_dag' do
169
196
  (@big_totem_pole.children - [@big_model_totem_pole, @big_totem_pole_model]).should == []
170
197
  @big_model_totem_pole.reload.children.should == [@big_red_model_totem_pole]
171
198
  @big_totem_pole_model.reload.children.should == [@big_red_model_totem_pole]
172
- end
199
+ end
173
200
 
174
201
  describe "when there is a single long inheritance chain" do
175
202
  before(:each) do
@@ -195,14 +222,14 @@ describe 'acts_as_dag' do
195
222
  end
196
223
 
197
224
  it "should return multiple instances of descendants before breaking the old link" do
198
- @totem.descendants.sort_by(&:id).should == [@totem, @totem_pole, @big_totem_pole, @big_model_totem_pole, @big_model_totem_pole, @big_red_model_totem_pole, @big_red_model_totem_pole].sort_by(&:id)
225
+ @totem.descendants.sort_by(&:id).should == [@totem, @totem_pole, @big_totem_pole, @big_model_totem_pole, @big_model_totem_pole, @big_red_model_totem_pole, @big_red_model_totem_pole].sort_by(&:id)
199
226
  end
200
227
 
201
228
  it "should return the correct inheritance chain after breaking the old link" do
202
229
  @totem_pole.remove_child(@big_model_totem_pole)
203
230
 
204
- @totem_pole.children.sort_by(&:id).should == [@big_totem_pole].sort_by(&:id)
205
- @totem.descendants.sort_by(&:id).should == [@totem, @totem_pole, @big_totem_pole, @big_model_totem_pole, @big_red_model_totem_pole].sort_by(&:id)
231
+ @totem_pole.children.sort_by(&:id).should == [@big_totem_pole].sort_by(&:id)
232
+ @totem.descendants.sort_by(&:id).should == [@totem, @totem_pole, @big_totem_pole, @big_model_totem_pole, @big_red_model_totem_pole].sort_by(&:id)
206
233
  end
207
234
 
208
235
  it "should return the correct inheritance chain after breaking the old link when there is are two ancestor root nodes" do
@@ -215,7 +242,7 @@ describe 'acts_as_dag' do
215
242
  @totem.descendants.sort_by(&:id).should == [@totem, @totem_pole, @big_totem_pole, @big_model_totem_pole, @big_red_model_totem_pole].sort_by(&:id)
216
243
  end
217
244
  end
218
- end
245
+ end
219
246
  end
220
247
 
221
248
  describe "and two paths of the same length exist to the same node" do
@@ -229,14 +256,14 @@ describe 'acts_as_dag' do
229
256
  @grandpa.add_child(@dad)
230
257
  @dad.add_child(@child)
231
258
  @child.add_parent(@mom)
232
- @mom.add_parent(@grandpa)
259
+ @mom.add_parent(@grandpa)
233
260
  end
234
261
 
235
262
  it "descendants should not return multiple instances of a child" do
236
263
  @grandpa.descendants.sort_by(&:id).should == [@grandpa, @dad, @mom, @child].sort_by(&:id)
237
- end
264
+ end
238
265
 
239
- describe "and a link between parent and ancestor is removed" do
266
+ describe "and a link between parent and ancestor is removed" do
240
267
  before(:each) do
241
268
  # the incest is undone!
242
269
  @dad.remove_parent(@grandpa)
@@ -253,7 +280,7 @@ describe 'acts_as_dag' do
253
280
  @mom.descendants.sort_by(&:id).should == [@mom, @child].sort_by(&:id)
254
281
  @dad.descendants.sort_by(&:id).should == [@dad, @child].sort_by(&:id)
255
282
  @grandpa.descendants.sort_by(&:id).should == [@grandpa, @mom, @child].sort_by(&:id)
256
- end
283
+ end
257
284
  end
258
285
  end
259
286
  end
@@ -269,7 +296,6 @@ describe 'acts_as_dag' do
269
296
  describe "models with unified link tables" do
270
297
  before(:each) do
271
298
  @klass = UnifiedLinkModel
272
- @klass.logger = Logger.new(STDOUT)
273
299
  end
274
300
 
275
301
  it_should_behave_like "DAG Model"
@@ -280,5 +306,5 @@ describe 'acts_as_dag' do
280
306
  record.parent_links.first.category_type.should == @klass.name
281
307
  record.descendant_links.first.category_type.should == @klass.name
282
308
  end
283
- end
284
- end
309
+ end
310
+ end
data/spec/spec_helper.rb CHANGED
@@ -10,7 +10,7 @@ ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":me
10
10
  ActiveRecord::Schema.define(:version => 0) do
11
11
 
12
12
  # MODEL TABLES
13
-
13
+
14
14
  create_table :separate_link_models, :force => true do |t|
15
15
  t.string :name
16
16
  end
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts_as_dag
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.2
5
- prerelease:
4
+ version: 1.2.3
6
5
  platform: ruby
7
6
  authors:
8
7
  - Nicholas Jakobsen
@@ -10,22 +9,20 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-08-15 00:00:00.000000000 Z
12
+ date: 2014-06-05 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: activerecord
17
16
  requirement: !ruby/object:Gem::Requirement
18
- none: false
19
17
  requirements:
20
- - - ~>
18
+ - - "~>"
21
19
  - !ruby/object:Gem::Version
22
20
  version: '4.0'
23
21
  type: :runtime
24
22
  prerelease: false
25
23
  version_requirements: !ruby/object:Gem::Requirement
26
- none: false
27
24
  requirements:
28
- - - ~>
25
+ - - "~>"
29
26
  - !ruby/object:Gem::Version
30
27
  version: '4.0'
31
28
  description:
@@ -34,34 +31,33 @@ executables: []
34
31
  extensions: []
35
32
  extra_rdoc_files: []
36
33
  files:
37
- - lib/acts_as_dag/acts_as_dag.rb
34
+ - LICENSE
35
+ - README.rdoc
38
36
  - lib/acts_as_dag.rb
37
+ - lib/acts_as_dag/acts_as_dag.rb
39
38
  - spec/acts_as_dag_spec.rb
40
39
  - spec/spec_helper.rb
41
- - LICENSE
42
- - README.rdoc
43
40
  homepage: http://github.com/rrn/acts_as_dag
44
41
  licenses: []
42
+ metadata: {}
45
43
  post_install_message:
46
44
  rdoc_options: []
47
45
  require_paths:
48
46
  - lib
49
47
  required_ruby_version: !ruby/object:Gem::Requirement
50
- none: false
51
48
  requirements:
52
- - - '>='
49
+ - - ">="
53
50
  - !ruby/object:Gem::Version
54
51
  version: '0'
55
52
  required_rubygems_version: !ruby/object:Gem::Requirement
56
- none: false
57
53
  requirements:
58
- - - '>='
54
+ - - ">="
59
55
  - !ruby/object:Gem::Version
60
56
  version: '0'
61
57
  requirements: []
62
58
  rubyforge_project:
63
- rubygems_version: 1.8.25
59
+ rubygems_version: 2.2.2
64
60
  signing_key:
65
- specification_version: 3
61
+ specification_version: 4
66
62
  summary: Adds directed acyclic graph functionality to ActiveRecord.
67
63
  test_files: []