resort 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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