dm-is-list 0.9.11 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +46 -0
- data/Manifest.txt +2 -2
- data/README.rdoc +220 -0
- data/Rakefile +2 -3
- data/lib/dm-is-list/is/list.rb +493 -78
- data/lib/dm-is-list/is/version.rb +1 -1
- data/lib/dm-is-list.rb +1 -9
- data/spec/integration/list_spec.rb +981 -140
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +11 -8
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +14 -31
- data/History.txt +0 -17
- data/README.txt +0 -57
data/History.rdoc
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
=== 0.10.0 / 2009-10-15
|
2
|
+
|
3
|
+
* Major changes:
|
4
|
+
|
5
|
+
* Rewrote the README for better clarity and usage information.
|
6
|
+
|
7
|
+
* Made :move accept more vectors (:top, :bottom)
|
8
|
+
|
9
|
+
* Aliased #left_sibling & :right_sibling methods to more obvious => :higher_item, :lower_item, :previous_item, :next_item
|
10
|
+
|
11
|
+
* Improved the Specs and made them more comprehensive. ( Too comprehensive? )
|
12
|
+
|
13
|
+
* Improved the documentation for each of the methods.
|
14
|
+
|
15
|
+
* Issue fixes:
|
16
|
+
|
17
|
+
* [:735] Fixed. Incorporated patch from Brian Terlson. NB! see point below.
|
18
|
+
|
19
|
+
* [:737] Fixed. Incorporated specs from Brian Terlson [ http://github.com/bterlson/dm-more/commit/6eb521636e945f396723a53fa5a8cba1c9ef1350 ]
|
20
|
+
|
21
|
+
* [:738] Semi-fixed. Fixes item.move(-1) cases, but NOT item.position = -1 cases, due to a wish to reduce the number of SQL queries.
|
22
|
+
|
23
|
+
* [:739] Fixed. Fixes item.move(:to => 2) should retain correct list order.
|
24
|
+
|
25
|
+
* [:740] Fixed. Fixes item.reorder_list(\[:title.asc\]) with correct list positions and order.
|
26
|
+
|
27
|
+
* [:818] Addressed / Fixed. Same issue as [:738]. Use item.move(1) instead of item.position = 1.
|
28
|
+
|
29
|
+
|
30
|
+
=== 0.9.11 / 2009-03-29
|
31
|
+
|
32
|
+
* No changes this version
|
33
|
+
|
34
|
+
=== 0.9.10 / 2009-01-19
|
35
|
+
|
36
|
+
* No changes this version
|
37
|
+
|
38
|
+
=== 0.9.9 / 2009-01-04
|
39
|
+
|
40
|
+
* No changes this version
|
41
|
+
|
42
|
+
=== 0.9.8 / 2008-12-07
|
43
|
+
|
44
|
+
* 1 bug fix:
|
45
|
+
|
46
|
+
* Applied patch to fix bug with manual positioning [#672 state:resolved]
|
data/Manifest.txt
CHANGED
data/README.rdoc
ADDED
@@ -0,0 +1,220 @@
|
|
1
|
+
= dm-is-list
|
2
|
+
|
3
|
+
DataMapper plugin for creating and organizing lists.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
=== Stable
|
8
|
+
|
9
|
+
Install the +dm-more+ gem, which will by default install +dm-is-list+ and other required gems.
|
10
|
+
|
11
|
+
$ (sudo)? gem install dm-more
|
12
|
+
|
13
|
+
=== Edge
|
14
|
+
|
15
|
+
Download or clone +dm-more+ from Github[http://github.com/datamapper/dm-more/].
|
16
|
+
|
17
|
+
$ cd /path/to/dm-more
|
18
|
+
|
19
|
+
$ rake install # will install all the dm-more gems (some of which are required by dm-is-list)
|
20
|
+
|
21
|
+
# enter your password at the prompt, if required
|
22
|
+
$ password ...
|
23
|
+
|
24
|
+
|
25
|
+
== Getting started
|
26
|
+
|
27
|
+
First of all, for a better understanding of this gem, make sure you study the '<tt>dm-is-list/spec/integration/list_spec.rb</tt>' file.
|
28
|
+
|
29
|
+
----
|
30
|
+
|
31
|
+
Require +dm-is-list+ in your app.
|
32
|
+
|
33
|
+
require 'dm-core' # must be required first
|
34
|
+
require 'dm-is-list'
|
35
|
+
|
36
|
+
|
37
|
+
Lets say we have a User class, and we want to give users the possibility of
|
38
|
+
having their own todo-lists.
|
39
|
+
|
40
|
+
|
41
|
+
class User
|
42
|
+
include DataMapper::Resource
|
43
|
+
|
44
|
+
property :id, Serial
|
45
|
+
property :name, String
|
46
|
+
|
47
|
+
has n, :todos
|
48
|
+
end
|
49
|
+
|
50
|
+
class Todo
|
51
|
+
include DataMapper::Resource
|
52
|
+
|
53
|
+
property :id, Serial
|
54
|
+
property :title, String
|
55
|
+
property :done, DateTime
|
56
|
+
|
57
|
+
belongs_to :user
|
58
|
+
|
59
|
+
# here we define that this should be a list, scoped on :user_id
|
60
|
+
is :list, :scope => [:user_id]
|
61
|
+
end
|
62
|
+
|
63
|
+
Once we have our Users and Lists, we might want to work with...
|
64
|
+
|
65
|
+
== Movements of list items
|
66
|
+
|
67
|
+
Any list item can be moved around <b>within the same list</b> easily through the <tt>\#move</tt> method.
|
68
|
+
|
69
|
+
|
70
|
+
=== :move( vector )
|
71
|
+
|
72
|
+
There are number of convenient vectors that help you move items around within the list.
|
73
|
+
|
74
|
+
item = Todo.get(1)
|
75
|
+
other = Todo.get(2)
|
76
|
+
|
77
|
+
item.move(:highest) # moves to top of list.
|
78
|
+
item.move(:lowest) # moves to bottom of list.
|
79
|
+
item.move(:top) # moves to top of list.
|
80
|
+
item.move(:bottom) # moves to bottom of list.
|
81
|
+
item.move(:up) # moves one up (:higher and :up is the same) within the scope.
|
82
|
+
item.move(:down) # moves one up (:lower and :down is the same) within the scope.
|
83
|
+
item.move(:to => position) # moves item to a specific position.
|
84
|
+
item.move(:above => other) # moves item above the other item.*
|
85
|
+
item.move(:below => other) # moves item above the other item.*
|
86
|
+
|
87
|
+
# * won't move if the other item is in another scope. (should this be enabled?)
|
88
|
+
|
89
|
+
The list will act as intelligently as possible and keep positions in a logical running order.
|
90
|
+
|
91
|
+
|
92
|
+
=== :move( Integer )
|
93
|
+
|
94
|
+
<b>NOTE! VERY IMPORTANT!</b>
|
95
|
+
|
96
|
+
If you set the position manually, and then save, <b>the list will NOT reorganize itself</b>.
|
97
|
+
|
98
|
+
item.position = 3 # setting position manually
|
99
|
+
item.save # the item will now have position 3, but the list may have two items with the same position.
|
100
|
+
|
101
|
+
# alternatively
|
102
|
+
item.update(:position => 3) # sets the position manually, but does not reorganize the list positions.
|
103
|
+
|
104
|
+
|
105
|
+
You should therefore <b>always use</b> the <tt>item.move(N)</tt> syntax instead.
|
106
|
+
|
107
|
+
item.move(3) # does the same as above, but in one call AND *reorganizes* the list.
|
108
|
+
|
109
|
+
<hr>
|
110
|
+
|
111
|
+
<b>Hold On!</b>
|
112
|
+
|
113
|
+
<tt>dm-is-list</tt> used to work with <tt>item.position = 1</tt> type syntax. Why this change?
|
114
|
+
|
115
|
+
The main reason behind this change was that the previous version of <tt>dm-is-list</tt> created a LOT of
|
116
|
+
extra SQL queries in order to support the manual updating of position, and as a result had a quite a few bugs/issues,
|
117
|
+
which have been fixed in this version.
|
118
|
+
|
119
|
+
The other reason is that I couldn't work out how to keep the functionality without adding the extra queries. But perhaps you can ?
|
120
|
+
|
121
|
+
<hr>
|
122
|
+
|
123
|
+
See "<b>Batch Changing Positions</b>" below for information on how to change the positions on a whole list.
|
124
|
+
|
125
|
+
== Movements between scopes
|
126
|
+
|
127
|
+
When you move items between scopes, the list will try to work with your intentions.
|
128
|
+
|
129
|
+
|
130
|
+
Move the item from list to new list and add the item to the bottom of that list.
|
131
|
+
|
132
|
+
item.user_id # => 1
|
133
|
+
item.move_to_list(10) # => the scope id ie User.get(10).id
|
134
|
+
|
135
|
+
# results in...
|
136
|
+
item.user_id # => 10
|
137
|
+
item.position # => < bottom of the list >
|
138
|
+
|
139
|
+
|
140
|
+
Move the item from list to new list and add at the position given.
|
141
|
+
|
142
|
+
item.user_id # => 1
|
143
|
+
item.move_to_list(10, 2) # => the scope id ie User.get(10).id, position => 2
|
144
|
+
|
145
|
+
# results in...
|
146
|
+
item.user_id # => 10
|
147
|
+
item.position # => 2
|
148
|
+
|
149
|
+
|
150
|
+
== Batch Changing Positions
|
151
|
+
|
152
|
+
A common scenario when working with lists is the sorting of a whole list via something like JQuery's sortable() functionality.
|
153
|
+
<br>
|
154
|
+
(Think re-arranging the order of Todo's according to priority or something similar)
|
155
|
+
|
156
|
+
|
157
|
+
=== Optimum scenario
|
158
|
+
|
159
|
+
The most SQL query efficient way of changing the positions is:
|
160
|
+
|
161
|
+
|
162
|
+
sort_order = [5,4,3,2,1] # list from AJAX request..
|
163
|
+
|
164
|
+
items = Todo.all(:user => @u1) # loads all 5 items in the list
|
165
|
+
|
166
|
+
items.each{ |item| item.update(:position => sort_order.index(item.id) + 1) } # remember the +1 since array's are indexed from 0
|
167
|
+
|
168
|
+
|
169
|
+
The above code will result in something like these queries.
|
170
|
+
|
171
|
+
# SELECT "id", "title", "position", "user_id" FROM "todos" WHERE "user_id" = 1 ORDER BY "position"
|
172
|
+
# UPDATE "todos" SET "position" = 5 WHERE "id" = 1
|
173
|
+
# UPDATE "todos" SET "position" = 4 WHERE "id" = 2
|
174
|
+
# UPDATE "todos" SET "position" = 2 WHERE "id" = 4
|
175
|
+
# UPDATE "todos" SET "position" = 1 WHERE "id" = 5
|
176
|
+
|
177
|
+
<b>Remember!</b> Your sort order list has to be the same length as the found items in the list, or your loop will fail.
|
178
|
+
|
179
|
+
|
180
|
+
=== Wasteful scenario
|
181
|
+
|
182
|
+
You can also use this version, but it will create upto <b>5 times as many SQL queries</b>. :(
|
183
|
+
|
184
|
+
|
185
|
+
sort_order = ['5','4','3','2','1'] # list from AJAX request..
|
186
|
+
|
187
|
+
items = Todo.all(:user => @u1) # loads all 5 items in the list
|
188
|
+
|
189
|
+
items.each{ |item| item.move(sort_order.index(item.id).to_i + 1) } # remember the +1 since array's are indexed from 0
|
190
|
+
|
191
|
+
The above code will result in something like these queries:
|
192
|
+
|
193
|
+
# SELECT "id", "title", "position", "user_id" FROM "todos" WHERE "user_id" = 1 ORDER BY "position"
|
194
|
+
|
195
|
+
# SELECT "id", "title", "position", "user_id" FROM "todos" WHERE "user_id" = 1 ORDER BY "position" DESC LIMIT 1
|
196
|
+
# SELECT "id" FROM "todos" WHERE "user_id" = 1 AND "id" IN (1, 2, 3, 4, 5) AND "position" BETWEEN 1 AND 5 ORDER BY "position"
|
197
|
+
# UPDATE "todos" SET "position" = "position" + -1 WHERE "user_id" = 1 AND "position" BETWEEN 1 AND 5
|
198
|
+
# SELECT "id", "position" FROM "todos" WHERE "id" IN (1, 2, 3, 4, 5) ORDER BY "id"
|
199
|
+
# UPDATE "todos" SET "position" = 5 WHERE "id" = 1
|
200
|
+
|
201
|
+
# SELECT "id", "title", "position", "user_id" FROM "todos" WHERE "user_id" = 1 ORDER BY "position" DESC LIMIT 1
|
202
|
+
# SELECT "id" FROM "todos" WHERE "user_id" = 1 AND "id" IN (1, 2, 3, 4, 5) AND "position" BETWEEN 1 AND 4 ORDER BY "position"
|
203
|
+
# UPDATE "todos" SET "position" = "position" + -1 WHERE "user_id" = 1 AND "position" BETWEEN 1 AND 4
|
204
|
+
# SELECT "id", "position" FROM "todos" WHERE "id" IN (2, 3, 4, 5) ORDER BY "id"
|
205
|
+
# UPDATE "todos" SET "position" = 4 WHERE "id" = 2
|
206
|
+
|
207
|
+
# ...
|
208
|
+
|
209
|
+
As you can see it will also do the job, but will be more expensive.
|
210
|
+
|
211
|
+
|
212
|
+
== RTFM
|
213
|
+
|
214
|
+
As I said above, for a better understanding of this gem/plugin, make sure you study the '<tt>dm-is-list/spec/integration/list_spec.rb</tt>' tests.
|
215
|
+
|
216
|
+
|
217
|
+
== Errors / Bugs
|
218
|
+
|
219
|
+
If something is not behaving intuitively, it is a bug, and should be reported.
|
220
|
+
Report it here: http://datamapper.lighthouseapp.com/
|
data/Rakefile
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
require 'rubygems'
|
3
2
|
|
4
3
|
ROOT = Pathname(__FILE__).dirname.expand_path
|
5
4
|
JRUBY = RUBY_PLATFORM =~ /java/
|
@@ -14,10 +13,10 @@ GEM_NAME = 'dm-is-list'
|
|
14
13
|
GEM_VERSION = DataMapper::Is::List::VERSION
|
15
14
|
GEM_DEPENDENCIES = [['dm-core', GEM_VERSION], ['dm-adjust', GEM_VERSION]]
|
16
15
|
GEM_CLEAN = %w[ log pkg coverage ]
|
17
|
-
GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.
|
16
|
+
GEM_EXTRAS = { :has_rdoc => true, :extra_rdoc_files => %w[ README.rdoc LICENSE TODO History.rdoc ] }
|
18
17
|
|
19
18
|
PROJECT_NAME = 'datamapper'
|
20
|
-
PROJECT_URL = "http://github.com/
|
19
|
+
PROJECT_URL = "http://github.com/datamapper/dm-more/tree/master/#{GEM_NAME}"
|
21
20
|
PROJECT_DESCRIPTION = PROJECT_SUMMARY = 'DataMapper plugin for creating and organizing lists'
|
22
21
|
|
23
22
|
[ ROOT, ROOT.parent ].each do |dir|
|