dagnabit 2.2.1 → 2.2.2

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.
@@ -1,9 +1,3 @@
1
- = This is the GitHub branch
2
-
3
- This branch is updated irregularly. The canonical dagnabit repository is hosted on Gitorious:
4
-
5
- http://gitorious.org/dagnabit/dagnabit
6
-
7
1
  = dagnabit
8
2
 
9
3
  dagnabit is (yet another) ActiveRecord plugin for directed acyclic graphs. It
@@ -83,6 +77,9 @@ In your node models, put
83
77
  +acts_as_dag_link+ accepts some configuration options. These configuration
84
78
  options are discussed below.
85
79
 
80
+ For a code example of a complete setup, see the <tt>dagnabit-test</tt> script
81
+ in +bin+.
82
+
86
83
  === Link table schemas
87
84
 
88
85
  Link storage is accomplished with two tables having identical schemas. One
@@ -109,6 +106,9 @@ The behavior of the plugin with a deviant schema is unspecified.
109
106
  * +transitive_closure_table_name+: The table where tuples in the transitive
110
107
  closure of the graph should be stored. Defaults to
111
108
  <tt>#{link_table_name}_transitive_closure_tuples</tt>.
109
+ * +transitive_closure_class_name+: The transitive closure is represented with
110
+ an ActiveRecord class whose name defaults to +TransitiveClosureLink+. Set this
111
+ option to change that name.
112
112
  * +descendant_id_column+: Column in the link tables for recording the ID of a
113
113
  descendant. Defaults to +descendant_id+.
114
114
  * +ancestor_id_column+: Column in the link tables for recording the ID of a
@@ -146,22 +146,20 @@ edge model was called +Link+, these would be valid expressions:
146
146
 
147
147
  +acts_as_dag_node+ adds the following instance methods to nodes:
148
148
 
149
- * +descendants+: All descendants of the node. Read-only.
149
+ * +children+: All children of the node. Read-only.
150
+ * +parents+: All parents of the node. Read-only.
150
151
  * +ancestors+: All ancestors of the node. Read-only.
152
+ * +descendants+: All descendants of the node. Read-only.
151
153
 
152
154
  === Link interface
153
155
 
154
156
  The following class methods are available on links:
155
157
 
156
158
  * +paths+: Retrieves all paths from one node to another.
157
- * +path+: Returns whether a node is reachable from another node.
158
- * +find_edge+: Finds an edge from one node to another, or nil if none exists.
159
+ * <tt>path?</tt>: Returns whether a node is reachable from another node.
159
160
  * +build_edge+: Builds an edge from one node to another node.
160
161
  * +connect+: Builds and saves an edge from one node to another. Identical to
161
162
  <tt>build_edge(nodeA, nodeB).save</tt>.
162
- * <tt>connect!</tt>: Builds and saves an edge from one node to another, raising
163
- an exception if save fails. Identical to <tt>build_edge(nodeA,
164
- nodeB).save!</tt>.
165
163
 
166
164
  == Introduction to the codebase
167
165
 
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 2
3
3
  :minor: 2
4
- :patch: 1
4
+ :patch: 2
5
5
  :build:
@@ -6,7 +6,7 @@
6
6
  #
7
7
 
8
8
  require 'rubygems'
9
- require 'activerecord'
9
+ require 'active_record'
10
10
 
11
11
  src = File.dirname(__FILE__) + '/../lib/dagnabit.rb'
12
12
  if File.exists?(src)
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{dagnabit}
8
- s.version = "2.2.1"
8
+ s.version = "2.2.2"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["David Yip"]
12
- s.date = %q{2009-12-07}
12
+ s.date = %q{2010-02-04}
13
13
  s.default_executable = %q{dagnabit-test}
14
14
  s.email = %q{yipdw@northwestern.edu}
15
15
  s.executables = ["dagnabit-test"]
@@ -75,7 +75,9 @@ Gem::Specification.new do |s|
75
75
  s.rubygems_version = %q{1.3.5}
76
76
  s.summary = %q{Directed acyclic graph plugin for ActiveRecord}
77
77
  s.test_files = [
78
- "test/connections/native_postgresql/connection.rb",
78
+ "test/benchmark/helper.rb",
79
+ "test/benchmark/linear_benchmark.rb",
80
+ "test/connections/native_postgresql/connection.rb",
79
81
  "test/connections/native_sqlite3/connection.rb",
80
82
  "test/dagnabit/link/test_associations.rb",
81
83
  "test/dagnabit/link/test_class_methods.rb",
@@ -3,7 +3,11 @@ module Dagnabit
3
3
  module TransitiveClosureRecalculation
4
4
  module OnUpdate
5
5
  def after_update
6
+ current_values = dag_link_column_names.map { |n| connection.quote(send(n)) }
6
7
  old_values = dag_link_column_names.map { |n| connection.quote(changes[n].try(:first) || send(n)) }
8
+
9
+ return unless current_values != old_values
10
+
7
11
  update_transitive_closure_for_destroy(*old_values)
8
12
  update_transitive_closure_for_create
9
13
  end
@@ -0,0 +1,43 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'active_record'
4
+ require 'active_support/test_case'
5
+
6
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
8
+ require 'dagnabit'
9
+
10
+ ActiveRecord::Base.logger = Logger.new("benchmark.log")
11
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
12
+
13
+ ActiveRecord::Schema.define do
14
+ [:links, :links_transitive_closure_tuples].each do |table|
15
+ create_table table do |t|
16
+ t.integer :ancestor_id
17
+ t.integer :descendant_id
18
+ t.string :ancestor_type
19
+ t.string :descendant_type
20
+ end
21
+ end
22
+
23
+ create_table :nodes do |t|
24
+ t.string :data
25
+ end
26
+ end
27
+
28
+ class Link < ActiveRecord::Base
29
+ acts_as_dag_link
30
+ end
31
+
32
+ class Node < ActiveRecord::Base
33
+ acts_as_dag_node_linked_by 'Link'
34
+ end
35
+
36
+ REPETITIONS = 5
37
+
38
+ class BenchmarkTestCase < ActiveSupport::TestCase
39
+ def teardown
40
+ Node.delete_all
41
+ Link.delete_all
42
+ end
43
+ end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class LinearBenchmark < BenchmarkTestCase
4
+ def test_speed
5
+ Benchmark.bm do |x|
6
+ root = Node.create
7
+ last_node = root
8
+
9
+ 100.times do |i|
10
+ target = Node.create
11
+
12
+ x.report("Graph depth: #{i+1}") { Link.connect(last_node, target) }
13
+
14
+ assert_equal 1, last_node.children.length
15
+ assert_equal i+1, root.descendants.length
16
+
17
+ last_node = target
18
+ end
19
+ end
20
+ end
21
+
22
+ def test_deletion_from_long_list
23
+ nodes = []
24
+ last_node = Node.create
25
+
26
+ puts 'Building long list...'
27
+ 50.times do |i|
28
+ target = Node.create
29
+ Link.connect(last_node, target)
30
+ last_node = target
31
+
32
+ nodes << target
33
+ end
34
+
35
+ Benchmark.bm do |x|
36
+ nodes.each_with_index do |node, i|
37
+ x.report("Destroying node #{i}") { node.destroy }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -134,6 +134,17 @@ module Dagnabit
134
134
  tc = CustomTransitiveClosureLink.find(:first, :conditions => { :the_ancestor_id => n1.id, :the_descendant_id => n3.id })
135
135
  assert_nil tc, 'expected to not find path from n1 to n3'
136
136
  end
137
+
138
+ should "not recalculate transitive closure if neither a link's source nor target changed" do
139
+ n1 = ::Node.create
140
+ n2 = ::Node.create
141
+
142
+ l1 = ::Link.new(:ancestor => n1, :descendant => n2)
143
+
144
+ l1.expects(:update_transitive_closure_for_destroy).never
145
+ l1.save
146
+ l1.save
147
+ end
137
148
  end
138
149
  end
139
150
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dagnabit
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Yip
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-07 00:00:00 -06:00
12
+ date: 2010-02-04 00:00:00 -06:00
13
13
  default_executable: dagnabit-test
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -141,6 +141,8 @@ signing_key:
141
141
  specification_version: 3
142
142
  summary: Directed acyclic graph plugin for ActiveRecord
143
143
  test_files:
144
+ - test/benchmark/helper.rb
145
+ - test/benchmark/linear_benchmark.rb
144
146
  - test/connections/native_postgresql/connection.rb
145
147
  - test/connections/native_sqlite3/connection.rb
146
148
  - test/dagnabit/link/test_associations.rb