meskyanichi-make_sortable 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Michael van Rooijen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,207 @@
1
+ = Make Sortable
2
+
3
+ This plugin/gem provides an easy way to implement a simple database record sorting solution.
4
+
5
+ == Installation
6
+
7
+ gem sources -a http://gems.github.com
8
+ sudo gem install meskyanichi-make_sortable
9
+
10
+
11
+ == Simple Setup
12
+
13
+ Add the "make_sortable" method to your controller.
14
+
15
+ class PostsController < ApplicationController
16
+ make_sortable
17
+ end
18
+
19
+ The above will assume that:
20
+
21
+ - You want to make "posts" sortable
22
+ - You are using the "posts" controller
23
+ - You are using the "post" model
24
+ - You have a "position" attribute in your "post" model
25
+ - You have a "position" attribute in your "posts" table
26
+
27
+ Now, this single method, without any options, is already enough to start sorting!
28
+ It will make 4 methods available to you in the view. Check the example below, it should make sense.
29
+
30
+ ==== RAILS_ROOT/app/views/posts/index.html.erb
31
+
32
+ <table>
33
+ <tr>
34
+ <th>Up</th>
35
+ <th>Down</th>
36
+ <th>Name</th>
37
+ </tr>
38
+
39
+ <% @posts.each_with_index do |post, index| %>
40
+ <tr>
41
+ <td><%= button_up_for_posts_position(:object => @posts, :index => index) %></td>
42
+ <td><%= button_down_for_posts_position(:object => @posts, :index => index) %></td>
43
+ <td><%= post.name %></td>
44
+ </tr>
45
+ <% end %>
46
+ </table>
47
+
48
+ Above you see a simple table, with posts being looped out using the "each_with_index" method.
49
+ It is important that you use the "each_with_index" method, rather than just the "each" method
50
+ since you will need the index to determine the position of each record.
51
+
52
+ That's it! Just click on the up or down button and it works.
53
+
54
+ ==== What I always like to do is go into my mode, in this case, post.rb and add a default_scope:
55
+
56
+ class Post < ActiveRecord::Base
57
+ default_scope :order => :position
58
+ end
59
+
60
+ This will make sure that by default, all records are sorted by "position".
61
+
62
+
63
+ == Slightly more advanced setup
64
+
65
+ So, the above is quite easy to utilize if you follow the conventions, which in my option, are fine.
66
+ Adding 1 method in a controller and providing you with helper methods to generate the buttons for the view. Quite nice.
67
+
68
+ Now now, there are a couple of settings you can adjust through the make_sortable method. Settings you can adjust are:
69
+
70
+ - the controller (:controller) that should be used (default: controller that it's invoked on)
71
+ - the model (:model) that should be used (default: singular form of the controller name that the method is invoked on)
72
+ - the attribute (:attribute) inside the model that should be used (default: position)
73
+ - the redirect path (:redirect_path) where the user should be redirected to after the process (default: index action of specified controller)
74
+ - the filter (:filter) which you can use for associations. (default: nil)
75
+
76
+
77
+ === Specifying the :controller and :model options with make_sortable()
78
+
79
+ The only time you would want to do this is when you for example have a bunch of posts displayed
80
+ and wish to have their comments displayed below them on the same screen. Also, at the same time, you wish
81
+ for these comments to ALSO be "sortable" from this location.
82
+
83
+ ==== Requirement
84
+
85
+ class PostsController < ApplicationController
86
+ make_sortable # for posts
87
+ make_sortable :controller => :comments,
88
+ :model => :comment
89
+ end
90
+
91
+ We need to invoke a second "make_sortable" with the :controller => :comments and :model => :comment to let the view
92
+ know it needs to generate the methods for comments as well for any PostController action.
93
+
94
+ NOTE: Do not add any other options to the make_sortable for the comments. These settings need to be specified inside the CommentsController
95
+ where they belong.
96
+
97
+ ==== So be sure to add the "make_sortable" method inside the CommentsController
98
+
99
+ class CommentsController < ApplicationController
100
+ make_sortable
101
+ end
102
+
103
+ And add any additional options to the "make_sortable" method here, NOT inside the PostsController.
104
+
105
+
106
+ === Using a different model/database attribute
107
+
108
+ So you have your database set up with the attribute "order" instead of "position" and wish to use it instead of the default "position".
109
+
110
+ ==== Apply the following option to the "make_sortable()" method
111
+
112
+ class PostsController < ApplicationController
113
+ make_sortable :attribute => :order
114
+ end
115
+
116
+ === Changing the "Redirect Path"
117
+
118
+ If you do not wish to have your users be redirected to the index action after clicking on a "up" or "down" button to update the records "position",
119
+ you can change this very easily.
120
+
121
+ ==== Redirecting to a different action
122
+
123
+ class PostsController < ApplicationController
124
+ make_sortable :redirect_path => {:action => "other_action"}
125
+ end
126
+
127
+ If you simply wish to return to the page on which you were when clicking on the "up" or "down" button, apply the following option.
128
+
129
+ ==== Redirecting Back
130
+
131
+ class PostsController < ApplicationController
132
+ make_sortable :redirect_path => :back
133
+ end
134
+
135
+ === Filtering position updates
136
+
137
+ So you are building a web application which has mulitple users, and each user has it's own posts. Obviously you do not want "User 1" to update
138
+ "User 2"'s posts position. By default, "User 1" will have the ability to update "ALL" posts when updating his. Of course, that'd mean "User 1" should be able to see other users' posts. Regardless, it's best to just filter out that kind of behavior on the back-end to prevent it from ever happening.
139
+
140
+ For example, we have a logged in user, and we store all it's data inside the "current_user" method/variable. It's an AR Object.
141
+ Now, when this user clicks on the "up" or "down" button of a post item, we want to make sure that regardless of what he sees on the front-end,
142
+ can't be adjusted unless he is the owner of the post.
143
+
144
+ ==== You can accomplish this by adding the following option
145
+
146
+ class PostsController < ApplicationController
147
+ make_sortable :filter => current_user
148
+ end
149
+
150
+ ==== If you need to chain in a way (maybe for the users' -> post' -> comments), you can just do the following
151
+
152
+ class CommentsController < ApplicationController
153
+ make_sortable :filter => current_user.post
154
+ end
155
+
156
+ == View Helpers
157
+
158
+ When the "make_sortable" method is invoked on a controller, it will dynamically generate 4 view helpers for you to use.
159
+
160
+ ==== Let's say we've written the following
161
+
162
+ class PostsController < ApplicationController
163
+ make_sortable
164
+ end
165
+
166
+ The above would provide you with 4 methods. These methods will be available to all "PostController" views.
167
+
168
+ - button_up_for_posts_position :object, :index, :html
169
+ - button_down_for_posts_position :object, :index, :html
170
+ - link_up_for_posts_position :object, :index, :html
171
+ - link_down_for_posts_position :object, :index, :html
172
+
173
+ If you for any reason need these methods inside a different controller, see the (above) topic:
174
+ "Specifying the :controller and :model options with make_sortable()"
175
+
176
+ All 4 methods take the same arguments. Let me explain.
177
+
178
+ ==== Argument: :object
179
+ This is a required argument. It expects you to provide the object/(array) on which you are performing the .each_with_index method.
180
+
181
+ button_up_for_posts_position(:object => @posts)
182
+
183
+ ==== Argument: :index
184
+ This is a required argument. It expects you to provide the index of the currently looping object(record). You can get this index when calling .each_with_index on the @posts object/(array)
185
+
186
+ @posts.each_with_index do |post, index|
187
+ button_up_for_posts_position(:object => @posts, :index => index)
188
+ end
189
+
190
+ The example above is basically all that's required to get the sorting gem working. The :html argument is optional.
191
+ Basically, it's like the "link_to()" and "button_to()" methods in the Rails-Core. With it you can provide any additional HTML attributes to the HTML tag.
192
+
193
+ ==== Argument: :html
194
+
195
+ button_up_for_posts_position(:object => @posts, :index => index, :html => {
196
+ :id => "post_id_#{post.id}",
197
+ :class => "post_class",
198
+ :etc => "etc_etc_etc"
199
+ })
200
+
201
+ So you are free to add whatever additional html attributes you like to all 4 methods.
202
+
203
+
204
+
205
+ == Copyright
206
+
207
+ Copyright (c) 2009, Michael van Rooijen / Final Creation. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,54 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "make_sortable"
8
+ gem.summary = "The \"Make Sortable\" Plugin/Gem makes database records sortable in a simple, quick and easy way."
9
+ gem.description = "This plugin/gem provides an easy way to implement a simple database record sorting solution."
10
+ gem.email = "meskyan@gmail.com"
11
+ gem.homepage = "http://github.com/meskyanichi/make_sortable"
12
+ gem.authors = ["Michael van Rooijen", "Jeff Kreeftmeijer"]
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
16
+ end
17
+
18
+ require 'rake/testtask'
19
+ Rake::TestTask.new(:test) do |test|
20
+ test.libs << 'lib' << 'test'
21
+ test.pattern = 'test/**/*_test.rb'
22
+ test.verbose = true
23
+ end
24
+
25
+ begin
26
+ require 'rcov/rcovtask'
27
+ Rcov::RcovTask.new do |test|
28
+ test.libs << 'test'
29
+ test.pattern = 'test/**/*_test.rb'
30
+ test.verbose = true
31
+ end
32
+ rescue LoadError
33
+ task :rcov do
34
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
35
+ end
36
+ end
37
+
38
+ task :test => :check_dependencies
39
+
40
+ task :default => :test
41
+
42
+ require 'rake/rdoctask'
43
+ Rake::RDocTask.new do |rdoc|
44
+ if File.exist?('VERSION')
45
+ version = File.read('VERSION')
46
+ else
47
+ version = ""
48
+ end
49
+
50
+ rdoc.rdoc_dir = 'rdoc'
51
+ rdoc.title = "make_sortable #{version}"
52
+ rdoc.rdoc_files.include('README*')
53
+ rdoc.rdoc_files.include('lib/**/*.rb')
54
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ ActionController::Base.send(:include, MakeSortable)
@@ -0,0 +1,20 @@
1
+ module MakeSortable
2
+ module Actions
3
+ # Generates the necessary controller action which the user must route to.
4
+ def generate_controller_action
5
+ Kernel.const_get(controller_fullname).class_eval do
6
+ options = MakeSortable::get_options
7
+ define_method options[:attribute] do
8
+ params[options[:controller]].each_with_index do |id, index|
9
+ unless options[:filter]
10
+ Kernel.const_get(options[:model]).update_all(["#{options[:attribute]}=?", index+1], ['id=?', id])
11
+ else
12
+ options[:filter].send(options[:model].underscore.pluralize.to_sym).update_all(["#{options[:attribute]}=?", index+1], ['id=?', id])
13
+ end
14
+ end
15
+ redirect_to options[:redirect_path]
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ module MakeSortable
2
+ module Array
3
+
4
+ # Swaps values of an array.
5
+ def swap(a,b)
6
+ swapped = self.clone
7
+ swapped[a], swapped[b] = self[b], self[a]
8
+ swapped
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,78 @@
1
+ module MakeSortable
2
+ module Helpers
3
+
4
+ # This method generates the necessary view helpers to generate the up/down links/buttons.
5
+ def generate_view_helpers
6
+
7
+ # Open the ActionController::Base class to insert the helper methods for the views
8
+ ActionController::Base.class_eval do
9
+
10
+ # Includes ActionView::Helpers to be able to generate specific HTML tags for the methods below
11
+ include ActionView::Helpers
12
+
13
+ options = MakeSortable::get_options
14
+
15
+ # Enable Helper Method for Views
16
+ helper_method "button_up_for_#{options[:controller]}_#{options[:attribute]}",
17
+ "link_up_for_#{options[:controller]}_#{options[:attribute]}",
18
+ "button_down_for_#{options[:controller]}_#{options[:attribute]}",
19
+ "link_down_for_#{options[:controller]}_#{options[:attribute]}"
20
+
21
+ # Loop through both the button and link symbols to generate link_to and button_to helpers
22
+ [:button, :link].each do |trigger|
23
+
24
+ # Defines the up button helper method for the specified controller/action and attribute
25
+ define_method "#{trigger}_up_for_#{options[:controller]}_#{options[:attribute]}" do |view_options|
26
+ if trigger.eql?(:button)
27
+ if view_options[:index] > 0
28
+
29
+ button_to( view_options[:name] || "up",
30
+ {:controller => options[:controller],
31
+ :action => options[:attribute],
32
+ options[:controller].to_sym => view_options[:object].swap(view_options[:index],
33
+ view_options[:index] -1 )}, view_options[:html])
34
+
35
+ end
36
+ else
37
+ if view_options[:index] > 0
38
+
39
+ link_to( view_options[:name] || "up",
40
+ {:controller => options[:controller],
41
+ :action => options[:attribute],
42
+ options[:controller].to_sym => view_options[:object].swap(view_options[:index],
43
+ view_options[:index] -1 )}, view_options[:html])
44
+
45
+ end
46
+ end
47
+ end
48
+
49
+ # Defines the helper method for the specified controller/action and attribute
50
+ define_method "#{trigger}_down_for_#{options[:controller]}_#{options[:attribute]}" do |view_options|
51
+ if trigger.eql?(:button)
52
+ if view_options[:index] < view_options[:object].length - 1
53
+
54
+ button_to( view_options[:name] || "down",
55
+ {:controller => options[:controller],
56
+ :action => options[:attribute],
57
+ options[:controller].to_sym => view_options[:object].swap(view_options[:index],
58
+ view_options[:index] +1 )}, view_options[:html])
59
+
60
+ end
61
+ else
62
+ if view_options[:index] < view_options[:object].length - 1
63
+
64
+ link_to( view_options[:name] || "down",
65
+ {:controller => options[:controller],
66
+ :action => options[:attribute],
67
+ options[:controller].to_sym => view_options[:object].swap(view_options[:index],
68
+ view_options[:index] +1 )}, view_options[:html])
69
+
70
+ end
71
+ end
72
+ end
73
+
74
+ end # => Each
75
+ end # => ActionController::Base
76
+ end # => MakeSortable::Helpers::generate_view_helpers
77
+ end # => MakeSortable::Helpers
78
+ end # => MakeSortable
@@ -0,0 +1,67 @@
1
+ module MakeSortable
2
+
3
+ class << self
4
+
5
+ include MakeSortable::Actions
6
+ include MakeSortable::Helpers
7
+
8
+ attr_accessor :controller, :controller_fullname, :attribute, :redirect_path, :filter, :model
9
+
10
+ # Sets all the required options. These will be available throughout the library.
11
+ def set_options(options, controller_name)
12
+ @controller = options[:controller] || controller_name
13
+ @controller_fullname = "#{@controller}_controller".camelcase
14
+ @attribute = options[:attribute] || 'position'
15
+ @redirect_path = options[:redirect_path] || {:action => :index}
16
+ @filter = options[:filter]
17
+
18
+ if options[:model].blank?
19
+ @model = controller_name.singularize.camelcase
20
+ else
21
+ @model = options[:model].to_s.singularize.camelcase
22
+ end
23
+ end
24
+
25
+ # Returns the set of options in their corresponding hash-key name.
26
+ def get_options
27
+ @options = Hash.new unless defined?(@options)
28
+ ['controller', 'controller_fullname', 'attribute', 'redirect_path', 'filter', 'model'].each do |option|
29
+ @options[option] = instance_variable_get("@#{option}")
30
+ end
31
+ @options.symbolize_keys
32
+ end
33
+
34
+ end
35
+
36
+ # Initializes when the module gets included into ActiveRecord::Base
37
+ def self.included(base)
38
+ base.extend InitializeMethods
39
+ end
40
+
41
+ # ActMethods are not initialized unless the user requests it.
42
+ module InitializeMethods
43
+
44
+ # Initializes the positioning method
45
+ def make_sortable(options = {})
46
+
47
+ # Define and Return the controller, model and attribute
48
+ MakeSortable::set_options(options, controller_name)
49
+
50
+ # Include the Array module into the Array Class to add the "swap" method functionality
51
+ unless Array.methods.respond_to?(:swap)
52
+ Array.send(:include, MakeSortable::Array)
53
+ end
54
+
55
+ # Generates the controller action
56
+ # Makes it available in the corresponding controller
57
+ MakeSortable::generate_controller_action
58
+
59
+ # Generates the view helpers
60
+ # Makes them available in ActionController::Base
61
+ MakeSortable::generate_view_helpers
62
+
63
+ end # => InitializeMethods#make_sortable
64
+ end # => InitializeMethods
65
+ end # => MakeSortable
66
+
67
+ ActionController::Base.send(:include, MakeSortable)
@@ -0,0 +1,54 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{make_sortable}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael van Rooijen", "Jeff Kreeftmeijer"]
12
+ s.date = %q{2009-08-16}
13
+ s.description = %q{This plugin/gem provides an easy way to implement a simple database record sorting solution.}
14
+ s.email = %q{meskyan@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".gitignore",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "init.rb",
27
+ "lib/make_sortable.rb",
28
+ "lib/make_sortable/actions.rb",
29
+ "lib/make_sortable/array.rb",
30
+ "lib/make_sortable/helpers.rb",
31
+ "make_sortable.gemspec",
32
+ "test/make_sortable_test.rb",
33
+ "test/test_helper.rb"
34
+ ]
35
+ s.homepage = %q{http://github.com/meskyanichi/make_sortable}
36
+ s.rdoc_options = ["--charset=UTF-8"]
37
+ s.require_paths = ["lib"]
38
+ s.rubygems_version = %q{1.3.5}
39
+ s.summary = %q{The "Make Sortable" Plugin/Gem makes database records sortable in a simple, quick and easy way.}
40
+ s.test_files = [
41
+ "test/make_sortable_test.rb",
42
+ "test/test_helper.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class MakeSortableTest < Test::Unit::TestCase
4
+ should "probably rename this file and start testing for real" do
5
+ flunk "hey buddy, you should probably rename this file and start testing for real"
6
+ end
7
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+
5
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ require 'make_sortable'
8
+
9
+ class Test::Unit::TestCase
10
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meskyanichi-make_sortable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael van Rooijen
8
+ - Jeff Kreeftmeijer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-08-16 00:00:00 -07:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: This plugin/gem provides an easy way to implement a simple database record sorting solution.
18
+ email: meskyan@gmail.com
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files:
24
+ - LICENSE
25
+ - README.rdoc
26
+ files:
27
+ - .document
28
+ - .gitignore
29
+ - LICENSE
30
+ - README.rdoc
31
+ - Rakefile
32
+ - VERSION
33
+ - init.rb
34
+ - lib/make_sortable.rb
35
+ - lib/make_sortable/actions.rb
36
+ - lib/make_sortable/array.rb
37
+ - lib/make_sortable/helpers.rb
38
+ - make_sortable.gemspec
39
+ - test/make_sortable_test.rb
40
+ - test/test_helper.rb
41
+ has_rdoc: false
42
+ homepage: http://github.com/meskyanichi/make_sortable
43
+ licenses:
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.3.5
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: The "Make Sortable" Plugin/Gem makes database records sortable in a simple, quick and easy way.
68
+ test_files:
69
+ - test/make_sortable_test.rb
70
+ - test/test_helper.rb