all_sorts 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1 @@
1
+ require 'autotest/bundler'
data/.gemtest ADDED
File without changes
data/.gitignore ADDED
@@ -0,0 +1,41 @@
1
+ !.gitignore
2
+ *.gem
3
+ *.rbc
4
+ *.sw[a-p]
5
+ *.tmproj
6
+ *.tmproject
7
+ *.un~
8
+ *~
9
+ .DS_Store
10
+ .Spotlight-V100
11
+ .Trashes
12
+ ._*
13
+ .bundle
14
+ .config
15
+ .directory
16
+ .elc
17
+ .redcar
18
+ .yardoc
19
+ /.emacs.desktop
20
+ /.emacs.desktop.lock
21
+ Desktop.ini
22
+ Gemfile.lock
23
+ Icon?
24
+ InstalledFiles
25
+ Session.vim
26
+ Thumbs.db
27
+ \#*\#
28
+ _yardoc
29
+ auto-save-list
30
+ coverage
31
+ doc/
32
+ lib/bundler/man
33
+ pkg
34
+ pkg/*
35
+ rdoc
36
+ spec/reports
37
+ test/tmp
38
+ test/version_tmp
39
+ tmp
40
+ tmtags
41
+ tramp
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format=nested
3
+ --backtrace
data/.yardopts ADDED
@@ -0,0 +1,3 @@
1
+ --markup markdown
2
+ -
3
+ LICENSE.md
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'http://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gem_template.gemspec
4
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,10 @@
1
+ Copyright (c) 2011, Code for America
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
5
+
6
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8
+ * Neither the name of Code for America nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9
+
10
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # All Sorts
2
+
3
+ A DSL for sorting active record results based on hash keys with the term _sort_ in them.
4
+
5
+ ## Installation
6
+
7
+ ### Bundler
8
+ gem 'all_sorts'
9
+
10
+ ### Other
11
+ gem install all_sorts
12
+
13
+ ## Usage
14
+ All Sorts was originally developed to fill the need of being able to
15
+ sort by one or multiple columns passed in the URL, however it works with
16
+ ActiveRecord and basically takes in a hash. This gem adds a ".sort" method
17
+ to ActiveRecord which basically does some clever stuff by looking at the
18
+ hash keys, creates a string by which to sort results, and calls ".order"
19
+ with that string.
20
+
21
+ It also adds a ".sortable_fields" method for you to limit by which fields
22
+ the records may be ordered.
23
+
24
+ ## URL Examples
25
+ * http://whatever.com/wherever/?sort_name=asc
26
+ * http://whatever.com/wherever/?sort_1_name=asc
27
+ * http://whatever.com/wherever/?sort_1_name=asc&sort_2_salary=desc
28
+
29
+ ## Using sortable_fields limiter in your model
30
+ ``` ruby
31
+ class User < ActiveRecord::Base
32
+ sortable_fields :name, :salary
33
+ end
34
+ ```
35
+
36
+ ## Active Record Calls
37
+ ### Using with all the "params" from the URL (usual usage)
38
+ ``` ruby
39
+ users = User.sort(params).all
40
+ ```
41
+
42
+ ### Example of how it just takes in a Hash
43
+ ```ruby
44
+ #GIVEN THE DATA IN THE DB IS AS FOLLOWS:
45
+ adam:
46
+ id: 1
47
+ name: Adam
48
+ salary: 80000
49
+ bonus: true
50
+
51
+ dave1:
52
+ id: 2
53
+ name: Dave
54
+ salary: 9000
55
+ bonus: true
56
+
57
+ dave2:
58
+ id: 3
59
+ name: Dave
60
+ salary: 70000
61
+ bonus: true
62
+
63
+ admin:
64
+ id: 12
65
+ name: admin
66
+ salary: 10000
67
+ bonus: false
68
+
69
+ goofy:
70
+ id: 13
71
+ name: Goofy
72
+ salary: 11000
73
+ bonus: false
74
+
75
+ #THE CALL
76
+ users = User.sort({'sort_1_name' => 'asc', 'sort_2_salary' => 'desc'}).all
77
+
78
+ #RESULTS
79
+ [#<User id: 1, name: "Adam", salary: 80000, bonus: true, created_at: "2011-06-08 15:30:06", updated_at: "2011-06-08 15:30:06">,
80
+ #<User id: 3, name: "Dave", salary: 70000, bonus: true, created_at: "2011-06-08 15:30:06", updated_at: "2011-06-08 15:30:06">,
81
+ #<User id: 2, name: "Dave", salary: 9000, bonus: true, created_at: "2011-06-08 15:30:06", updated_at: "2011-06-08 15:30:06">,
82
+ #<User id: 13, name: "Goofy", salary: 11000, bonus: false, created_at: "2011-06-08 15:30:06", updated_at: "2011-06-08 15:30:06">,
83
+ #<User id: 12, name: "admin", salary: 10000, bonus: false, created_at: "2011-06-08 15:30:06", updated_at: "2011-06-08 15:30:06">]
84
+ ```
85
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'bundler'
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new(:spec)
8
+
9
+ task :default => :spec
10
+ task :test => :spec
11
+
12
+ require 'yard'
13
+ namespace :doc do
14
+ YARD::Rake::YardocTask.new do |task|
15
+ task.files = ['LICENSE.md', 'lib/**/*.rb']
16
+ task.options = ['--markup', 'markdown']
17
+ end
18
+ end
data/all_sorts.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/all_sorts/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.name = 'all_sorts'
6
+ gem.version = AllSorts::VERSION
7
+ gem.author = "Phil Spitler"
8
+ gem.email = 'pspitler@gmail.com'
9
+ gem.homepage = 'https://github.com/philspitler/all_sorts'
10
+ gem.summary = 'A DSL for sorting active record results based on hash keys with the term _sort_ in them.'
11
+ gem.description = ''
12
+
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{|f| File.basename(f)}
16
+ gem.require_paths = ['lib']
17
+
18
+ gem.add_development_dependency 'maruku', '~> 0.6'
19
+ gem.add_development_dependency 'rake', '~> 0.9'
20
+ gem.add_development_dependency 'rspec', '~> 2.6'
21
+ gem.add_development_dependency 'simplecov', '~> 0.4'
22
+ gem.add_development_dependency 'yard', '~> 0.7'
23
+ gem.add_development_dependency 'sqlite3'
24
+
25
+ gem.add_dependency 'activerecord', '>= 3.0.1'
26
+ end
@@ -0,0 +1,3 @@
1
+ module AllSorts
2
+ VERSION = "1.0.0"
3
+ end
data/lib/all_sorts.rb ADDED
@@ -0,0 +1,32 @@
1
+ require 'active_record'
2
+
3
+ module AllSorts
4
+ attr_accessor :sortable_fields
5
+ def sort(params)
6
+
7
+ #remove non filter params
8
+ params.delete_if { |key, value| key.to_s.index('sort_').nil? }
9
+ keys = params.keys.sort
10
+ #params.keys.sort_by {|s| s.to_s}.map {|key| [key, params[key]] }
11
+
12
+ sorters = []
13
+
14
+ keys.each do |key, value|
15
+ keysplit = key.to_s.split('_')
16
+ unless @sortable_fields and not @sortable_fields.include?(keysplit.last.to_sym)
17
+ if column_names.include?(keysplit.last)
18
+ sorters << "#{keysplit.last} #{params[key]}"
19
+ end
20
+ end
21
+ end
22
+
23
+ order(sorters)
24
+ end
25
+
26
+
27
+ def sortable_fields(*fields)
28
+ @sortable_fields = fields
29
+ end
30
+ end
31
+
32
+ ActiveRecord::Base.extend AllSorts
@@ -0,0 +1,47 @@
1
+ require 'helper'
2
+ require 'finders/activerecord_test_connector'
3
+ ActiverecordTestConnector.setup
4
+
5
+ describe AllSorts do
6
+ extend ActiverecordTestConnector::FixtureSetup
7
+ fixtures :users
8
+ fixtures :posts
9
+
10
+ it "sorts by a single field" do
11
+ posts = Post.sort({'sort_title' => 'desc'}).all
12
+ post_ids = posts.map do |post|
13
+ post.id
14
+ end
15
+ post_ids.should == [3, 2, 1]
16
+
17
+ posts = Post.sort({'sort_title' => 'asc'}).all
18
+ post_ids = posts.map do |post|
19
+ post.id
20
+ end
21
+ post_ids.should == [1, 2, 3]
22
+ end
23
+
24
+ it "ignores fields not in sortable_fields if sortable_fields is set" do
25
+ posts = Post.sort({'sort_body' => 'desc'}).all
26
+ post_ids = posts.map do |post|
27
+ post.id
28
+ end
29
+ post_ids.should == [1, 2, 3]
30
+ end
31
+
32
+ it "sorts by multiple fields" do
33
+ users = User.sort({'sort_1_name' => 'asc', 'sort_2_salary' => 'desc'}).all
34
+ user_ids = users.map do |user|
35
+ user.id
36
+ end
37
+ user_ids.should == [1, 3, 2, 13, 12]
38
+ end
39
+
40
+ it "ignores fields that don't make sense" do
41
+ users = User.sort({'sort_1_name' => 'asc', 'sort_2_blah' => 'desc'}).all
42
+ user_ids = users.map do |user|
43
+ user.id
44
+ end
45
+ user_ids.should == [1, 2, 3, 13, 12]
46
+ end
47
+ end
@@ -0,0 +1,104 @@
1
+ require 'active_record'
2
+ require 'active_record/version'
3
+ require 'active_record/fixtures'
4
+ require 'active_support/multibyte' # needed for Ruby 1.9.1
5
+
6
+ $query_count = $query_sql = nil
7
+
8
+ module ActiverecordTestConnector
9
+ extend self
10
+
11
+ attr_accessor :able_to_connect
12
+ attr_accessor :connected
13
+
14
+ FIXTURES_PATH = File.expand_path('../../fixtures', __FILE__)
15
+
16
+ # Set our defaults
17
+ self.connected = false
18
+ self.able_to_connect = true
19
+
20
+ def setup
21
+ unless self.connected || !self.able_to_connect
22
+ setup_connection
23
+ load_schema
24
+ add_load_path FIXTURES_PATH
25
+ self.connected = true
26
+ end
27
+ rescue Exception => e # errors from ActiveRecord setup
28
+ $stderr.puts "\nSkipping ActiveRecord tests: #{e}\n\n"
29
+ self.able_to_connect = false
30
+ end
31
+
32
+ private
33
+
34
+ def add_load_path(path)
35
+ dep = defined?(ActiveSupport::Dependencies) ? ActiveSupport::Dependencies : ::Dependencies
36
+ dep.autoload_paths.unshift path
37
+ end
38
+
39
+ def setup_connection
40
+ ActiveRecord::Base.establish_connection(
41
+ :adapter => "sqlite3",
42
+ :database => ":memory:"
43
+ )
44
+ prepare ActiveRecord::Base.connection
45
+ end
46
+
47
+ def load_schema
48
+ ActiveRecord::Base.silence do
49
+ ActiveRecord::Migration.verbose = false
50
+ load File.join(FIXTURES_PATH, 'schema.rb')
51
+ end
52
+ end
53
+
54
+ def prepare(conn)
55
+ class << conn
56
+ IGNORED_SQL = /^(?:PRAGMA|SELECT (?:currval|CAST|@@IDENTITY|@@ROWCOUNT)|SHOW FIELDS)\b/
57
+
58
+ def execute_with_counting(sql, name = nil, &block)
59
+ if $query_count and IGNORED_SQL !~ sql
60
+ $query_count += 1
61
+ $query_sql << sql
62
+ end
63
+ execute_without_counting(sql, name, &block)
64
+ end
65
+
66
+ alias_method_chain :execute, :counting
67
+ end
68
+ end
69
+
70
+ module FixtureSetup
71
+ def fixtures(*tables)
72
+ table_names = tables.map { |t| t.to_s }
73
+
74
+ fixtures = Fixtures.create_fixtures ActiverecordTestConnector::FIXTURES_PATH, table_names
75
+ @@loaded_fixtures = {}
76
+ @@fixture_cache = {}
77
+
78
+ unless fixtures.nil?
79
+ if fixtures.instance_of?(Fixtures)
80
+ @@loaded_fixtures[fixtures.table_name] = fixtures
81
+ else
82
+ fixtures.each { |f| @@loaded_fixtures[f.table_name] = f }
83
+ end
84
+ end
85
+
86
+ table_names.each do |table_name|
87
+ define_method(table_name) do |*fixtures|
88
+ @@fixture_cache[table_name] ||= {}
89
+
90
+ instances = fixtures.map do |fixture|
91
+ if @@loaded_fixtures[table_name][fixture.to_s]
92
+ @@fixture_cache[table_name][fixture] ||= @@loaded_fixtures[table_name][fixture.to_s].find
93
+ else
94
+ raise StandardError, "No fixture with name '#{fixture}' found for table '#{table_name}'"
95
+ end
96
+ end
97
+
98
+ instances.size == 1 ? instances.first : instances
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
@@ -0,0 +1,3 @@
1
+ class Post < ActiveRecord::Base
2
+ sortable_fields :title, :published_at
3
+ end
@@ -0,0 +1,16 @@
1
+ post1:
2
+ id: 1
3
+ title: "Post 1 title"
4
+ body: "Post 1 body"
5
+
6
+ post2:
7
+ id: 2
8
+ title: "Post 2 title"
9
+ body: "Post 2 body"
10
+
11
+ post3:
12
+ id: 3
13
+ title: "Post 3 title"
14
+ body: "Post 3 body"
15
+
16
+
@@ -0,0 +1,17 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table "users", :force => true do |t|
3
+ t.column "name", :text
4
+ t.column "salary", :integer, :default => 70000
5
+ t.column "bonus", :boolean, :default => false
6
+ t.column "created_at", :datetime
7
+ t.column "updated_at", :datetime
8
+ end
9
+
10
+ create_table "posts", :force => true do |t|
11
+ t.column "title", :string
12
+ t.column "body", :text
13
+ t.column "published_at", :datetime
14
+ t.column "created_at", :datetime
15
+ t.column "updated_at", :datetime
16
+ end
17
+ end
@@ -0,0 +1,2 @@
1
+ class User < ActiveRecord::Base
2
+ end
@@ -0,0 +1,30 @@
1
+ adam:
2
+ id: 1
3
+ name: Adam
4
+ salary: 80000
5
+ bonus: true
6
+
7
+ dave1:
8
+ id: 2
9
+ name: Dave
10
+ salary: 9000
11
+ bonus: true
12
+
13
+ dave2:
14
+ id: 3
15
+ name: Dave
16
+ salary: 70000
17
+ bonus: true
18
+
19
+ admin:
20
+ id: 12
21
+ name: admin
22
+ salary: 10000
23
+ bonus: false
24
+
25
+ goofy:
26
+ id: 13
27
+ name: Goofy
28
+ salary: 11000
29
+ bonus: false
30
+
data/spec/helper.rb ADDED
@@ -0,0 +1,6 @@
1
+ $:.unshift File.expand_path('..', __FILE__)
2
+ $:.unshift File.expand_path('../../lib', __FILE__)
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+ require 'all_sorts'
6
+ require 'rspec'
metadata ADDED
@@ -0,0 +1,187 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: all_sorts
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Phil Spitler
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-06-09 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: maruku
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 6
31
+ version: "0.6"
32
+ type: :development
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rake
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ - 9
45
+ version: "0.9"
46
+ type: :development
47
+ version_requirements: *id002
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id003 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ~>
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 2
58
+ - 6
59
+ version: "2.6"
60
+ type: :development
61
+ version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: simplecov
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ~>
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ - 4
73
+ version: "0.4"
74
+ type: :development
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: yard
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ~>
83
+ - !ruby/object:Gem::Version
84
+ segments:
85
+ - 0
86
+ - 7
87
+ version: "0.7"
88
+ type: :development
89
+ version_requirements: *id005
90
+ - !ruby/object:Gem::Dependency
91
+ name: sqlite3
92
+ prerelease: false
93
+ requirement: &id006 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ type: :development
102
+ version_requirements: *id006
103
+ - !ruby/object:Gem::Dependency
104
+ name: activerecord
105
+ prerelease: false
106
+ requirement: &id007 !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ segments:
112
+ - 3
113
+ - 0
114
+ - 1
115
+ version: 3.0.1
116
+ type: :runtime
117
+ version_requirements: *id007
118
+ description: ""
119
+ email: pspitler@gmail.com
120
+ executables: []
121
+
122
+ extensions: []
123
+
124
+ extra_rdoc_files: []
125
+
126
+ files:
127
+ - .autotest
128
+ - .gemtest
129
+ - .gitignore
130
+ - .rspec
131
+ - .yardopts
132
+ - Gemfile
133
+ - LICENSE.md
134
+ - README.md
135
+ - Rakefile
136
+ - all_sorts.gemspec
137
+ - lib/all_sorts.rb
138
+ - lib/all_sorts/version.rb
139
+ - spec/all_sorts_spec.rb
140
+ - spec/finders/activerecord_test_connector.rb
141
+ - spec/fixtures/post.rb
142
+ - spec/fixtures/posts.yml
143
+ - spec/fixtures/schema.rb
144
+ - spec/fixtures/user.rb
145
+ - spec/fixtures/users.yml
146
+ - spec/helper.rb
147
+ has_rdoc: true
148
+ homepage: https://github.com/philspitler/all_sorts
149
+ licenses: []
150
+
151
+ post_install_message:
152
+ rdoc_options: []
153
+
154
+ require_paths:
155
+ - lib
156
+ required_ruby_version: !ruby/object:Gem::Requirement
157
+ none: false
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ segments:
162
+ - 0
163
+ version: "0"
164
+ required_rubygems_version: !ruby/object:Gem::Requirement
165
+ none: false
166
+ requirements:
167
+ - - ">="
168
+ - !ruby/object:Gem::Version
169
+ segments:
170
+ - 0
171
+ version: "0"
172
+ requirements: []
173
+
174
+ rubyforge_project:
175
+ rubygems_version: 1.3.7
176
+ signing_key:
177
+ specification_version: 3
178
+ summary: A DSL for sorting active record results based on hash keys with the term _sort_ in them.
179
+ test_files:
180
+ - spec/all_sorts_spec.rb
181
+ - spec/finders/activerecord_test_connector.rb
182
+ - spec/fixtures/post.rb
183
+ - spec/fixtures/posts.yml
184
+ - spec/fixtures/schema.rb
185
+ - spec/fixtures/user.rb
186
+ - spec/fixtures/users.yml
187
+ - spec/helper.rb