mongoid_listable 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZGRjNjdkNDcwYWI2YjJhNzY1OTY1ZGQ4ODZkMWE3ZTlmYWJlMDkzYQ==
4
+ M2JkMzNmNGMyODlkMTEwMzRkZjhkNjcwOGE2ZmEyZDU5YmI3NmE2Zg==
5
5
  data.tar.gz: !binary |-
6
- NTZkOWZhNTFjYmYxMDQ4MjI3NTczZTdhMGQwYjlhYmMwN2I0Nzc1OA==
6
+ MmJjNDY1OGIyOThmNmNkMTVhN2NiNGQ3YzVkYjkwNTdhMDU2YzkzZQ==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NjZlY2E4MGVhMGI1OWFjMTQ5NGU2MTQ3NjQ0Y2U1NDJmMzhkMmVlMTkxZGUy
10
- Y2QyMDFlZGJlMWVhNjU4NmI5NWMwMTFhYmYwY2RlYWQ2MjBhM2UyNDZjOTVi
11
- ZjAxYTRmOTg2YmFmYjU3MzQwZjRmNDFiY2IzMTUwMjBhNDllMWQ=
9
+ YzBhYmRkYzMwN2FkNDlhZjNkY2Q0MzI1MzAwNmE4ZjFkZTMxMzNjN2VkNmU3
10
+ MzNkZmUxZTEzZmE3YjA2ZjVhNjgzMmIzMDIwODE2MWI2Yzk3OGMyYmJkYjkz
11
+ NWFjN2RjYTIzN2I3MmZmYTZmNWI3ZDQyOWEyZDc0YzBhNDUzZmU=
12
12
  data.tar.gz: !binary |-
13
- NDc1M2YwYzlkZDFjODhhZDQ0ODVmYWUxOGU2MTA2ZGM3M2NmYjg4ZmIyNzdl
14
- N2I5ZGE0MjNjYzJhNWEwY2FhOGQ1YmQ4M2ZlMmQ3MWMxOWNjNzIwMGMyMGIz
15
- MmM5NjljODU4ZDBiM2QzODEyMTRiNjk2Y2ZmYmY4OWQ0OTdmODM=
13
+ YzI5MGM3MTZjYjg2MWY3ZjQzNTExNGYzMWJmNzA3ZjFkNWZlZTlmMzdlYjQ4
14
+ MWVhZWVkMTQ3NGU3ZjFiODI0NTU0NDQ0MWZjNzhkNGM3MGIzMTFiYjliMTRi
15
+ M2Q4NDk5MWRlODA5MWIyOTdmOWZhZjFiZjYyODg1NDhkNWFlMTg=
@@ -35,8 +35,9 @@ module Mongoid
35
35
  # @since 0.0.6
36
36
  def _setter name, meta
37
37
  before_method "#{name}=" do |objects|
38
+ objects ||= []
38
39
  objects.each_with_index do |object, index|
39
- object.update_attribute field_name(meta), index + 1
40
+ object.set field_name(meta), index + 1
40
41
  end
41
42
 
42
43
  (send(name).to_a - objects).each do |object|
@@ -18,9 +18,11 @@ module Mongoid
18
18
  def added name, meta
19
19
  callback = "#{name.to_s.singularize}_added"
20
20
  define_method callback do |object|
21
- object.update_attribute field_name(meta), has_many_count(name)
21
+ if object[field_name(meta)].nil?
22
+ object.set field_name(meta), has_many_count(name) + 1
23
+ end
22
24
  end
23
- meta[:after_add] = callback
25
+ meta[:before_add] = callback
24
26
  self
25
27
  end
26
28
 
@@ -41,7 +43,7 @@ module Mongoid
41
43
  position = object.send field_name
42
44
  send(name).where(field_name.gt => position)
43
45
  .each_with_index do |object, index|
44
- object.update_attribute field_name, position + index
46
+ object.set field_name, position + index
45
47
  end
46
48
  object.unset field_name
47
49
  end
@@ -50,9 +52,60 @@ module Mongoid
50
52
  self
51
53
  end
52
54
 
55
+ # Defines a mongoid before_create callback.
56
+ # Sets the position field to current object count + 1
57
+ #
58
+ # @param [ Hash ] The configuration hash
59
+ #
60
+ # @return [ Object ] self
61
+ #
62
+ # @since 0.1.0
63
+ def created configuration
64
+ define_method __method__ do
65
+ set configuration[:column], self.class.count + 1
66
+ end
67
+ before_create __method__
68
+ self
69
+ end
70
+
71
+ # Defines a mongoid before_update callback.
72
+ # If the position column has changed, apply the change.
73
+ # Hoe the change is applied varies depending on the redrection
74
+ # of the update.
75
+ #
76
+ # @param [ Hash ] The configuration hash
77
+ #
78
+ # @return [ Object ] self
79
+ #
80
+ # @since 0.1.0
81
+ def updated configuration
82
+ define_method __method__ do
83
+ column = configuration[:column]
84
+ apply_change_on column if send("#{column}_changed?")
85
+ end
86
+ before_update __method__
87
+ self
88
+ end
89
+
90
+ # Defines a mongoid before_destroy callback.
91
+ # Resets all sibling object's higher in the list
92
+ #
93
+ # @param [ Hash ] The configuration hash
94
+ #
95
+ # @return [ Object ] self
96
+ #
97
+ # @since 0.1.0
98
+ def destroyed configuration
99
+ define_method __method__ do
100
+ column = configuration[:column]
101
+ reposition siblings.gt(column => position), column, position
102
+ end
103
+ before_destroy __method__
104
+ self
105
+ end
106
+
53
107
  end
54
108
 
55
- end
56
-
109
+ end
57
110
  end
58
111
  end
@@ -8,6 +8,27 @@ module Mongoid
8
8
 
9
9
  module ClassMethods
10
10
 
11
+ # Macro to set basic position field on an object
12
+ #
13
+ # @param [ Hash ] options The options hash
14
+ #
15
+ # @return self
16
+ #
17
+ # @since 0.1.0
18
+ def listed options={}
19
+ configuration = { column: :position }
20
+ configuration.merge! options if options.is_a?(Hash)
21
+
22
+ field configuration[:column], type: Integer
23
+
24
+ created(configuration)
25
+ .updated(configuration)
26
+ .destroyed(configuration)
27
+
28
+ scope :list, order_by(configuration[:column] => :asc)
29
+ self
30
+ end
31
+
11
32
  # Macro to set relation on which to make a list
12
33
  #
13
34
  # @param [ Symbol ] name The name of the has_many relation
@@ -1,5 +1,5 @@
1
1
  module Mongoid
2
2
  module Listable
3
- VERSION = '0.0.8'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
@@ -30,6 +30,7 @@ module Mongoid
30
30
 
31
31
  # Proxies to the class level version
32
32
  #
33
+ # @param [ MetaData ] meta The MetaData class
33
34
  # @see Class.field_name
34
35
  #
35
36
  # @since 0.0.6
@@ -41,10 +42,80 @@ module Mongoid
41
42
  # Needed because the mongoid callbacks dont update
42
43
  # has_many relations until after invoked.
43
44
  #
45
+ # @param [ Symbol ] name The name of the has_many relation
46
+ #
44
47
  # @since 0.0.7
45
48
  def has_many_count name
46
49
  send(name).uniq(&:id).count
47
50
  end
48
51
 
52
+ private
53
+
54
+ # Applies a position change on column. Which objects are repositioned
55
+ # depends on the direction of the change.
56
+ #
57
+ # @param [ Symbol ] name The name of position column
58
+ #
59
+ # @since 0.1.0
60
+ def apply_change_on column
61
+ from, to = change_on column
62
+ if to > from
63
+ reposition siblings.between(column => from..to), column, from
64
+ elsif to < from
65
+ reposition siblings.between(column => to..from), column, to + 1
66
+ end
67
+ set column, to
68
+ end
69
+
70
+ # Resets column on objects starting at 'start'
71
+ #
72
+ # @param [ Array ] objects The objects to interate
73
+ # @param [ Symbol ] column The column to update
74
+ # @param [ Integer ] start The starting position
75
+ #
76
+ # @since 0.1.0
77
+ def reposition objects, column, start
78
+ objects.each_with_index do |object, index|
79
+ object.set column, start + index
80
+ end
81
+ end
82
+
83
+ # Returns the old and new values for column
84
+ #
85
+ # @param [ Symbol ] column The column to retrieve the change
86
+ # @return [Array] [from, to]
87
+ #
88
+ # @since 0.1.0
89
+ def change_on column
90
+ from, to = send "#{column}_change"
91
+ to = safe_to to
92
+ [from, to]
93
+ end
94
+
95
+ # Ensures the 'to' value is within acceptable bounds
96
+ #
97
+ # @param [ Integer ] to The supplied position value
98
+ # @return [ Integer ] The acceptable position value
99
+ #
100
+ # @since 0.1.0
101
+ def safe_to to
102
+ if to > self.class.count
103
+ self.class.count
104
+ elsif to < 1
105
+ 1
106
+ else
107
+ to
108
+ end
109
+ end
110
+
111
+ # Retrieves an object's list siblings
112
+ #
113
+ # @return [ Array ]
114
+ #
115
+ # @since 0.1.0
116
+ def siblings
117
+ self.class.list.ne id: id
118
+ end
119
+
49
120
  end
50
121
  end
@@ -1 +1,4 @@
1
1
  require 'mongoid/listable'
2
+
3
+
4
+
data/spec/models/photo.rb CHANGED
@@ -7,4 +7,6 @@ class Photo
7
7
 
8
8
  belongs_to :user
9
9
 
10
+ listed
11
+
10
12
  end
@@ -3,41 +3,122 @@ require 'spec_helper'
3
3
  describe Mongoid::Listable do
4
4
 
5
5
  before :all do
6
- @user = User.create!
7
- @photos = []
8
- 10.times { @photos << Photo.create }
6
+ User.create!
7
+ 10.times { Photo.create }
9
8
  end
10
9
 
11
10
  it 'created a user' do
12
- expect(@user).to be_true
11
+ expect(User.first).to be_true
13
12
  end
14
13
 
15
14
  it 'created 10 photos' do
16
- expect(@photos.count).to eq(10)
15
+ expect(Photo.count).to eq(10)
17
16
  end
18
17
 
19
- it 'assigns all photos to a user with the default setter' do
20
- @user.photos = @photos
21
- expect(@user.photos.count).to eq(@photos.count)
18
+ it 'added the position field for a photo' do
19
+ expect(Photo.instance_methods.include?(:position)).to be_true
22
20
  end
23
21
 
24
- it 'assigns all photos to a user with the default ids setter' do
25
- ids = @photos.collect(&:id)
26
- @user.photo_ids = ids
27
- expect(@user.photos.count).to eq(@photos.count)
22
+ it 'orders photos' do
23
+ Photo.list.each_with_index do |photo, index|
24
+ expect(photo.position).to eq(index + 1)
25
+ end
26
+ end
27
+
28
+ it 'updates photo order on position change higher' do
29
+ photo_a_id = Photo.list[3].id
30
+ photo_b_id = Photo.list[7].id
31
+
32
+ expect(Photo.find(photo_a_id).position).to eq(4)
33
+ expect(Photo.find(photo_b_id).position).to eq(8)
34
+
35
+ Photo.find(photo_a_id).update_attribute :position, 9
36
+
37
+ expect(Photo.find(photo_a_id).position).to eq(9)
38
+ expect(Photo.find(photo_b_id).position).to eq(7)
39
+ end
40
+
41
+ it 'updates photo order on position change lower' do
42
+ photo_a_id = Photo.list[5].id
43
+ photo_b_id = Photo.list[9].id
44
+
45
+ expect(Photo.find(photo_a_id).position).to eq(6)
46
+ expect(Photo.find(photo_b_id).position).to eq(10)
47
+
48
+ Photo.find(photo_a_id).update_attribute :position, 2
49
+
50
+ expect(Photo.find(photo_a_id).position).to eq(2)
51
+ expect(Photo.find(photo_b_id).position).to eq(10)
52
+ end
53
+
54
+ it 'updates photo order on photo destroy' do
55
+ photo_a_id = Photo.list[5].id
56
+ photo_b_id = Photo.list[9].id
57
+
58
+ expect(Photo.find(photo_b_id).position).to eq(10)
59
+
60
+ Photo.find(photo_a_id).destroy
61
+
62
+ expect(Photo.find(photo_b_id).position).to eq(9)
63
+ end
64
+
65
+ it 'creates a new photo' do
66
+ Photo.create
67
+ expect(Photo.all.count).to eq(10)
68
+ expect(Photo.last.position).to eq(10)
69
+ end
70
+
71
+ it 'adds photos to a user with the default setter' do
72
+ User.first.photos = Photo.all
73
+ expect(User.first.photos.count).to eq(10)
74
+ end
75
+
76
+ it 'orders photos for a user' do
77
+ User.first.photos.each_with_index do |photo, index|
78
+ expect(photo.user_position).to eq(index + 1)
79
+ end
80
+ end
81
+
82
+ it 'removes photos from a user' do
83
+ User.first.photos = nil
84
+ expect(User.first.photos.count).to eq(0)
85
+ end
86
+
87
+ it 'adds 5 photos to a user with the default ids setter' do
88
+ User.first.photo_ids = Photo.all[0..4].map &:id
89
+ expect(User.first.photos.count).to eq(5)
90
+ end
91
+
92
+ it 'adds all photos to a user with the default ids setter' do
93
+ User.first.photo_ids = Photo.all.map &:id
94
+ expect(User.first.photos.count).to eq(10)
95
+ end
96
+
97
+ it 'orders photos for a user' do
98
+ User.first.photos.each_with_index do |photo, index|
99
+ expect(photo.user_position).to eq(index + 1)
100
+ end
101
+ end
102
+
103
+ it 'adds a new photo to a user' do
104
+ User.first.photos << Photo.new
105
+ expect(User.first.photos.count).to eq(11)
106
+ expect(User.first.photos.last.user_position).to eq(11)
28
107
  end
29
108
 
30
- it 'removes a photo from a user using the delete method' do
31
- @user.photos.delete @photos[0]
32
- expect(@user.photos.count).to eq(@photos.count - 1)
109
+ it 'adds a created photo to a user' do
110
+ User.first.photos << Photo.create
111
+ expect(User.first.photos.count).to eq(12)
112
+ expect(User.first.photos.last.user_position).to eq(12)
33
113
  end
34
114
 
35
- it 'removes a photo from a user using the default setter' do
36
- @user.photos = @photos[0..4]
37
- expect(@user.photos.count).to eq(@photos.count - 5)
115
+ it 'deletes a photo from a user' do
116
+ User.first.photos.delete(Photo.all[5])
117
+ expect(User.first.photos.count).to eq(11)
118
+ expect(User.first.photos.last.user_position).to eq(11)
38
119
  end
39
120
 
40
- it 'updated the position field for all the photos' do
121
+ it 'orders photos for a user' do
41
122
  User.first.photos.each_with_index do |photo, index|
42
123
  expect(photo.user_position).to eq(index + 1)
43
124
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mongoid_listable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - richardcalahan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-09 00:00:00.000000000 Z
11
+ date: 2013-11-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mongoid