resort 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ graph.png
6
+ .yardoc/*
7
+ doc/*
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use ruby-1.9.2@resort
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,47 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ require 'rspec/core/rake_task'
5
+ desc "Run resort specs"
6
+ RSpec::Core::RakeTask.new
7
+
8
+ require 'yard'
9
+ YARD::Rake::YardocTask.new(:docs) do |t|
10
+ t.files = ['lib/**/*.rb']
11
+ t.options = ['-m', 'markdown', '--no-private', '-r', 'Readme.md', '--title', 'Resort documentation']
12
+ end
13
+
14
+ site = 'doc'
15
+ source_branch = 'master'
16
+ deploy_branch = 'gh-pages'
17
+
18
+ desc "generate and deploy documentation website to github pages"
19
+ multitask :pages do
20
+ puts ">>> Deploying #{deploy_branch} branch to Github Pages <<<"
21
+ require 'git'
22
+ repo = Git.open('.')
23
+ puts "\n>>> Checking out #{deploy_branch} branch <<<\n"
24
+ repo.branch("#{deploy_branch}").checkout
25
+ (Dir["*"] - [site]).each { |f| rm_rf(f) }
26
+ Dir["#{site}/*"].each {|f| mv(f, "./")}
27
+ rm_rf(site)
28
+ puts "\n>>> Moving generated site files <<<\n"
29
+ Dir["**/*"].each {|f| repo.add(f) }
30
+ repo.status.deleted.each {|f, s| repo.remove(f)}
31
+ puts "\n>>> Commiting: Site updated at #{Time.now.utc} <<<\n"
32
+ message = ENV["MESSAGE"] || "Site updated at #{Time.now.utc}"
33
+ repo.commit(message)
34
+ puts "\n>>> Pushing generated site to #{deploy_branch} branch <<<\n"
35
+ repo.push
36
+ puts "\n>>> Github Pages deploy complete <<<\n"
37
+ repo.branch("#{source_branch}").checkout
38
+ end
39
+
40
+ task :doc => [:docs]
41
+
42
+ desc "Generate and open class diagram (needs Graphviz installed)"
43
+ task :graph do |t|
44
+ `bundle exec yard graph -d --full --no-private | dot -Tpng -o graph.png && open graph.png`
45
+ end
46
+
47
+ task :default => [:spec]
data/Readme.md ADDED
@@ -0,0 +1,92 @@
1
+ #resort
2
+
3
+ Resort provides sorting capabilities to your Rails 3 models.
4
+
5
+ ##Install
6
+
7
+ $ gem install resort
8
+
9
+ Or in your Gemfile:
10
+
11
+ gem 'resort'
12
+
13
+ ##Rationale
14
+
15
+ Most other sorting plugins work with an absolute `position` attribute that sets
16
+ the _weight_ of a given element within a tree. This field has no semantic sense,
17
+ since "84" by itself gives you absolutely no information about an element's
18
+ position or its relations with other elements of the tree.
19
+
20
+ Resort is implemented quite like a [binary tree](http://en.wikipedia.org/wiki/Binary_tree),
21
+ rather than relying on absolute position values. This way, every model
22
+ references a `next` and a `previous`, which seems a bit more sensible :)
23
+
24
+ ##Usage
25
+
26
+ You must add two fields (`next_id` and `first`) to your model's table:
27
+
28
+ class AddResortFieldsToProducts < ActiveRecord::Migration
29
+ def self.up
30
+ add_column :products, :next_id, :integer
31
+ add_column :products, :first, :boolean
32
+ end
33
+
34
+ def self.down
35
+ remove_column :products, :next_id
36
+ remove_column :products, :first
37
+ end
38
+ end
39
+
40
+ Then in your Product model:
41
+
42
+ class Product < ActiveRecord::Base
43
+ resort!
44
+ end
45
+
46
+ **NOTE**: By default, Resort will treat _all products_ as a single big tree.
47
+ If you wanted to limit the tree scope, i.e. treating every ProductLine as a
48
+ separate tree of sortable products, you must override the `siblings` method:
49
+
50
+ class Product < ActiveRecord::Base
51
+ resort!
52
+
53
+ def siblings
54
+ # Tree contains only products from my own product line
55
+ self.product_line.products
56
+ end
57
+ end
58
+
59
+ ###API
60
+
61
+ Every time a product is created, it will be appended after the last element.
62
+
63
+ Moreover, now a `product` responds to the following methods:
64
+
65
+ * `first?` &mdash; Returns true if the element is the first of the tree.
66
+ * `append_to(other_element)` &mdash; Appends the element _after_ another element.
67
+
68
+ And the class Product has a new scope named `ordered` that returns the
69
+ products in order.
70
+
71
+ ##Under the hood
72
+
73
+ Run the test suite by typing:
74
+
75
+ rake spec
76
+
77
+ You can also build the documentation with the following command:
78
+
79
+ rake docs
80
+
81
+ ## Note on Patches/Pull Requests
82
+
83
+ * Fork the project.
84
+ * Make your feature addition or bug fix.
85
+ * Add tests for it. This is important so I don't break it in a
86
+ future version unintentionally.
87
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
88
+ * Send us a pull request. Bonus points for topic branches.
89
+
90
+ ## Copyright
91
+
92
+ Copyright (c) 2011 Codegram. See LICENSE for details.
@@ -0,0 +1,4 @@
1
+ module Resort
2
+ # Resort's version number
3
+ VERSION = "0.0.1"
4
+ end
data/lib/resort.rb ADDED
@@ -0,0 +1,204 @@
1
+ # # Resort
2
+ #
3
+ # A tool that allows any ActiveRecord model to be sorted.
4
+ #
5
+ # Unlike most Rails sorting plugins (acts_as_list, etc), Resort is based
6
+ # on linked lists rather than absolute position fields.
7
+ #
8
+ # @example Using Resort in an ActiveRecord model
9
+ # # In the migration
10
+ # create_table :products do |t|
11
+ # t.text :name
12
+ # t.references :next
13
+ # t.boolean :first
14
+ # end
15
+ #
16
+ # # Model
17
+ # class Product < ActiveRecord::Base
18
+ # resort!
19
+ #
20
+ # # A sortable model must implement #siblings method, which should
21
+ # # return and ActiveRecord::Relation with all the models to be
22
+ # # considered as `peers` in the list representing the sorted
23
+ # # products, i.e. its siblings.
24
+ # def siblings
25
+ # self.class.scoped
26
+ # end
27
+ # end
28
+ #
29
+ # product = Product.create(:name => 'Bread')
30
+ # product.first? # => true
31
+ #
32
+ # another_product = Product.create(:name => 'Milk')
33
+ # yet_another_product = Product.create(:name => 'Salami')
34
+ #
35
+ # yet_another_product.append_to(product)
36
+ #
37
+ # Product.ordered.map(&:name)
38
+ # # => ['Bread', 'Salami', 'Milk']
39
+ module Resort
40
+ # The module encapsulating all the Resort functionality.
41
+ #
42
+ # @todo Refactor into a more OO solution, maybe implementing a LinkedList
43
+ # object.
44
+ module Sortable
45
+ class << self
46
+ # When included, extends the includer with {ClassMethods}, and includes
47
+ # {InstanceMethods} in it.
48
+ #
49
+ # It also establishes the required relationships. It is necessary that
50
+ # the includer table has the following database columns:
51
+ #
52
+ # t.references :next
53
+ # t.boolean :first
54
+ #
55
+ # @param [ActiveRecord::Base] base the includer `ActiveRecord` model.
56
+ def included(base)
57
+ base.extend ClassMethods
58
+ base.send :include, InstanceMethods
59
+
60
+ base.has_one :previous, :class_name => base.name, :foreign_key => 'next_id', :inverse_of => :next
61
+ base.belongs_to :next, :class_name => base.name, :inverse_of => :previous
62
+
63
+ base.after_create :include_in_list!
64
+ base.after_destroy :delete_from_list
65
+ end
66
+ end
67
+
68
+ # Class methods to be used from the model class.
69
+ module ClassMethods
70
+ # Returns the first element of the list.
71
+ #
72
+ # @return [ActiveRecord::Base] the first element of the list.
73
+ def first_in_order
74
+ where(:first => true).first
75
+ end
76
+
77
+ # Returns eager-loaded Components in order.
78
+ #
79
+ # OPTIMIZE: Avoid creating as many hashes.
80
+ # @return [Array<ActiveRecord::Base>] the ordered elements
81
+ def ordered
82
+ ordered_elements = []
83
+ elements = {}
84
+
85
+ scoped.each do |element|
86
+ if element.first?
87
+ ordered_elements << element
88
+ else
89
+ elements[element.id] = element
90
+ end
91
+ end
92
+
93
+ elements.length.times do
94
+ ordered_elements << elements[ordered_elements.last.next_id]
95
+ end
96
+ ordered_elements
97
+ end
98
+ end
99
+
100
+ # Instance methods to use.
101
+ module InstanceMethods
102
+
103
+ # Default definition of siblings, i.e. every instance of the model.
104
+ #
105
+ # Can be overriden to specify a different scope for the siblings.
106
+ # For example, if we wanted to limit a products tree inside a ProductLine
107
+ # scope, we would do the following:
108
+ #
109
+ # class Product < ActiveRecord::Base
110
+ # belongs_to :product_line
111
+ #
112
+ # resort!
113
+ #
114
+ # def siblings
115
+ # self.product_line.products
116
+ # end
117
+ #
118
+ # This way, every product line is an independent tree of sortable
119
+ # products.
120
+ #
121
+ # @return [ActiveRecord::Relation] the element's siblings relation.
122
+ def siblings
123
+ self.class.scoped
124
+ end
125
+ # Includes the object in the linked list.
126
+ #
127
+ # If there are no other objects, it prepends the object so that it is
128
+ # in the first position. Otherwise, it appends it to the end of the
129
+ # empty list.
130
+ def include_in_list!
131
+ _siblings.count > 0 ? push\
132
+ : prepend
133
+ end
134
+
135
+ # Puts the object in the first position of the list.
136
+ def prepend
137
+ return if first?
138
+
139
+ if _siblings.count > 0
140
+ delete_from_list
141
+ _siblings.where(:first => true).first.append_to(self)
142
+ end
143
+
144
+ self.update_attribute(:first, true)
145
+ end
146
+
147
+ # Puts the object in the last position of the list.
148
+ def push
149
+ return if last?
150
+ last_element = _siblings.where(:next_id => nil).first
151
+ self.append_to(last_element)
152
+ end
153
+
154
+ # Puts the object right after another object in the list.
155
+ def append_to(another)
156
+ if self.next
157
+ delete_from_list
158
+ elsif last?
159
+ self.previous.update_attribute(:next_id, nil)
160
+ self.previous = nil
161
+ end
162
+
163
+ self.update_attribute(:next_id, another.next_id)
164
+ another.update_attribute(:next_id, self.id)
165
+ end
166
+
167
+ private
168
+
169
+ def delete_from_list
170
+ if first? && self.next
171
+ self.update_attribute(:first, nil) unless frozen?
172
+ self.next.first = true
173
+ self.next.previous = nil
174
+ self.next.save!
175
+ elsif self.previous
176
+ previous.next = self.next
177
+ previous.save!
178
+ self.update_attribute(:next_id, nil) unless frozen?
179
+ end
180
+ end
181
+
182
+ def last?
183
+ self.previous && !self.next
184
+ end
185
+
186
+ def _siblings
187
+ table = self.class.arel_table
188
+ siblings.where(table[:id].not_eq(self.id))
189
+ end
190
+ end
191
+ end
192
+ # Helper class methods to be injected into ActiveRecord::Base class.
193
+ # They will be available to every model.
194
+ module ClassMethods
195
+ # Helper class method to include Resort::Sortable in an ActiveRecord
196
+ # model.
197
+ def resort!
198
+ include Sortable
199
+ end
200
+ end
201
+ end
202
+
203
+ require 'active_record' unless defined?(ActiveRecord)
204
+ ActiveRecord::Base.extend Resort::ClassMethods
data/resort.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "resort/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "resort"
7
+ s.version = Resort::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Oriol Gual", "Josep M. Bach", "Josep Jaume Rey"]
10
+ s.email = ["info@codegram.com"]
11
+ s.homepage = "http://codegram.github.com/resort"
12
+ s.summary = %q{Positionless model sorting for Rails 3.}
13
+ s.description = %q{Positionless model sorting for Rails 3.}
14
+
15
+ s.rubyforge_project = "resort"
16
+
17
+ s.add_runtime_dependency 'activerecord', '~> 3.0.5'
18
+ s.add_development_dependency 'sqlite3'
19
+ s.add_development_dependency 'rspec', '~> 2.5.0'
20
+ s.add_development_dependency 'yard'
21
+ s.add_development_dependency 'bluecloth'
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,283 @@
1
+ require 'spec_helper'
2
+
3
+ class Article < ActiveRecord::Base
4
+ resort!
5
+ end
6
+
7
+ module Resort
8
+ describe Sortable do
9
+
10
+ subject { Article.new }
11
+
12
+ context 'when included' do
13
+ it 'creates previous and next relationships' do
14
+ subject.should respond_to(:previous, :next)
15
+ end
16
+
17
+ it 'includes base with InstanceMethods' do
18
+ subject.class.ancestors.should include(Sortable::InstanceMethods)
19
+ end
20
+ it 'extend base with ClassMethods' do
21
+ (class << subject.class; self; end).ancestors.should include(Sortable::ClassMethods)
22
+ end
23
+ it 'defines a siblings method' do
24
+ subject.class.instance_methods.should include(:siblings)
25
+ end
26
+ end
27
+
28
+ describe 'ClassMethods' do
29
+ describe "#first_in_order" do
30
+ it 'returns the first element of the list' do
31
+ first = double :article
32
+ Article.should_receive(:where).with(:first => true).and_return [first]
33
+
34
+ Article.first_in_order
35
+ end
36
+ end
37
+ describe "#ordered" do
38
+ before do
39
+ Article.destroy_all
40
+
41
+ 4.times do |i|
42
+ Article.create(:name => i.to_s)
43
+ end
44
+
45
+ @article1 = Article.find_by_name('0')
46
+ @article2 = Article.find_by_name('1')
47
+ @article3 = Article.find_by_name('2')
48
+ @article4 = Article.find_by_name('3')
49
+ end
50
+ it 'returns the first element of the list' do
51
+ Article.ordered.should == [@article1, @article2, @article3, @article4]
52
+ end
53
+ after do
54
+ Article.destroy_all
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "after create" do
60
+ context 'when there are no siblings' do
61
+ it 'prepends the element' do
62
+ article = Article.create(:name => 'first!')
63
+
64
+ article.should be_first
65
+ article.next.should be_nil
66
+ article.previous.should be_nil
67
+ end
68
+ end
69
+ context 'otherwise' do
70
+ it 'appends the element' do
71
+ Article.create(:name => "1")
72
+ Article.create(:name => 'last!')
73
+
74
+ article = Article.find_by_name('last!')
75
+
76
+ article.should be_last
77
+ article.previous.name.should == '1'
78
+ end
79
+ end
80
+ after do
81
+ Article.destroy_all
82
+ end
83
+ end
84
+
85
+ describe "after destroy" do
86
+ context 'when the element is the first' do
87
+ it 'removes the element' do
88
+ article = Article.create(:name => 'first!')
89
+ article2 = Article.create(:name => 'second!')
90
+ article3 = Article.create(:name => 'last!')
91
+
92
+ article = Article.find_by_name('first!')
93
+ article.destroy
94
+
95
+ article2 = Article.find_by_name('second!')
96
+
97
+ article2.should be_first
98
+ article2.previous.should be_nil
99
+ end
100
+ end
101
+ context 'when the element is in the middle' do
102
+ it 'removes the element' do
103
+ article = Article.create(:name => 'first!')
104
+ article2 = Article.create(:name => 'second!')
105
+ article3 = Article.create(:name => 'last!')
106
+
107
+ article = Article.find_by_name('first!')
108
+
109
+ article2 = Article.find_by_name('second!')
110
+ article2.destroy
111
+
112
+ article = Article.find_by_name('first!')
113
+ article3 = Article.find_by_name('last!')
114
+
115
+ article.should be_first
116
+ article.next.name.should == 'last!'
117
+ article3.previous.name.should == 'first!'
118
+ end
119
+ end
120
+ context 'when the element is last' do
121
+ it 'removes the element' do
122
+ article = Article.create(:name => 'first!')
123
+ article2 = Article.create(:name => 'second!')
124
+ article3 = Article.create(:name => 'last!')
125
+
126
+ article3.destroy
127
+
128
+ article2.next.should be_nil
129
+ end
130
+ end
131
+ after do
132
+ Article.destroy_all
133
+ end
134
+ end
135
+
136
+ describe 'InstanceMethods' do
137
+ before do
138
+ Article.destroy_all
139
+ Article.create(:name => "1")
140
+ Article.create(:name => "2")
141
+ Article.create(:name => "3")
142
+ Article.create(:name => "4")
143
+
144
+ @article1 = Article.find_by_name('1')
145
+ @article2 = Article.find_by_name('2')
146
+ @article3 = Article.find_by_name('3')
147
+ @article4 = Article.find_by_name('4')
148
+ end
149
+
150
+ describe "#push" do
151
+ it "appends the element to the list" do
152
+ @article1.push
153
+
154
+ article1 = Article.find_by_name('1')
155
+ article1.previous.should == @article4
156
+ article1.next.should be_nil
157
+ end
158
+ context 'when the article is already last' do
159
+ it 'does nothing' do
160
+ @article4.push
161
+
162
+ @article4.previous.name.should == '3'
163
+ @article4.next.should be_nil
164
+ end
165
+ end
166
+ end
167
+
168
+ describe "#prepend" do
169
+ it "prepends the element" do
170
+ @article3.prepend
171
+
172
+ article3 = Article.find_by_name('3')
173
+
174
+ article3.should be_first
175
+ article3.previous.should be_nil
176
+ article3.next.name.should == '1'
177
+ end
178
+ context 'when the article is already first' do
179
+ it 'does nothing' do
180
+ @article1.prepend
181
+
182
+ @article1.previous.should be_nil
183
+ @article1.next.name.should == '2'
184
+ end
185
+ end
186
+ end
187
+
188
+ describe "#append_to" do
189
+ context 'appending 1 after 2' do
190
+ it "appends the element after another element" do
191
+ @article1.append_to(@article2)
192
+
193
+ article2 = Article.find_by_name('2')
194
+ article2.next.name.should == '1'
195
+
196
+ article1 = Article.find_by_name('1')
197
+ article1.next.name.should == '3'
198
+ article1.previous.name.should == '2'
199
+ @article3.previous.name.should == '1'
200
+
201
+ article2.should be_first
202
+ end
203
+ end
204
+ context 'appending 1 after 3' do
205
+ it "appends the element after another element" do
206
+ @article1.append_to(@article3)
207
+
208
+ article2 = Article.find_by_name('2')
209
+ article2.should be_first
210
+ article2.previous.should be_nil
211
+
212
+ article1 = Article.find_by_name('1')
213
+ article1.should_not be_first
214
+ article1.previous.name.should == '3'
215
+ article1.next.name.should == '4'
216
+
217
+ @article3.next.name.should == '1'
218
+
219
+ @article4.previous.name.should == '1'
220
+ end
221
+ end
222
+ context 'appending 2 after 3' do
223
+ it "appends the element after another element" do
224
+ @article2.append_to(@article3)
225
+
226
+ article1 = Article.find_by_name('1')
227
+ article1.next.name.should == '3'
228
+
229
+ article2 = Article.find_by_name('2')
230
+ article2.previous.name.should == '3'
231
+ article2.next.name.should == '4'
232
+
233
+ @article3.previous.name.should == '1'
234
+ @article3.next.name.should == '2'
235
+
236
+ @article4.previous.name.should == '2'
237
+ end
238
+ end
239
+ context 'appending 2 after 4' do
240
+ it "appends the element after another element" do
241
+ @article2.append_to(@article4)
242
+
243
+ article1 = Article.find_by_name('1')
244
+ article3 = Article.find_by_name('3')
245
+
246
+ article1.next.name.should == '3'
247
+ article3.previous.name.should == '1'
248
+
249
+ article2 = Article.find_by_name('2')
250
+ article2.previous.name.should == '4'
251
+ article2.should be_last
252
+
253
+ @article4.next.name.should == '2'
254
+ end
255
+ end
256
+ context 'appending 4 after 2' do
257
+ it "appends the element after another element" do
258
+ @article4.append_to(@article2)
259
+
260
+ article3 = Article.find_by_name('3')
261
+ article3.next.should be_nil
262
+ article3.previous.name.should == '4'
263
+
264
+ article4 = Article.find_by_name('4')
265
+ @article2.next.name.should == '4'
266
+ article4.previous.name.should == '2'
267
+ article4.next.name.should == '3'
268
+ end
269
+ end
270
+
271
+ context 'when the article is already after the other element' do
272
+ it 'does nothing' do
273
+ @article2.append_to(@article1)
274
+
275
+ @article1.next.name.should == '2'
276
+ @article2.previous.name.should == '1'
277
+ end
278
+ end
279
+ end
280
+ end
281
+
282
+ end
283
+ end
@@ -0,0 +1,19 @@
1
+ require 'rspec'
2
+ require 'resort'
3
+
4
+ ActiveRecord::Base.establish_connection(
5
+ :adapter => 'sqlite3',
6
+ :database => ':memory:'
7
+ )
8
+
9
+ ActiveRecord::Schema.define do
10
+ create_table :articles do |t|
11
+ t.string :name
12
+ t.integer :price
13
+
14
+ t.boolean :first
15
+ t.references :next
16
+
17
+ t.timestamps
18
+ end
19
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resort
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Oriol Gual
9
+ - Josep M. Bach
10
+ - Josep Jaume Rey
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+
15
+ date: 2011-03-18 00:00:00 +01:00
16
+ default_executable:
17
+ dependencies:
18
+ - !ruby/object:Gem::Dependency
19
+ name: activerecord
20
+ prerelease: false
21
+ requirement: &id001 !ruby/object:Gem::Requirement
22
+ none: false
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 3.0.5
27
+ type: :runtime
28
+ version_requirements: *id001
29
+ - !ruby/object:Gem::Dependency
30
+ name: sqlite3
31
+ prerelease: false
32
+ requirement: &id002 !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: "0"
38
+ type: :development
39
+ version_requirements: *id002
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ prerelease: false
43
+ requirement: &id003 !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ~>
47
+ - !ruby/object:Gem::Version
48
+ version: 2.5.0
49
+ type: :development
50
+ version_requirements: *id003
51
+ - !ruby/object:Gem::Dependency
52
+ name: yard
53
+ prerelease: false
54
+ requirement: &id004 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ type: :development
61
+ version_requirements: *id004
62
+ - !ruby/object:Gem::Dependency
63
+ name: bluecloth
64
+ prerelease: false
65
+ requirement: &id005 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ type: :development
72
+ version_requirements: *id005
73
+ description: Positionless model sorting for Rails 3.
74
+ email:
75
+ - info@codegram.com
76
+ executables: []
77
+
78
+ extensions: []
79
+
80
+ extra_rdoc_files: []
81
+
82
+ files:
83
+ - .gitignore
84
+ - .rspec
85
+ - .rvmrc
86
+ - Gemfile
87
+ - Rakefile
88
+ - Readme.md
89
+ - lib/resort.rb
90
+ - lib/resort/version.rb
91
+ - resort.gemspec
92
+ - spec/resort_spec.rb
93
+ - spec/spec_helper.rb
94
+ has_rdoc: true
95
+ homepage: http://codegram.github.com/resort
96
+ licenses: []
97
+
98
+ post_install_message:
99
+ rdoc_options: []
100
+
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: "0"
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: "0"
115
+ requirements: []
116
+
117
+ rubyforge_project: resort
118
+ rubygems_version: 1.5.2
119
+ signing_key:
120
+ specification_version: 3
121
+ summary: Positionless model sorting for Rails 3.
122
+ test_files:
123
+ - spec/resort_spec.rb
124
+ - spec/spec_helper.rb