liszt 0.0.7 → 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.
- 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
|