mongoid-ancestry 0.3.1 → 0.4.0

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: a3b4a81fd8d6fc037f515cc4c08ea4fd4cf8ec12
4
+ data.tar.gz: cce7627b8e3f643465488670beb4eb7f34369ff5
5
+ SHA512:
6
+ metadata.gz: 048b43039e92f3bcf4781463edb2cf96518d5f1c9489a40c17c7bdf0c2c4861c72738fef4bd91811601b1fe2dba1f5791eae3606f188ec27b0eeff6360c3adcd
7
+ data.tar.gz: 596b28a5d4af2e07c3899bd6ccac9fefb9d3a39b91bd9071cb7be8c1a807e0eae78a95eda47823116af2185a00734794625ed238bccc7b88c12648c33c01d654
data/.gitignore CHANGED
@@ -40,3 +40,5 @@ pkg
40
40
  #
41
41
  # For vim:
42
42
  #*.swp
43
+ .ruby-version
44
+ Gemfile.lock
data/.travis.yml CHANGED
@@ -1,5 +1,9 @@
1
1
  script: "bundle exec rspec spec"
2
2
  rvm:
3
3
  - 1.9.3
4
+ - ruby-head
5
+ env:
6
+ - MONGOID_VERSION=3
7
+ - MONGOID_VERSION=4
4
8
  services:
5
9
  - mongodb
data/Gemfile CHANGED
@@ -1,10 +1,12 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- ruby '1.9.3'
4
-
5
3
  gemspec
6
4
 
7
- group :test do
8
- gem 'rake'
9
- gem 'rspec', '~> 2.5'
5
+ case version = ENV['MONGOID_VERSION'] || "~> 3.1"
6
+ when /4/
7
+ gem "mongoid", :github => 'mongoid/mongoid'
8
+ when /3/
9
+ gem "mongoid", "~> 3.1"
10
+ else
11
+ gem "mongoid", version
10
12
  end
data/README.md CHANGED
@@ -7,7 +7,7 @@ Mongoid-ancestry is a gem/plugin that allows the records of a Ruby on Rails Mong
7
7
 
8
8
  ## Installation
9
9
 
10
- ### It's Rails 3 only.
10
+ ### It's Rails 3+ only.
11
11
 
12
12
  To apply Mongoid-ancestry to any Mongoid model, follow these simple steps:
13
13
 
@@ -25,7 +25,7 @@ Your model is now a tree!
25
25
 
26
26
  ## Mongoid compatibility
27
27
 
28
- This gem only supports Mongoid 3.x starting with version 0.3.0.
28
+ This gem only supports Mongoid 3.x starting with version 0.3.0. And Mongoid 4.x starting with version 0.4.0
29
29
 
30
30
  If you want to use Mongoid version 2.x, you should either use this gem in a 0.2.x version or checkout the "mongoid-2.4-stable" branch. You can ask bundler to stick with 0.2.x versions of this gem by adding this to your Gemfile: `gem 'mongoid-ancestry', '~> 0.2.2'`
31
31
 
@@ -1,15 +1,19 @@
1
1
  module Mongoid
2
2
  module Ancestry
3
+ unless Mongoid.mongoid3?
4
+ include Mongoid::Attributes::Dynamic
5
+ end
3
6
  module ClassMethods
4
7
  def has_ancestry(opts = {})
5
8
  defaults = {
6
9
  :ancestry_field => :ancestry,
7
10
  :cache_depth => false,
8
11
  :depth_cache_field => :ancestry_depth,
9
- :orphan_strategy => :destroy
12
+ :orphan_strategy => :destroy,
13
+ :touchable => false
10
14
  }
11
15
 
12
- valid_opts = [:ancestry_field, :cache_depth, :depth_cache_field, :orphan_strategy]
16
+ valid_opts = [:ancestry_field, :cache_depth, :depth_cache_field, :orphan_strategy, :touchable]
13
17
  unless opts.is_a?(Hash) && opts.keys.all? {|opt| valid_opts.include?(opt) }
14
18
  raise Error.new("Invalid options for has_ancestry. Only hash is allowed.\n Defaults: #{defaults.inspect}")
15
19
  end
@@ -29,6 +33,10 @@ module Mongoid
29
33
  cattr_reader :orphan_strategy
30
34
  self.orphan_strategy = opts[:orphan_strategy]
31
35
 
36
+ # Create touch accessor and set to option or default
37
+ cattr_accessor :touchable
38
+ self.touchable = opts[:touchable]
39
+
32
40
  # Validate format of ancestry column value
33
41
  primary_key_format = opts[:primary_key_format] || /[a-z0-9]+/
34
42
  validates_format_of ancestry_field, :with => /\A#{primary_key_format.source}(\/#{primary_key_format.source})*\Z/, :allow_nil => true
@@ -51,24 +59,28 @@ module Mongoid
51
59
 
52
60
  # Create named scopes for depth
53
61
  {:before_depth => 'lt', :to_depth => 'lte', :at_depth => nil, :from_depth => 'gte', :after_depth => 'gt'}.each do |scope_name, operator|
54
- scope scope_name, lambda { |depth|
62
+ scope scope_name, ->(depth) {
55
63
  raise Error.new("Named scope '#{scope_name}' is only available when depth caching is enabled.") unless opts[:cache_depth]
56
64
  where( (operator ? depth_cache_field.send(operator.to_sym) : depth_cache_field) => depth)
57
65
  }
58
66
  end
59
67
 
60
- scope :roots, where(ancestry_field => nil)
61
- scope :ancestors_of, lambda { |object| where(to_node(object).ancestor_conditions) }
62
- scope :children_of, lambda { |object| where(to_node(object).child_conditions) }
63
- scope :descendants_of, lambda { |object| any_of(to_node(object).descendant_conditions) }
64
- scope :subtree_of, lambda { |object| any_of(to_node(object).subtree_conditions) }
65
- scope :siblings_of, lambda { |object| where(to_node(object).sibling_conditions) }
66
- scope :ordered_by_ancestry, asc(:"#{self.base_class.ancestry_field}")
67
- scope :ordered_by_ancestry_and, lambda {|by| ordered_by_ancestry.order_by([by]) }
68
+ scope :roots, -> { where(ancestry_field => nil) }
69
+ scope :ancestors_of, ->(object) { where(to_node(object).ancestor_conditions) }
70
+ scope :children_of, ->(object) { where(to_node(object).child_conditions) }
71
+ scope :descendants_of, ->(object) { any_of(to_node(object).descendant_conditions) }
72
+ scope :subtree_of, ->(object) { any_of(to_node(object).subtree_conditions) }
73
+ scope :siblings_of, ->(object) { where(to_node(object).sibling_conditions) }
74
+ scope :ordered_by_ancestry, -> { asc(:"#{self.base_class.ancestry_field}") }
75
+ scope :ordered_by_ancestry_and, ->(by) { ordered_by_ancestry.order_by([by]) }
68
76
 
69
77
  # Update descendants with new ancestry before save
70
78
  before_save :update_descendants_with_new_ancestry
71
79
 
80
+ before_save :touch_parent, if: ->(obj) {
81
+ obj.touchable && obj.send(:"#{self.class.ancestry_field}_changed?")
82
+ }
83
+
72
84
  # Apply orphan strategy before destroy
73
85
  before_destroy :apply_orphan_strategy
74
86
  end
@@ -32,6 +32,10 @@ module Mongoid
32
32
  end
33
33
  end
34
34
 
35
+ def touch_parent
36
+ parent.touch
37
+ end
38
+
35
39
  # Apply orphan strategy
36
40
  def apply_orphan_strategy
37
41
  # Skip this if callbacks are disabled
@@ -117,7 +121,8 @@ module Mongoid
117
121
  end
118
122
 
119
123
  def parent_id
120
- ancestor_ids.empty? ? nil : ancestor_ids.last
124
+ parent_id = read_attribute(self.base_class.ancestry_field).to_s.split('/').last
125
+ return cast_primary_key(parent_id) if parent_id
121
126
  end
122
127
 
123
128
  def parent
@@ -228,13 +233,29 @@ module Mongoid
228
233
  def cast_primary_key(key)
229
234
  if primary_key_type == Integer
230
235
  key.to_i
231
- elsif primary_key_type == Moped::BSON::ObjectId && key =~ /[a-z0-9]{24}/
232
- Moped::BSON::ObjectId.from_string(key)
236
+ elsif is_primary_key_type_bson_objectid? && key =~ /[a-z0-9]{24}/
237
+ bson_objectid_from_string(key)
233
238
  else
234
239
  key
235
240
  end
236
241
  end
237
242
 
243
+ def is_primary_key_type_bson_objectid?
244
+ if Mongoid.mongoid3?
245
+ primary_key_type == Moped::BSON::ObjectId
246
+ else
247
+ primary_key_type == BSON::ObjectId
248
+ end
249
+ end
250
+
251
+ def bson_objectid_from_string(key)
252
+ if Mongoid.mongoid3?
253
+ Moped::BSON::ObjectId.from_string(key)
254
+ else
255
+ BSON::ObjectId.from_string(key)
256
+ end
257
+ end
258
+
238
259
  def primary_key_type
239
260
  @primary_key_type ||= self.base_class.fields['_id'].options[:type]
240
261
  end
@@ -1,5 +1,14 @@
1
1
  module Mongoid
2
+
3
+ def self.mongoid3?
4
+ ::Mongoid.const_defined? :Observer # deprecated in Mongoid 4.x
5
+ end
6
+
7
+ def self.mongoid2?
8
+ ::Mongoid.const_defined? :Contexts # deprecated in Mongoid 3.x
9
+ end
10
+
2
11
  module Ancestry
3
- VERSION = '0.3.1'
12
+ VERSION = '0.4.0'
4
13
  end
5
14
  end
@@ -23,6 +23,8 @@ Gem::Specification.new do |s|
23
23
  "README.md"
24
24
  ]
25
25
 
26
- s.add_dependency('mongoid', "~> 3.0")
26
+ s.add_development_dependency "rake"
27
+ s.add_development_dependency "rspec"
28
+ s.add_runtime_dependency "mongoid"
27
29
  end
28
30
 
@@ -34,6 +34,18 @@ describe MongoidAncestry do
34
34
  end
35
35
  end
36
36
 
37
+ it "should have default touchable value" do
38
+ subject.with_model do |model|
39
+ model.touchable.should be_false
40
+ end
41
+ end
42
+
43
+ it "should set touchable value" do
44
+ subject.with_model touchable: true do |model|
45
+ model.touchable.should be_true
46
+ end
47
+ end
48
+
37
49
  it "should have non default orphan strategy" do
38
50
  subject.with_model :orphan_strategy => :rootify do |model|
39
51
  model.orphan_strategy.should eql(:rootify)
@@ -100,14 +100,14 @@ describe MongoidAncestry do
100
100
  subject.with_model :depth => 3, :width => 3 do |model, roots|
101
101
  model.orphan_strategy = :restrict
102
102
  root = roots.first.first
103
- expect { root.destroy }.to raise_error Mongoid::Ancestry::Error
104
- expect { root.children.first.children.first.destroy }.to_not raise_error Mongoid::Ancestry::Error
103
+ expect { root.destroy }.to raise_error
104
+ expect { root.children.first.children.first.destroy }.to_not raise_error
105
105
  end
106
106
  end
107
107
 
108
108
  it "should check that there are no errors on a valid tree" do
109
109
  subject.with_model :width => 3, :depth => 3 do |model, roots|
110
- expect { model.check_ancestry_integrity! }.to_not raise_error(Mongoid::Ancestry::Error)
110
+ expect { model.check_ancestry_integrity! }.to_not raise_error
111
111
  model.check_ancestry_integrity!(:report => :list).size.should eql(0)
112
112
  end
113
113
  end
@@ -115,7 +115,7 @@ describe MongoidAncestry do
115
115
  it "should check detection of invalid format for ancestry field" do
116
116
  subject.with_model :width => 3, :depth => 3 do |model, roots|
117
117
  roots.first.first.update_attribute model.ancestry_field, 'invalid_ancestry'
118
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
118
+ expect { model.check_ancestry_integrity! }.to raise_error
119
119
  model.check_ancestry_integrity!(:report => :list).size.should eql(1)
120
120
  end
121
121
  end
@@ -126,7 +126,7 @@ describe MongoidAncestry do
126
126
  node.without_ancestry_callbacks do
127
127
  node.update_attribute model.ancestry_field, 35
128
128
  end
129
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
129
+ expect { model.check_ancestry_integrity! }.to raise_error
130
130
  model.check_ancestry_integrity!(:report => :list).size.should eql(1)
131
131
  end
132
132
  end
@@ -135,7 +135,7 @@ describe MongoidAncestry do
135
135
  subject.with_model :width => 3, :depth => 3 do |model, roots|
136
136
  node = roots.first.first
137
137
  node.update_attribute model.ancestry_field, node.id
138
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
138
+ expect { model.check_ancestry_integrity! }.to raise_error
139
139
  model.check_ancestry_integrity!(:report => :list).size.should eql(1)
140
140
  end
141
141
  end
@@ -144,15 +144,15 @@ describe MongoidAncestry do
144
144
  subject.with_model do |model|
145
145
  model.destroy_all
146
146
  model.create!(model.ancestry_field => model.create!(model.ancestry_field => model.create!(model.ancestry_field => nil).id).id)
147
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
147
+ expect { model.check_ancestry_integrity! }.to raise_error
148
148
  model.check_ancestry_integrity!(:report => :list).size.should eql(1)
149
149
  end
150
150
  end
151
151
 
152
152
  def assert_integrity_restoration model
153
- expect { model.check_ancestry_integrity! }.to raise_error(Mongoid::Ancestry::IntegrityError)
153
+ expect { model.check_ancestry_integrity! }.to raise_error
154
154
  model.restore_ancestry_integrity!
155
- expect { model.check_ancestry_integrity! }.to_not raise_error(Mongoid::Ancestry::IntegrityError)
155
+ expect { model.check_ancestry_integrity! }.to_not raise_error
156
156
  end
157
157
 
158
158
  it "should check that integrity is restored for invalid format for ancestry field" do
@@ -232,7 +232,7 @@ describe MongoidAncestry do
232
232
  end
233
233
 
234
234
  it "should build ancestry from parent ids" do
235
- subject.with_model :skip_ancestry => true, :extra_columns => {:parent_id => 'Moped::BSON::ObjectId'} do |model|
235
+ subject.with_model :skip_ancestry => true, :extra_columns => {:parent_id => parent_id} do |model|
236
236
  [model.create!].each do |parent1|
237
237
  (Array.new(5) { model.create :parent_id => parent1.id }).each do |parent2|
238
238
  (Array.new(5) { model.create :parent_id => parent2.id }).each do |parent3|
@@ -297,4 +297,12 @@ describe MongoidAncestry do
297
297
  end
298
298
  end
299
299
 
300
+ def parent_id
301
+ if Mongoid.mongoid3?
302
+ 'Moped::BSON::ObjectId'
303
+ else
304
+ 'BSON::ObjectId'
305
+ end
306
+ end
307
+
300
308
  end
@@ -161,7 +161,7 @@ describe MongoidAncestry do
161
161
  end
162
162
  end
163
163
 
164
- it "should have depth caching" do
164
+ it "should have depth caching" do
165
165
  subject.with_model :depth => 3, :width => 3, :cache_depth => true, :depth_cache_field => :depth_cache do |model, roots|
166
166
  roots.each do |lvl0_node, lvl0_children|
167
167
  lvl0_node.depth_cache.should eql(0)
@@ -237,5 +237,18 @@ describe MongoidAncestry do
237
237
  end
238
238
  end
239
239
 
240
+ it "should not call touch on parent" do
241
+ subject.with_model do |model|
242
+ root = model.create!
243
+ expect{ root.children.create! }.to_not change{ root.reload.updated_at }
244
+ end
245
+ end
246
+
247
+ it "should call touch on parent" do
248
+ subject.with_model touchable: true do |model|
249
+ root = model.create!
250
+ expect{ root.children.create! }.to change{ root.reload.updated_at }
251
+ end
252
+ end
240
253
 
241
254
  end
data/spec/spec_helper.rb CHANGED
@@ -8,6 +8,9 @@ require 'mongoid-ancestry'
8
8
 
9
9
  Mongoid.load!(File.expand_path('../mongoid.yml', __FILE__), 'test')
10
10
  Mongoid.logger = Logger.new('log/test.log')
11
+ Moped.logger = Logger.new('log/test.log')
12
+ Mongoid.logger.level = Logger::DEBUG
13
+ Moped.logger.level = Logger::DEBUG
11
14
 
12
15
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
16
 
@@ -12,6 +12,7 @@ class MongoidAncestry
12
12
  const_set 'TestNode', model
13
13
  TestNode.send(:include, Mongoid::Document)
14
14
  TestNode.send(:include, Mongoid::Ancestry) unless skip_ancestry
15
+ TestNode.send(:include, Mongoid::Timestamps)
15
16
 
16
17
  extra_columns.each do |name, type|
17
18
  TestNode.send :field, name, :type => type.constantize
metadata CHANGED
@@ -1,8 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid-ancestry
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.3.1
4
+ version: 0.4.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Stefan Kroes
@@ -10,24 +9,50 @@ authors:
10
9
  autorequire:
11
10
  bindir: bin
12
11
  cert_chain: []
13
- date: 2013-02-18 00:00:00.000000000 Z
12
+ date: 2014-02-24 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
- type: :runtime
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
17
23
  version_requirements: !ruby/object:Gem::Requirement
18
24
  requirements:
19
- - - ~>
25
+ - - ">="
20
26
  - !ruby/object:Gem::Version
21
- version: '3.0'
22
- none: false
23
- name: mongoid
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rspec
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
24
36
  prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: mongoid
25
44
  requirement: !ruby/object:Gem::Requirement
26
45
  requirements:
27
- - - ~>
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
28
54
  - !ruby/object:Gem::Version
29
- version: '3.0'
30
- none: false
55
+ version: '0'
31
56
  description: Organise Mongoid model into a tree structure
32
57
  email:
33
58
  - eagle.anton@gmail.com
@@ -36,10 +61,9 @@ extensions: []
36
61
  extra_rdoc_files:
37
62
  - README.md
38
63
  files:
39
- - .gitignore
40
- - .travis.yml
64
+ - ".gitignore"
65
+ - ".travis.yml"
41
66
  - Gemfile
42
- - Gemfile.lock
43
67
  - Guardfile
44
68
  - MIT-LICENSE
45
69
  - README.md
@@ -62,33 +86,26 @@ files:
62
86
  homepage: http://github.com/skyeagle/mongoid-ancestry
63
87
  licenses:
64
88
  - MIT
89
+ metadata: {}
65
90
  post_install_message:
66
91
  rdoc_options: []
67
92
  require_paths:
68
93
  - lib
69
94
  required_ruby_version: !ruby/object:Gem::Requirement
70
95
  requirements:
71
- - - ! '>='
96
+ - - ">="
72
97
  - !ruby/object:Gem::Version
73
- segments:
74
- - 0
75
- hash: -3773754502524018059
76
98
  version: '0'
77
- none: false
78
99
  required_rubygems_version: !ruby/object:Gem::Requirement
79
100
  requirements:
80
- - - ! '>='
101
+ - - ">="
81
102
  - !ruby/object:Gem::Version
82
- segments:
83
- - 0
84
- hash: -3773754502524018059
85
103
  version: '0'
86
- none: false
87
104
  requirements: []
88
105
  rubyforge_project: mongoid-ancestry
89
- rubygems_version: 1.8.24
106
+ rubygems_version: 2.2.1
90
107
  signing_key:
91
- specification_version: 3
108
+ specification_version: 4
92
109
  summary: Ancestry allows the records of a Mongoid model to be organised in a tree
93
110
  structure, using a single, intuitively formatted database field. It exposes all
94
111
  the standard tree structure relations (ancestors, parent, root, children, siblings,
data/Gemfile.lock DELETED
@@ -1,44 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- mongoid-ancestry (0.3.1)
5
- mongoid (~> 3.0)
6
-
7
- GEM
8
- remote: https://rubygems.org/
9
- specs:
10
- activemodel (3.2.12)
11
- activesupport (= 3.2.12)
12
- builder (~> 3.0.0)
13
- activesupport (3.2.12)
14
- i18n (~> 0.6)
15
- multi_json (~> 1.0)
16
- builder (3.0.4)
17
- diff-lcs (1.1.3)
18
- i18n (0.6.1)
19
- mongoid (3.1.1)
20
- activemodel (~> 3.2)
21
- moped (~> 1.4.2)
22
- origin (~> 1.0)
23
- tzinfo (~> 0.3.22)
24
- moped (1.4.2)
25
- multi_json (1.6.1)
26
- origin (1.0.11)
27
- rake (10.0.3)
28
- rspec (2.12.0)
29
- rspec-core (~> 2.12.0)
30
- rspec-expectations (~> 2.12.0)
31
- rspec-mocks (~> 2.12.0)
32
- rspec-core (2.12.2)
33
- rspec-expectations (2.12.1)
34
- diff-lcs (~> 1.1.3)
35
- rspec-mocks (2.12.2)
36
- tzinfo (0.3.35)
37
-
38
- PLATFORMS
39
- ruby
40
-
41
- DEPENDENCIES
42
- mongoid-ancestry!
43
- rake
44
- rspec (~> 2.5)