liszt 0.0.7 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -6
- data/Gemfile +2 -3
- data/Rakefile +1 -32
- data/lib/liszt/redis_list.rb +9 -5
- data/lib/liszt/version.rb +1 -1
- data/lib/liszt.rb +74 -47
- data/liszt.gemspec +8 -4
- data/test/fixtures/groups.yml +14 -0
- data/test/{dummy_2.3/test/fixtures → fixtures}/people.yml +0 -0
- data/test/liszt_test.rb +174 -37
- data/test/redis_list_test.rb +36 -37
- data/test/test_helper.rb +91 -20
- metadata +86 -150
- data/Gemfile.lock +0 -104
- data/Gemfile.rails2 +0 -8
- data/Gemfile.rails2.lock +0 -45
- data/test/dummy_2.3/Rakefile +0 -10
- data/test/dummy_2.3/app/controllers/application_controller.rb +0 -10
- data/test/dummy_2.3/app/models/group.rb +0 -2
- data/test/dummy_2.3/app/models/person.rb +0 -3
- data/test/dummy_2.3/config/boot.rb +0 -114
- data/test/dummy_2.3/config/database.yml +0 -22
- data/test/dummy_2.3/config/environment.rb +0 -43
- data/test/dummy_2.3/config/environments/development.rb +0 -17
- data/test/dummy_2.3/config/environments/test.rb +0 -28
- data/test/dummy_2.3/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy_2.3/config/initializers/bundler.rb +0 -4
- data/test/dummy_2.3/config/initializers/cookie_verification_secret.rb +0 -7
- data/test/dummy_2.3/config/initializers/inflections.rb +0 -10
- data/test/dummy_2.3/config/initializers/mime_types.rb +0 -5
- data/test/dummy_2.3/config/initializers/new_rails_defaults.rb +0 -21
- data/test/dummy_2.3/config/initializers/session_store.rb +0 -15
- data/test/dummy_2.3/config/locales/en.yml +0 -5
- data/test/dummy_2.3/config/routes.rb +0 -43
- data/test/dummy_2.3/db/migrate/20110922194432_create_people.rb +0 -15
- data/test/dummy_2.3/db/migrate/20110922194512_create_groups.rb +0 -12
- data/test/dummy_2.3/db/schema.rb +0 -27
- data/test/dummy_2.3/db/seeds.rb +0 -7
- data/test/dummy_2.3/script/about +0 -4
- data/test/dummy_2.3/script/console +0 -3
- data/test/dummy_2.3/script/dbconsole +0 -3
- data/test/dummy_2.3/script/destroy +0 -3
- data/test/dummy_2.3/script/generate +0 -3
- data/test/dummy_2.3/script/performance/benchmarker +0 -3
- data/test/dummy_2.3/script/performance/profiler +0 -3
- data/test/dummy_2.3/script/plugin +0 -3
- data/test/dummy_2.3/script/runner +0 -3
- data/test/dummy_2.3/script/server +0 -3
- data/test/dummy_2.3/test/fixtures/groups.yml +0 -12
- data/test/dummy_3.1/Rakefile +0 -7
- data/test/dummy_3.1/app/controllers/application_controller.rb +0 -3
- data/test/dummy_3.1/app/models/.gitkeep +0 -0
- data/test/dummy_3.1/app/models/group.rb +0 -2
- data/test/dummy_3.1/app/models/person.rb +0 -3
- data/test/dummy_3.1/config/application.rb +0 -45
- data/test/dummy_3.1/config/boot.rb +0 -10
- data/test/dummy_3.1/config/database.yml +0 -25
- data/test/dummy_3.1/config/environment.rb +0 -5
- data/test/dummy_3.1/config/environments/development.rb +0 -27
- data/test/dummy_3.1/config/environments/test.rb +0 -39
- data/test/dummy_3.1/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy_3.1/config/initializers/inflections.rb +0 -10
- data/test/dummy_3.1/config/initializers/mime_types.rb +0 -5
- data/test/dummy_3.1/config/initializers/secret_token.rb +0 -7
- data/test/dummy_3.1/config/initializers/session_store.rb +0 -8
- data/test/dummy_3.1/config/initializers/wrap_parameters.rb +0 -12
- data/test/dummy_3.1/config/locales/en.yml +0 -5
- data/test/dummy_3.1/config/routes.rb +0 -58
- data/test/dummy_3.1/config.ru +0 -4
- data/test/dummy_3.1/db/migrate/20110922194058_create_people.rb +0 -11
- data/test/dummy_3.1/db/migrate/20110922194126_create_groups.rb +0 -8
- data/test/dummy_3.1/db/schema.rb +0 -29
- data/test/dummy_3.1/lib/assets/.gitkeep +0 -0
- data/test/dummy_3.1/log/.gitkeep +0 -0
- data/test/dummy_3.1/script/rails +0 -6
- data/test/dummy_3.1/test/fixtures/groups.yml +0 -12
- data/test/dummy_3.1/test/fixtures/people.yml +0 -59
data/.gitignore
CHANGED
@@ -2,13 +2,11 @@
|
|
2
2
|
log/*.log
|
3
3
|
pkg/
|
4
4
|
doc/
|
5
|
-
test/
|
6
|
-
test/
|
7
|
-
test/dummy_2.3/tmp/
|
8
|
-
test/dummy_3.1/db/*.sqlite3
|
9
|
-
test/dummy_3.1/log/*.log
|
10
|
-
test/dummy_3.1/tmp/
|
5
|
+
test/app/log/*.log
|
6
|
+
test/app/tmp/
|
11
7
|
.yardoc/
|
12
8
|
.rvmrc
|
13
9
|
/tags
|
14
10
|
/dump.rdb
|
11
|
+
coverage/
|
12
|
+
Gemfile.lock
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
@@ -2,12 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'bundler/gem_tasks'
|
4
4
|
|
5
|
-
desc "Install gems for Rails 2.3.14 and Rails 3.1.0"
|
6
|
-
task :install_bundle do
|
7
|
-
system "bundle install --gemfile Gemfile"
|
8
|
-
system "bundle install --gemfile Gemfile.rails2"
|
9
|
-
end
|
10
|
-
|
11
5
|
begin
|
12
6
|
require 'yard'
|
13
7
|
YARD::Rake::YardocTask.new
|
@@ -23,29 +17,4 @@ Rake::TestTask.new(:test) do |t|
|
|
23
17
|
t.verbose = false
|
24
18
|
end
|
25
19
|
|
26
|
-
|
27
|
-
Dir.chdir "test/dummy_2.3"
|
28
|
-
system "env RAILS_ENV=test BUNDLE_GEMFILE=../../Gemfile.rails2 bundle exec #{cmd}"
|
29
|
-
Dir.chdir "../dummy_3.1"
|
30
|
-
system "env RAILS_ENV=test BUNDLE_GEMFILE=../../Gemfile bundle exec #{cmd}"
|
31
|
-
Dir.chdir "../.."
|
32
|
-
end
|
33
|
-
|
34
|
-
desc "Create and migrate the test databases for Rails 2.3.14 and Rails 3.1.0"
|
35
|
-
task :set_up_test_dbs do
|
36
|
-
execute "rake db:create"
|
37
|
-
execute "rake db:migrate"
|
38
|
-
end
|
39
|
-
|
40
|
-
desc "Open console in Rails 2.3.14 app"
|
41
|
-
task :console_rails_2 do
|
42
|
-
Dir.chdir("test/dummy_2.3")
|
43
|
-
system("env RAILS_ENV=test BUNDLE_GEMFILE=../../Gemfile.rails2 bundle exec script/console")
|
44
|
-
end
|
45
|
-
|
46
|
-
desc "Run tests on Rails 2.3.14"
|
47
|
-
task :test_rails_2 do
|
48
|
-
system("env BUNDLE_GEMFILE=Gemfile.rails2 bundle exec rake test")
|
49
|
-
end
|
50
|
-
|
51
|
-
task :default => [:test, :test_rails_2]
|
20
|
+
task :default => :test
|
data/lib/liszt/redis_list.rb
CHANGED
@@ -79,9 +79,11 @@ module Liszt
|
|
79
79
|
# Push the given id onto the bottom of the list.
|
80
80
|
# @param [Fixnum] id
|
81
81
|
def push!(id)
|
82
|
-
redis.
|
83
|
-
|
84
|
-
|
82
|
+
redis.multi do
|
83
|
+
redis.rpop(@key)
|
84
|
+
redis.rpush(@key, id)
|
85
|
+
redis.rpush(@key, '*')
|
86
|
+
end
|
85
87
|
end
|
86
88
|
|
87
89
|
# Remove the given id from the list.
|
@@ -92,8 +94,10 @@ module Liszt
|
|
92
94
|
|
93
95
|
# Clear all items from the list.
|
94
96
|
def clear
|
95
|
-
redis.
|
96
|
-
|
97
|
+
redis.multi do
|
98
|
+
redis.del(@key)
|
99
|
+
redis.rpush(@key, '*')
|
100
|
+
end
|
97
101
|
end
|
98
102
|
|
99
103
|
# Return the number of ids in the list, or nil if it's uninitialized.
|
data/lib/liszt/version.rb
CHANGED
data/lib/liszt.rb
CHANGED
@@ -2,26 +2,38 @@ require "liszt/version"
|
|
2
2
|
require "liszt/instantizeable"
|
3
3
|
require "liszt/redis_list"
|
4
4
|
|
5
|
+
require "active_record"
|
6
|
+
|
5
7
|
module Liszt
|
6
|
-
|
8
|
+
class << self
|
9
|
+
attr_accessor :redis
|
10
|
+
|
11
|
+
def merge_id_lists(canonical, modified, append = false)
|
12
|
+
if append
|
13
|
+
(modified + (canonical - modified)) & canonical
|
14
|
+
else
|
15
|
+
((canonical - modified) + modified) & canonical
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
7
19
|
|
8
20
|
# Set up a scoped ordering for this model.
|
9
21
|
#
|
10
|
-
# Liszt currently only supports one type of ranking per model. It also
|
11
|
-
# currently support re-sorting lists when a scope changes. The
|
12
|
-
# that attributes used as scopes won't change after creation.
|
22
|
+
# Liszt currently only supports one type of ranking per model. It also
|
23
|
+
# doesn't currently support re-sorting lists when a scope changes. The
|
24
|
+
# assumption is that attributes used as scopes won't change after creation.
|
13
25
|
#
|
14
|
-
# The other major limitation at the moment is that scopes can't be
|
15
|
-
# If a record has nil for a scope value, its associated list
|
16
|
-
# any items in it.
|
26
|
+
# The other major limitation at the moment is that scopes can't be
|
27
|
+
# <tt>nil</tt>. If a record has nil for a scope value, its associated list
|
28
|
+
# will never have any items in it.
|
17
29
|
#
|
18
30
|
# @param [Hash] options
|
19
31
|
# @option options [Symbol, Array] :scope The attribute or attributes to use
|
20
32
|
# as list constraints.
|
21
33
|
# @option options [Hash] :conditions Any extra constraints to impose.
|
22
|
-
# @option options [Proc] :sort_by A lambda to pass into initialize_list! the
|
23
|
-
# time an item is added to an uninitialized list. It has the same
|
24
|
-
# <tt>Enumerable#sort_by</tt>.
|
34
|
+
# @option options [Proc] :sort_by A lambda to pass into initialize_list! the
|
35
|
+
# first time an item is added to an uninitialized list. It has the same
|
36
|
+
# semantics as <tt>Enumerable#sort_by</tt>.
|
25
37
|
def acts_as_liszt(options = {})
|
26
38
|
extend Instantizeable
|
27
39
|
extend ClassMethods
|
@@ -49,21 +61,20 @@ module Liszt
|
|
49
61
|
end
|
50
62
|
|
51
63
|
def initialize_list!(obj={}, &block)
|
52
|
-
objects =
|
64
|
+
objects = liszt_relation(obj).to_a
|
53
65
|
|
54
66
|
# If the caller provided a block, or if they passed in a default
|
55
67
|
# with the :sort_by option, sort the objects by that block's
|
56
68
|
# output before populating the list with their ids. If not, put
|
57
69
|
# the objects in descending order by id.
|
58
|
-
ids =
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
70
|
+
ids = case
|
71
|
+
when block_given?
|
72
|
+
objects.sort_by(&block).map(&:id)
|
73
|
+
when @liszt_sort_by
|
74
|
+
objects.sort_by(&@liszt_sort_by).map(&:id)
|
75
|
+
else
|
76
|
+
objects.map(&:id).sort.reverse
|
77
|
+
end
|
67
78
|
|
68
79
|
ordered_list(obj).clear_and_populate!(ids)
|
69
80
|
ids
|
@@ -87,27 +98,45 @@ module Liszt
|
|
87
98
|
|
88
99
|
def ordered_list_items(obj={}, opts={})
|
89
100
|
force_refresh = opts.delete(:force_refresh) || false
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
#
|
94
|
-
|
95
|
-
|
96
|
-
objs = find(:all, {:conditions => liszt_query(obj)}.merge(opts))
|
97
|
-
real_ids = objs.map(&:id)
|
98
|
-
unlisted_ids = real_ids - ids
|
99
|
-
if unlisted_ids.count > 0
|
100
|
-
ids = ordered_list(obj).clear_and_populate!(unlisted_ids + ids)
|
101
|
-
end
|
101
|
+
previously_initialized = ordered_list_initialized?(obj)
|
102
|
+
|
103
|
+
# If the list isn't initialized already, we can trust ordered_list_ids to
|
104
|
+
# do the initialization correctly and ignore the force_refresh flag.
|
105
|
+
if force_refresh && previously_initialized
|
106
|
+
refresh_ordered_list(obj)
|
102
107
|
else
|
103
|
-
|
108
|
+
list_ids = ordered_list_ids(obj)
|
109
|
+
records = where('id in (?)', list_ids).to_a
|
110
|
+
records.sort_by { |obj| list_ids.index(obj.id) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Synchronizes the ordered list with the database, returning the relevant
|
115
|
+
# records in order.
|
116
|
+
def refresh_ordered_list(obj={})
|
117
|
+
list_ids = ordered_list_ids(obj)
|
118
|
+
records = liszt_relation(obj).to_a
|
119
|
+
real_ids = records.map(&:id)
|
120
|
+
merged_ids = Liszt.merge_id_lists(
|
121
|
+
real_ids, list_ids, @liszt_append_new_items)
|
122
|
+
|
123
|
+
if merged_ids != list_ids
|
124
|
+
ordered_list(obj).clear_and_populate!(merged_ids)
|
104
125
|
end
|
105
126
|
|
106
|
-
|
127
|
+
records.sort_by { |obj| merged_ids.index(obj.id) }
|
107
128
|
end
|
108
129
|
|
109
|
-
|
110
|
-
|
130
|
+
# Update the given object's list with the given ids. Returns the final list
|
131
|
+
# of ids, which may be different from the given list if the given list was
|
132
|
+
# inconsistent with the database.
|
133
|
+
def update_ordered_list(obj, new_ids)
|
134
|
+
records = ordered_list_items(obj, force_refresh: true)
|
135
|
+
real_ids = records.map(&:id)
|
136
|
+
merged_ids = Liszt.merge_id_lists(
|
137
|
+
real_ids, new_ids, @liszt_append_new_items)
|
138
|
+
|
139
|
+
ordered_list(obj).clear_and_populate!(merged_ids)
|
111
140
|
end
|
112
141
|
|
113
142
|
def meets_list_conditions?(obj={})
|
@@ -115,6 +144,7 @@ module Liszt
|
|
115
144
|
end
|
116
145
|
|
117
146
|
private
|
147
|
+
|
118
148
|
# Return the key for the Redis list that includes the given object.
|
119
149
|
def liszt_key(obj={})
|
120
150
|
key = "liszt:#{table_name}"
|
@@ -124,9 +154,9 @@ module Liszt
|
|
124
154
|
key
|
125
155
|
end
|
126
156
|
|
127
|
-
# Return
|
128
|
-
#
|
129
|
-
def
|
157
|
+
# Return a relation/scope containing objects eligible to be in the list
|
158
|
+
# that includes the given object.
|
159
|
+
def liszt_relation(obj={})
|
130
160
|
if @liszt_query.nil?
|
131
161
|
query = ['1 = 1']
|
132
162
|
|
@@ -147,7 +177,7 @@ module Liszt
|
|
147
177
|
@liszt_query = query
|
148
178
|
end
|
149
179
|
|
150
|
-
@liszt_query + @liszt_scope.map { |scope| obj[scope] }
|
180
|
+
where(@liszt_query + @liszt_scope.map { |scope| obj[scope] })
|
151
181
|
end
|
152
182
|
end
|
153
183
|
|
@@ -155,7 +185,7 @@ module Liszt
|
|
155
185
|
def self.included(base)
|
156
186
|
base.class_eval do
|
157
187
|
after_create :add_to_list
|
158
|
-
after_update :
|
188
|
+
after_update :add_to_or_remove_from_list
|
159
189
|
after_destroy :remove_from_list
|
160
190
|
end
|
161
191
|
end
|
@@ -170,16 +200,12 @@ module Liszt
|
|
170
200
|
end
|
171
201
|
end
|
172
202
|
else
|
173
|
-
|
174
|
-
initialize_list! &self.class.liszt_sort_by
|
175
|
-
else
|
176
|
-
initialize_list!
|
177
|
-
end
|
203
|
+
initialize_list!
|
178
204
|
end
|
179
205
|
true
|
180
206
|
end
|
181
207
|
|
182
|
-
def
|
208
|
+
def add_to_or_remove_from_list
|
183
209
|
if meets_list_conditions?
|
184
210
|
add_to_list
|
185
211
|
else
|
@@ -211,4 +237,5 @@ module Liszt
|
|
211
237
|
end
|
212
238
|
end
|
213
239
|
|
240
|
+
# @@ TODO: use an actual railtie
|
214
241
|
ActiveRecord::Base.extend Liszt
|
data/liszt.gemspec
CHANGED
@@ -16,9 +16,13 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
17
|
s.require_paths = %w{lib}
|
18
18
|
|
19
|
-
s.add_runtime_dependency
|
20
|
-
s.add_runtime_dependency
|
19
|
+
s.add_runtime_dependency "activerecord", ">= 3.0.0"
|
20
|
+
s.add_runtime_dependency "redis"
|
21
21
|
|
22
|
-
s.add_development_dependency
|
23
|
-
s.add_development_dependency
|
22
|
+
s.add_development_dependency "minitest"
|
23
|
+
s.add_development_dependency "pry"
|
24
|
+
s.add_development_dependency "rake"
|
25
|
+
s.add_development_dependency "rdiscount"
|
26
|
+
s.add_development_dependency "sqlite3"
|
27
|
+
s.add_development_dependency "yard"
|
24
28
|
end
|
File without changes
|
data/test/liszt_test.rb
CHANGED
@@ -1,59 +1,56 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
fixtures :people
|
6
|
-
|
7
|
-
setup do
|
3
|
+
describe Liszt do
|
4
|
+
before do
|
8
5
|
Liszt.redis.flushall
|
9
6
|
end
|
10
7
|
|
11
|
-
|
12
|
-
|
8
|
+
describe "before initialization" do
|
9
|
+
it "isn't initialized" do
|
13
10
|
assert !people(:nelson).ordered_list_initialized?
|
14
11
|
end
|
15
12
|
|
16
|
-
|
17
|
-
|
13
|
+
it "initializes successfully" do
|
14
|
+
people(:nelson).initialize_list!
|
18
15
|
assert people(:nelson).ordered_list_initialized?
|
19
16
|
end
|
20
17
|
|
21
|
-
|
22
|
-
|
18
|
+
it "auto-initializes successfully" do
|
19
|
+
people(:nelson).ordered_list_ids
|
23
20
|
assert people(:nelson).ordered_list_initialized?
|
24
21
|
end
|
25
22
|
end
|
26
23
|
|
27
|
-
|
28
|
-
|
24
|
+
describe "after initialization" do
|
25
|
+
before do
|
29
26
|
people(:nelson).initialize_list!(&:id)
|
30
27
|
@id = people(:nelson).id
|
31
28
|
@current_list = Person.ordered_list_ids(people(:nelson))
|
32
29
|
end
|
33
30
|
|
34
|
-
|
35
|
-
|
31
|
+
describe "basic functionality" do
|
32
|
+
it "moves to top" do
|
36
33
|
people(:nelson).move_to_top!
|
37
34
|
@current_list.delete(@id)
|
38
35
|
@current_list.unshift(@id)
|
39
36
|
assert_equal people(:nelson).ordered_list_ids, @current_list
|
40
37
|
end
|
41
38
|
|
42
|
-
|
39
|
+
it "moves up" do
|
43
40
|
old_index = people(:nelson).ordered_list_ids.index(@id)
|
44
41
|
people(:nelson).move_up!
|
45
42
|
@current_list.swap(old_index, old_index - 1)
|
46
43
|
assert_equal people(:nelson).ordered_list_ids, @current_list
|
47
44
|
end
|
48
45
|
|
49
|
-
|
46
|
+
it "moves down" do
|
50
47
|
old_index = people(:nelson).ordered_list_ids.index(@id)
|
51
48
|
people(:nelson).move_down!
|
52
49
|
@current_list.swap(old_index, old_index + 1)
|
53
50
|
assert_equal people(:nelson).ordered_list_ids, @current_list
|
54
51
|
end
|
55
52
|
|
56
|
-
|
53
|
+
it "moves to bottom" do
|
57
54
|
people(:nelson).move_to_bottom!
|
58
55
|
@current_list.delete(@id)
|
59
56
|
@current_list.push(@id)
|
@@ -61,73 +58,213 @@ class LisztTest < ActiveSupport::TestCase
|
|
61
58
|
end
|
62
59
|
end
|
63
60
|
|
64
|
-
|
65
|
-
|
61
|
+
describe "ActiveRecord hooks" do
|
62
|
+
before do
|
66
63
|
Person.initialize_list!(:group_id => 1, :is_male => true)
|
67
64
|
@person = Person.new(:name => "John Smith", :group_id => 1, :is_male => true)
|
68
65
|
end
|
69
66
|
|
70
|
-
|
67
|
+
it "isn't in list before saving" do
|
71
68
|
assert !@person.ordered_list_items.include?(@person)
|
72
69
|
end
|
73
70
|
|
74
|
-
|
71
|
+
it "is in list after saving" do
|
75
72
|
@person.save
|
76
73
|
assert @person.ordered_list_items.include?(@person)
|
77
74
|
end
|
78
75
|
|
79
|
-
|
76
|
+
it "is removed from list after deletion" do
|
80
77
|
@person.save
|
81
78
|
@person.destroy
|
82
79
|
assert !@person.ordered_list_items.include?(@person)
|
83
80
|
end
|
84
81
|
end
|
85
82
|
|
86
|
-
|
87
|
-
|
83
|
+
describe "options" do
|
84
|
+
before do
|
88
85
|
Person.initialize_list!(:group_id => 1, :is_male => true)
|
89
86
|
@person = Person.new(:name => "John Smith", :group_id => 1, :is_male => true)
|
90
87
|
end
|
91
88
|
|
92
|
-
|
89
|
+
it "doesn't confirm the list when force_refresh is nil" do
|
93
90
|
@person.save
|
94
91
|
@person.remove_from_list
|
95
92
|
assert !@person.ordered_list_items.include?(@person)
|
96
93
|
assert !@person.ordered_list_ids.include?(@person.id)
|
97
94
|
end
|
98
95
|
|
99
|
-
|
96
|
+
it "confirms the list when force_refresh is true" do
|
100
97
|
@person.save
|
101
98
|
@person.remove_from_list
|
102
99
|
assert @person.ordered_list_items(:force_refresh => true).include?(@person)
|
103
100
|
assert @person.ordered_list_ids.include?(@person.id)
|
104
101
|
end
|
105
102
|
|
106
|
-
|
103
|
+
it "removes incorrect items from the list when force_refresh is true" do
|
107
104
|
@person.save
|
108
|
-
|
105
|
+
@person.ordered_list.push(12314231)
|
106
|
+
assert @person.ordered_list_ids.include?(12314231)
|
107
|
+
@person.ordered_list_items
|
108
|
+
assert @person.ordered_list_ids.include?(12314231)
|
109
|
+
@person.ordered_list_items(:force_refresh => true)
|
110
|
+
refute @person.ordered_list_ids.include?(12314231)
|
109
111
|
end
|
110
112
|
end
|
111
113
|
end
|
112
114
|
|
113
|
-
|
114
|
-
|
115
|
-
Group.acts_as_liszt :sort_by => lambda { |o| o.id }
|
116
|
-
end
|
117
|
-
|
118
|
-
should "sort a newly initialized list with the given proc" do
|
115
|
+
describe "auto-initialization" do
|
116
|
+
it "sorts a newly initialized list with the given proc" do
|
119
117
|
assert !Group.ordered_list_initialized?
|
120
118
|
Group.initialize_list!
|
121
119
|
assert Group.ordered_list_initialized?
|
122
120
|
assert_equal Group.ordered_list_ids, [1, 2, 3]
|
123
121
|
end
|
124
122
|
|
125
|
-
|
126
|
-
g = Group.new
|
123
|
+
it "sorts a newly auto-initialized (by record creation) list" do
|
124
|
+
g = Group.new(is_foo: true, is_bar: nil)
|
127
125
|
assert !Group.ordered_list_initialized?
|
128
126
|
g.save
|
129
127
|
assert Group.ordered_list_initialized?
|
130
128
|
assert_equal Group.ordered_list_ids, [1, 2, 3, g.id]
|
131
129
|
end
|
130
|
+
|
131
|
+
it "sorts a newly auto-initialized (by querying) list" do
|
132
|
+
assert !Group.ordered_list_initialized?
|
133
|
+
Group.ordered_list_items
|
134
|
+
assert Group.ordered_list_initialized?
|
135
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "sorts by id descending if there is no proc" do
|
139
|
+
nelson = people(:nelson)
|
140
|
+
refute nelson.ordered_list_initialized?
|
141
|
+
Person.create!(group_id: nelson.group_id, is_male: nelson.is_male)
|
142
|
+
assert nelson.ordered_list_initialized?
|
143
|
+
nelson.ordered_list_ids.must_equal nelson.ordered_list_ids.sort.reverse
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "with :conditions and :append_new_items" do
|
148
|
+
before do
|
149
|
+
Group.initialize_list!
|
150
|
+
assert Group.ordered_list_initialized?
|
151
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3]
|
152
|
+
end
|
153
|
+
|
154
|
+
it "appends records that meet the conditions" do
|
155
|
+
Group.create!(is_foo: true, is_bar: true)
|
156
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3]
|
157
|
+
|
158
|
+
Group.create!(is_foo: false, is_bar: nil)
|
159
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3]
|
160
|
+
|
161
|
+
g = Group.create!(is_foo: true, is_bar: nil)
|
162
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3, g.id]
|
163
|
+
end
|
164
|
+
|
165
|
+
it "inserts/removes records if an update changes the conditions" do
|
166
|
+
g = Group.create!(is_foo: true, is_bar: nil)
|
167
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3, g.id]
|
168
|
+
g.update_attributes is_bar: true
|
169
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3]
|
170
|
+
g.update_attributes is_bar: nil
|
171
|
+
assert_equal Group.ordered_list_ids, [1, 2, 3, g.id]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe ".update_ordered_list" do
|
176
|
+
before do
|
177
|
+
@nelson = people(:nelson)
|
178
|
+
@nelson.initialize_list!
|
179
|
+
@id1, @id2, @id3, @id4 = @nelson.ordered_list_ids
|
180
|
+
end
|
181
|
+
|
182
|
+
it "reorders the elements based on the given list" do
|
183
|
+
retval = @nelson.update_ordered_list [@id4, @id3, @id2, @id1]
|
184
|
+
retval.must_equal [@id4, @id3, @id2, @id1]
|
185
|
+
@nelson.ordered_list_ids.must_equal [@id4, @id3, @id2, @id1]
|
186
|
+
end
|
187
|
+
|
188
|
+
describe "when the existing list is missing elements from the db" do
|
189
|
+
before do
|
190
|
+
@nelson.ordered_list.remove @id3
|
191
|
+
@nelson.ordered_list_ids.must_equal [@id1, @id2, @id4]
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "and the user also didn't provide them" do
|
195
|
+
it "prepends those elements to the list" do
|
196
|
+
retval = @nelson.update_ordered_list [@id4, @id2, @id1]
|
197
|
+
retval.must_equal [@id3, @id4, @id2, @id1]
|
198
|
+
@nelson.ordered_list_ids.must_equal [@id3, @id4, @id2, @id1]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
describe "and the user provided them as part of their ordering" do
|
203
|
+
it "adds those elements where the user provided them" do
|
204
|
+
@nelson.update_ordered_list [@id4, @id2, @id3, @id1]
|
205
|
+
@nelson.ordered_list_ids.must_equal [@id4, @id2, @id3, @id1]
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe "and the user provided one but not another" do
|
210
|
+
before do
|
211
|
+
@nelson.ordered_list.remove @id2
|
212
|
+
end
|
213
|
+
|
214
|
+
it "prepends only the one that wasn't provided" do
|
215
|
+
@nelson.update_ordered_list [@id4, @id2, @id1]
|
216
|
+
@nelson.ordered_list_ids.must_equal [@id3, @id4, @id2, @id1]
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "when the existing list contains extra elements" do
|
222
|
+
before do
|
223
|
+
@nelson.ordered_list << 123
|
224
|
+
end
|
225
|
+
|
226
|
+
it "removes those elements from the list" do
|
227
|
+
@nelson.update_ordered_list [@id4, @id3, @id2, @id1]
|
228
|
+
@nelson.ordered_list_ids.must_equal [@id4, @id3, @id2, @id1]
|
229
|
+
end
|
230
|
+
|
231
|
+
it "ignores those elements if given by the user" do
|
232
|
+
@nelson.update_ordered_list [@id4, @id3, 123, @id2, @id1]
|
233
|
+
@nelson.ordered_list_ids.must_equal [@id4, @id3, @id2, @id1]
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "when the list given by the user omits needed elements" do
|
238
|
+
it "prepends them to the list" do
|
239
|
+
@nelson.update_ordered_list [@id4, @id3, @id1]
|
240
|
+
@nelson.ordered_list_ids.must_equal [@id2, @id4, @id3, @id1]
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe "when the list given by the user contains nonexistent elements" do
|
245
|
+
it "ignores them and calls back" do
|
246
|
+
@nelson.update_ordered_list [@id4, @id3, 123, @id2, @id1]
|
247
|
+
@nelson.ordered_list_ids.must_equal [@id4, @id3, @id2, @id1]
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe ".update_ordered_list with :append_new_items" do
|
253
|
+
it "appends missing elements to the list" do
|
254
|
+
group = groups(:one)
|
255
|
+
group.initialize_list!
|
256
|
+
id1, id2, id3 = group.ordered_list_ids
|
257
|
+
|
258
|
+
group.ordered_list.remove id2
|
259
|
+
group.ordered_list_ids.must_equal [id1, id3]
|
260
|
+
|
261
|
+
group.update_ordered_list [id3, id1]
|
262
|
+
|
263
|
+
group.ordered_list_ids.must_equal [id3, id1, id2]
|
264
|
+
|
265
|
+
group.update_ordered_list [id1, id2]
|
266
|
+
|
267
|
+
group.ordered_list_ids.must_equal [id1, id2, id3]
|
268
|
+
end
|
132
269
|
end
|
133
270
|
end
|