hierarchy 1.0.5 → 1.0.6
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.
- data/README.textile +9 -12
- data/hierarchy.gemspec +11 -26
- data/lib/hierarchy.rb +23 -30
- data/templates/add_ltree_type.rb +4 -10
- metadata +69 -111
- data/.document +0 -5
- data/.rspec +0 -1
- data/Gemfile +0 -11
- data/Gemfile.lock +0 -93
- data/Rakefile +0 -39
- data/VERSION +0 -1
- data/spec/hierarchy_spec.rb +0 -116
- data/spec/index_path_spec.rb +0 -31
- data/spec/spec_helper.rb +0 -26
data/README.textile
CHANGED
@@ -1,23 +1,20 @@
|
|
1
1
|
h1. Hierarchy -- Use PostgreSQL @LTREE@ columns in ActiveRecord
|
2
2
|
|
3
3
|
| *Author* | Tim Morgan |
|
4
|
-
| *Version* | 1.0.
|
4
|
+
| *Version* | 1.0.6 (Nov 27, 2010) |
|
5
5
|
| *License* | Released under the MIT license. |
|
6
6
|
|
7
7
|
h2. About
|
8
8
|
|
9
|
-
The @LTREE@ column type is a PostgreSQL-specific type (
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
The @LTREE@ column type is a PostgreSQL-specific type (available from the ltree
|
10
|
+
extension) for representing hierarchies. It is more efficient than the typical
|
11
|
+
way of accomplishing hierarchical structures in SQL, the @parent_id@ column (or
|
12
|
+
similar).
|
13
13
|
|
14
14
|
This gem lets you use an @LTREE@-utilizing hierarchy in ActiveRecord. Including
|
15
|
-
this gem in your project gets you a
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
*Though I don't know for sure, I suspect when Arel 2.0 is supported in Rails, I
|
20
|
-
will be able to remove this monkey-patching ugliness.
|
15
|
+
this gem in your project gets you a module you can include in your models,
|
16
|
+
providing an abundance of methods to help you navigate and manipulate the
|
17
|
+
hierarchy.
|
21
18
|
|
22
19
|
h2. Installation
|
23
20
|
|
@@ -69,7 +66,7 @@ You also have access to a wealth of ways to traverse the hierarchy:
|
|
69
66
|
<pre><code>
|
70
67
|
person.children.where(gender: :male)
|
71
68
|
person.top_level?
|
72
|
-
Person.treeified #=> returns a
|
69
|
+
Person.treeified #=> returns a traversible tree of all people
|
73
70
|
</code></pre>
|
74
71
|
|
75
72
|
For more information on what you can do, see the {Hierarchy} module
|
data/hierarchy.gemspec
CHANGED
@@ -4,73 +4,58 @@
|
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
|
-
s.name =
|
8
|
-
s.version = "1.0.
|
7
|
+
s.name = "hierarchy"
|
8
|
+
s.version = "1.0.6"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tim Morgan"]
|
12
|
-
s.date =
|
13
|
-
s.description =
|
14
|
-
s.email =
|
12
|
+
s.date = "2011-12-02"
|
13
|
+
s.description = "Adds ActiveRecord support for hierarchical data structures using PostgreSQL's LTREE column type."
|
14
|
+
s.email = "git@timothymorgan.info"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
17
|
"README.textile"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
".document",
|
21
|
-
".rspec",
|
22
|
-
"Gemfile",
|
23
|
-
"Gemfile.lock",
|
24
20
|
"LICENSE",
|
25
21
|
"README.textile",
|
26
|
-
"Rakefile",
|
27
|
-
"VERSION",
|
28
22
|
"hierarchy.gemspec",
|
29
23
|
"lib/hierarchy.rb",
|
30
24
|
"lib/hierarchy/index_path.rb",
|
31
25
|
"lib/hierarchy/node.rb",
|
32
26
|
"lib/hierarchy_generator.rb",
|
33
|
-
"spec/hierarchy_spec.rb",
|
34
|
-
"spec/index_path_spec.rb",
|
35
|
-
"spec/spec_helper.rb",
|
36
27
|
"templates/add_ltree_type.rb"
|
37
28
|
]
|
38
|
-
s.homepage =
|
29
|
+
s.homepage = "http://github.com/riscfuture/hierarchy"
|
39
30
|
s.require_paths = ["lib"]
|
40
31
|
s.required_ruby_version = Gem::Requirement.new(">= 1.9")
|
41
|
-
s.rubygems_version =
|
42
|
-
s.summary =
|
43
|
-
s.test_files = [
|
44
|
-
"spec/hierarchy_spec.rb",
|
45
|
-
"spec/index_path_spec.rb",
|
46
|
-
"spec/spec_helper.rb"
|
47
|
-
]
|
32
|
+
s.rubygems_version = "1.8.11"
|
33
|
+
s.summary = "Use PostgreSQL LTREE type with ActiveRecord"
|
48
34
|
|
49
35
|
if s.respond_to? :specification_version then
|
50
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
36
|
s.specification_version = 3
|
52
37
|
|
53
38
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
39
|
s.add_runtime_dependency(%q<rails>, [">= 3.0.2"])
|
40
|
+
s.add_runtime_dependency(%q<pg>, [">= 0"])
|
55
41
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
56
42
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
57
43
|
s.add_development_dependency(%q<RedCloth>, [">= 0"])
|
58
|
-
s.add_development_dependency(%q<pg>, [">= 0"])
|
59
44
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
60
45
|
else
|
61
46
|
s.add_dependency(%q<rails>, [">= 3.0.2"])
|
47
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
62
48
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
63
49
|
s.add_dependency(%q<yard>, [">= 0"])
|
64
50
|
s.add_dependency(%q<RedCloth>, [">= 0"])
|
65
|
-
s.add_dependency(%q<pg>, [">= 0"])
|
66
51
|
s.add_dependency(%q<rspec>, [">= 0"])
|
67
52
|
end
|
68
53
|
else
|
69
54
|
s.add_dependency(%q<rails>, [">= 3.0.2"])
|
55
|
+
s.add_dependency(%q<pg>, [">= 0"])
|
70
56
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
71
57
|
s.add_dependency(%q<yard>, [">= 0"])
|
72
58
|
s.add_dependency(%q<RedCloth>, [">= 0"])
|
73
|
-
s.add_dependency(%q<pg>, [">= 0"])
|
74
59
|
s.add_dependency(%q<rspec>, [">= 0"])
|
75
60
|
end
|
76
61
|
end
|
data/lib/hierarchy.rb
CHANGED
@@ -1,21 +1,3 @@
|
|
1
|
-
# @private
|
2
|
-
module Arel
|
3
|
-
# @private
|
4
|
-
module Attributes
|
5
|
-
# @private
|
6
|
-
def self.for_with_psql(column)
|
7
|
-
case column.sql_type
|
8
|
-
when 'ltree' then String
|
9
|
-
else for_without_psql(column)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
unless singleton_class.method_defined?(:for_without_psql)
|
13
|
-
singleton_class.send :alias_method, :for_without_psql, :for
|
14
|
-
singleton_class.send :alias_method, :for, :for_with_psql
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
1
|
require 'hierarchy_generator'
|
20
2
|
require 'hierarchy/index_path'
|
21
3
|
require 'hierarchy/node'
|
@@ -44,19 +26,20 @@ module Hierarchy
|
|
44
26
|
extend ActiveSupport::Concern
|
45
27
|
|
46
28
|
# @private
|
47
|
-
included do
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
base.scope :parent_of, ->(obj) { obj.top_level? ? base.where('false') : base.where(id: obj.index_path.last) }
|
52
|
-
base.scope :children_of, ->(obj) { base.where(path: obj.my_path) }
|
53
|
-
base.scope :ancestors_of, ->(obj) { obj.top_level? ? base.where('false') : base.where(id: obj.index_path.to_a) }
|
54
|
-
base.scope :descendants_of, ->(obj) { base.where([ "path <@ ?", obj.my_path ]) }
|
55
|
-
base.scope :siblings_of, ->(obj) { base.where(path: obj.path) }
|
56
|
-
base.scope :priority_order, base.order("NLEVEL(path) ASC")
|
57
|
-
base.scope :top_level, base.where([ "path IS NULL or path = ?", '' ])
|
29
|
+
included do
|
30
|
+
extend ActiveSupport::Memoizable
|
31
|
+
memoize :index_path, :ancestors
|
58
32
|
|
59
|
-
|
33
|
+
scope :parent_of, ->(obj) { obj.top_level? ? where('false') : where(id: obj.index_path.last) }
|
34
|
+
scope :children_of, ->(obj) { where(path: obj.my_path) }
|
35
|
+
scope :ancestors_of, ->(obj) { obj.top_level? ? where('false') : where(id: obj.index_path.to_a) }
|
36
|
+
scope :descendants_of, ->(obj) { where("path <@ ?", obj.my_path) }
|
37
|
+
scope :siblings_of, ->(obj) { where(path: obj.path) }
|
38
|
+
scope :priority_order, order("NLEVEL(path) ASC")
|
39
|
+
scope :top_level, where("path IS NULL or path = ?", '')
|
40
|
+
|
41
|
+
before_save { |obj| obj.path ||= '' }
|
42
|
+
before_save :update_children_with_new_parent
|
60
43
|
end
|
61
44
|
|
62
45
|
module ClassMethods
|
@@ -161,5 +144,15 @@ module Hierarchy
|
|
161
144
|
def index_path
|
162
145
|
IndexPath.from_ltree path.to_s
|
163
146
|
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
# if our parent has changed, update our children's paths
|
151
|
+
def update_children_with_new_parent
|
152
|
+
if path_changed? and not new_record? then
|
153
|
+
old_path = (path_was.blank? ? id.to_s : "#{path_was}.#{id}")
|
154
|
+
self.class.where("path <@ ?", old_path).update_all([ "path = TEXT2LTREE(REPLACE(LTREE2TEXT(path), ?, ?))", old_path, my_path ])
|
155
|
+
end
|
156
|
+
end
|
164
157
|
end
|
165
158
|
end
|
data/templates/add_ltree_type.rb
CHANGED
@@ -1,15 +1,9 @@
|
|
1
1
|
class AddLtreeType < ActiveRecord::Migration
|
2
|
-
def
|
3
|
-
|
4
|
-
puts cmd
|
5
|
-
result = system(cmd)
|
6
|
-
raise "Bad exit" unless result
|
2
|
+
def up
|
3
|
+
execute "CREATE EXTENSION ltree"
|
7
4
|
end
|
8
5
|
|
9
|
-
def
|
10
|
-
|
11
|
-
puts cmd
|
12
|
-
result = system(cmd)
|
13
|
-
raise "Bad exit" unless result
|
6
|
+
def down
|
7
|
+
execute "DROP EXTENSION ltree"
|
14
8
|
end
|
15
9
|
end
|
metadata
CHANGED
@@ -1,163 +1,121 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: hierarchy
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
- 5
|
9
|
-
version: 1.0.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.6
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Tim Morgan
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-12-02 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rails
|
22
|
-
requirement: &
|
16
|
+
requirement: &70260260128220 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
segments:
|
28
|
-
- 3
|
29
|
-
- 0
|
30
|
-
- 2
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
31
21
|
version: 3.0.2
|
32
22
|
type: :runtime
|
33
23
|
prerelease: false
|
34
|
-
version_requirements: *
|
35
|
-
- !ruby/object:Gem::Dependency
|
24
|
+
version_requirements: *70260260128220
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: pg
|
27
|
+
requirement: &70260260127240 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70260260127240
|
36
|
+
- !ruby/object:Gem::Dependency
|
36
37
|
name: jeweler
|
37
|
-
requirement: &
|
38
|
+
requirement: &70260260126200 !ruby/object:Gem::Requirement
|
38
39
|
none: false
|
39
|
-
requirements:
|
40
|
-
- -
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
|
43
|
-
- 0
|
44
|
-
version: "0"
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
45
44
|
type: :development
|
46
45
|
prerelease: false
|
47
|
-
version_requirements: *
|
48
|
-
- !ruby/object:Gem::Dependency
|
46
|
+
version_requirements: *70260260126200
|
47
|
+
- !ruby/object:Gem::Dependency
|
49
48
|
name: yard
|
50
|
-
requirement: &
|
49
|
+
requirement: &70260260125260 !ruby/object:Gem::Requirement
|
51
50
|
none: false
|
52
|
-
requirements:
|
53
|
-
- -
|
54
|
-
- !ruby/object:Gem::Version
|
55
|
-
|
56
|
-
- 0
|
57
|
-
version: "0"
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
58
55
|
type: :development
|
59
56
|
prerelease: false
|
60
|
-
version_requirements: *
|
61
|
-
- !ruby/object:Gem::Dependency
|
57
|
+
version_requirements: *70260260125260
|
58
|
+
- !ruby/object:Gem::Dependency
|
62
59
|
name: RedCloth
|
63
|
-
requirement: &
|
64
|
-
none: false
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
segments:
|
69
|
-
- 0
|
70
|
-
version: "0"
|
71
|
-
type: :development
|
72
|
-
prerelease: false
|
73
|
-
version_requirements: *id004
|
74
|
-
- !ruby/object:Gem::Dependency
|
75
|
-
name: pg
|
76
|
-
requirement: &id005 !ruby/object:Gem::Requirement
|
60
|
+
requirement: &70260260124220 !ruby/object:Gem::Requirement
|
77
61
|
none: false
|
78
|
-
requirements:
|
79
|
-
- -
|
80
|
-
- !ruby/object:Gem::Version
|
81
|
-
|
82
|
-
- 0
|
83
|
-
version: "0"
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
84
66
|
type: :development
|
85
67
|
prerelease: false
|
86
|
-
version_requirements: *
|
87
|
-
- !ruby/object:Gem::Dependency
|
68
|
+
version_requirements: *70260260124220
|
69
|
+
- !ruby/object:Gem::Dependency
|
88
70
|
name: rspec
|
89
|
-
requirement: &
|
71
|
+
requirement: &70260260123540 !ruby/object:Gem::Requirement
|
90
72
|
none: false
|
91
|
-
requirements:
|
92
|
-
- -
|
93
|
-
- !ruby/object:Gem::Version
|
94
|
-
|
95
|
-
- 0
|
96
|
-
version: "0"
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
97
77
|
type: :development
|
98
78
|
prerelease: false
|
99
|
-
version_requirements: *
|
100
|
-
description: Adds ActiveRecord support for
|
79
|
+
version_requirements: *70260260123540
|
80
|
+
description: Adds ActiveRecord support for hierarchical data structures using PostgreSQL's
|
81
|
+
LTREE column type.
|
101
82
|
email: git@timothymorgan.info
|
102
83
|
executables: []
|
103
|
-
|
104
84
|
extensions: []
|
105
|
-
|
106
|
-
extra_rdoc_files:
|
85
|
+
extra_rdoc_files:
|
107
86
|
- LICENSE
|
108
87
|
- README.textile
|
109
|
-
files:
|
110
|
-
- .document
|
111
|
-
- .rspec
|
112
|
-
- Gemfile
|
113
|
-
- Gemfile.lock
|
88
|
+
files:
|
114
89
|
- LICENSE
|
115
90
|
- README.textile
|
116
|
-
- Rakefile
|
117
|
-
- VERSION
|
118
91
|
- hierarchy.gemspec
|
119
92
|
- lib/hierarchy.rb
|
120
93
|
- lib/hierarchy/index_path.rb
|
121
94
|
- lib/hierarchy/node.rb
|
122
95
|
- lib/hierarchy_generator.rb
|
123
|
-
- spec/hierarchy_spec.rb
|
124
|
-
- spec/index_path_spec.rb
|
125
|
-
- spec/spec_helper.rb
|
126
96
|
- templates/add_ltree_type.rb
|
127
|
-
has_rdoc: true
|
128
97
|
homepage: http://github.com/riscfuture/hierarchy
|
129
98
|
licenses: []
|
130
|
-
|
131
99
|
post_install_message:
|
132
100
|
rdoc_options: []
|
133
|
-
|
134
|
-
require_paths:
|
101
|
+
require_paths:
|
135
102
|
- lib
|
136
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
104
|
none: false
|
138
|
-
requirements:
|
139
|
-
- -
|
140
|
-
- !ruby/object:Gem::Version
|
141
|
-
|
142
|
-
|
143
|
-
- 9
|
144
|
-
version: "1.9"
|
145
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '1.9'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
110
|
none: false
|
147
|
-
requirements:
|
148
|
-
- -
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
|
151
|
-
- 0
|
152
|
-
version: "0"
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
153
115
|
requirements: []
|
154
|
-
|
155
116
|
rubyforge_project:
|
156
|
-
rubygems_version: 1.
|
117
|
+
rubygems_version: 1.8.11
|
157
118
|
signing_key:
|
158
119
|
specification_version: 3
|
159
120
|
summary: Use PostgreSQL LTREE type with ActiveRecord
|
160
|
-
test_files:
|
161
|
-
- spec/hierarchy_spec.rb
|
162
|
-
- spec/index_path_spec.rb
|
163
|
-
- spec/spec_helper.rb
|
121
|
+
test_files: []
|
data/.document
DELETED
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
-cfs
|
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
RedCloth (4.2.3)
|
5
|
-
abstract (1.0.0)
|
6
|
-
actionmailer (3.0.3)
|
7
|
-
actionpack (= 3.0.3)
|
8
|
-
mail (~> 2.2.9)
|
9
|
-
actionpack (3.0.3)
|
10
|
-
activemodel (= 3.0.3)
|
11
|
-
activesupport (= 3.0.3)
|
12
|
-
builder (~> 2.1.2)
|
13
|
-
erubis (~> 2.6.6)
|
14
|
-
i18n (~> 0.4)
|
15
|
-
rack (~> 1.2.1)
|
16
|
-
rack-mount (~> 0.6.13)
|
17
|
-
rack-test (~> 0.5.6)
|
18
|
-
tzinfo (~> 0.3.23)
|
19
|
-
activemodel (3.0.3)
|
20
|
-
activesupport (= 3.0.3)
|
21
|
-
builder (~> 2.1.2)
|
22
|
-
i18n (~> 0.4)
|
23
|
-
activerecord (3.0.3)
|
24
|
-
activemodel (= 3.0.3)
|
25
|
-
activesupport (= 3.0.3)
|
26
|
-
arel (~> 2.0.2)
|
27
|
-
tzinfo (~> 0.3.23)
|
28
|
-
activeresource (3.0.3)
|
29
|
-
activemodel (= 3.0.3)
|
30
|
-
activesupport (= 3.0.3)
|
31
|
-
activesupport (3.0.3)
|
32
|
-
arel (2.0.4)
|
33
|
-
builder (2.1.2)
|
34
|
-
diff-lcs (1.1.2)
|
35
|
-
erubis (2.6.6)
|
36
|
-
abstract (>= 1.0.0)
|
37
|
-
git (1.2.5)
|
38
|
-
i18n (0.4.2)
|
39
|
-
jeweler (1.5.1)
|
40
|
-
bundler (~> 1.0.0)
|
41
|
-
git (>= 1.2.5)
|
42
|
-
rake
|
43
|
-
mail (2.2.10)
|
44
|
-
activesupport (>= 2.3.6)
|
45
|
-
i18n (~> 0.4.1)
|
46
|
-
mime-types (~> 1.16)
|
47
|
-
treetop (~> 1.4.8)
|
48
|
-
mime-types (1.16)
|
49
|
-
pg (0.9.0)
|
50
|
-
polyglot (0.3.1)
|
51
|
-
rack (1.2.1)
|
52
|
-
rack-mount (0.6.13)
|
53
|
-
rack (>= 1.0.0)
|
54
|
-
rack-test (0.5.6)
|
55
|
-
rack (>= 1.0)
|
56
|
-
rails (3.0.3)
|
57
|
-
actionmailer (= 3.0.3)
|
58
|
-
actionpack (= 3.0.3)
|
59
|
-
activerecord (= 3.0.3)
|
60
|
-
activeresource (= 3.0.3)
|
61
|
-
activesupport (= 3.0.3)
|
62
|
-
bundler (~> 1.0)
|
63
|
-
railties (= 3.0.3)
|
64
|
-
railties (3.0.3)
|
65
|
-
actionpack (= 3.0.3)
|
66
|
-
activesupport (= 3.0.3)
|
67
|
-
rake (>= 0.8.7)
|
68
|
-
thor (~> 0.14.4)
|
69
|
-
rake (0.8.7)
|
70
|
-
rspec (2.1.0)
|
71
|
-
rspec-core (~> 2.1.0)
|
72
|
-
rspec-expectations (~> 2.1.0)
|
73
|
-
rspec-mocks (~> 2.1.0)
|
74
|
-
rspec-core (2.1.0)
|
75
|
-
rspec-expectations (2.1.0)
|
76
|
-
diff-lcs (~> 1.1.2)
|
77
|
-
rspec-mocks (2.1.0)
|
78
|
-
thor (0.14.6)
|
79
|
-
treetop (1.4.9)
|
80
|
-
polyglot (>= 0.3.1)
|
81
|
-
tzinfo (0.3.23)
|
82
|
-
yard (0.6.3)
|
83
|
-
|
84
|
-
PLATFORMS
|
85
|
-
ruby
|
86
|
-
|
87
|
-
DEPENDENCIES
|
88
|
-
RedCloth
|
89
|
-
jeweler
|
90
|
-
pg
|
91
|
-
rails (>= 3.0.2)
|
92
|
-
rspec
|
93
|
-
yard
|
data/Rakefile
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'bundler'
|
3
|
-
begin
|
4
|
-
Bundler.setup(:default, :development)
|
5
|
-
rescue Bundler::BundlerError => e
|
6
|
-
$stderr.puts e.message
|
7
|
-
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
-
exit e.status_code
|
9
|
-
end
|
10
|
-
require 'rake'
|
11
|
-
|
12
|
-
require 'jeweler'
|
13
|
-
Jeweler::Tasks.new do |gem|
|
14
|
-
gem.name = "hierarchy"
|
15
|
-
gem.summary = %Q{Use PostgreSQL LTREE type with ActiveRecord}
|
16
|
-
gem.description = %Q{Adds ActiveRecord support for hierarchial data structures using PostgreSQL's LTREE column type.}
|
17
|
-
gem.email = "git@timothymorgan.info"
|
18
|
-
gem.homepage = "http://github.com/riscfuture/hierarchy"
|
19
|
-
gem.authors = [ "Tim Morgan" ]
|
20
|
-
gem.required_ruby_version = '>= 1.9'
|
21
|
-
end
|
22
|
-
Jeweler::RubygemsDotOrgTasks.new
|
23
|
-
|
24
|
-
require 'rspec/core/rake_task'
|
25
|
-
RSpec::Core::RakeTask.new
|
26
|
-
|
27
|
-
require 'yard'
|
28
|
-
YARD::Rake::YardocTask.new('doc') do |doc|
|
29
|
-
doc.options << "-m" << "textile"
|
30
|
-
doc.options << "--protected"
|
31
|
-
doc.options << "--no-private"
|
32
|
-
doc.options << "-r" << "README.textile"
|
33
|
-
doc.options << "-o" << "doc"
|
34
|
-
doc.options << "--title" << "Hierarchy Documentation".inspect
|
35
|
-
|
36
|
-
doc.files = [ 'lib/**/*', 'README.textile' ]
|
37
|
-
end
|
38
|
-
|
39
|
-
task(default: :spec)
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.0.5
|
data/spec/hierarchy_spec.rb
DELETED
@@ -1,116 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Hierarchy do
|
4
|
-
before :each do
|
5
|
-
@objects = Hash.new
|
6
|
-
2.times { |i| @objects[:"grandparent_#{i + 1}"] = Model.create! }
|
7
|
-
2.times do |gp_num|
|
8
|
-
2.times { |i| @objects[:"parent_#{gp_num + 1}_#{i + 1}"] = Model.create!(parent: @objects[:"grandparent_#{gp_num + 1}"]) }
|
9
|
-
end
|
10
|
-
2.times do |gp_num|
|
11
|
-
2.times do |p_num|
|
12
|
-
2.times { |i| @objects[:"child_#{gp_num + 1}_#{p_num + 1}_#{i + 1}"] = Model.create!(parent: @objects[:"parent_#{gp_num + 1}_#{p_num + 1}"]) }
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe ".parent_of" do
|
18
|
-
it "should return the parent object" do
|
19
|
-
Model.parent_of(@objects[:parent_1_1]).should == [ @objects[:grandparent_1] ]
|
20
|
-
Model.parent_of(@objects[:parent_2_2]).should == [ @objects[:grandparent_2] ]
|
21
|
-
end
|
22
|
-
|
23
|
-
it "should return an empty relation for top-level objects" do
|
24
|
-
Model.parent_of(@objects[:grandparent_1]).should be_empty
|
25
|
-
Model.parent_of(@objects[:grandparent_2]).should be_empty
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe ".children_of" do
|
30
|
-
it "should return the direct children of an object" do
|
31
|
-
Model.children_of(@objects[:grandparent_1]).should == [ :parent_1_1, :parent_1_2 ].map { |name| @objects[name] }
|
32
|
-
Model.children_of(@objects[:parent_2_1]).should == [ :child_2_1_1, :child_2_1_2 ].map { |name| @objects[name] }
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should return an empty relation for leaf objects" do
|
36
|
-
Model.children_of(@objects[:child_1_1_1]).should be_empty
|
37
|
-
Model.children_of(@objects[:child_2_2_2]).should be_empty
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe ".ancestors_of" do
|
42
|
-
it "should return all ancestors of an object" do
|
43
|
-
Model.ancestors_of(@objects[:child_1_2_1]).should == [ :grandparent_1, :parent_1_2 ].map { |name| @objects[name] }
|
44
|
-
Model.ancestors_of(@objects[:parent_2_1]).should == [ @objects[:grandparent_2] ]
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should return an empty relation for top-level objects" do
|
48
|
-
Model.ancestors_of(@objects[:grandparent_1]).should be_empty
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
describe ".descendants_of" do
|
53
|
-
it "should return all descendants of an object" do
|
54
|
-
Model.descendants_of(@objects[:grandparent_2]).should == [ :parent_2_1, :parent_2_2, :child_2_1_1, :child_2_1_2, :child_2_2_1, :child_2_2_2 ].map { |name| @objects[name] }
|
55
|
-
Model.descendants_of(@objects[:parent_2_1]).should == [ :child_2_1_1, :child_2_1_2 ].map { |name| @objects[name] }
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should return an empty relation for leaf objects" do
|
59
|
-
Model.children_of(@objects[:child_1_1_1]).should be_empty
|
60
|
-
Model.children_of(@objects[:child_2_2_2]).should be_empty
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe ".siblings_of" do
|
65
|
-
it "should return all sibling objects" do
|
66
|
-
Model.siblings_of(@objects[:parent_1_1]).should == [ :parent_1_1, :parent_1_2 ].map { |name| @objects[name] }
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
describe "#parent=" do
|
71
|
-
it "should raise an error if parent is unsaved" do
|
72
|
-
expect { Model.create!.parent = Model.new }.to raise_error(ArgumentError)
|
73
|
-
end
|
74
|
-
|
75
|
-
it "should set the path ltree appropriately" do
|
76
|
-
ggp = Model.create!
|
77
|
-
gp = Model.create!(path: ggp.id.to_s)
|
78
|
-
pa = Model.create!(path: "#{ggp.id}.#{gp.id}")
|
79
|
-
path = [ ggp.id, gp.id, pa.id ].join('.')
|
80
|
-
|
81
|
-
object = Model.new
|
82
|
-
parent = Model.create!(path: path)
|
83
|
-
object.parent = parent
|
84
|
-
object.save!
|
85
|
-
object.path.should eql("#{path}.#{parent.id}")
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
describe "#top_level?" do
|
90
|
-
it "should return true for a top-level object" do
|
91
|
-
Model.create!.should be_top_level
|
92
|
-
end
|
93
|
-
|
94
|
-
it "should return false for an object with a parent" do
|
95
|
-
parent = Model.create!
|
96
|
-
Model.create!(parent: parent).should_not be_top_level
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
describe "#bottom_level?" do
|
101
|
-
it "should return true for an object with no children" do
|
102
|
-
Model.create!.should be_bottom_level
|
103
|
-
end
|
104
|
-
it "should return false for an object with children" do
|
105
|
-
parent = Model.create!
|
106
|
-
Model.create!(parent: parent)
|
107
|
-
parent.should_not be_bottom_level
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
describe "#ancestors" do
|
112
|
-
it "should return an empty array for a top-level object" do
|
113
|
-
Model.create!.ancestors.should eql([])
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
data/spec/index_path_spec.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe Hierarchy::IndexPath do
|
4
|
-
describe ".<=>" do
|
5
|
-
def compare(ip1, ip2)
|
6
|
-
Hierarchy::IndexPath.new(*ip1) <=> Hierarchy::IndexPath.new(*ip2)
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should return -1 if this index path comes before the given index path" do
|
10
|
-
# all except last digit equal
|
11
|
-
compare([ 1,2,3 ], [ 1,2,4 ]).should eql(-1)
|
12
|
-
# unequal in higher precedence
|
13
|
-
compare([ 1,2,3 ], [ 1,3,2 ]).should eql(-1)
|
14
|
-
# other is longer
|
15
|
-
compare([ 1,2,3 ], [ 1,2,3,4 ]).should eql(-1)
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should return 1 if this index path comes after the given index path" do
|
19
|
-
# all except last digit equal
|
20
|
-
compare([ 1,2,4 ], [ 1,2,3 ]).should eql(1)
|
21
|
-
# unequal in higher precedence
|
22
|
-
compare([ 1,3,2 ], [ 1,2,3 ]).should eql(1)
|
23
|
-
# this is longer
|
24
|
-
compare([ 1,2,3,4 ], [ 1,2,3, ]).should eql(1)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should return 0 if the index paths are equal" do
|
28
|
-
compare([ 1,2,3 ], [ 1,2,3 ]).should eql(0)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
Bundler.require :default, :test
|
2
|
-
require 'active_support'
|
3
|
-
require 'active_record'
|
4
|
-
|
5
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
-
|
8
|
-
require 'hierarchy'
|
9
|
-
|
10
|
-
ActiveRecord::Base.establish_connection(
|
11
|
-
adapter: 'postgresql',
|
12
|
-
database: 'hierarchy_test',
|
13
|
-
username: 'hierarchy_tester'
|
14
|
-
)
|
15
|
-
system "psql -f `pg_config --sharedir`/contrib/ltree.sql hierarchy_test &>/dev/null"
|
16
|
-
|
17
|
-
class Model < ActiveRecord::Base
|
18
|
-
include Hierarchy
|
19
|
-
end
|
20
|
-
|
21
|
-
RSpec.configure do |config|
|
22
|
-
config.before(:each) do
|
23
|
-
Model.connection.execute "DROP TABLE IF EXISTS models"
|
24
|
-
Model.connection.execute "CREATE TABLE models (id SERIAL PRIMARY KEY, path LTREE NOT NULL DEFAULT '')"
|
25
|
-
end
|
26
|
-
end
|