mongoid_listable 0.0.8 → 0.1.0

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.
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