pax_global_header 0000666 0000000 0000000 00000000064 13337530425 0014517 g ustar 00root root 0000000 0000000 52 comment=f721bba2a3fd1d87ba2f0d63717827e113f5bfc5
ruby-acts-as-list-0.9.15/ 0000775 0000000 0000000 00000000000 13337530425 0015076 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/.gemtest 0000664 0000000 0000000 00000000000 13337530425 0016535 0 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/.gitignore 0000664 0000000 0000000 00000000224 13337530425 0017064 0 ustar 00root root 0000000 0000000 *.gem
.bundle
Gemfile.lock
pkg/*
.rvmrc
*.tmproj
.rbenv-version
.ruby-gemset
.ruby-version
# Appraisal generated lockfiles
*.gemfile.lock
.DS_Store
ruby-acts-as-list-0.9.15/.travis.yml 0000664 0000000 0000000 00000003017 13337530425 0017210 0 ustar 00root root 0000000 0000000 language: ruby
cache: bundler
# Explicit usage of containerized builds, should provide faster feedback
# see https://docs.travis-ci.com/user/workers/container-based-infrastructure/
# and https://docs.travis-ci.com/user/ci-environment/#Virtualization-environments
sudo: false
before_install:
- gem install bundler -v 1.16.1
before_script:
- mysql -e 'create database acts_as_list;'
- psql -c 'create database acts_as_list;' -U postgres
rvm:
- 1.9.3
- 2.0.0
- 2.1.10
- 2.2.6
- 2.3.6
- 2.4.3
- 2.5.0
env:
- DB=sqlite
- DB=mysql
- DB=postgresql
gemfile:
- gemfiles/rails_3_2.gemfile
- gemfiles/rails_4_1.gemfile
- gemfiles/rails_4_2.gemfile
- gemfiles/rails_5_0.gemfile
- gemfiles/rails_5_1.gemfile
- gemfiles/rails_5_2.gemfile
matrix:
exclude:
- rvm: 1.9.3
gemfile: gemfiles/rails_5_0.gemfile
- rvm: 1.9.3
gemfile: gemfiles/rails_5_1.gemfile
- rvm: 1.9.3
gemfile: gemfiles/rails_5_2.gemfile
- rvm: 2.0.0
gemfile: gemfiles/rails_5_0.gemfile
- rvm: 2.0.0
gemfile: gemfiles/rails_5_1.gemfile
- rvm: 2.0.0
gemfile: gemfiles/rails_5_2.gemfile
- rvm: 2.1.10
gemfile: gemfiles/rails_5_0.gemfile
- rvm: 2.1.10
gemfile: gemfiles/rails_5_1.gemfile
- rvm: 2.1.10
gemfile: gemfiles/rails_5_2.gemfile
- rvm: 2.4.3
gemfile: gemfiles/rails_3_2.gemfile
- rvm: 2.4.3
gemfile: gemfiles/rails_4_1.gemfile
- rvm: 2.5.0
gemfile: gemfiles/rails_3_2.gemfile
- rvm: 2.5.0
gemfile: gemfiles/rails_4_1.gemfile
ruby-acts-as-list-0.9.15/Appraisals 0000664 0000000 0000000 00000001702 13337530425 0017120 0 ustar 00root root 0000000 0000000 appraise "rails-3-2" do
group :mysql do
gem "mysql2", "~> 0.3.21", platforms: [:ruby]
end
gem "activerecord", "~> 3.2.22.2"
group :test do
gem "after_commit_exception_notification"
end
end
appraise "rails-4-1" do
group :mysql do
gem "mysql2", "~> 0.3.21", platforms: [:ruby]
end
gem "activerecord", "~> 4.1.16"
group :test do
gem "after_commit_exception_notification"
end
end
appraise "rails-4-2" do
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gem "activerecord", "~> 4.2.10"
end
appraise "rails-5-0" do
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gem "activerecord", "~> 5.0.6"
end
appraise "rails-5-1" do
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gem "activerecord", "~> 5.1.4"
end
appraise "rails-5-2" do
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gem "activerecord", "~> 5.2.0.rc1"
end
ruby-acts-as-list-0.9.15/CHANGELOG.md 0000664 0000000 0000000 00000116334 13337530425 0016717 0 ustar 00root root 0000000 0000000 # Change Log
## [v0.9.14](https://github.com/swanandp/acts_as_list/tree/v0.9.14) (2018-06-05)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.13...v0.9.14)
**Closed issues:**
- `insert\_at` saves invalid ActiveRecord objects [\#311](https://github.com/swanandp/acts_as_list/issues/311)
**Merged pull requests:**
- \#311 Don't insert invalid ActiveRecord objects [\#312](https://github.com/swanandp/acts_as_list/pull/312) ([seanabrahams](https://github.com/seanabrahams))
## [v0.9.13](https://github.com/swanandp/acts_as_list/tree/v0.9.13) (2018-06-05)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.12...v0.9.13)
**Merged pull requests:**
- Fix unique index constraint failure on item destroy [\#313](https://github.com/swanandp/acts_as_list/pull/313) ([yjukaku](https://github.com/yjukaku))
## [v0.9.12](https://github.com/swanandp/acts_as_list/tree/v0.9.12) (2018-05-02)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.11...v0.9.12)
**Closed issues:**
- acts\_as\_list methods on has\_many through [\#308](https://github.com/swanandp/acts_as_list/issues/308)
- Travis badge [\#307](https://github.com/swanandp/acts_as_list/issues/307)
- Unscoping breaks STI subclasses, but is soon to be fixed in Rails [\#291](https://github.com/swanandp/acts_as_list/issues/291)
- Refactor string eval for scope\_condition [\#227](https://github.com/swanandp/acts_as_list/issues/227)
**Merged pull requests:**
- mocha/minitest, not mocha/mini\_test now. [\#310](https://github.com/swanandp/acts_as_list/pull/310) ([jmarkbrooks](https://github.com/jmarkbrooks))
## [v0.9.11](https://github.com/swanandp/acts_as_list/tree/v0.9.11) (2018-03-19)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.10...v0.9.11)
**Closed issues:**
- Setting `position: nil` on update returns `Column 'position' cannot be null` instead of putting the item at the start or the end of the list, like it does on create. [\#302](https://github.com/swanandp/acts_as_list/issues/302)
- Switching to Semaphore [\#301](https://github.com/swanandp/acts_as_list/issues/301)
- Dropping jruby support [\#300](https://github.com/swanandp/acts_as_list/issues/300)
- Rails 5.2.0 [\#299](https://github.com/swanandp/acts_as_list/issues/299)
- Cannot update record position when scoped to enum [\#298](https://github.com/swanandp/acts_as_list/issues/298)
- `add\_new\_at: :top` does not work [\#296](https://github.com/swanandp/acts_as_list/issues/296)
- remove\_from\_list causing "wrong number of arguments \(given 2, expected 0..1\)" [\#293](https://github.com/swanandp/acts_as_list/issues/293)
- Passing raw strings to reorder deprecated in Rails 5.2 [\#290](https://github.com/swanandp/acts_as_list/issues/290)
**Merged pull requests:**
- Fix Test Suite [\#306](https://github.com/swanandp/acts_as_list/pull/306) ([brendon](https://github.com/brendon))
- Add frozen\_string\_literal pragma to ruby files [\#305](https://github.com/swanandp/acts_as_list/pull/305) ([krzysiek1507](https://github.com/krzysiek1507))
- Use symbols instead of SQL strings for reorder \(for Rails 5.2\) [\#294](https://github.com/swanandp/acts_as_list/pull/294) ([jhawthorn](https://github.com/jhawthorn))
## [v0.9.10](https://github.com/swanandp/acts_as_list/tree/v0.9.10) (2017-11-19)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.9...v0.9.10)
**Closed issues:**
- Make insert\_at respect position when creating a new record [\#287](https://github.com/swanandp/acts_as_list/issues/287)
- Why does acts\_as\_list override rails validation on it's own field? [\#269](https://github.com/swanandp/acts_as_list/issues/269)
**Merged pull requests:**
- Change error classes parents [\#288](https://github.com/swanandp/acts_as_list/pull/288) ([alexander-lazarov](https://github.com/alexander-lazarov))
## [v0.9.9](https://github.com/swanandp/acts_as_list/tree/v0.9.9) (2017-10-03)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.8...v0.9.9)
**Merged pull requests:**
- Added fixed values option for scope array [\#286](https://github.com/swanandp/acts_as_list/pull/286) ([smoyth](https://github.com/smoyth))
## [v0.9.8](https://github.com/swanandp/acts_as_list/tree/v0.9.8) (2017-09-28)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.7...v0.9.8)
**Closed issues:**
- Deadlocking in update\_positions count query [\#285](https://github.com/swanandp/acts_as_list/issues/285)
- Updating the position fails uniqueness constraint. [\#275](https://github.com/swanandp/acts_as_list/issues/275)
## [v0.9.7](https://github.com/swanandp/acts_as_list/tree/v0.9.7) (2017-07-06)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.6...v0.9.7)
## [v0.9.6](https://github.com/swanandp/acts_as_list/tree/v0.9.6) (2017-07-05)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.5...v0.9.6)
**Closed issues:**
- undefined method `+' for nil:NilClass [\#278](https://github.com/swanandp/acts_as_list/issues/278)
- Enum does not scope correctly [\#277](https://github.com/swanandp/acts_as_list/issues/277)
- Can we don't use remove\_from\_list when destroy a lot objects? [\#276](https://github.com/swanandp/acts_as_list/issues/276)
- The NoUpdate code rely's on AS::Concern [\#273](https://github.com/swanandp/acts_as_list/issues/273)
- ActiveRecord associations are no longer required \(even though belongs\_to\_required\_by\_default == true\) [\#268](https://github.com/swanandp/acts_as_list/issues/268)
- Unique constraint violation on move\_higher, move\_lower, destroy [\#267](https://github.com/swanandp/acts_as_list/issues/267)
**Merged pull requests:**
- Fix Fixnum deprecation warnings. [\#282](https://github.com/swanandp/acts_as_list/pull/282) ([patrickdavey](https://github.com/patrickdavey))
- Fix update to scope that was defined with an enum [\#281](https://github.com/swanandp/acts_as_list/pull/281) ([scottmalone](https://github.com/scottmalone))
- Refactor update\_all\_with\_touch [\#279](https://github.com/swanandp/acts_as_list/pull/279) ([ledestin](https://github.com/ledestin))
- Remove AS::Concern from NoUpdate [\#274](https://github.com/swanandp/acts_as_list/pull/274) ([brendon](https://github.com/brendon))
- Use `ActiveSupport.on\_load` to hook into ActiveRecord [\#272](https://github.com/swanandp/acts_as_list/pull/272) ([brendon](https://github.com/brendon))
## [v0.9.5](https://github.com/swanandp/acts_as_list/tree/v0.9.5) (2017-04-04)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.4...v0.9.5)
**Closed issues:**
- acts\_as\_list\_class.maximum\(position\_column\) is causing the entire table to lock [\#264](https://github.com/swanandp/acts_as_list/issues/264)
- Be more precise with unscope-ing [\#263](https://github.com/swanandp/acts_as_list/issues/263)
**Merged pull requests:**
- Use bottom\_position\_in\_list instead of the highest value in the table [\#266](https://github.com/swanandp/acts_as_list/pull/266) ([brendon](https://github.com/brendon))
- Be more surgical about unscoping [\#265](https://github.com/swanandp/acts_as_list/pull/265) ([brendon](https://github.com/brendon))
## [v0.9.4](https://github.com/swanandp/acts_as_list/tree/v0.9.4) (2017-03-16)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.3...v0.9.4)
**Merged pull requests:**
- Optimize first? and last? instance methods. [\#262](https://github.com/swanandp/acts_as_list/pull/262) ([marshall-lee](https://github.com/marshall-lee))
## [v0.9.3](https://github.com/swanandp/acts_as_list/tree/v0.9.3) (2017-03-14)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.2...v0.9.3)
**Closed issues:**
- Rails 5.1.0.beta1 deprecation [\#257](https://github.com/swanandp/acts_as_list/issues/257)
- Move item X after item Y [\#256](https://github.com/swanandp/acts_as_list/issues/256)
- Is there way to specify the position when creating a resource? [\#255](https://github.com/swanandp/acts_as_list/issues/255)
**Merged pull requests:**
- Don't update a child destroyed via relation [\#261](https://github.com/swanandp/acts_as_list/pull/261) ([brendon](https://github.com/brendon))
- No update list for collection classes [\#260](https://github.com/swanandp/acts_as_list/pull/260) ([IlkhamGaysin](https://github.com/IlkhamGaysin))
- Fix deprecation introduced in ActiveRecord 5.1.0.beta1. Closes \#257 [\#259](https://github.com/swanandp/acts_as_list/pull/259) ([CvX](https://github.com/CvX))
- Refactor column definer module [\#258](https://github.com/swanandp/acts_as_list/pull/258) ([ledestin](https://github.com/ledestin))
## [v0.9.2](https://github.com/swanandp/acts_as_list/tree/v0.9.2) (2017-02-07)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.1...v0.9.2)
**Closed issues:**
- Getting invalid input syntax for uuid [\#253](https://github.com/swanandp/acts_as_list/issues/253)
## [v0.9.1](https://github.com/swanandp/acts_as_list/tree/v0.9.1) (2017-01-26)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.9.0...v0.9.1)
**Closed issues:**
- DEPRECATION WARNING on rails 5.0 as of acts\_as\_list 0.9 [\#251](https://github.com/swanandp/acts_as_list/issues/251)
- highter\_items returns items with the same position value [\#247](https://github.com/swanandp/acts_as_list/issues/247)
- Broken with unique constraint on position [\#245](https://github.com/swanandp/acts_as_list/issues/245)
**Merged pull requests:**
- fixes \#251 table\_exists? deprecation warning with Rails 5.0 [\#252](https://github.com/swanandp/acts_as_list/pull/252) ([zharikovpro](https://github.com/zharikovpro))
## [v0.9.0](https://github.com/swanandp/acts_as_list/tree/v0.9.0) (2017-01-23)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.8.2...v0.9.0)
**Closed issues:**
- warning: too many arguments for format string [\#239](https://github.com/swanandp/acts_as_list/issues/239)
- Broken tests related to time comparison [\#238](https://github.com/swanandp/acts_as_list/issues/238)
- Shuffling positions is halting the callback chain [\#234](https://github.com/swanandp/acts_as_list/issues/234)
- Reorder positions [\#233](https://github.com/swanandp/acts_as_list/issues/233)
- Tests break when upgrading from 0.7.2 to 0.7.4 [\#228](https://github.com/swanandp/acts_as_list/issues/228)
- RE \#221 needing a test [\#226](https://github.com/swanandp/acts_as_list/issues/226)
- Adding to existing model with data and methods don't work [\#209](https://github.com/swanandp/acts_as_list/issues/209)
- Position is set incorrectly when circular dependencies exist [\#153](https://github.com/swanandp/acts_as_list/issues/153)
**Merged pull requests:**
- Revert "Updates documentation with valid string interpolation syntax" [\#250](https://github.com/swanandp/acts_as_list/pull/250) ([brendon](https://github.com/brendon))
- Updates documentation with valid string interpolation syntax [\#249](https://github.com/swanandp/acts_as_list/pull/249) ([naveedkakal](https://github.com/naveedkakal))
- Comply to tests warnings [\#248](https://github.com/swanandp/acts_as_list/pull/248) ([randoum](https://github.com/randoum))
- insert\_at respects unique not null check \(\>= 0\) db constraints [\#246](https://github.com/swanandp/acts_as_list/pull/246) ([zharikovpro](https://github.com/zharikovpro))
- acts\_as\_list\_no\_update [\#244](https://github.com/swanandp/acts_as_list/pull/244) ([randoum](https://github.com/randoum))
- Update README.md [\#243](https://github.com/swanandp/acts_as_list/pull/243) ([rahuldstiwari](https://github.com/rahuldstiwari))
- Fixed tests to prevent warning: too many arguments for format string [\#242](https://github.com/swanandp/acts_as_list/pull/242) ([brendon](https://github.com/brendon))
- Be explicit about ordering when mapping :pos [\#241](https://github.com/swanandp/acts_as_list/pull/241) ([brendon](https://github.com/brendon))
- Improve load method [\#240](https://github.com/swanandp/acts_as_list/pull/240) ([brendon](https://github.com/brendon))
- Fix non regular sequence movement [\#237](https://github.com/swanandp/acts_as_list/pull/237) ([tiagotex](https://github.com/tiagotex))
- Add travis config for testing against multiple databases [\#236](https://github.com/swanandp/acts_as_list/pull/236) ([fschwahn](https://github.com/fschwahn))
- Extract modules [\#229](https://github.com/swanandp/acts_as_list/pull/229) ([ledestin](https://github.com/ledestin))
## [v0.8.2](https://github.com/swanandp/acts_as_list/tree/v0.8.2) (2016-09-23)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.8.1...v0.8.2)
**Closed issues:**
- We're a repo now, no longer a fork attached to rails/acts\_as\_list [\#232](https://github.com/swanandp/acts_as_list/issues/232)
- Break away from rails/acts\_as\_list [\#224](https://github.com/swanandp/acts_as_list/issues/224)
- Problem when inserting straight at top of list [\#109](https://github.com/swanandp/acts_as_list/issues/109)
**Merged pull requests:**
- Show items with same position in higher and lower items [\#231](https://github.com/swanandp/acts_as_list/pull/231) ([jpalumickas](https://github.com/jpalumickas))
- fix setting position when previous position was nil [\#230](https://github.com/swanandp/acts_as_list/pull/230) ([StoneFrog](https://github.com/StoneFrog))
## [v0.8.1](https://github.com/swanandp/acts_as_list/tree/v0.8.1) (2016-09-06)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.8.0...v0.8.1)
**Closed issues:**
- Rubinius Intermittent testing error [\#218](https://github.com/swanandp/acts_as_list/issues/218)
- ActiveRecord dependency causes rake assets:compile to fail without access to a database [\#84](https://github.com/swanandp/acts_as_list/issues/84)
**Merged pull requests:**
- Refactor class\_eval with string into class\_eval with block [\#215](https://github.com/swanandp/acts_as_list/pull/215) ([rdvdijk](https://github.com/rdvdijk))
## [v0.8.0](https://github.com/swanandp/acts_as_list/tree/v0.8.0) (2016-08-23)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.7...v0.8.0)
**Closed issues:**
- Behavior with DB default seems unclear [\#219](https://github.com/swanandp/acts_as_list/issues/219)
**Merged pull requests:**
- No longer a need specify additional rbx gems [\#225](https://github.com/swanandp/acts_as_list/pull/225) ([brendon](https://github.com/brendon))
- Fix position when no serial positions [\#223](https://github.com/swanandp/acts_as_list/pull/223) ([jpalumickas](https://github.com/jpalumickas))
- Bug: Specifying a position with add\_new\_at: :top fails to insert at that position [\#220](https://github.com/swanandp/acts_as_list/pull/220) ([brendon](https://github.com/brendon))
## [v0.7.7](https://github.com/swanandp/acts_as_list/tree/v0.7.7) (2016-08-18)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.6...v0.7.7)
**Closed issues:**
- Issue after upgrading to 0.7.5: No connection pool with id primary found. [\#214](https://github.com/swanandp/acts_as_list/issues/214)
- Changing scope is inconsistent based on add\_new\_at [\#138](https://github.com/swanandp/acts_as_list/issues/138)
- Duplicate positions and lost items [\#76](https://github.com/swanandp/acts_as_list/issues/76)
**Merged pull requests:**
- Add quoted table names to some columns [\#221](https://github.com/swanandp/acts_as_list/pull/221) ([jpalumickas](https://github.com/jpalumickas))
- Appraisals cleanup [\#217](https://github.com/swanandp/acts_as_list/pull/217) ([brendon](https://github.com/brendon))
- Fix insert\_at\_position in race condition [\#195](https://github.com/swanandp/acts_as_list/pull/195) ([danielross](https://github.com/danielross))
## [v0.7.6](https://github.com/swanandp/acts_as_list/tree/v0.7.6) (2016-07-15)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.5...v0.7.6)
**Closed issues:**
- add\_new\_at nil with scope causes NoMethodError [\#211](https://github.com/swanandp/acts_as_list/issues/211)
**Merged pull requests:**
- Add class method acts\_as\_list\_top as reader for configured top\_of\_list [\#213](https://github.com/swanandp/acts_as_list/pull/213) ([krzysiek1507](https://github.com/krzysiek1507))
- Bugfix/add new at nil on scope change [\#212](https://github.com/swanandp/acts_as_list/pull/212) ([greatghoul](https://github.com/greatghoul))
## [v0.7.5](https://github.com/swanandp/acts_as_list/tree/v0.7.5) (2016-06-30)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.4...v0.7.5)
**Implemented enhancements:**
- Touch when reordering [\#173](https://github.com/swanandp/acts_as_list/pull/173) ([botandrose](https://github.com/botandrose))
**Closed issues:**
- Exception raised when calling destroy "NameError - instance variable @scope\_changed not defined:" [\#206](https://github.com/swanandp/acts_as_list/issues/206)
- Undefined instance variable @scope\_changed since 0.7.3 [\#199](https://github.com/swanandp/acts_as_list/issues/199)
- Reordering large lists is slow [\#198](https://github.com/swanandp/acts_as_list/issues/198)
- Reparenting child leaves gap in source list in rails 5 [\#194](https://github.com/swanandp/acts_as_list/issues/194)
- Support rails 5 ? [\#186](https://github.com/swanandp/acts_as_list/issues/186)
- I get a NoMethodError: undefined method `acts\_as\_list' when trying to include acts\_as\_list [\#176](https://github.com/swanandp/acts_as_list/issues/176)
- Phenomenon of mysterious value of the position is skipped by one [\#166](https://github.com/swanandp/acts_as_list/issues/166)
- Model.find being called twice with acts\_as\_list on destroy [\#161](https://github.com/swanandp/acts_as_list/issues/161)
- `scope\_changed?` problem with acts\_as\_paranoid [\#158](https://github.com/swanandp/acts_as_list/issues/158)
- Inconsistent behaviour between Symbol and Array scopes [\#155](https://github.com/swanandp/acts_as_list/issues/155)
- insert\_at doesn't seem to be working in ActiveRecord callback \(Rails 4.2\) [\#150](https://github.com/swanandp/acts_as_list/issues/150)
- Project Documentation link redirects to expired domain [\#149](https://github.com/swanandp/acts_as_list/issues/149)
- Problem when updating an position of array of AR objects. [\#137](https://github.com/swanandp/acts_as_list/issues/137)
- Unexpected behaviour when inserting consecutive items with default positions [\#124](https://github.com/swanandp/acts_as_list/issues/124)
- self.reload prone to error [\#122](https://github.com/swanandp/acts_as_list/issues/122)
- Rails 3.0.x in\_list causes the return of default\_scope [\#120](https://github.com/swanandp/acts_as_list/issues/120)
- Relationships with dependency:destroy cause ActiveRecord::RecordNotFound [\#118](https://github.com/swanandp/acts_as_list/issues/118)
- Using insert\_at with values with type String [\#117](https://github.com/swanandp/acts_as_list/issues/117)
- Batch setting of position [\#112](https://github.com/swanandp/acts_as_list/issues/112)
- position: 0 now makes model pushed to top? [\#110](https://github.com/swanandp/acts_as_list/issues/110)
- Create element in default position [\#103](https://github.com/swanandp/acts_as_list/issues/103)
- Enhancement: Expose scope object [\#97](https://github.com/swanandp/acts_as_list/issues/97)
- Shuffle list [\#96](https://github.com/swanandp/acts_as_list/issues/96)
- Creating an item with a nil scope should not add it to the list [\#92](https://github.com/swanandp/acts_as_list/issues/92)
- Performance Improvements [\#88](https://github.com/swanandp/acts_as_list/issues/88)
- has\_many :through or has\_many\_and\_belongs\_to\_many support [\#86](https://github.com/swanandp/acts_as_list/issues/86)
- move\_higher/move\_lower vs move\_to\_top/move\_to\_bottom act differently when item is already at top or bottom [\#77](https://github.com/swanandp/acts_as_list/issues/77)
- Limiting the list size [\#61](https://github.com/swanandp/acts_as_list/issues/61)
- Adding multiple creates strange ordering [\#55](https://github.com/swanandp/acts_as_list/issues/55)
- Feature: sort [\#26](https://github.com/swanandp/acts_as_list/issues/26)
**Merged pull requests:**
- Fix position when no serial positions [\#208](https://github.com/swanandp/acts_as_list/pull/208) ([PoslinskiNet](https://github.com/PoslinskiNet))
- Removed duplicated assignment [\#207](https://github.com/swanandp/acts_as_list/pull/207) ([shunwen](https://github.com/shunwen))
- Quote all identifiers [\#205](https://github.com/swanandp/acts_as_list/pull/205) ([fabn](https://github.com/fabn))
- Start testing Rails 5 [\#203](https://github.com/swanandp/acts_as_list/pull/203) ([brendon](https://github.com/brendon))
- Lock! the record before destroying [\#201](https://github.com/swanandp/acts_as_list/pull/201) ([brendon](https://github.com/brendon))
- Fix ambiguous column error when joining some relations [\#180](https://github.com/swanandp/acts_as_list/pull/180) ([natw](https://github.com/natw))
## [v0.7.4](https://github.com/swanandp/acts_as_list/tree/v0.7.4) (2016-04-15)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.3...v0.7.4)
**Closed issues:**
- Releasing a new gem version [\#196](https://github.com/swanandp/acts_as_list/issues/196)
**Merged pull requests:**
- Fix scope changed [\#200](https://github.com/swanandp/acts_as_list/pull/200) ([brendon](https://github.com/brendon))
## [v0.7.3](https://github.com/swanandp/acts_as_list/tree/v0.7.3) (2016-04-14)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/v0.7.2...v0.7.3)
## [v0.7.2](https://github.com/swanandp/acts_as_list/tree/v0.7.2) (2016-04-01)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.7.2...v0.7.2)
**Closed issues:**
- DEPRECATION WARNING: Passing string to define callback on Rails 5 beta 3 [\#191](https://github.com/swanandp/acts_as_list/issues/191)
- Why is `add\_to\_list\_bottom` private? [\#187](https://github.com/swanandp/acts_as_list/issues/187)
- Ordering of children when there are two possible parent models. [\#172](https://github.com/swanandp/acts_as_list/issues/172)
- Fix the jruby and rbx builds [\#169](https://github.com/swanandp/acts_as_list/issues/169)
- Unable to run tests [\#162](https://github.com/swanandp/acts_as_list/issues/162)
- shuffle\_positions\_on\_intermediate\_items is creating problems [\#134](https://github.com/swanandp/acts_as_list/issues/134)
- introduce Changelog file to quickly track changes [\#68](https://github.com/swanandp/acts_as_list/issues/68)
- Mongoid support? [\#52](https://github.com/swanandp/acts_as_list/issues/52)
**Merged pull requests:**
- Add filename/line number to class\_eval call [\#193](https://github.com/swanandp/acts_as_list/pull/193) ([hfwang](https://github.com/hfwang))
- Use a symbol as a string to define callback [\#192](https://github.com/swanandp/acts_as_list/pull/192) ([brendon](https://github.com/brendon))
- Pin changelog generator to a working version [\#190](https://github.com/swanandp/acts_as_list/pull/190) ([fabn](https://github.com/fabn))
- Fix bug, position is recomputed when object saved [\#188](https://github.com/swanandp/acts_as_list/pull/188) ([chrisortman](https://github.com/chrisortman))
- Update bundler before running tests, fixes test run on travis [\#179](https://github.com/swanandp/acts_as_list/pull/179) ([fabn](https://github.com/fabn))
- Changelog generator, closes \#68 [\#177](https://github.com/swanandp/acts_as_list/pull/177) ([fabn](https://github.com/fabn))
- Updating README example [\#175](https://github.com/swanandp/acts_as_list/pull/175) ([ryanbillings](https://github.com/ryanbillings))
- Adds description about various options available with the acts\_as\_list method [\#168](https://github.com/swanandp/acts_as_list/pull/168) ([udit7590](https://github.com/udit7590))
- Small changes to DRY up list.rb [\#163](https://github.com/swanandp/acts_as_list/pull/163) ([Albin-Willman](https://github.com/Albin-Willman))
- Only swap changed attributes which are persistable, i.e. are DB columns. [\#152](https://github.com/swanandp/acts_as_list/pull/152) ([ludwigschubert](https://github.com/ludwigschubert))
## [0.7.2](https://github.com/swanandp/acts_as_list/tree/0.7.2) (2015-05-06)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.7.1...0.7.2)
## [0.7.1](https://github.com/swanandp/acts_as_list/tree/0.7.1) (2015-05-06)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.7.0...0.7.1)
**Merged pull requests:**
- Update README.md [\#159](https://github.com/swanandp/acts_as_list/pull/159) ([tibastral](https://github.com/tibastral))
## [0.7.0](https://github.com/swanandp/acts_as_list/tree/0.7.0) (2015-05-01)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.6.0...0.7.0)
**Closed issues:**
- Problem with reordering scoped list items [\#154](https://github.com/swanandp/acts_as_list/issues/154)
- Can no longer load acts\_as\_list in isolation if Rails is installed [\#145](https://github.com/swanandp/acts_as_list/issues/145)
**Merged pull requests:**
- Fix regression with using acts\_as\_list on base classes [\#147](https://github.com/swanandp/acts_as_list/pull/147) ([botandrose](https://github.com/botandrose))
- Don't require rails when loading [\#146](https://github.com/swanandp/acts_as_list/pull/146) ([botandrose](https://github.com/botandrose))
## [0.6.0](https://github.com/swanandp/acts_as_list/tree/0.6.0) (2014-12-24)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.5.0...0.6.0)
**Closed issues:**
- Deprecation Warning: sanitize\_sql\_hash\_for\_conditions is deprecated and will be removed in Rails 5.0 [\#143](https://github.com/swanandp/acts_as_list/issues/143)
- Release a new gem version [\#136](https://github.com/swanandp/acts_as_list/issues/136)
**Merged pull requests:**
- Fix sanitize\_sql\_hash\_for\_conditions deprecation warning in Rails 4.2 [\#140](https://github.com/swanandp/acts_as_list/pull/140) ([eagletmt](https://github.com/eagletmt))
- Simpler method to find the subclass name [\#139](https://github.com/swanandp/acts_as_list/pull/139) ([brendon](https://github.com/brendon))
- Rails4 enum column support [\#130](https://github.com/swanandp/acts_as_list/pull/130) ([arunagw](https://github.com/arunagw))
- use eval for determing the self.class.name useful when this is used in an abstract class [\#123](https://github.com/swanandp/acts_as_list/pull/123) ([flarik](https://github.com/flarik))
## [0.5.0](https://github.com/swanandp/acts_as_list/tree/0.5.0) (2014-10-31)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.4.0...0.5.0)
**Closed issues:**
- I want to have my existing records works like list [\#133](https://github.com/swanandp/acts_as_list/issues/133)
- Add Support For Multiple Indexes [\#127](https://github.com/swanandp/acts_as_list/issues/127)
- changing parent\_id does not update item positions [\#126](https://github.com/swanandp/acts_as_list/issues/126)
- How to exclude objects to be positioned? [\#125](https://github.com/swanandp/acts_as_list/issues/125)
- Scope for Polymorphic association + ManyToMany [\#106](https://github.com/swanandp/acts_as_list/issues/106)
- Bug when use \#insert\_at on an invalid ActiveRecord object [\#99](https://github.com/swanandp/acts_as_list/issues/99)
- has\_many :through with acts as list [\#95](https://github.com/swanandp/acts_as_list/issues/95)
- Update position when scope changes [\#19](https://github.com/swanandp/acts_as_list/issues/19)
**Merged pull requests:**
- Cast column default value to int before comparing with position column [\#129](https://github.com/swanandp/acts_as_list/pull/129) ([wioux](https://github.com/wioux))
- Fix travis builds for rbx [\#128](https://github.com/swanandp/acts_as_list/pull/128) ([meineerde](https://github.com/meineerde))
- Use unscoped blocks instead of chaining [\#121](https://github.com/swanandp/acts_as_list/pull/121) ([brendon](https://github.com/brendon))
- Make acts\_as\_list more compatible with BINARY column [\#116](https://github.com/swanandp/acts_as_list/pull/116) ([sikachu](https://github.com/sikachu))
- Added help notes on non-association scopes [\#115](https://github.com/swanandp/acts_as_list/pull/115) ([VorontsovIE](https://github.com/VorontsovIE))
- Let AR::Base properly lazy-loaded if Railtie is available [\#114](https://github.com/swanandp/acts_as_list/pull/114) ([amatsuda](https://github.com/amatsuda))
## [0.4.0](https://github.com/swanandp/acts_as_list/tree/0.4.0) (2014-02-22)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.3.0...0.4.0)
**Closed issues:**
- insert\_at creates gaps [\#108](https://github.com/swanandp/acts_as_list/issues/108)
- move\_lower and move\_higher not working returning nil [\#57](https://github.com/swanandp/acts_as_list/issues/57)
- Mass-assignment issue with 0.1.8 [\#50](https://github.com/swanandp/acts_as_list/issues/50)
- validates error [\#49](https://github.com/swanandp/acts_as_list/issues/49)
- Ability to move multiple at once [\#40](https://github.com/swanandp/acts_as_list/issues/40)
- Duplicates created when using accepts\_nested\_attributes\_for [\#29](https://github.com/swanandp/acts_as_list/issues/29)
**Merged pull requests:**
- Update README [\#107](https://github.com/swanandp/acts_as_list/pull/107) ([Senjai](https://github.com/Senjai))
- Add license info: license file and gemspec [\#105](https://github.com/swanandp/acts_as_list/pull/105) ([chulkilee](https://github.com/chulkilee))
- Fix top position when position is lower than top position [\#104](https://github.com/swanandp/acts_as_list/pull/104) ([csaura](https://github.com/csaura))
- Get specs running under Rails 4.1.0.beta1 [\#101](https://github.com/swanandp/acts_as_list/pull/101) ([petergoldstein](https://github.com/petergoldstein))
- Add support for JRuby and Rubinius specs [\#100](https://github.com/swanandp/acts_as_list/pull/100) ([petergoldstein](https://github.com/petergoldstein))
- Use the correct syntax for conditions in Rails 4 on the readme. [\#94](https://github.com/swanandp/acts_as_list/pull/94) ([gotjosh](https://github.com/gotjosh))
- Adds `required\_ruby\_version` to gemspec [\#90](https://github.com/swanandp/acts_as_list/pull/90) ([tvdeyen](https://github.com/tvdeyen))
## [0.3.0](https://github.com/swanandp/acts_as_list/tree/0.3.0) (2013-08-02)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.2.0...0.3.0)
**Closed issues:**
- act\_as\_list didn't install with bundle install [\#83](https://github.com/swanandp/acts_as_list/issues/83)
- Cannot update to version 0.1.7 [\#48](https://github.com/swanandp/acts_as_list/issues/48)
- when position is null all new items get inserted in position 1 [\#41](https://github.com/swanandp/acts_as_list/issues/41)
**Merged pull requests:**
- Test against activerecord v3 and v4 [\#82](https://github.com/swanandp/acts_as_list/pull/82) ([sanemat](https://github.com/sanemat))
- Fix check\_scope to work on lists with array scopes [\#81](https://github.com/swanandp/acts_as_list/pull/81) ([conzett](https://github.com/conzett))
- Rails4 compatibility [\#80](https://github.com/swanandp/acts_as_list/pull/80) ([philippfranke](https://github.com/philippfranke))
- Add tests for moving within scope and add method: move\_within\_scope [\#79](https://github.com/swanandp/acts_as_list/pull/79) ([philippfranke](https://github.com/philippfranke))
- Option to not automatically add items to the list [\#72](https://github.com/swanandp/acts_as_list/pull/72) ([forrest](https://github.com/forrest))
## [0.2.0](https://github.com/swanandp/acts_as_list/tree/0.2.0) (2013-02-28)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.9...0.2.0)
**Merged pull requests:**
- Fix update\_all deprecation warnings in Rails 4.0.0.beta1 [\#73](https://github.com/swanandp/acts_as_list/pull/73) ([soffes](https://github.com/soffes))
- Add quotes to Id in SQL requests [\#69](https://github.com/swanandp/acts_as_list/pull/69) ([noefroidevaux](https://github.com/noefroidevaux))
- Update position when scope changes [\#67](https://github.com/swanandp/acts_as_list/pull/67) ([philippfranke](https://github.com/philippfranke))
- add and categorize public instance methods in readme; add misc notes to ... [\#66](https://github.com/swanandp/acts_as_list/pull/66) ([barelyknown](https://github.com/barelyknown))
- Updates \#bottom\_item .find syntax to \>= Rails 3 compatible syntax. [\#65](https://github.com/swanandp/acts_as_list/pull/65) ([tvdeyen](https://github.com/tvdeyen))
- add GitHub Flavored Markdown to README [\#63](https://github.com/swanandp/acts_as_list/pull/63) ([phlipper](https://github.com/phlipper))
## [0.1.9](https://github.com/swanandp/acts_as_list/tree/0.1.9) (2012-12-04)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.8...0.1.9)
**Closed issues:**
- Mysql2 error [\#54](https://github.com/swanandp/acts_as_list/issues/54)
- Use alternative column name? [\#53](https://github.com/swanandp/acts_as_list/issues/53)
**Merged pull requests:**
- attr-accessible can be damaging, is not always necessary. [\#60](https://github.com/swanandp/acts_as_list/pull/60) ([graemeworthy](https://github.com/graemeworthy))
- More reliable lower/higher item detection [\#59](https://github.com/swanandp/acts_as_list/pull/59) ([miks](https://github.com/miks))
- Instructions for using an array with scope [\#58](https://github.com/swanandp/acts_as_list/pull/58) ([zukowski](https://github.com/zukowski))
- Attr accessible patch, should solve \#50 [\#51](https://github.com/swanandp/acts_as_list/pull/51) ([fabn](https://github.com/fabn))
- support accepts\_nested\_attributes\_for multi-destroy [\#46](https://github.com/swanandp/acts_as_list/pull/46) ([saberma](https://github.com/saberma))
## [0.1.8](https://github.com/swanandp/acts_as_list/tree/0.1.8) (2012-08-09)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.7...0.1.8)
## [0.1.7](https://github.com/swanandp/acts_as_list/tree/0.1.7) (2012-08-09)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.6...0.1.7)
**Closed issues:**
- Remove use of update\_attribute [\#44](https://github.com/swanandp/acts_as_list/issues/44)
- Order is reversed when adding multiple rows at once [\#34](https://github.com/swanandp/acts_as_list/issues/34)
**Merged pull requests:**
- Fixed issue with update\_positions that wasn't taking 'scope\_condition' into account [\#47](https://github.com/swanandp/acts_as_list/pull/47) ([bastien](https://github.com/bastien))
- Replaced usage of update\_attribute with update\_attribute! [\#45](https://github.com/swanandp/acts_as_list/pull/45) ([kevmoo](https://github.com/kevmoo))
- use self.class.primary\_key instead of id in shuffle\_positions\_on\_intermediate\_items [\#42](https://github.com/swanandp/acts_as_list/pull/42) ([servercrunch](https://github.com/servercrunch))
- initialize gem [\#39](https://github.com/swanandp/acts_as_list/pull/39) ([megatux](https://github.com/megatux))
- Added ability to set item positions directly \(e.g. In a form\) [\#38](https://github.com/swanandp/acts_as_list/pull/38) ([dubroe](https://github.com/dubroe))
- Prevent SQL error when position\_column is not unique [\#37](https://github.com/swanandp/acts_as_list/pull/37) ([hinrik](https://github.com/hinrik))
- Add installation instructions to README.md [\#35](https://github.com/swanandp/acts_as_list/pull/35) ([mark-rushakoff](https://github.com/mark-rushakoff))
## [0.1.6](https://github.com/swanandp/acts_as_list/tree/0.1.6) (2012-04-19)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.5...0.1.6)
**Closed issues:**
- eval mistakenly resolved the module path [\#32](https://github.com/swanandp/acts_as_list/issues/32)
- Duplicated positions when creating parent and children from scratch in 0.1.5 [\#31](https://github.com/swanandp/acts_as_list/issues/31)
- add info about v0.1.5 require Rails 3 [\#28](https://github.com/swanandp/acts_as_list/issues/28)
- position not updated with move\_higher or move\_lover [\#23](https://github.com/swanandp/acts_as_list/issues/23)
**Merged pull requests:**
- update ActiveRecord class eval to support ActiveSupport on\_load [\#33](https://github.com/swanandp/acts_as_list/pull/33) ([mergulhao](https://github.com/mergulhao))
- Add :add\_new\_at option [\#30](https://github.com/swanandp/acts_as_list/pull/30) ([mjbellantoni](https://github.com/mjbellantoni))
## [0.1.5](https://github.com/swanandp/acts_as_list/tree/0.1.5) (2012-02-24)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.4...0.1.5)
**Closed issues:**
- increment\_positions\_on\_lower\_items called twice on insert\_at with new item [\#21](https://github.com/swanandp/acts_as_list/issues/21)
- Change bundler dependency from ~\>1.0.0 to ~\>1.0 [\#20](https://github.com/swanandp/acts_as_list/issues/20)
- decrement\_positions\_on\_lower\_items method [\#17](https://github.com/swanandp/acts_as_list/issues/17)
- New gem release [\#16](https://github.com/swanandp/acts_as_list/issues/16)
- acts\_as\_list :scope =\> "doesnt\_seem\_to\_work" [\#12](https://github.com/swanandp/acts_as_list/issues/12)
- don't work perfectly with default\_scope [\#11](https://github.com/swanandp/acts_as_list/issues/11)
- MySQL: Position column MUST NOT have default [\#10](https://github.com/swanandp/acts_as_list/issues/10)
- insert\_at fails on postgresql w/ non-null constraint on postion\_column [\#8](https://github.com/swanandp/acts_as_list/issues/8)
**Merged pull requests:**
- Efficiency improvement for insert\_at when repositioning an existing item [\#27](https://github.com/swanandp/acts_as_list/pull/27) ([bradediger](https://github.com/bradediger))
- Use before validate instead of before create [\#25](https://github.com/swanandp/acts_as_list/pull/25) ([webervin](https://github.com/webervin))
- Massive test refactorings. [\#24](https://github.com/swanandp/acts_as_list/pull/24) ([splattael](https://github.com/splattael))
- Silent migrations to reduce test noise. [\#22](https://github.com/swanandp/acts_as_list/pull/22) ([splattael](https://github.com/splattael))
- Should decrement lower items after the item has been destroyed to avoid unique key conflicts. [\#18](https://github.com/swanandp/acts_as_list/pull/18) ([aepstein](https://github.com/aepstein))
- Fix spelling and grammer [\#15](https://github.com/swanandp/acts_as_list/pull/15) ([tmiller](https://github.com/tmiller))
- store\_at\_0 should yank item from the list then decrement items to avoid r [\#14](https://github.com/swanandp/acts_as_list/pull/14) ([aepstein](https://github.com/aepstein))
- Support default\_scope ordering by calling .unscoped [\#13](https://github.com/swanandp/acts_as_list/pull/13) ([tanordheim](https://github.com/tanordheim))
## [0.1.4](https://github.com/swanandp/acts_as_list/tree/0.1.4) (2011-07-27)
[Full Changelog](https://github.com/swanandp/acts_as_list/compare/0.1.3...0.1.4)
**Merged pull requests:**
- Fix sqlite3 dependency [\#7](https://github.com/swanandp/acts_as_list/pull/7) ([joneslee85](https://github.com/joneslee85))
## [0.1.3](https://github.com/swanandp/acts_as_list/tree/0.1.3) (2011-06-10)
**Closed issues:**
- Graph like behaviour [\#5](https://github.com/swanandp/acts_as_list/issues/5)
- Updated Gem? [\#4](https://github.com/swanandp/acts_as_list/issues/4)
**Merged pull requests:**
- Converted into a gem... plus some slight refactors [\#6](https://github.com/swanandp/acts_as_list/pull/6) ([chaffeqa](https://github.com/chaffeqa))
- Fixed test issue for test\_injection: expected SQL was reversed. [\#3](https://github.com/swanandp/acts_as_list/pull/3) ([afriqs](https://github.com/afriqs))
- Added an option to set the top of the position [\#2](https://github.com/swanandp/acts_as_list/pull/2) ([danielcooper](https://github.com/danielcooper))
- minor change to acts\_as\_list's callbacks [\#1](https://github.com/swanandp/acts_as_list/pull/1) ([tiegz](https://github.com/tiegz))
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* ruby-acts-as-list-0.9.15/Gemfile 0000664 0000000 0000000 00000000636 13337530425 0016376 0 ustar 00root root 0000000 0000000 source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gemspec
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
ruby-acts-as-list-0.9.15/MIT-LICENSE 0000664 0000000 0000000 00000002054 13337530425 0016533 0 ustar 00root root 0000000 0000000 Copyright (c) 2007 David Heinemeier Hansson
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
ruby-acts-as-list-0.9.15/README.md 0000664 0000000 0000000 00000021375 13337530425 0016365 0 ustar 00root root 0000000 0000000 # ActsAsList
## Build Status
[](https://secure.travis-ci.org/swanandp/acts_as_list)
## Description
This `acts_as` extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a `position` column defined as an integer on the mapped database table.
## 0.8.0 Upgrade Notes
There are a couple of changes of behaviour from `0.8.0` onwards:
- If you specify `add_new_at: :top`, new items will be added to the top of the list like always. But now, if you specify a position at insert time: `.create(position: 3)`, the position will be respected. In this example, the item will end up at position `3` and will move other items further down the list. Before `0.8.0` the position would be ignored and the item would still be added to the top of the list. [#220](https://github.com/swanandp/acts_as_list/pull/220)
- `acts_as_list` now copes with disparate position integers (i.e. gaps between the numbers). There has been a change in behaviour for the `higher_items` method. It now returns items with the first item in the collection being the closest item to the reference item, and the last item in the collection being the furthest from the reference item (a.k.a. the first item in the list). [#223](https://github.com/swanandp/acts_as_list/pull/223)
## Installation
In your Gemfile:
gem 'acts_as_list'
Or, from the command line:
gem install acts_as_list
## Example
At first, you need to add a `position` column to desired table:
rails g migration AddPositionToTodoItem position:integer
rake db:migrate
After that you can use `acts_as_list` method in the model:
```ruby
class TodoList < ActiveRecord::Base
has_many :todo_items, -> { order(position: :asc) }
end
class TodoItem < ActiveRecord::Base
belongs_to :todo_list
acts_as_list scope: :todo_list
end
todo_list = TodoList.find(...)
todo_list.todo_items.first.move_to_bottom
todo_list.todo_items.last.move_higher
```
## Instance Methods Added To ActiveRecord Models
You'll have a number of methods added to each instance of the ActiveRecord model that to which `acts_as_list` is added.
In `acts_as_list`, "higher" means further up the list (a lower `position`), and "lower" means further down the list (a higher `position`). That can be confusing, so it might make sense to add tests that validate that you're using the right method given your context.
### Methods That Change Position and Reorder List
- `list_item.insert_at(2)`
- `list_item.move_lower` will do nothing if the item is the lowest item
- `list_item.move_higher` will do nothing if the item is the highest item
- `list_item.move_to_bottom`
- `list_item.move_to_top`
- `list_item.remove_from_list`
### Methods That Change Position Without Reordering List
- `list_item.increment_position`
- `list_item.decrement_position`
- `list_item.set_list_position(3)`
### Methods That Return Attributes of the Item's List Position
- `list_item.first?`
- `list_item.last?`
- `list_item.in_list?`
- `list_item.not_in_list?`
- `list_item.default_position?`
- `list_item.higher_item`
- `list_item.higher_items` will return all the items above `list_item` in the list (ordered by the position, ascending)
- `list_item.lower_item`
- `list_item.lower_items` will return all the items below `list_item` in the list (ordered by the position, ascending)
## Adding `acts_as_list` To An Existing Model
As it stands `acts_as_list` requires position values to be set on the model before the instance methods above will work. Adding something like the below to your migration will set the default position. Change the parameters to order if you want a different initial ordering.
```ruby
class AddPositionToTodoItem < ActiveRecord::Migration
def change
add_column :todo_items, :position, :integer
TodoItem.order(:updated_at).each.with_index(1) do |todo_item, index|
todo_item.update_column :position, index
end
end
end
```
If you are using the scope option things can get a bit more complicated. Let's say you have `acts_as_list scope: :todo_list`, you might instead need something like this:
```ruby
TodoList.all.each do |todo_list|
todo_list.todo_items.order(:updated_at).each.with_index(1) do |todo_item, index|
todo_item.update_column :position, index
end
end
```
## Notes
All `position` queries (select, update, etc.) inside gem methods are executed without the default scope (i.e. `Model.unscoped`), this will prevent nasty issues when the default scope is different from `acts_as_list` scope.
The `position` column is set after validations are called, so you should not put a `presence` validation on the `position` column.
If you need a scope by a non-association field you should pass an array, containing field name, to a scope:
```ruby
class TodoItem < ActiveRecord::Base
# `kind` is a plain text field (e.g. 'work', 'shopping', 'meeting'), not an association
acts_as_list scope: [:kind]
end
```
You can also add multiple scopes in this fashion:
```ruby
class TodoItem < ActiveRecord::Base
acts_as_list scope: [:kind, :owner_id]
end
```
Furthermore, you can optionally include a hash of fixed parameters that will be included in all queries:
```ruby
class TodoItem < ActiveRecord::Base
acts_as_list scope: [:kind, :owner_id, deleted_at: nil]
end
```
This is useful when using this gem in conjunction with the popular [acts_as_paranoid](https://github.com/ActsAsParanoid/acts_as_paranoid) gem.
## More Options
- `column`
default: `position`. Use this option if the column name in your database is different from position.
- `top_of_list`
default: `1`. Use this option to define the top of the list. Use 0 to make the collection act more like an array in its indexing.
- `add_new_at`
default: `:bottom`. Use this option to specify whether objects get added to the `:top` or `:bottom` of the list. `nil` will result in new items not being added to the list on create, i.e, position will be kept nil after create.
## Disabling temporarily
If you need to temporarily disable `acts_as_list` during specific operations such as mass-update or imports:
```ruby
TodoItem.acts_as_list_no_update do
perform_mass_update
end
```
In an `acts_as_list_no_update` block, all callbacks are disabled, and positions are not updated. New records will be created with
the default value from the database. It is your responsibility to correctly manage `positions` values.
You can also pass an array of classes as an argument to disable database updates on just those classes. It can be any ActiveRecord class that has acts_as_list enabled.
```ruby
class TodoList < ActiveRecord::Base
has_many :todo_items, -> { order(position: :asc) }
acts_as_list
end
class TodoItem < ActiveRecord::Base
belongs_to :todo_list
has_many :todo_attachments, -> { order(position: :asc) }
acts_as_list scope: :todo_list
end
class TodoAttachment < ActiveRecord::Base
belongs_to :todo_list
acts_as_list scope: :todo_item
end
TodoItem.acts_as_list_no_update([TodoAttachment]) do
TodoItem.find(10).update(position: 2)
TodoAttachment.find(10).update(position: 1)
TodoAttachment.find(11).update(position: 2)
TodoList.find(2).update(position: 3) # For this instance the callbacks will be called because we haven't passed the class as an argument
end
```
## Versions
Version `0.9.0` adds `acts_as_list_no_update` (https://github.com/swanandp/acts_as_list/pull/244) and compatibility with not-null and uniqueness constraints on the database (https://github.com/swanandp/acts_as_list/pull/246). These additions shouldn't break compatibility with existing implementations.
As of version `0.7.5` Rails 5 is supported.
All versions `0.1.5` onwards require Rails 3.0.x and higher.
## Workflow Status
[](http://waffle.io/swanandp/acts_as_list)
## Roadmap
1. Sort based feature
## Contributing to `acts_as_list`
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
- Fork the project
- Start a feature/bugfix branch
- Commit and push until you are happy with your contribution
- Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
- I would recommend using Rails 3.1.x and higher for testing the build before a pull request. The current test harness does not quite work with 3.0.x. The plugin itself works, but the issue lies with testing infrastructure.
## Copyright
Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
ruby-acts-as-list-0.9.15/Rakefile 0000664 0000000 0000000 00000002256 13337530425 0016550 0 ustar 00root root 0000000 0000000 require "rubygems"
require "bundler/setup"
Bundler::GemHelper.install_tasks
require "rake/testtask"
# Run the test with "rake" or "rake test"
desc "Default: run acts_as_list unit tests."
task default: :test
desc "Test the acts_as_list plugin."
Rake::TestTask.new(:test) do |t|
t.libs << "test" << "."
t.test_files = Rake::FileList["test/**/test_*.rb"]
t.verbose = false
end
begin
# Run the rdoc task to generate rdocs for this gem
require "rdoc/task"
RDoc::Task.new do |rdoc|
require "acts_as_list/version"
version = ActiveRecord::Acts::List::VERSION
rdoc.rdoc_dir = "rdoc"
rdoc.title = "acts_as_list #{version}"
rdoc.rdoc_files.include("README*")
rdoc.rdoc_files.include("lib/**/*.rb")
end
rescue LoadError
puts "RDocTask is not supported on this platform."
rescue StandardError
puts "RDocTask is not supported on this platform."
end
# See https://github.com/skywinder/github-changelog-generator#rake-task for details
# and github_changelog_generator --help for available options
require 'github_changelog_generator/task'
GitHubChangelogGenerator::RakeTask.new :changelog do |config|
config.project = 'acts_as_list'
config.user = 'swanandp'
end
ruby-acts-as-list-0.9.15/acts_as_list.gemspec 0000664 0000000 0000000 00000002701 13337530425 0021113 0 ustar 00root root 0000000 0000000 # -*- encoding: utf-8 -*-
$:.push File.expand_path("../lib", __FILE__)
require "acts_as_list/version"
Gem::Specification.new do |s|
# Description Meta...
s.name = "acts_as_list"
s.version = ActiveRecord::Acts::List::VERSION
s.platform = Gem::Platform::RUBY
s.authors = ["David Heinemeier Hansson", "Swanand Pagnis", "Quinn Chaffee"]
s.email = ["swanand.pagnis@gmail.com"]
s.homepage = "http://github.com/swanandp/acts_as_list"
s.summary = "A gem adding sorting, reordering capabilities to an active_record model, allowing it to act as a list"
s.description = 'This "acts_as" extension provides the capabilities for sorting and reordering a number of objects in a list. The class that has this specified needs to have a "position" column defined as an integer on the mapped database table.'
s.license = "MIT"
s.rubyforge_project = "acts_as_list"
s.required_ruby_version = ">= 1.9.2"
# Load Paths...
s.files = `git ls-files`.split("\n")
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
s.require_paths = ["lib"]
# Dependencies (installed via "bundle install")
s.add_dependency "activerecord", ">= 3.0"
s.add_development_dependency "bundler", ">= 1.0.0"
end
ruby-acts-as-list-0.9.15/gemfiles/ 0000775 0000000 0000000 00000000000 13337530425 0016671 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/gemfiles/rails_3_2.gemfile 0000664 0000000 0000000 00000001144 13337530425 0022000 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
gem "activerecord", "~> 3.2.22.2"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
gem "after_commit_exception_notification"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
group :mysql do
gem "mysql2", "~> 0.3.21", platforms: [:ruby]
end
gemspec path: "../"
ruby-acts-as-list-0.9.15/gemfiles/rails_4_1.gemfile 0000664 0000000 0000000 00000001142 13337530425 0021776 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
gem "activerecord", "~> 4.1.16"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
gem "after_commit_exception_notification"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
group :mysql do
gem "mysql2", "~> 0.3.21", platforms: [:ruby]
end
gemspec path: "../"
ruby-acts-as-list-0.9.15/gemfiles/rails_4_2.gemfile 0000664 0000000 0000000 00000001066 13337530425 0022004 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
gem "activerecord", "~> 4.2.10"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gemspec path: "../"
ruby-acts-as-list-0.9.15/gemfiles/rails_5_0.gemfile 0000664 0000000 0000000 00000001065 13337530425 0022002 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
gem "activerecord", "~> 5.0.6"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gemspec path: "../"
ruby-acts-as-list-0.9.15/gemfiles/rails_5_1.gemfile 0000664 0000000 0000000 00000001065 13337530425 0022003 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
gem "activerecord", "~> 5.1.4"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gemspec path: "../"
ruby-acts-as-list-0.9.15/gemfiles/rails_5_2.gemfile 0000664 0000000 0000000 00000001071 13337530425 0022001 0 ustar 00root root 0000000 0000000 # This file was generated by Appraisal
source "http://rubygems.org"
gem "rack", "~> 1", platforms: [:ruby_19, :ruby_20, :ruby_21]
gem "rake"
gem "appraisal"
gem "github_changelog_generator", "1.9.0"
gem "activerecord", "~> 5.2.0.rc1"
group :test do
gem "minitest", "~> 5.0"
gem "test_after_commit", "~> 0.4.2"
gem "timecop"
gem "mocha"
end
group :sqlite do
gem "sqlite3", platforms: [:ruby]
end
group :postgresql do
gem "pg", "~> 0.18.0", platforms: [:ruby]
end
group :mysql do
gem "mysql2", "~> 0.4.10", platforms: [:ruby]
end
gemspec path: "../"
ruby-acts-as-list-0.9.15/init.rb 0000664 0000000 0000000 00000000141 13337530425 0016362 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
$:.unshift "#{File.dirname(__FILE__)}/lib"
require "acts_as_list"
ruby-acts-as-list-0.9.15/lib/ 0000775 0000000 0000000 00000000000 13337530425 0015644 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/lib/acts_as_list.rb 0000664 0000000 0000000 00000001217 13337530425 0020642 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require "acts_as_list/active_record/acts/list"
require "acts_as_list/active_record/acts/position_column_method_definer"
require "acts_as_list/active_record/acts/scope_method_definer"
require "acts_as_list/active_record/acts/top_of_list_method_definer"
require "acts_as_list/active_record/acts/add_new_at_method_definer"
require "acts_as_list/active_record/acts/aux_method_definer"
require "acts_as_list/active_record/acts/callback_definer"
require "acts_as_list/active_record/acts/no_update"
require "acts_as_list/active_record/acts/sequential_updates_method_definer"
require "acts_as_list/active_record/acts/active_record"
ruby-acts-as-list-0.9.15/lib/acts_as_list/ 0000775 0000000 0000000 00000000000 13337530425 0020314 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/ 0000775 0000000 0000000 00000000000 13337530425 0023125 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/ 0000775 0000000 0000000 00000000000 13337530425 0024057 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/active_record.rb 0000664 0000000 0000000 00000000173 13337530425 0027216 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
ActiveSupport.on_load :active_record do
extend ActiveRecord::Acts::List::ClassMethods
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/add_new_at_method_definer.rb 0000664 0000000 0000000 00000000372 13337530425 0031527 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::AddNewAtMethodDefiner #:nodoc:
def self.call(caller_class, add_new_at)
caller_class.class_eval do
define_method :add_new_at do
add_new_at
end
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/aux_method_definer.rb 0000664 0000000 0000000 00000000363 13337530425 0030237 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::AuxMethodDefiner #:nodoc:
def self.call(caller_class)
caller_class.class_eval do
define_method :acts_as_list_class do
caller_class
end
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/callback_definer.rb 0000664 0000000 0000000 00000001444 13337530425 0027637 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::CallbackDefiner #:nodoc:
def self.call(caller_class, add_new_at)
caller_class.class_eval do
before_validation :check_top_position, unless: :act_as_list_no_update?
before_destroy :reload, unless: Proc.new { new_record? || destroyed_via_scope? || act_as_list_no_update? }
after_destroy :decrement_positions_on_lower_items, unless: Proc.new { destroyed_via_scope? || act_as_list_no_update? }
before_update :check_scope, unless: :act_as_list_no_update?
after_update :update_positions, unless: :act_as_list_no_update?
after_commit :clear_scope_changed
if add_new_at.present?
before_create "add_to_list_#{add_new_at}".to_sym, unless: :act_as_list_no_update?
end
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/list.rb 0000664 0000000 0000000 00000046103 13337530425 0025363 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord
module Acts #:nodoc:
module List #:nodoc:
module ClassMethods
# Configuration options are:
#
# * +column+ - specifies the column name to use for keeping the position integer (default: +position+)
# * +scope+ - restricts what is to be considered a list. Given a symbol, it'll attach _id
# (if it hasn't already been added) and use that as the foreign key restriction. It's also possible
# to give it an entire string that is interpolated if you need a tighter scope than just a foreign key.
# Example: acts_as_list scope: 'todo_list_id = #{todo_list_id} AND completed = 0'
# * +top_of_list+ - defines the integer used for the top of the list. Defaults to 1. Use 0 to make the collection
# act more like an array in its indexing.
# * +add_new_at+ - specifies whether objects get added to the :top or :bottom of the list. (default: +bottom+)
# `nil` will result in new items not being added to the list on create.
# * +sequential_updates+ - specifies whether insert_at should update objects positions during shuffling
# one by one to respect position column unique not null constraint.
# Defaults to true if position column has unique index, otherwise false.
# If constraint is deferrable initially deferred, overriding it with false will speed up insert_at.
def acts_as_list(options = {})
configuration = { column: "position", scope: "1 = 1", top_of_list: 1, add_new_at: :bottom }
configuration.update(options) if options.is_a?(Hash)
caller_class = self
ActiveRecord::Acts::List::PositionColumnMethodDefiner.call(caller_class, configuration[:column])
ActiveRecord::Acts::List::ScopeMethodDefiner.call(caller_class, configuration[:scope])
ActiveRecord::Acts::List::TopOfListMethodDefiner.call(caller_class, configuration[:top_of_list])
ActiveRecord::Acts::List::AddNewAtMethodDefiner.call(caller_class, configuration[:add_new_at])
ActiveRecord::Acts::List::AuxMethodDefiner.call(caller_class)
ActiveRecord::Acts::List::CallbackDefiner.call(caller_class, configuration[:add_new_at])
ActiveRecord::Acts::List::SequentialUpdatesMethodDefiner.call(caller_class, configuration[:column], configuration[:sequential_updates])
include ActiveRecord::Acts::List::InstanceMethods
include ActiveRecord::Acts::List::NoUpdate
end
# This +acts_as+ extension provides the capabilities for sorting and reordering a number of objects in a list.
# The class that has this specified needs to have a +position+ column defined as an integer on
# the mapped database table.
#
# Todo list example:
#
# class TodoList < ActiveRecord::Base
# has_many :todo_items, order: "position"
# end
#
# class TodoItem < ActiveRecord::Base
# belongs_to :todo_list
# acts_as_list scope: :todo_list
# end
#
# todo_list.first.move_to_bottom
# todo_list.last.move_higher
# All the methods available to a record that has had acts_as_list specified. Each method works
# by assuming the object to be the item in the list, so chapter.move_lower would move that chapter
# lower in the list of all chapters. Likewise, chapter.first? would return +true+ if that chapter is
# the first in the list of all chapters.
end
module InstanceMethods
# Insert the item at the given position (defaults to the top position of 1).
def insert_at(position = acts_as_list_top)
insert_at_position(position)
end
def insert_at!(position = acts_as_list_top)
insert_at_position(position, true)
end
# Swap positions with the next lower item, if one exists.
def move_lower
return unless lower_item
acts_as_list_class.transaction do
if lower_item.send(position_column) != self.send(position_column)
swap_positions(lower_item, self)
else
lower_item.decrement_position
increment_position
end
end
end
# Swap positions with the next higher item, if one exists.
def move_higher
return unless higher_item
acts_as_list_class.transaction do
if higher_item.send(position_column) != self.send(position_column)
swap_positions(higher_item, self)
else
higher_item.increment_position
decrement_position
end
end
end
# Move to the bottom of the list. If the item is already in the list, the items below it have their
# position adjusted accordingly.
def move_to_bottom
return unless in_list?
acts_as_list_class.transaction do
decrement_positions_on_lower_items
assume_bottom_position
end
end
# Move to the top of the list. If the item is already in the list, the items above it have their
# position adjusted accordingly.
def move_to_top
return unless in_list?
acts_as_list_class.transaction do
increment_positions_on_higher_items
assume_top_position
end
end
# Removes the item from the list.
def remove_from_list
if in_list?
decrement_positions_on_lower_items
set_list_position(nil)
end
end
# Move the item within scope. If a position within the new scope isn't supplied, the item will
# be appended to the end of the list.
def move_within_scope(scope_id)
send("#{scope_name}=", scope_id)
save!
end
# Increase the position of this item without adjusting the rest of the list.
def increment_position
return unless in_list?
set_list_position(self.send(position_column).to_i + 1)
end
# Decrease the position of this item without adjusting the rest of the list.
def decrement_position
return unless in_list?
set_list_position(self.send(position_column).to_i - 1)
end
def first?
return false unless in_list?
!higher_items(1).exists?
end
def last?
return false unless in_list?
!lower_items(1).exists?
end
# Return the next higher item in the list.
def higher_item
return nil unless in_list?
higher_items(1).first
end
# Return the next n higher items in the list
# selects all higher items by default
def higher_items(limit=nil)
limit ||= acts_as_list_list.count
position_value = send(position_column)
acts_as_list_list.
where("#{quoted_position_column_with_table_name} <= ?", position_value).
where("#{quoted_table_name}.#{self.class.primary_key} != ?", self.send(self.class.primary_key)).
reorder(acts_as_list_order_argument(:desc)).
limit(limit)
end
# Return the next lower item in the list.
def lower_item
return nil unless in_list?
lower_items(1).first
end
# Return the next n lower items in the list
# selects all lower items by default
def lower_items(limit=nil)
limit ||= acts_as_list_list.count
position_value = send(position_column)
acts_as_list_list.
where("#{quoted_position_column_with_table_name} >= ?", position_value).
where("#{quoted_table_name}.#{self.class.primary_key} != ?", self.send(self.class.primary_key)).
reorder(acts_as_list_order_argument(:asc)).
limit(limit)
end
# Test if this record is in a list
def in_list?
!not_in_list?
end
def not_in_list?
send(position_column).nil?
end
def default_position
acts_as_list_class.columns_hash[position_column.to_s].default
end
def default_position?
default_position && default_position.to_i == send(position_column)
end
# Sets the new position and saves it
def set_list_position(new_position, raise_exception_if_save_fails=false)
write_attribute position_column, new_position
raise_exception_if_save_fails ? save! : save
end
private
def swap_positions(item1, item2)
item1_position = item1.send(position_column)
item1.set_list_position(item2.send(position_column))
item2.set_list_position(item1_position)
end
def acts_as_list_list
if ActiveRecord::VERSION::MAJOR < 4
acts_as_list_class.unscoped do
acts_as_list_class.where(scope_condition)
end
else
acts_as_list_class.unscope(:where).where(scope_condition)
end
end
# Poorly named methods. They will insert the item at the desired position if the position
# has been set manually using position=, not necessarily the top or bottom of the list:
def add_to_list_top
if assume_default_position?
increment_positions_on_all_items
self[position_column] = acts_as_list_top
else
increment_positions_on_lower_items(self[position_column], id)
end
# Make sure we know that we've processed this scope change already
@scope_changed = false
# Don't halt the callback chain
true
end
def add_to_list_bottom
if assume_default_position?
self[position_column] = bottom_position_in_list.to_i + 1
else
increment_positions_on_lower_items(self[position_column], id)
end
# Make sure we know that we've processed this scope change already
@scope_changed = false
# Don't halt the callback chain
true
end
def assume_default_position?
not_in_list? ||
persisted? && internal_scope_changed? && !position_changed ||
default_position?
end
# Overwrite this method to define the scope of the list changes
def scope_condition() {} end
# Returns the bottom position number in the list.
# bottom_position_in_list # => 2
def bottom_position_in_list(except = nil)
item = bottom_item(except)
item ? item.send(position_column) : acts_as_list_top - 1
end
# Returns the bottom item
def bottom_item(except = nil)
scope = acts_as_list_list
if except
scope = scope.where("#{quoted_table_name}.#{self.class.primary_key} != ?", except.id)
end
scope.in_list.reorder(acts_as_list_order_argument(:desc)).first
end
# Forces item to assume the bottom position in the list.
def assume_bottom_position
set_list_position(bottom_position_in_list(self).to_i + 1)
end
# Forces item to assume the top position in the list.
def assume_top_position
set_list_position(acts_as_list_top)
end
# This has the effect of moving all the higher items down one.
def increment_positions_on_higher_items
return unless in_list?
acts_as_list_list.where("#{quoted_position_column_with_table_name} < ?", send(position_column).to_i).increment_all
end
# This has the effect of moving all the lower items down one.
def increment_positions_on_lower_items(position, avoid_id = nil)
scope = acts_as_list_list
if avoid_id
scope = scope.where("#{quoted_table_name}.#{self.class.primary_key} != ?", avoid_id)
end
scope.where("#{quoted_position_column_with_table_name} >= ?", position).increment_all
end
# This has the effect of moving all the higher items up one.
def decrement_positions_on_higher_items(position)
acts_as_list_list.where("#{quoted_position_column_with_table_name} <= ?", position).decrement_all
end
# This has the effect of moving all the lower items up one.
def decrement_positions_on_lower_items(position=nil)
return unless in_list?
position ||= send(position_column).to_i
if sequential_updates?
acts_as_list_list.where("#{quoted_position_column_with_table_name} > ?", position).reorder(acts_as_list_order_argument(:asc)).each do |item|
item.decrement!(position_column)
end
else
acts_as_list_list.where("#{quoted_position_column_with_table_name} > ?", position).decrement_all
end
end
# Increments position (position_column) of all items in the list.
def increment_positions_on_all_items
acts_as_list_list.increment_all
end
# Reorders intermediate items to support moving an item from old_position to new_position.
# unique constraint prevents regular increment_all and forces to do increments one by one
# http://stackoverflow.com/questions/7703196/sqlite-increment-unique-integer-field
# both SQLite and PostgreSQL (and most probably MySQL too) has same issue
# that's why *sequential_updates?* check alters implementation behavior
def shuffle_positions_on_intermediate_items(old_position, new_position, avoid_id = nil)
return if old_position == new_position
scope = acts_as_list_list
if avoid_id
scope = scope.where("#{quoted_table_name}.#{self.class.primary_key} != ?", avoid_id)
end
if old_position < new_position
# Decrement position of intermediate items
#
# e.g., if moving an item from 2 to 5,
# move [3, 4, 5] to [2, 3, 4]
items = scope.where(
"#{quoted_position_column_with_table_name} > ?", old_position
).where(
"#{quoted_position_column_with_table_name} <= ?", new_position
)
if sequential_updates?
items.reorder(acts_as_list_order_argument(:asc)).each do |item|
item.decrement!(position_column)
end
else
items.decrement_all
end
else
# Increment position of intermediate items
#
# e.g., if moving an item from 5 to 2,
# move [2, 3, 4] to [3, 4, 5]
items = scope.where(
"#{quoted_position_column_with_table_name} >= ?", new_position
).where(
"#{quoted_position_column_with_table_name} < ?", old_position
)
if sequential_updates?
items.reorder(acts_as_list_order_argument(:desc)).each do |item|
item.increment!(position_column)
end
else
items.increment_all
end
end
end
def insert_at_position(position, raise_exception_if_save_fails=false)
return set_list_position(position, raise_exception_if_save_fails) if new_record?
with_lock do
if in_list?
old_position = send(position_column).to_i
return if position == old_position
# temporary move after bottom with gap, avoiding duplicate values
# gap is required to leave room for position increments
# positive number will be valid with unique not null check (>= 0) db constraint
temporary_position = bottom_position_in_list + 2
set_list_position(temporary_position, raise_exception_if_save_fails)
shuffle_positions_on_intermediate_items(old_position, position, id)
else
increment_positions_on_lower_items(position)
end
set_list_position(position, raise_exception_if_save_fails)
end
end
def update_positions
return unless position_before_save_changed?
old_position = position_before_save || bottom_position_in_list + 1
new_position = send(position_column).to_i
return unless acts_as_list_list.where(
"#{quoted_position_column_with_table_name} = #{new_position}"
).count > 1
shuffle_positions_on_intermediate_items old_position, new_position, id
end
def position_before_save_changed?
if ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR >= 1 ||
ActiveRecord::VERSION::MAJOR > 5
saved_change_to_attribute? position_column
else
send "#{position_column}_changed?"
end
end
def position_before_save
if ActiveRecord::VERSION::MAJOR == 5 && ActiveRecord::VERSION::MINOR >= 1 ||
ActiveRecord::VERSION::MAJOR > 5
attribute_before_last_save position_column
else
send "#{position_column}_was"
end
end
def internal_scope_changed?
return @scope_changed if defined?(@scope_changed)
@scope_changed = scope_changed?
end
def clear_scope_changed
remove_instance_variable(:@scope_changed) if defined?(@scope_changed)
end
def check_scope
if internal_scope_changed?
cached_changes = changes
cached_changes.each { |attribute, values| send("#{attribute}=", values[0]) }
send('decrement_positions_on_lower_items') if lower_item
cached_changes.each { |attribute, values| send("#{attribute}=", values[1]) }
send("add_to_list_#{add_new_at}") if add_new_at.present?
end
end
# This check is skipped if the position is currently the default position from the table
# as modifying the default position on creation is handled elsewhere
def check_top_position
if send(position_column) && !default_position? && send(position_column) < acts_as_list_top
self[position_column] = acts_as_list_top
end
end
# When using raw column name it must be quoted otherwise it can raise syntax errors with SQL keywords (e.g. order)
def quoted_position_column
@_quoted_position_column ||= self.class.connection.quote_column_name(position_column)
end
# Used in order clauses
def quoted_table_name
@_quoted_table_name ||= acts_as_list_class.quoted_table_name
end
def quoted_position_column_with_table_name
@_quoted_position_column_with_table_name ||= "#{quoted_table_name}.#{quoted_position_column}"
end
def acts_as_list_order_argument(direction = :asc)
if ActiveRecord::VERSION::MAJOR >= 4
{ position_column => direction }
else
"#{quoted_position_column_with_table_name} #{direction.to_s.upcase}"
end
end
end
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/no_update.rb 0000664 0000000 0000000 00000006566 13337530425 0026377 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord
module Acts
module List
module NoUpdate
def self.included(base)
base.extend ClassMethods
end
class ArrayTypeError < ArgumentError
def initialize
super("The first argument must be an array")
end
end
class DisparityClassesError < ArgumentError
def initialize
super("The first argument should contain ActiveRecord or ApplicationRecord classes")
end
end
module ClassMethods
# Lets you selectively disable all act_as_list database updates
# for the duration of a block.
#
# ==== Examples
#
# class TodoList < ActiveRecord::Base
# has_many :todo_items, -> { order(position: :asc) }
# end
#
# class TodoItem < ActiveRecord::Base
# belongs_to :todo_list
#
# acts_as_list scope: :todo_list
# end
#
# TodoItem.acts_as_list_no_update do
# TodoList.first.update(position: 2)
# end
#
# You can also pass an array of classes as an argument to disable database updates on just those classes.
# It can be any ActiveRecord class that has acts_as_list enabled.
#
# ==== Examples
#
# class TodoList < ActiveRecord::Base
# has_many :todo_items, -> { order(position: :asc) }
# acts_as_list
# end
#
# class TodoItem < ActiveRecord::Base
# belongs_to :todo_list
# has_many :todo_attachments, -> { order(position: :asc) }
#
# acts_as_list scope: :todo_list
# end
#
# class TodoAttachment < ActiveRecord::Base
# belongs_to :todo_list
# acts_as_list scope: :todo_item
# end
#
# TodoItem.acts_as_list_no_update([TodoAttachment]) do
# TodoItem.find(10).update(position: 2)
# TodoAttachment.find(10).update(position: 1)
# TodoAttachment.find(11).update(position: 2)
# TodoList.find(2).update(position: 3) # For this instance the callbacks will be called because we haven't passed the class as an argument
# end
def acts_as_list_no_update(extra_classes = [], &block)
return raise ArrayTypeError unless extra_classes.is_a?(Array)
extra_classes << self
return raise DisparityClassesError unless active_record_objects?(extra_classes)
NoUpdate.apply_to(extra_classes, &block)
end
private
def active_record_objects?(extra_classes)
extra_classes.all? { |klass| klass.ancestors.include? ActiveRecord::Base }
end
end
class << self
def apply_to(klasses)
extracted_klasses.push(*klasses)
yield
ensure
extracted_klasses.clear
end
def applied_to?(klass)
!(klass.ancestors & extracted_klasses).empty?
end
private
def extracted_klasses
Thread.current[:act_as_list_no_update] ||= []
end
end
def act_as_list_no_update?
NoUpdate.applied_to?(self.class)
end
end
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/position_column_method_definer.rb 0000664 0000000 0000000 00000005176 13337530425 0032672 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::PositionColumnMethodDefiner #:nodoc:
def self.call(caller_class, position_column)
define_class_methods(caller_class, position_column)
define_instance_methods(caller_class, position_column)
if mass_assignment_protection_was_used_by_user?(caller_class)
protect_attributes_from_mass_assignment(caller_class, position_column)
end
end
private
def self.define_class_methods(caller_class, position_column)
caller_class.class_eval do
define_singleton_method :quoted_position_column do
@_quoted_position_column ||= connection.quote_column_name(position_column)
end
define_singleton_method :quoted_position_column_with_table_name do
@_quoted_position_column_with_table_name ||= "#{caller_class.quoted_table_name}.#{quoted_position_column}"
end
define_singleton_method :decrement_all do
update_all_with_touch "#{quoted_position_column} = (#{quoted_position_column_with_table_name} - 1)"
end
define_singleton_method :increment_all do
update_all_with_touch "#{quoted_position_column} = (#{quoted_position_column_with_table_name} + 1)"
end
define_singleton_method :update_all_with_touch do |updates|
update_all(updates + touch_record_sql)
end
private
define_singleton_method :touch_record_sql do
new.touch_record_sql
end
end
end
def self.define_instance_methods(caller_class, position_column)
caller_class.class_eval do
attr_reader :position_changed
define_method :position_column do
position_column
end
define_method :"#{position_column}=" do |position|
write_attribute(position_column, position)
@position_changed = true
end
define_method :touch_record_sql do
cached_quoted_now = quoted_current_time_from_proper_timezone
timestamp_attributes_for_update_in_model.map do |attr|
", #{connection.quote_column_name(attr)} = #{cached_quoted_now}"
end.join
end
private
delegate :connection, to: self
def quoted_current_time_from_proper_timezone
connection.quote(connection.quoted_date(
current_time_from_proper_timezone))
end
end
end
def self.mass_assignment_protection_was_used_by_user?(caller_class)
caller_class.class_eval do
respond_to?(:accessible_attributes) and accessible_attributes.present?
end
end
def self.protect_attributes_from_mass_assignment(caller_class, position_column)
caller_class.class_eval do
attr_accessible position_column.to_sym
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/scope_method_definer.rb 0000664 0000000 0000000 00000004276 13337530425 0030562 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::ScopeMethodDefiner #:nodoc:
extend ActiveSupport::Inflector
def self.call(caller_class, scope)
scope = idify(scope) if scope.is_a?(Symbol)
caller_class.class_eval do
define_method :scope_name do
scope
end
if scope.is_a?(Symbol)
define_method :scope_condition do
{ scope => send(:"#{scope}") }
end
define_method :scope_changed? do
changed.include?(scope_name.to_s)
end
define_method :destroyed_via_scope? do
return false if ActiveRecord::VERSION::MAJOR < 4
scope == (destroyed_by_association && destroyed_by_association.foreign_key.to_sym)
end
elsif scope.is_a?(Array)
define_method :scope_condition do
# The elements of the Array can be symbols, strings, or hashes.
# If symbols or strings, they are treated as column names and the current value is looked up.
# If hashes, they are treated as fixed values.
scope.inject({}) do |hash, column_or_fixed_vals|
if column_or_fixed_vals.is_a?(Hash)
fixed_vals = column_or_fixed_vals
hash.merge!(fixed_vals)
else
column = column_or_fixed_vals
hash.merge!({ column.to_sym => read_attribute(column.to_sym) })
end
end
end
define_method :scope_changed? do
(scope_condition.keys & changed.map(&:to_sym)).any?
end
define_method :destroyed_via_scope? do
return false if ActiveRecord::VERSION::MAJOR < 4
scope_condition.keys.include? (destroyed_by_association && destroyed_by_association.foreign_key.to_sym)
end
else
define_method :scope_condition do
eval "%{#{scope}}"
end
define_method :scope_changed? do
false
end
define_method :destroyed_via_scope? do
false
end
end
self.scope :in_list, lambda { where("#{quoted_position_column_with_table_name} IS NOT NULL") }
end
end
def self.idify(name)
return name if name.to_s =~ /_id$/
foreign_key(name).to_sym
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/sequential_updates_method_definer.rb 0000664 0000000 0000000 00000001740 13337530425 0033341 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::SequentialUpdatesMethodDefiner #:nodoc:
def self.call(caller_class, column, sequential_updates_option)
caller_class.class_eval do
define_method :sequential_updates? do
if !defined?(@sequential_updates)
if sequential_updates_option.nil?
table_exists =
if ActiveRecord::VERSION::MAJOR >= 5
caller_class.connection.data_source_exists?(caller_class.table_name)
else
caller_class.connection.table_exists?(caller_class.table_name)
end
index_exists = caller_class.connection.index_exists?(caller_class.table_name, column, unique: true)
@sequential_updates = table_exists && index_exists
else
@sequential_updates = sequential_updates_option
end
else
@sequential_updates
end
end
private :sequential_updates?
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/active_record/acts/top_of_list_method_definer.rb 0000664 0000000 0000000 00000000537 13337530425 0031766 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord::Acts::List::TopOfListMethodDefiner #:nodoc:
def self.call(caller_class, top_of_list)
caller_class.class_eval do
define_singleton_method :acts_as_list_top do
top_of_list.to_i
end
define_method :acts_as_list_top do
top_of_list.to_i
end
end
end
end
ruby-acts-as-list-0.9.15/lib/acts_as_list/version.rb 0000664 0000000 0000000 00000000174 13337530425 0022330 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module ActiveRecord
module Acts
module List
VERSION = '0.9.15'
end
end
end
ruby-acts-as-list-0.9.15/test/ 0000775 0000000 0000000 00000000000 13337530425 0016055 5 ustar 00root root 0000000 0000000 ruby-acts-as-list-0.9.15/test/database.yml 0000664 0000000 0000000 00000000421 13337530425 0020341 0 ustar 00root root 0000000 0000000 sqlite:
adapter: sqlite3
database: "file:memdb1?mode=memory&cache=shared"
mysql:
adapter: mysql2
username: root
password:
database: acts_as_list
postgresql:
adapter: postgresql
username: postgres
password:
database: acts_as_list
min_messages: ERROR
ruby-acts-as-list-0.9.15/test/helper.rb 0000664 0000000 0000000 00000002737 13337530425 0017672 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
# $DEBUG = true
require "rubygems"
require "bundler/setup"
begin
Bundler.setup(:default, :development)
rescue Bundler::BundlerError => e
$stderr.puts e.message
$stderr.puts "Run `bundle install` to install missing gems"
exit e.status_code
end
require "active_record"
require "minitest/autorun"
require "mocha/minitest"
require "#{File.dirname(__FILE__)}/../init"
if defined?(ActiveRecord::VERSION) &&
ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR >= 2
# Was removed in Rails 5 and is effectively true.
ActiveRecord::Base.raise_in_transactional_callbacks = true
end
db_config = YAML.load_file(File.expand_path("../database.yml", __FILE__)).fetch(ENV["DB"] || "sqlite")
ActiveRecord::Base.establish_connection(db_config)
ActiveRecord::Schema.verbose = false
# Returns true if ActiveRecord is rails 3, 4 version
def rails_3
defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 3
end
def rails_4
defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::MAJOR >= 4
end
def teardown_db
if ActiveRecord::VERSION::MAJOR >= 5
tables = ActiveRecord::Base.connection.data_sources
else
tables = ActiveRecord::Base.connection.tables
end
tables.each do |table|
ActiveRecord::Base.connection.drop_table(table)
end
end
require "shared"
# require 'logger'
# ActiveRecord::Base.logger = Logger.new(STDOUT)
def assert_equal_or_nil(a, b)
if a.nil?
assert_nil b
else
assert_equal a, b
end
end
ruby-acts-as-list-0.9.15/test/shared.rb 0000664 0000000 0000000 00000000632 13337530425 0017651 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
# Common shared behaviour.
module Shared
autoload :List, 'shared_list'
autoload :ListSub, 'shared_list_sub'
autoload :ZeroBased, 'shared_zero_based'
autoload :ArrayScopeList, 'shared_array_scope_list'
autoload :TopAddition, 'shared_top_addition'
autoload :NoAddition, 'shared_no_addition'
autoload :Quoting, 'shared_quoting'
end
ruby-acts-as-list-0.9.15/test/shared_array_scope_list.rb 0000664 0000000 0000000 00000016471 13337530425 0023303 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module ArrayScopeList
def setup
(1..4).each { |counter| ArrayScopeListMixin.create! pos: counter, parent_id: 5, parent_type: 'ParentClass' }
(1..4).each { |counter| ArrayScopeListMixin.create! pos: counter, parent_id: 6, parent_type: 'ParentClass' }
end
def test_reordering
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 4).first.insert_at(4)
assert_equal [1, 3, 2, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:pos)
end
def test_move_to_bottom_with_next_to_last_item
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 3).first.move_to_bottom
assert_equal [1, 2, 4, 3], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
end
def test_next_prev
assert_equal ArrayScopeListMixin.where(id: 2).first, ArrayScopeListMixin.where(id: 1).first.lower_item
assert_nil ArrayScopeListMixin.where(id: 1).first.higher_item
assert_equal ArrayScopeListMixin.where(id: 3).first, ArrayScopeListMixin.where(id: 4).first.higher_item
assert_nil ArrayScopeListMixin.where(id: 4).first.lower_item
end
def test_injection
item = ArrayScopeListMixin.new(parent_id: 1, parent_type: 'ParentClass')
assert_equal "pos", item.position_column
end
def test_insert
new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 1, new.pos
assert new.first?
assert new.last?
new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 2, new.pos
assert !new.first?
assert new.last?
new = ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass') }
assert_equal_or_nil $default_position,new.pos
assert_equal $default_position.is_a?(Integer), new.first?
assert !new.last?
new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 3, new.pos
assert !new.first?
assert new.last?
new = ArrayScopeListMixin.create(parent_id: 0, parent_type: 'ParentClass')
assert_equal 1, new.pos
assert new.first?
assert new.last?
end
def test_insert_at
new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 1, new.pos
new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 2, new.pos
new = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 3, new.pos
new_noup = ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass') }
assert_equal_or_nil $default_position,new_noup.pos
new4 = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 4, new4.pos
new4.insert_at(3)
assert_equal 3, new4.pos
new.reload
assert_equal 4, new.pos
new.insert_at(2)
assert_equal 2, new.pos
new4.reload
assert_equal 4, new4.pos
new5 = ArrayScopeListMixin.create(parent_id: 20, parent_type: 'ParentClass')
assert_equal 5, new5.pos
new5.insert_at(1)
assert_equal 1, new5.pos
new4.reload
assert_equal 5, new4.pos
new_noup.reload
assert_equal_or_nil $default_position, new_noup.pos
end
def test_delete_middle
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 2).first.destroy
assert_equal [1, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
assert_equal 1, ArrayScopeListMixin.where(id: 1).first.pos
assert_equal 2, ArrayScopeListMixin.where(id: 3).first.pos
assert_equal 3, ArrayScopeListMixin.where(id: 4).first.pos
ArrayScopeListMixin.where(id: 1).first.destroy
assert_equal [3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
assert_equal 1, ArrayScopeListMixin.where(id: 3).first.pos
assert_equal 2, ArrayScopeListMixin.where(id: 4).first.pos
ArrayScopeListMixin.acts_as_list_no_update { ArrayScopeListMixin.where(id: 3).first.destroy }
assert_equal [4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
assert_equal 2, ArrayScopeListMixin.where(id: 4).first.pos
end
def test_remove_from_list_should_then_fail_in_list?
assert_equal true, ArrayScopeListMixin.where(id: 1).first.in_list?
ArrayScopeListMixin.where(id: 1).first.remove_from_list
assert_equal false, ArrayScopeListMixin.where(id: 1).first.in_list?
end
def test_remove_from_list_should_set_position_to_nil
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 2).first.remove_from_list
assert_equal 1, ArrayScopeListMixin.where(id: 1).first.pos
assert_nil ArrayScopeListMixin.where(id: 2).first.pos
assert_equal 2, ArrayScopeListMixin.where(id: 3).first.pos
assert_equal 3, ArrayScopeListMixin.where(id: 4).first.pos
end
def test_remove_before_destroy_does_not_shift_lower_items_twice
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
ArrayScopeListMixin.where(id: 2).first.remove_from_list
ArrayScopeListMixin.where(id: 2).first.destroy
assert_equal [1, 3, 4], ArrayScopeListMixin.where(parent_id: 5, parent_type: 'ParentClass').order('pos').map(&:id)
assert_equal 1, ArrayScopeListMixin.where(id: 1).first.pos
assert_equal 2, ArrayScopeListMixin.where(id: 3).first.pos
assert_equal 3, ArrayScopeListMixin.where(id: 4).first.pos
end
end
end
ruby-acts-as-list-0.9.15/test/shared_list.rb 0000664 0000000 0000000 00000024367 13337530425 0020717 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module List
def setup
(1..4).each do |counter|
node = ListMixin.new parent_id: 5
node.pos = counter
node.save!
end
end
def test_reordering
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], ListMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_move_to_bottom_with_next_to_last_item
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 3).first.move_to_bottom
assert_equal [1, 2, 4, 3], ListMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_next_prev
assert_equal ListMixin.where(id: 2).first, ListMixin.where(id: 1).first.lower_item
assert_nil ListMixin.where(id: 1).first.higher_item
assert_equal ListMixin.where(id: 3).first, ListMixin.where(id: 4).first.higher_item
assert_nil ListMixin.where(id: 4).first.lower_item
end
def test_injection
item = ListMixin.new(parent_id: 1)
assert_equal({ parent_id: 1 }, item.scope_condition)
assert_equal "pos", item.position_column
end
def test_insert
new = ListMixin.create(parent_id: 20)
assert_equal 1, new.pos
assert new.first?
assert new.last?
new = ListMixin.create(parent_id: 20)
assert_equal 2, new.pos
assert !new.first?
assert new.last?
new = ListMixin.acts_as_list_no_update { ListMixin.create(parent_id: 20) }
assert_equal_or_nil $default_position, new.pos
assert_equal $default_position.is_a?(Integer), new.first?
assert !new.last?
new = ListMixin.create(parent_id: 20)
assert_equal 3, new.pos
assert !new.first?
assert new.last?
new = ListMixin.create(parent_id: 0)
assert_equal 1, new.pos
assert new.first?
assert new.last?
end
def test_insert_at
new = ListMixin.create(parent_id: 20)
assert_equal 1, new.pos
new = ListMixin.create(parent_id: 20)
assert_equal 2, new.pos
new = ListMixin.create(parent_id: 20)
assert_equal 3, new.pos
new_noup = ListMixin.acts_as_list_no_update { ListMixin.create(parent_id: 20) }
assert_equal_or_nil $default_position, new_noup.pos
new4 = ListMixin.create(parent_id: 20)
assert_equal 4, new4.pos
new4.insert_at(3)
assert_equal 3, new4.pos
new.reload
assert_equal 4, new.pos
new.insert_at(2)
assert_equal 2, new.pos
new4.reload
assert_equal 4, new4.pos
new5 = ListMixin.create(parent_id: 20)
assert_equal 5, new5.pos
new5.insert_at(1)
assert_equal 1, new5.pos
new4.reload
assert_equal 5, new4.pos
new_noup.reload
assert_equal_or_nil $default_position, new_noup.pos
last1 = ListMixin.where('pos IS NOT NULL').order('pos').last
last2 = ListMixin.where('pos IS NOT NULL').order('pos').last
last1.insert_at(1)
last2.insert_at(1)
pos_list = ListMixin.where(parent_id: 20).order("pos ASC#{' NULLS FIRST' if ENV['DB'] == 'postgresql'}").map(&:pos)
assert_equal [$default_position, 1, 2, 3, 4, 5], pos_list
end
def test_insert_at_after_dup
new1 = ListMixin.create(parent_id: 20)
new2 = ListMixin.create(parent_id: 20)
new3 = ListMixin.create(parent_id: 20)
duped = new1.dup
duped.save
[new1, new2, new3, duped].map(&:reload)
assert_equal [1, 2, 3, 4], [duped.pos, new1.pos, new2.pos, new3.pos]
end
def test_delete_middle
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.destroy
assert_equal [1, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 1).first.pos
assert_equal 2, ListMixin.where(id: 3).first.pos
assert_equal 3, ListMixin.where(id: 4).first.pos
ListMixin.where(id: 1).first.destroy
assert_equal [3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 3).first.pos
assert_equal 2, ListMixin.where(id: 4).first.pos
ListMixin.acts_as_list_no_update { ListMixin.where(id: 3).first.destroy }
assert_equal [4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 2, ListMixin.where(id: 4).first.pos
end
def test_with_string_based_scope
new = ListWithStringScopeMixin.create(parent_id: 500)
assert_equal 1, new.pos
assert new.first?
assert new.last?
end
def test_nil_scope
new1, new2, new3 = ListMixin.create, ListMixin.create, ListMixin.create
new2.move_higher
assert_equal [new2, new1, new3].map(&:id), ListMixin.where(parent_id: nil).order('pos').map(&:id)
end
def test_update_position_when_scope_changes
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.create(parent_id: 6)
ListMixin.where(id: 2).first.move_within_scope(6)
assert_equal 2, ListMixin.where(id: 2).first.pos
assert_equal [1, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 1).first.pos
assert_equal 2, ListMixin.where(id: 3).first.pos
assert_equal 3, ListMixin.where(id: 4).first.pos
ListMixin.where(id: 2).first.move_within_scope(5)
assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_remove_from_list_should_then_fail_in_list?
assert_equal true, ListMixin.where(id: 1).first.in_list?
ListMixin.where(id: 1).first.remove_from_list
assert_equal false, ListMixin.where(id: 1).first.in_list?
end
def test_remove_from_list_should_set_position_to_nil
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.remove_from_list
assert_equal 1, ListMixin.where(id: 1).first.pos
assert_nil ListMixin.where(id: 2).first.pos
assert_equal 2, ListMixin.where(id: 3).first.pos
assert_equal 3, ListMixin.where(id: 4).first.pos
end
def test_remove_before_destroy_does_not_shift_lower_items_twice
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.remove_from_list
ListMixin.where(id: 2).first.destroy
assert_equal [1, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 1).first.pos
assert_equal 2, ListMixin.where(id: 3).first.pos
assert_equal 3, ListMixin.where(id: 4).first.pos
end
def test_before_destroy_callbacks_do_not_update_position_to_nil_before_deleting_the_record
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
# We need to trigger all the before_destroy callbacks without actually
# destroying the record so we can see the affect the callbacks have on
# the record.
# NOTE: Hotfix for rails3 ActiveRecord
list = ListMixin.where(id: 2).first
if list.respond_to?(:run_callbacks)
# Refactored to work according to Rails3 ActiveRSupport Callbacks
list.run_callbacks(:destroy) if rails_3
list.run_callbacks(:before_destroy) if !rails_3
else
list.send(:callback, :before_destroy)
end
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 1).first.pos
assert_equal 2, ListMixin.where(id: 2).first.pos
assert_equal 2, ListMixin.where(id: 3).first.pos
assert_equal 3, ListMixin.where(id: 4).first.pos
end
def test_before_create_callback_adds_to_bottom
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
new = ListMixin.create(parent_id: 5)
assert_equal 5, new.pos
assert !new.first?
assert new.last?
assert_equal [1, 2, 3, 4, 5], ListMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_before_create_callback_adds_to_given_position
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
new = ListMixin.new(parent_id: 5)
new.pos = 1
new.save!
assert_equal 1, new.pos
assert new.first?
assert !new.last?
assert_equal [5, 1, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
new6 = ListMixin.new(parent_id: 5)
new6.pos = 3
new6.save!
assert_equal 3, new6.pos
assert !new6.first?
assert !new6.last?
assert_equal [5, 1, 6, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos').map(&:id)
new = ListMixin.new(parent_id: 5)
new.pos = 3
ListMixin.acts_as_list_no_update { new.save! }
assert_equal 3, new.pos
assert_equal 3, new6.pos
assert !new.first?
assert !new.last?
assert_equal [5, 1, 6, 7, 2, 3, 4], ListMixin.where(parent_id: 5).order('pos, id').map(&:id)
end
def test_non_persisted_records_dont_get_lock_called
new = ListMixin.new(parent_id: 5)
new.destroy
end
def test_invalid_records_dont_get_inserted
new = ListMixinError.new(parent_id: 5, state: nil)
assert !new.valid?
new.insert_at(1)
assert !new.persisted?
end
def test_invalid_records_raise_error_with_insert_at!
new = ListMixinError.new(parent_id: 5, state: nil)
assert !new.valid?
assert_raises ActiveRecord::RecordInvalid do
new.insert_at!(1)
end
end
end
end
ruby-acts-as-list-0.9.15/test/shared_list_sub.rb 0000664 0000000 0000000 00000014573 13337530425 0021566 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module ListSub
def setup
(1..4).each do |i|
node = ((i % 2 == 1) ? ListMixinSub1 : ListMixinSub2).new parent_id: 5000
node.pos = i
node.save!
end
end
def test_reordering
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
end
def test_move_to_bottom_with_next_to_last_item
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 3).first.move_to_bottom
assert_equal [1, 2, 4, 3], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
end
def test_next_prev
assert_equal ListMixin.where(id: 2).first, ListMixin.where(id: 1).first.lower_item
assert_nil ListMixin.where(id: 1).first.higher_item
assert_equal ListMixin.where(id: 3).first, ListMixin.where(id: 4).first.higher_item
assert_nil ListMixin.where(id: 4).first.lower_item
end
def test_next_prev_not_regular_sequence
ListMixin.all.each do |item|
item.update_attributes(pos: item.pos * 5)
end
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
assert_equal [5, 10, 15, 20], ListMixin.where(parent_id: 5000).order('id').map(&:pos)
ListMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
assert_equal [5, 15, 10, 20], ListMixin.where(parent_id: 5000).order('id').map(&:pos)
ListMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
assert_equal [5, 10, 15, 20], ListMixin.where(parent_id: 5000).order('id').map(&:pos)
ListMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
end
def test_next_prev_groups
li1 = ListMixin.where(id: 1).first
li2 = ListMixin.where(id: 2).first
li3 = ListMixin.where(id: 3).first
li4 = ListMixin.where(id: 4).first
assert_equal [li2, li3, li4], li1.lower_items
assert_equal [li4], li3.lower_items
assert_equal [li2, li3], li1.lower_items(2)
assert_equal [], li4.lower_items
assert_equal [li2, li1], li3.higher_items
assert_equal [li1], li2.higher_items
assert_equal [li3, li2], li4.higher_items(2)
assert_equal [], li1.higher_items
end
def test_next_prev_groups_with_same_position
li1 = ListMixin.where(id: 1).first
li2 = ListMixin.where(id: 2).first
li3 = ListMixin.where(id: 3).first
li4 = ListMixin.where(id: 4).first
li3.update_column(:pos, 2) # Make the same position as li2
assert_equal [1, 2, 2, 4], ListMixin.order(:pos).pluck(:pos)
assert_equal [li3, li4], li2.lower_items
assert_equal [li2, li4], li3.lower_items
assert_equal [li3, li1], li2.higher_items
assert_equal [li2, li1], li3.higher_items
end
def test_injection
item = ListMixin.new("parent_id"=>1)
assert_equal({ parent_id: 1 }, item.scope_condition)
assert_equal "pos", item.position_column
end
def test_insert_at
new = ListMixin.create("parent_id" => 20)
assert_equal 1, new.pos
new = ListMixinSub1.create("parent_id" => 20)
assert_equal 2, new.pos
new = ListMixinSub1.create("parent_id" => 20)
assert_equal 3, new.pos
new_noup = ListMixinSub1.acts_as_list_no_update { ListMixinSub1.create("parent_id" => 20) }
assert_equal_or_nil $default_position, new_noup.pos
new4 = ListMixin.create("parent_id" => 20)
assert_equal 4, new4.pos
new4.insert_at(3)
assert_equal 3, new4.pos
new.reload
assert_equal 4, new.pos
new.insert_at(2)
assert_equal 2, new.pos
new4.reload
assert_equal 4, new4.pos
new5 = ListMixinSub1.create("parent_id" => 20)
assert_equal 5, new5.pos
new5.insert_at(1)
assert_equal 1, new5.pos
new4.reload
assert_equal 5, new4.pos
new_noup.reload
assert_equal_or_nil $default_position, new_noup.pos
end
def test_delete_middle
assert_equal [1, 2, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
ListMixin.where(id: 2).first.destroy
assert_equal [1, 3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 1).first.pos
assert_equal 2, ListMixin.where(id: 3).first.pos
assert_equal 3, ListMixin.where(id: 4).first.pos
ListMixin.where(id: 1).first.destroy
assert_equal [3, 4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
assert_equal 1, ListMixin.where(id: 3).first.pos
assert_equal 2, ListMixin.where(id: 4).first.pos
ListMixin.acts_as_list_no_update { ListMixin.where(id: 3).first.destroy }
assert_equal [4], ListMixin.where(parent_id: 5000).order('pos').map(&:id)
assert_equal 2, ListMixin.where(id: 4).first.pos
end
def test_acts_as_list_class
assert_equal TheBaseClass, TheBaseSubclass.new.acts_as_list_class
assert_equal TheAbstractSubclass, TheAbstractSubclass.new.acts_as_list_class
end
end
end
ruby-acts-as-list-0.9.15/test/shared_no_addition.rb 0000664 0000000 0000000 00000001544 13337530425 0022223 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module NoAddition
def setup
(1..4).each { |counter| NoAdditionMixin.create! pos: counter, parent_id: 5 }
end
def test_insert
new = NoAdditionMixin.create(parent_id: 20)
assert_nil new.pos
assert !new.in_list?
new = NoAdditionMixin.create(parent_id: 20)
assert_nil new.pos
end
def test_update_does_not_add_to_list
new = NoAdditionMixin.create(parent_id: 20)
new.update_attribute(:updated_at, Time.now) # force some change
new.reload
assert !new.in_list?
end
def test_update_scope_does_not_add_to_list
new = NoAdditionMixin.create
new.update_attribute(:parent_id, 20)
new.reload
assert !new.in_list?
new.update_attribute(:parent_id, 5)
new.reload
assert !new.in_list?
end
end
end
ruby-acts-as-list-0.9.15/test/shared_quoting.rb 0000664 0000000 0000000 00000000677 13337530425 0021430 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module Quoting
def setup
3.times { |counter| QuotedList.create! order: counter }
end
def test_create
assert_equal QuotedList.in_list.size, 3
end
# This test execute raw queries involving table name
def test_moving
item = QuotedList.first
item.higher_items
item.lower_items
item.send :bottom_item # Part of private api
end
end
end
ruby-acts-as-list-0.9.15/test/shared_top_addition.rb 0000664 0000000 0000000 00000007156 13337530425 0022416 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module TopAddition
def setup
(1..4).each { |counter| TopAdditionMixin.create! pos: counter, parent_id: 5 }
end
def test_setup_state
# If we explicitly define a position (as above) then that position is what gets applied
assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_reordering
TopAdditionMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
TopAdditionMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
TopAdditionMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
TopAdditionMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
TopAdditionMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
TopAdditionMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_injection
item = TopAdditionMixin.new(parent_id: 1)
assert_equal({ parent_id: 1 }, item.scope_condition)
assert_equal "pos", item.position_column
end
def test_insert
new = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new.pos
assert new.first?
assert new.last?
new = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new.pos
assert new.first?
assert !new.last?
new = TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.create(parent_id: 20) }
assert_equal_or_nil $default_position, new.pos
assert_equal $default_position.is_a?(Integer), new.first?
assert !new.last?
new = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new.pos
assert_equal $default_position.nil?, new.first?
assert !new.last?
new = TopAdditionMixin.create(parent_id: 0)
assert_equal 1, new.pos
assert new.first?
assert new.last?
end
def test_insert_at
new = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new.pos
new = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new.pos
new = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new.pos
new = TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.create(parent_id: 20) }
assert_equal_or_nil $default_position, new.pos
new4 = TopAdditionMixin.create(parent_id: 20)
assert_equal 1, new4.pos
new4.insert_at(3)
assert_equal 3, new4.pos
end
def test_supplied_position
new = TopAdditionMixin.create(parent_id: 20, pos: 3)
assert_equal 3, new.pos
end
def test_delete_middle
TopAdditionMixin.where(id: 2).first.destroy
assert_equal [1, 3, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, TopAdditionMixin.where(id: 1).first.pos
assert_equal 2, TopAdditionMixin.where(id: 3).first.pos
assert_equal 3, TopAdditionMixin.where(id: 4).first.pos
TopAdditionMixin.acts_as_list_no_update { TopAdditionMixin.where(id: 3).first.destroy }
assert_equal [1, 4], TopAdditionMixin.where(parent_id: 5).order('pos').map(&:id)
assert_equal 1, TopAdditionMixin.where(id: 1).first.pos
assert_equal 3, TopAdditionMixin.where(id: 4).first.pos
end
end
end
ruby-acts-as-list-0.9.15/test/shared_zero_based.rb 0000664 0000000 0000000 00000005656 13337530425 0022061 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
module Shared
module ZeroBased
def setup
(1..4).each { |counter| ZeroBasedMixin.create! pos: counter, parent_id: 5 }
end
def test_insert
new = ZeroBasedMixin.create(parent_id: 20)
assert_equal 0, new.pos
assert new.first?
assert new.last?
new = ZeroBasedMixin.create(parent_id: 20)
assert_equal 1, new.pos
assert !new.first?
assert new.last?
new = ZeroBasedMixin.acts_as_list_no_update { ZeroBasedMixin.create(parent_id: 20) }
assert_equal_or_nil $default_position, new.pos
assert !new.first?
assert !new.last?
new = ZeroBasedMixin.create(parent_id: 20)
assert_equal 2, new.pos
assert !new.first?
assert new.last?
new = ZeroBasedMixin.create(parent_id: 0)
assert_equal 0, new.pos
assert new.first?
assert new.last?
new = ZeroBasedMixin.create(parent_id: 1, pos: -500)
assert_equal 0, new.pos
assert new.first?
assert new.last?
end
def test_reordering
assert_equal [1, 2, 3, 4], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
ListMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], ZeroBasedMixin.where(parent_id: 5).order('pos').map(&:id)
end
def test_insert_at
new = ZeroBasedMixin.create(parent_id: 20)
assert_equal 0, new.pos
new = ZeroBasedMixin.create(parent_id: 20)
assert_equal 1, new.pos
new = ZeroBasedMixin.create(parent_id: 20)
assert_equal 2, new.pos
new_noup = ZeroBasedMixin.acts_as_list_no_update { ZeroBasedMixin.create(parent_id: 20) }
assert_equal_or_nil $default_position, new_noup.pos
new4 = ZeroBasedMixin.create(parent_id: 20)
assert_equal 3, new4.pos
new4.insert_at(2)
assert_equal 2, new4.pos
new.reload
assert_equal 3, new.pos
new.insert_at(2)
assert_equal 2, new.pos
new4.reload
assert_equal 3, new4.pos
new5 = ListMixin.create(parent_id: 20)
assert_equal 4, new5.pos
new5.insert_at(1)
assert_equal 1, new5.pos
new4.reload
assert_equal 4, new4.pos
new_noup.reload
assert_equal_or_nil $default_position, new_noup.pos
end
end
end
ruby-acts-as-list-0.9.15/test/test_joined_list.rb 0000664 0000000 0000000 00000003101 13337530425 0021737 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'helper'
class Section < ActiveRecord::Base
has_many :items
acts_as_list
scope :visible, -> { where(visible: true) }
end
class Item < ActiveRecord::Base
belongs_to :section
acts_as_list scope: :section
scope :visible, -> { where(visible: true).joins(:section).merge(Section.visible) }
end
class JoinedTestCase < Minitest::Test
def setup
ActiveRecord::Base.connection.create_table :sections do |t|
t.column :position, :integer
t.column :visible, :boolean, default: true
end
ActiveRecord::Base.connection.create_table :items do |t|
t.column :position, :integer
t.column :section_id, :integer
t.column :visible, :boolean, default: true
end
ActiveRecord::Base.connection.schema_cache.clear!
[Section, Item].each(&:reset_column_information)
super
end
def teardown
teardown_db
super
end
end
# joining the relation returned by `#higher_items` or `#lower_items` to another table
# previously could result in ambiguous column names in the query
class TestHigherLowerItems < JoinedTestCase
def test_higher_items
section = Section.create
item1 = Item.create section: section
item2 = Item.create section: section
item3 = Item.create section: section
assert_equal item3.higher_items.visible, [item2, item1]
end
def test_lower_items
section = Section.create
item1 = Item.create section: section
item2 = Item.create section: section
item3 = Item.create section: section
assert_equal item1.lower_items.visible, [item2, item3]
end
end
ruby-acts-as-list-0.9.15/test/test_list.rb 0000664 0000000 0000000 00000065045 13337530425 0020426 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
# NOTE: following now done in helper.rb (better Readability)
require 'helper'
def setup_db(position_options = {})
$default_position = position_options[:default]
# sqlite cannot drop/rename/alter columns and add constraints after table creation
sqlite = ENV.fetch("DB", "sqlite") == "sqlite"
# AR caches columns options like defaults etc. Clear them!
ActiveRecord::Base.connection.create_table :mixins do |t|
t.column :pos, :integer, position_options unless position_options[:positive] && sqlite
t.column :active, :boolean, default: true
t.column :parent_id, :integer
t.column :parent_type, :string
t.column :created_at, :datetime
t.column :updated_at, :datetime
t.column :state, :integer
end
if position_options[:unique] && !(sqlite && position_options[:positive])
ActiveRecord::Base.connection.add_index :mixins, :pos, unique: true
end
if position_options[:positive]
if sqlite
# SQLite cannot add constraint after table creation, also cannot add unique inside ADD COLUMN
ActiveRecord::Base.connection.execute('ALTER TABLE mixins ADD COLUMN pos integer8 NOT NULL CHECK (pos > 0) DEFAULT 1')
ActiveRecord::Base.connection.execute('CREATE UNIQUE INDEX index_mixins_on_pos ON mixins(pos)')
else
ActiveRecord::Base.connection.execute('ALTER TABLE mixins ADD CONSTRAINT pos_check CHECK (pos > 0)')
end
end
# This table is used to test table names and column names quoting
ActiveRecord::Base.connection.create_table 'table-name' do |t|
t.column :order, :integer
end
mixins = [ Mixin, ListMixin, ListMixinSub1, ListMixinSub2, ListWithStringScopeMixin,
ArrayScopeListMixin, ZeroBasedMixin, DefaultScopedMixin,
DefaultScopedWhereMixin, TopAdditionMixin, NoAdditionMixin, QuotedList ]
mixins << EnumArrayScopeListMixin if rails_4
ActiveRecord::Base.connection.schema_cache.clear!
mixins.each do |klass|
klass.reset_column_information
end
end
def setup_db_with_default
setup_db default: 0
end
class Mixin < ActiveRecord::Base
self.table_name = 'mixins'
end
class ListMixin < Mixin
acts_as_list column: "pos", scope: :parent
end
class ListMixinSub1 < ListMixin
end
class ListMixinSub2 < ListMixin
if rails_3
validates :pos, presence: true
else
validates_presence_of :pos
end
end
class ListMixinError < ListMixin
if rails_3
validates :state, presence: true
else
validates_presence_of :state
end
end
class ListWithStringScopeMixin < Mixin
acts_as_list column: "pos", scope: 'parent_id = #{parent_id}'
end
class ArrayScopeListMixin < Mixin
acts_as_list column: "pos", scope: [:parent_id, :parent_type]
end
class ArrayScopeListWithHashMixin < Mixin
acts_as_list column: "pos", scope: [:parent_id, state: nil]
end
if rails_4
class EnumArrayScopeListMixin < Mixin
STATE_VALUES = %w(active archived)
enum state: STATE_VALUES
acts_as_list column: "pos", scope: [:parent_id, :state]
end
end
class ZeroBasedMixin < Mixin
acts_as_list column: "pos", top_of_list: 0, scope: [:parent_id]
end
class DefaultScopedMixin < Mixin
acts_as_list column: "pos"
default_scope { order('pos ASC') }
end
class DefaultScopedWhereMixin < Mixin
acts_as_list column: "pos"
default_scope { order('pos ASC').where(active: true) }
def self.for_active_false_tests
if ActiveRecord::VERSION::MAJOR < 4
unscoped do
order('pos ASC').where(active: false)
end
else
unscope(:where).where(active: false)
end
end
end
class SequentialUpdatesDefault < Mixin
acts_as_list column: "pos"
end
class SequentialUpdatesFalseMixin < Mixin
acts_as_list column: "pos", sequential_updates: false
end
class TopAdditionMixin < Mixin
acts_as_list column: "pos", add_new_at: :top, scope: :parent_id
end
class NoAdditionMixin < Mixin
acts_as_list column: "pos", add_new_at: nil, scope: :parent_id
end
##
# The way we track changes to
# scope and position can get tripped up
# by someone using update_attributes within
# a callback because it causes multiple passes
# through the callback chain
module CallbackMixin
def self.included(base)
base.send :include, InstanceMethods
base.after_create :change_field
end
module InstanceMethods
def change_field
# doesn't matter what column changes, just
# need to change something
self.update_attributes(active: !self.active)
end
end
end
class TheAbstractClass < ActiveRecord::Base
self.abstract_class = true
self.table_name = 'mixins'
end
class TheAbstractSubclass < TheAbstractClass
acts_as_list column: "pos", scope: :parent
end
class TheBaseClass < ActiveRecord::Base
self.table_name = 'mixins'
acts_as_list column: "pos", scope: :parent
end
class TheBaseSubclass < TheBaseClass
end
class QuotedList < ActiveRecord::Base
self.table_name = 'table-name'
acts_as_list column: :order
end
class ActsAsListTestCase < Minitest::Test
# No default test required as this class is abstract.
# Need for test/unit.
undef_method :default_test if method_defined?(:default_test)
def teardown
teardown_db
end
end
class ZeroBasedTest < ActsAsListTestCase
include Shared::ZeroBased
def setup
setup_db
super
end
end
class ZeroBasedTestWithDefault < ActsAsListTestCase
include Shared::ZeroBased
def setup
setup_db_with_default
super
end
end
class ListTest < ActsAsListTestCase
include Shared::List
def setup
setup_db
super
end
def test_insert_race_condition
# the bigger n is the more likely we will have a race condition
n = 1000
(1..n).each do |counter|
node = ListMixin.new parent_id: 1
node.pos = counter
node.save!
end
wait_for_it = true
threads = []
4.times do |i|
threads << Thread.new do
true while wait_for_it
ActiveRecord::Base.connection_pool.with_connection do |c|
n.times do
begin
ListMixin.where(parent_id: 1).order('pos').last.insert_at(1)
rescue Exception
# ignore SQLite3::SQLException due to table locking
end
end
end
end
end
wait_for_it = false
threads.each(&:join)
assert_equal((1..n).to_a, ListMixin.where(parent_id: 1).order('pos').map(&:pos))
end
end
class ListWithCallbackTest < ActsAsListTestCase
include Shared::List
def setup
ListMixin.send(:include, CallbackMixin)
setup_db
super
end
end
class ListTestWithDefault < ActsAsListTestCase
include Shared::List
def setup
setup_db_with_default
super
end
end
class ListSubTest < ActsAsListTestCase
include Shared::ListSub
def setup
setup_db
super
end
end
class ListSubTestWithDefault < ActsAsListTestCase
include Shared::ListSub
def setup
setup_db_with_default
super
end
end
class ArrayScopeListTest < ActsAsListTestCase
include Shared::ArrayScopeList
def setup
setup_db
super
end
end
class ArrayScopeListTestWithDefault < ActsAsListTestCase
include Shared::ArrayScopeList
def setup
setup_db_with_default
super
end
end
class QuotingTestList < ActsAsListTestCase
include Shared::Quoting
def setup
setup_db_with_default
super
end
end
class DefaultScopedTest < ActsAsListTestCase
def setup
setup_db
(1..4).each { |counter| DefaultScopedMixin.create!({pos: counter}) }
end
def test_insert
new = DefaultScopedMixin.create
assert_equal 5, new.pos
assert !new.first?
assert new.last?
new = DefaultScopedMixin.create
assert_equal 6, new.pos
assert !new.first?
assert new.last?
new = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
assert_equal_or_nil $default_position, new.pos
assert_equal $default_position.is_a?(Integer), new.first?
assert !new.last?
new = DefaultScopedMixin.create
assert_equal 7, new.pos
assert !new.first?
assert new.last?
end
def test_reordering
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], DefaultScopedMixin.all.map(&:id)
end
def test_insert_at
new = DefaultScopedMixin.create
assert_equal 5, new.pos
new = DefaultScopedMixin.create
assert_equal 6, new.pos
new_noup = DefaultScopedMixin.acts_as_list_no_update { DefaultScopedMixin.create }
assert_equal_or_nil $default_position, new_noup.pos
new = DefaultScopedMixin.create
assert_equal 7, new.pos
new4 = DefaultScopedMixin.create
assert_equal 8, new4.pos
new4.insert_at(2)
assert_equal 2, new4.pos
new.reload
assert_equal 8, new.pos
new.insert_at(2)
assert_equal 2, new.pos
new4.reload
assert_equal 3, new4.pos
new5 = DefaultScopedMixin.create
assert_equal 9, new5.pos
new5.insert_at(1)
assert_equal 1, new5.pos
new4.reload
assert_equal 4, new4.pos
new_noup.reload
assert_equal_or_nil $default_position, new_noup.pos
end
def test_update_position
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 2).first.set_list_position(4)
assert_equal [1, 3, 4, 2], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 2).first.set_list_position(2)
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 1).first.set_list_position(4)
assert_equal [2, 3, 4, 1], DefaultScopedMixin.all.map(&:id)
DefaultScopedMixin.where(id: 1).first.set_list_position(1)
assert_equal [1, 2, 3, 4], DefaultScopedMixin.all.map(&:id)
end
end
class DefaultScopedWhereTest < ActsAsListTestCase
def setup
setup_db
(1..4).each { |counter| DefaultScopedWhereMixin.create! pos: counter, active: false }
end
def test_insert
new = DefaultScopedWhereMixin.create
assert_equal 5, new.pos
assert !new.first?
assert new.last?
new = DefaultScopedWhereMixin.create
assert_equal 6, new.pos
assert !new.first?
assert new.last?
new = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
assert_equal_or_nil $default_position, new.pos
assert_equal $default_position.is_a?(Integer), new.first?
assert !new.last?
new = DefaultScopedWhereMixin.create
assert_equal 7, new.pos
assert !new.first?
assert new.last?
end
def test_reordering
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.move_lower
assert_equal [1, 3, 2, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.move_higher
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.move_to_bottom
assert_equal [2, 3, 4, 1], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.move_to_top
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.move_to_bottom
assert_equal [1, 3, 4, 2], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 4).first.move_to_top
assert_equal [4, 1, 3, 2], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
end
def test_insert_at
new = DefaultScopedWhereMixin.create
assert_equal 5, new.pos
new = DefaultScopedWhereMixin.create
assert_equal 6, new.pos
new = DefaultScopedWhereMixin.create
assert_equal 7, new.pos
new_noup = DefaultScopedWhereMixin.acts_as_list_no_update { DefaultScopedWhereMixin.create }
assert_equal_or_nil $default_position, new_noup.pos
new4 = DefaultScopedWhereMixin.create
assert_equal 8, new4.pos
new4.insert_at(2)
assert_equal 2, new4.pos
new.reload
assert_equal 8, new.pos
new.insert_at(2)
assert_equal 2, new.pos
new4.reload
assert_equal 3, new4.pos
new5 = DefaultScopedWhereMixin.create
assert_equal 9, new5.pos
new5.insert_at(1)
assert_equal 1, new5.pos
new4.reload
assert_equal 4, new4.pos
new_noup.reload
assert_equal_or_nil $default_position, new_noup.pos
end
def test_update_position
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.set_list_position(4)
assert_equal [1, 3, 4, 2], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 2).first.set_list_position(2)
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.set_list_position(4)
assert_equal [2, 3, 4, 1], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
DefaultScopedWhereMixin.for_active_false_tests.where(id: 1).first.set_list_position(1)
assert_equal [1, 2, 3, 4], DefaultScopedWhereMixin.for_active_false_tests.map(&:id)
end
end
class MultiDestroyTest < ActsAsListTestCase
def setup
setup_db
end
# example:
#
# class TodoList < ActiveRecord::Base
# has_many :todo_items, order: "position"
# accepts_nested_attributes_for :todo_items, allow_destroy: true
# end
#
# class TodoItem < ActiveRecord::Base
# belongs_to :todo_list
# acts_as_list scope: :todo_list
# end
#
# Assume that there are three items.
# The user mark two items as deleted, click save button, form will be post:
#
# todo_list.todo_items_attributes = [
# {id: 1, _destroy: true},
# {id: 2, _destroy: true}
# ]
#
# Save toto_list, the position of item #3 should eql 1.
#
def test_destroy
new1 = DefaultScopedMixin.create
assert_equal 1, new1.pos
new2 = DefaultScopedMixin.create
assert_equal 2, new2.pos
new3 = DefaultScopedMixin.create
assert_equal 3, new3.pos
new4 = DefaultScopedMixin.create
assert_equal 4, new4.pos
new1.destroy
new2.destroy
new3.reload
new4.reload
assert_equal 1, new3.pos
assert_equal 2, new4.pos
DefaultScopedMixin.acts_as_list_no_update { new3.destroy }
new4.reload
assert_equal 2, new4.pos
end
end
#class TopAdditionMixin < Mixin
class TopAdditionTest < ActsAsListTestCase
include Shared::TopAddition
def setup
setup_db
super
end
end
class TopAdditionTestWithDefault < ActsAsListTestCase
include Shared::TopAddition
def setup
setup_db_with_default
super
end
end
class NoAdditionTest < ActsAsListTestCase
include Shared::NoAddition
def setup
setup_db
super
end
end
class MultipleListsTest < ActsAsListTestCase
def setup
setup_db
(1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 1}
(1..4).each { |counter| ListMixin.create! :pos => counter, :parent_id => 2}
end
def test_check_scope_order
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 1).order('pos').map(&:id)
assert_equal [5, 6, 7, 8], ListMixin.where(:parent_id => 2).order('pos').map(&:id)
ListMixin.find(4).update_attributes(:parent_id => 2, :pos => 2)
assert_equal [1, 2, 3], ListMixin.where(:parent_id => 1).order('pos').map(&:id)
assert_equal [5, 4, 6, 7, 8], ListMixin.where(:parent_id => 2).order('pos').map(&:id)
end
def test_check_scope_position
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 1).map(&:pos)
assert_equal [1, 2, 3, 4], ListMixin.where(:parent_id => 2).map(&:pos)
ListMixin.find(4).update_attributes(:parent_id => 2, :pos => 2)
assert_equal [1, 2, 3], ListMixin.where(:parent_id => 1).order('pos').map(&:pos)
assert_equal [1, 2, 3, 4, 5], ListMixin.where(:parent_id => 2).order('pos').map(&:pos)
end
end
if rails_4
class EnumArrayScopeListMixinTest < ActsAsListTestCase
def setup
setup_db
EnumArrayScopeListMixin.create! :parent_id => 1, :state => EnumArrayScopeListMixin.states['active']
EnumArrayScopeListMixin.create! :parent_id => 1, :state => EnumArrayScopeListMixin.states['archived']
EnumArrayScopeListMixin.create! :parent_id => 2, :state => EnumArrayScopeListMixin.states["active"]
EnumArrayScopeListMixin.create! :parent_id => 2, :state => EnumArrayScopeListMixin.states["archived"]
end
def test_positions
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 1, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 1, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active']).map(&:pos)
assert_equal [1], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos)
end
def test_update_state
active_item = EnumArrayScopeListMixin.find_by(:parent_id => 2, :state => EnumArrayScopeListMixin.states['active'])
active_item.update(state: EnumArrayScopeListMixin.states['archived'])
assert_equal [1, 2], EnumArrayScopeListMixin.where(:parent_id => 2, :state => EnumArrayScopeListMixin.states['archived']).map(&:pos).sort
end
end
end
class MultipleListsArrayScopeTest < ActsAsListTestCase
def setup
setup_db
(1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter,:parent_id => 1, :parent_type => 'anything'}
(1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter,:parent_id => 2, :parent_type => 'something'}
(1..4).each { |counter| ArrayScopeListMixin.create! :pos => counter,:parent_id => 3, :parent_type => 'anything'}
end
def test_order_after_all_scope_properties_are_changed
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
assert_equal [5, 6, 7, 8], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').order('pos').map(&:id)
ArrayScopeListMixin.find(2).update_attributes(:parent_id => 2, :pos => 2,:parent_type => 'something')
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
assert_equal [5, 2, 6, 7, 8], ArrayScopeListMixin.where(:parent_id => 2,:parent_type => 'something').order('pos').map(&:id)
end
def test_position_after_all_scope_properties_are_changed
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').map(&:pos)
ArrayScopeListMixin.find(4).update_attributes(:parent_id => 2, :pos => 2, :parent_type => 'something')
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
assert_equal [1, 2, 3, 4, 5], ArrayScopeListMixin.where(:parent_id => 2, :parent_type => 'something').order('pos').map(&:pos)
end
def test_order_after_one_scope_property_is_changed
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
assert_equal [9, 10, 11, 12], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').order('pos').map(&:id)
ArrayScopeListMixin.find(2).update_attributes(:parent_id => 3, :pos => 2)
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
assert_equal [9, 2, 10, 11, 12], ArrayScopeListMixin.where(:parent_id => 3,:parent_type => 'anything').order('pos').map(&:id)
end
def test_position_after_one_scope_property_is_changed
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').map(&:pos)
ArrayScopeListMixin.find(4).update_attributes(:parent_id => 3, :pos => 2)
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
assert_equal [1, 2, 3, 4, 5], ArrayScopeListMixin.where(:parent_id => 3, :parent_type => 'anything').order('pos').map(&:pos)
end
def test_order_after_moving_to_empty_list
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:id)
assert_equal [], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').order('pos').map(&:id)
ArrayScopeListMixin.find(2).update_attributes(:parent_id => 4, :pos => 1)
assert_equal [1, 3, 4], ArrayScopeListMixin.where(:parent_id => 1,:parent_type => 'anything').order('pos').map(&:id)
assert_equal [2], ArrayScopeListMixin.where(:parent_id => 4,:parent_type => 'anything').order('pos').map(&:id)
end
def test_position_after_moving_to_empty_list
assert_equal [1, 2, 3, 4], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').map(&:pos)
assert_equal [], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').map(&:pos)
ArrayScopeListMixin.find(2).update_attributes(:parent_id => 4, :pos => 1)
assert_equal [1, 2, 3], ArrayScopeListMixin.where(:parent_id => 1, :parent_type => 'anything').order('pos').map(&:pos)
assert_equal [1], ArrayScopeListMixin.where(:parent_id => 4, :parent_type => 'anything').order('pos').map(&:pos)
end
end
class ArrayScopeListWithHashTest
def setup
setup_db
@obj1 = ArrayScopeListWithHashMixin.create! :pos => counter, :parent_id => 1, :state => nil
@obj2 = ArrayScopeListWithHashMixin.create! :pos => counter, :parent_id => 1, :state => 'anything'
end
def test_scope_condition_correct
[@obj1, @obj2].each do |obj|
assert_equal({ :parent_id => 1, :state => nil }, obj.scope_condition)
end
end
end
require 'timecop'
class TouchTest < ActsAsListTestCase
def setup
setup_db
Timecop.freeze(yesterday) do
4.times { ListMixin.create! }
end
end
def now
@now ||= Time.current.change(usec: 0)
end
def yesterday
@yesterday ||= 1.day.ago
end
def updated_ats
ListMixin.order(:id).pluck(:updated_at)
end
def test_moving_item_lower_touches_self_and_lower_item
Timecop.freeze(now) do
ListMixin.first.move_lower
updated_ats[0..1].each do |updated_at|
assert_equal updated_at.to_i, now.to_i
end
updated_ats[2..3].each do |updated_at|
assert_equal updated_at.to_i, yesterday.to_i
end
end
end
def test_moving_item_higher_touches_self_and_higher_item
Timecop.freeze(now) do
ListMixin.all.second.move_higher
updated_ats[0..1].each do |updated_at|
assert_equal updated_at.to_i, now.to_i
end
updated_ats[2..3].each do |updated_at|
assert_equal updated_at.to_i, yesterday.to_i
end
end
end
def test_moving_item_to_bottom_touches_all_other_items
Timecop.freeze(now) do
ListMixin.first.move_to_bottom
updated_ats.each do |updated_at|
assert_equal updated_at.to_i, now.to_i
end
end
end
def test_moving_item_to_top_touches_all_other_items
Timecop.freeze(now) do
ListMixin.last.move_to_top
updated_ats.each do |updated_at|
assert_equal updated_at.to_i, now.to_i
end
end
end
def test_removing_item_touches_all_lower_items
Timecop.freeze(now) do
ListMixin.all.third.remove_from_list
updated_ats[0..1].each do |updated_at|
assert_equal updated_at.to_i, yesterday.to_i
end
updated_ats[2..2].each do |updated_at|
assert_equal updated_at.to_i, now.to_i
end
end
end
end
class ActsAsListTopTest < ActsAsListTestCase
def setup
setup_db
end
def test_acts_as_list_top
assert_equal 1, TheBaseSubclass.new.acts_as_list_top
assert_equal 0, ZeroBasedMixin.new.acts_as_list_top
end
def test_class_acts_as_list_top
assert_equal 1, TheBaseSubclass.acts_as_list_top
assert_equal 0, ZeroBasedMixin.acts_as_list_top
end
end
class NilPositionTest < ActsAsListTestCase
def setup
setup_db
end
def test_nil_position_ordering
new1 = DefaultScopedMixin.create pos: nil
new2 = DefaultScopedMixin.create pos: nil
new3 = DefaultScopedMixin.create pos: nil
DefaultScopedMixin.update_all(pos: nil)
assert_equal [nil, nil, nil], DefaultScopedMixin.all.map(&:pos)
new1.reload.pos = 1
new1.save
new3.reload.pos = 1
new3.save
assert_equal [1, 2], DefaultScopedMixin.where("pos IS NOT NULL").map(&:pos)
assert_equal [3, 1], DefaultScopedMixin.where("pos IS NOT NULL").map(&:id)
assert_nil new2.reload.pos
new2.reload.pos = 1
new2.save
assert_equal [1, 2, 3], DefaultScopedMixin.all.map(&:pos)
assert_equal [2, 3, 1], DefaultScopedMixin.all.map(&:id)
end
end
class SequentialUpdatesOptionDefaultTest < ActsAsListTestCase
def setup
setup_db
end
def test_sequential_updates_default_to_false_without_unique_index
assert_equal false, SequentialUpdatesDefault.new.send(:sequential_updates?)
end
end
class SequentialUpdatesMixinNotNullUniquePositiveConstraintsTest < ActsAsListTestCase
def setup
setup_db null: false, unique: true, positive: true
(1..4).each { |counter| SequentialUpdatesDefault.create!({pos: counter}) }
end
def test_sequential_updates_default_to_true_with_unique_index
assert_equal true, SequentialUpdatesDefault.new.send(:sequential_updates?)
end
def test_sequential_updates_option_override_with_false
assert_equal false, SequentialUpdatesFalseMixin.new.send(:sequential_updates?)
end
def test_insert_at
new = SequentialUpdatesDefault.create
assert_equal 5, new.pos
new.insert_at(1)
assert_equal 1, new.pos
new.insert_at(5)
assert_equal 5, new.pos
new.insert_at(3)
assert_equal 3, new.pos
end
def test_destroy
new_item = SequentialUpdatesDefault.create
assert_equal 5, new_item.pos
new_item.insert_at(2)
assert_equal 2, new_item.pos
new_item.destroy
assert_equal [1,2,3,4], SequentialUpdatesDefault.all.map(&:pos).sort
end
end
ruby-acts-as-list-0.9.15/test/test_no_update_for_extra_classes.rb 0000664 0000000 0000000 00000005726 13337530425 0025217 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'helper'
class TodoList < ActiveRecord::Base
has_many :todo_items
acts_as_list
end
class TodoItem < ActiveRecord::Base
belongs_to :todo_list
has_many :todo_item_attachments
acts_as_list scope: :todo_list
end
class TodoItemAttachment < ActiveRecord::Base
belongs_to :todo_item
acts_as_list scope: :todo_item
end
class NoUpdateForCollectionClassesTestCase < Minitest::Test
def setup
ActiveRecord::Base.connection.create_table :todo_lists do |t|
t.column :position, :integer
end
ActiveRecord::Base.connection.create_table :todo_items do |t|
t.column :position, :integer
t.column :todo_list_id, :integer
end
ActiveRecord::Base.connection.create_table :todo_item_attachments do |t|
t.column :position, :integer
t.column :todo_item_id, :integer
end
ActiveRecord::Base.connection.schema_cache.clear!
[TodoList, TodoItem, TodoItemAttachment].each(&:reset_column_information)
super
end
def teardown
teardown_db
super
end
end
class NoUpdateForCollectionClassesTest < NoUpdateForCollectionClassesTestCase
def setup
super
@list_1, @list_2 = (1..2).map { |counter| TodoList.create!(position: counter) }
@item_1, @item_2 = (1..2).map { |counter| TodoItem.create!(position: counter, todo_list_id: @list_1.id) }
@attachment_1, @attachment_2 = (1..2).map { |counter| TodoItemAttachment.create!(position: counter, todo_item_id: @item_1.id) }
end
def test_update
@item_1.update_attributes(position: 2)
assert_equal 2, @item_1.reload.position
assert_equal 1, @item_2.reload.position
end
def test_no_update_for_single_class_instances
TodoItem.acts_as_list_no_update { @item_1.update_attributes(position: 2) }
assert_equal 2, @item_1.reload.position
assert_equal 2, @item_2.reload.position
end
def test_no_update_for_different_class_instances
TodoItem.acts_as_list_no_update([TodoItemAttachment]) { update_records! }
assert_equal 2, @item_1.reload.position
assert_equal 2, @item_2.reload.position
assert_equal 2, @attachment_1.reload.position
assert_equal 2, @attachment_2.reload.position
assert_equal 2, @list_1.reload.position
assert_equal 1, @list_2.reload.position
end
def test_raising_array_type_error
exception = assert_raises ActiveRecord::Acts::List::NoUpdate::ArrayTypeError do
TodoList.acts_as_list_no_update(nil)
end
assert_equal("The first argument must be an array", exception.message )
end
def test_non_disparity_classes_error
exception = assert_raises ActiveRecord::Acts::List::NoUpdate::DisparityClassesError do
TodoList.acts_as_list_no_update([Class])
end
assert_equal("The first argument should contain ActiveRecord or ApplicationRecord classes", exception.message )
end
private
def update_records!
@item_1.update_attributes(position: 2)
@attachment_1.update_attributes(position: 2)
@list_1.update_attributes(position: 2)
end
end
ruby-acts-as-list-0.9.15/test/test_no_update_for_scope_destruction.rb 0000664 0000000 0000000 00000004555 13337530425 0026112 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'helper'
class DestructionTodoList < ActiveRecord::Base
has_many :destruction_todo_items, dependent: :destroy
has_many :destruction_tada_items, dependent: :destroy
end
class DestructionTodoItem < ActiveRecord::Base
belongs_to :destruction_todo_list
acts_as_list scope: :destruction_todo_list
end
class DestructionTadaItem < ActiveRecord::Base
belongs_to :destruction_todo_list
acts_as_list scope: [:destruction_todo_list_id, :enabled]
end
class NoUpdateForScopeDestructionTestCase < Minitest::Test
def setup
ActiveRecord::Base.connection.create_table :destruction_todo_lists do |t|
end
ActiveRecord::Base.connection.create_table :destruction_todo_items do |t|
t.column :position, :integer
t.column :destruction_todo_list_id, :integer
end
ActiveRecord::Base.connection.create_table :destruction_tada_items do |t|
t.column :position, :integer
t.column :destruction_todo_list_id, :integer
t.column :enabled, :boolean
end
ActiveRecord::Base.connection.schema_cache.clear!
[DestructionTodoList, DestructionTodoItem, DestructionTadaItem].each(&:reset_column_information)
super
end
def teardown
teardown_db
super
end
class NoUpdateForScopeDestructionTest < NoUpdateForScopeDestructionTestCase
def setup
super
@list = DestructionTodoList.create!
@todo_item_1 = DestructionTodoItem.create! position: 1, destruction_todo_list_id: @list.id
@tada_item_1 = DestructionTadaItem.create! position: 1, destruction_todo_list_id: @list.id, enabled: true
end
def test_no_update_children_when_parent_destroyed
if ActiveRecord::VERSION::MAJOR < 4
DestructionTodoItem.any_instance.expects(:decrement_positions_on_lower_items).once
DestructionTadaItem.any_instance.expects(:decrement_positions_on_lower_items).once
else
DestructionTodoItem.any_instance.expects(:decrement_positions_on_lower_items).never
DestructionTadaItem.any_instance.expects(:decrement_positions_on_lower_items).never
end
assert @list.destroy
end
def test_update_children_when_sibling_destroyed
@todo_item_1.expects(:decrement_positions_on_lower_items).once
@tada_item_1.expects(:decrement_positions_on_lower_items).once
assert @todo_item_1.destroy
assert @tada_item_1.destroy
end
end
end
ruby-acts-as-list-0.9.15/test/test_no_update_for_subclasses.rb 0000664 0000000 0000000 00000002542 13337530425 0024517 0 ustar 00root root 0000000 0000000 # frozen_string_literal: true
require 'helper'
class TodoItem < ActiveRecord::Base
acts_as_list
end
class SubTodoItem < TodoItem; end
class NoUpdateForSubclassesTestCase < Minitest::Test
def setup
ActiveRecord::Base.connection.create_table :todo_items do |t|
t.column :position, :integer
t.column :type, :string
end
ActiveRecord::Base.connection.schema_cache.clear!
[TodoItem, SubTodoItem].each(&:reset_column_information)
super
end
def teardown
teardown_db
super
end
end
class NoUpdateForSubclassesTest < NoUpdateForSubclassesTestCase
def setup
super
@item_1, @item_2 = (1..2).map do |counter|
SubTodoItem.create!(position: counter)
end
end
def test_update
@item_1.update_attributes(position: 2)
assert_equal 2, @item_1.reload.position
assert_equal 1, @item_2.reload.position
end
def test_no_update_for_subclass_instances_with_no_update_on_superclass
TodoItem.acts_as_list_no_update { @item_1.update_attributes(position: 2) }
assert_equal 2, @item_1.reload.position
assert_equal 2, @item_2.reload.position
end
def test_no_update_for_subclass_instances_with_no_update_on_subclass
SubTodoItem.acts_as_list_no_update { @item_1.update_attributes(position: 2) }
assert_equal 2, @item_1.reload.position
assert_equal 2, @item_2.reload.position
end
end