sortable-by 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e4ee31050e1942211f65f5fe2c65e770b1f14a0629b885487f2cc9ddb102775f
4
+ data.tar.gz: '076397a69e9246cd9ecf527197850e4de5170b50c38c16ec1baa3c449ba3a30c'
5
+ SHA512:
6
+ metadata.gz: 927d032e52aa0dc6d6e5ddfa06453a79e2b7433888c1b570cff06b6bcecd4acb64a402869cd5ea42b11168770b16a0c2c54785cffb8eed353dfbde36fbce64d2
7
+ data.tar.gz: 9d773d07c8dc4c29791693f0da13ad9ac6751516739dc5466601c59817695e29ff6b4d348776390102d04780f99beeed824bfdb9a2ee7a5ba4ee866bb5bae0d6
@@ -0,0 +1,5 @@
1
+ spec/tmp
2
+ pkg
3
+ *.gem
4
+ .rake_tasks~
5
+ .rubocop-*
@@ -0,0 +1,10 @@
1
+ inherit_from:
2
+ - https://gitlab.com/bsm/misc/raw/master/rubocop/default.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.5
6
+
7
+ Naming/MemoizedInstanceVariableName:
8
+ Enabled: false
9
+ Naming/FileName:
10
+ Exclude: [lib/sortable-by.rb]
@@ -0,0 +1,8 @@
1
+ sudo: false
2
+ rvm:
3
+ - 2.5
4
+ - 2.6
5
+ gemfile:
6
+ - Gemfile
7
+ before_install:
8
+ - gem install bundler
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
@@ -0,0 +1,74 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sortable-by (0.12.0)
5
+ activerecord
6
+ activesupport
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ activemodel (6.0.0)
12
+ activesupport (= 6.0.0)
13
+ activerecord (6.0.0)
14
+ activemodel (= 6.0.0)
15
+ activesupport (= 6.0.0)
16
+ activesupport (6.0.0)
17
+ concurrent-ruby (~> 1.0, >= 1.0.2)
18
+ i18n (>= 0.7, < 2)
19
+ minitest (~> 5.1)
20
+ tzinfo (~> 1.1)
21
+ zeitwerk (~> 2.1, >= 2.1.8)
22
+ ast (2.4.0)
23
+ concurrent-ruby (1.1.5)
24
+ diff-lcs (1.3)
25
+ i18n (1.6.0)
26
+ concurrent-ruby (~> 1.0)
27
+ jaro_winkler (1.5.3)
28
+ minitest (5.11.3)
29
+ parallel (1.17.0)
30
+ parser (2.6.3.0)
31
+ ast (~> 2.4.0)
32
+ rainbow (3.0.0)
33
+ rake (12.3.3)
34
+ rspec (3.8.0)
35
+ rspec-core (~> 3.8.0)
36
+ rspec-expectations (~> 3.8.0)
37
+ rspec-mocks (~> 3.8.0)
38
+ rspec-core (3.8.2)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-expectations (3.8.4)
41
+ diff-lcs (>= 1.2.0, < 2.0)
42
+ rspec-support (~> 3.8.0)
43
+ rspec-mocks (3.8.1)
44
+ diff-lcs (>= 1.2.0, < 2.0)
45
+ rspec-support (~> 3.8.0)
46
+ rspec-support (3.8.2)
47
+ rubocop (0.74.0)
48
+ jaro_winkler (~> 1.5.1)
49
+ parallel (~> 1.10)
50
+ parser (>= 2.6)
51
+ rainbow (>= 2.2.2, < 4.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 1.4.0, < 1.7)
54
+ ruby-progressbar (1.10.1)
55
+ sqlite3 (1.4.1)
56
+ thread_safe (0.3.6)
57
+ tzinfo (1.2.5)
58
+ thread_safe (~> 0.1)
59
+ unicode-display_width (1.6.0)
60
+ zeitwerk (2.1.9)
61
+
62
+ PLATFORMS
63
+ ruby
64
+
65
+ DEPENDENCIES
66
+ bundler
67
+ rake
68
+ rspec
69
+ rubocop
70
+ sortable-by!
71
+ sqlite3
72
+
73
+ BUNDLED WITH
74
+ 2.0.2
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2015-2018 Black Square Media
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.
@@ -0,0 +1,87 @@
1
+ # Sortable By
2
+
3
+ [![Build Status](https://travis-ci.org/bsm/sortable-by.png?branch=master)](https://travis-ci.org/bsm/sortable-by)
4
+ [![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ ActiveRecord plugin to parse the sort order from a query parameter, match against a white-list and generate a scope. Useful for [JSON-API][jsonapi] compatibility.
7
+
8
+ [jsonapi]: http://jsonapi.org/format/#fetching-sorting
9
+
10
+ ## Installation
11
+
12
+ Add `gem 'sortable-by'` to your Gemfile.
13
+
14
+ ## Usage
15
+
16
+ Simple:
17
+
18
+ ```ruby
19
+ class Post < ActiveRecord::Base
20
+ sortable_by :title, :id
21
+ end
22
+
23
+ Post.sorted_by('title') # => ORDER BY posts.title ASC
24
+ Post.sorted_by('-title') # => ORDER BY posts.title DESC
25
+ Post.sorted_by('bad,title') # => ORDER BY posts.title ASC
26
+ Post.sorted_by(nil) # => ORDER BY posts.title ASC
27
+ ```
28
+
29
+ Case-insensitive:
30
+
31
+ ```ruby
32
+ class Post < ActiveRecord::Base
33
+ sortable_by do |x|
34
+ x.field :title, as: arel_table[:title].lower
35
+ x.field :id
36
+ end
37
+ end
38
+
39
+ Post.sorted_by('title') # => ORDER BY LOWER(posts.title) ASC
40
+ ```
41
+
42
+ With custom default:
43
+
44
+ ```ruby
45
+ class Post < ActiveRecord::Base
46
+ sortable_by :id, :topic, :created_at, default: 'topic,-created_at'
47
+ end
48
+
49
+ Post.sorted_by(nil) # => ORDER BY posts.topic ASC, posts.created_at DESC
50
+ ```
51
+
52
+ Composition:
53
+
54
+ ```ruby
55
+ class App < ActiveRecord::Base
56
+ sortable_by :name, default: '-version' do |x|
57
+ x.field :version, as: %i[major minor patch]]
58
+ end
59
+ end
60
+
61
+ App.sorted_by('version') # => ORDER BY apps.major ASC, apps.minor ASC, apps.patch ASC
62
+ App.sorted_by(nil) # => ORDER BY apps.major DESC, apps.minor DESC, apps.patch DESC
63
+ ```
64
+
65
+ Associations (eager load):
66
+
67
+ ```ruby
68
+ class Product < ActiveRecord::Base
69
+ belongs_to :shop
70
+ sortable_by do |x|
71
+ x.field :name, as: arel_table[:name].lower
72
+ x.field :shop, as: Shop.arel_table[:name].lower, eager_load: :shop
73
+ x.default 'shop,name'
74
+ end
75
+ end
76
+ ```
77
+
78
+ Associations (custom scope):
79
+
80
+ ```
81
+ class Product < ActiveRecord::Base
82
+ belongs_to :shop
83
+ sortable_by do |x|
84
+ x.field :shop, as: Shop.arel_table[:name].lower, scope: -> { joins(:shop) }
85
+ end
86
+ end
87
+ ```
@@ -0,0 +1,9 @@
1
+ require 'bundler/setup'
2
+ require 'bundler/gem_tasks'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+ RuboCop::RakeTask.new(:rubocop)
8
+
9
+ task default: %i[spec rubocop]
@@ -0,0 +1 @@
1
+ require 'sortable_by'
@@ -0,0 +1,184 @@
1
+ require 'active_record'
2
+
3
+ module ActiveRecord # :nodoc:
4
+ module SortableBy # :nodoc:
5
+ class Config # :nodoc:
6
+ attr_reader :_fields, :_default
7
+
8
+ def initialize
9
+ @_fields = {}
10
+ @_default = nil
11
+ end
12
+
13
+ def dup
14
+ duplicate = self.class.new
15
+ duplicate.instance_variable_set :@_fields, _fields.deep_dup
16
+ duplicate.instance_variable_set :@_default, _default.deep_dup
17
+ duplicate
18
+ end
19
+
20
+ def field(name, opts={})
21
+ name = name.to_s
22
+ @_fields[name] = Field.new(name, opts)
23
+ @_default ||= name
24
+ end
25
+
26
+ def default(expr)
27
+ # legacy support
28
+ if expr.is_a?(Hash)
29
+ expr = expr.map do |field, dir|
30
+ [(dir == :desc ? '-' : ''), field].join
31
+ end.join(',')
32
+ end
33
+
34
+ @_default = expr.to_s
35
+ end
36
+
37
+ protected
38
+
39
+ def order(relation, expr, fallback=true)
40
+ matched = false
41
+ expr.to_s.split(',').each do |name|
42
+ name.strip!
43
+
44
+ rank = :asc
45
+ if name[0] == '-'
46
+ rank = :desc
47
+ name = name[1..-1]
48
+ end
49
+
50
+ field = _fields[name]
51
+ next unless field
52
+
53
+ matched = true
54
+ relation = field.order(relation, rank)
55
+ end
56
+
57
+ relation = order(relation, _default, false) if fallback && !matched && _default
58
+ relation
59
+ end
60
+ end
61
+
62
+ class Field # :nodoc:
63
+ def initialize(name, opts={})
64
+ @cols = Array.wrap(opts[:as])
65
+ @eager_load = Array.wrap(opts[:eager_load]).presence
66
+
67
+ # validate custom_scope
68
+ @custom_scope = opts[:scope]
69
+ raise ArgumentError, "Invalid sortable-by field '#{name}': scope must be a Proc." if @custom_scope && !@custom_scope.is_a?(Proc)
70
+
71
+ # normalize cols
72
+ @cols.push name if @cols.empty?
73
+ @cols.each do |col|
74
+ case col
75
+ when String, Symbol, Arel::Attributes::Attribute, Arel::Nodes::Node
76
+ next
77
+ when Proc
78
+ raise ArgumentError, "Invalid sortable-by field '#{name}': proc must accept 2 arguments." unless col.arity == 2
79
+ else
80
+ raise ArgumentError, "Invalid sortable-by field '#{name}': invalid type #{col.class}."
81
+ end
82
+ end
83
+ end
84
+
85
+ def order(relation, rank)
86
+ @cols.each do |col|
87
+ case col
88
+ when String, Symbol
89
+ relation = relation.order(col => rank)
90
+ when Arel::Nodes::Node, Arel::Attributes::Attribute
91
+ relation = relation.order(col.send(rank))
92
+ when Proc
93
+ relation = col.call(relation, rank)
94
+ end
95
+ end
96
+
97
+ relation = relation.eager_load(*@eager_load) if @eager_load
98
+ relation = relation.instance_eval(&@custom_scope) if @custom_scope
99
+ relation
100
+ end
101
+ end
102
+
103
+ def self.extended(base) # :nodoc:
104
+ base.class_attribute :_sortable_by_config, instance_accessor: false, instance_predicate: false
105
+ base._sortable_by_config = Config.new
106
+ end
107
+
108
+ def inherited(base) # :nodoc:
109
+ base._sortable_by_config = _sortable_by_config.deep_dup
110
+ super
111
+ end
112
+
113
+ # Declare sortable attributes and scopes. Examples:
114
+ #
115
+ # # Simple
116
+ # class Post < ActiveRecord::Base
117
+ # sortable_by :title, :id
118
+ # end
119
+ #
120
+ # # Case-insensitive
121
+ # class Post < ActiveRecord::Base
122
+ # sortable_by do |x|
123
+ # x.field :title, as: arel_table[:title].lower
124
+ # x.field :id
125
+ # end
126
+ # end
127
+ #
128
+ # # With default
129
+ # class Post < ActiveRecord::Base
130
+ # sortable_by :id, :topic, :created_at,
131
+ # default: 'topic,-created_at'
132
+ # end
133
+ #
134
+ # # Composition
135
+ # class App < ActiveRecord::Base
136
+ # sortable_by :name, default: '-version' do |x|
137
+ # x.field :version, as: %i[major minor patch]]
138
+ # end
139
+ # end
140
+ #
141
+ # # Associations (eager load)
142
+ # class Product < ActiveRecord::Base
143
+ # belongs_to :shop
144
+ #
145
+ # sortable_by do |x|
146
+ # x.field :name
147
+ # x.field :shop, as: Shop.arel_table[:name].lower, eager_load: :shop
148
+ # x.default 'shop,name'
149
+ # end
150
+ # end
151
+ #
152
+ # # Associations (custom scope)
153
+ # class Product < ActiveRecord::Base
154
+ # belongs_to :shop
155
+ #
156
+ # sortable_by do |x|
157
+ # x.field :shop, as: Shop.arel_table[:name].lower, scope: -> { joins(:shop) }
158
+ # end
159
+ # end
160
+ #
161
+ def sortable_by(*attributes)
162
+ config = _sortable_by_config
163
+ opts = attributes.extract_options!
164
+ default = opts.delete(:default)
165
+
166
+ attributes.each do |name|
167
+ config.field(name, opts)
168
+ end
169
+ config.default(default) if default
170
+ yield config if block_given?
171
+ config
172
+ end
173
+
174
+ # @param [String] expr the sort expr
175
+ # @return [ActiveRecord::Relation] the scoped relation
176
+ def sorted_by(expr)
177
+ _sortable_by_config.send :order, self, expr
178
+ end
179
+ end
180
+
181
+ class Base # :nodoc:
182
+ extend SortableBy
183
+ end
184
+ end
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'sortable-by'
3
+ s.version = '0.12.0'
4
+ s.authors = ['Dimitrij Denissenko']
5
+ s.email = ['dimitrij@blacksquaremedia.com']
6
+ s.summary = 'Generate white-listed sort scopes from URL parameter values'
7
+ s.description = 'ActiveRecord plugin'
8
+ s.homepage = 'https://github.com/bsm/sortable-by'
9
+ s.license = 'MIT'
10
+
11
+ s.files = `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^spec/}) }
12
+ s.test_files = `git ls-files -z -- spec/*`.split("\x0")
13
+ s.require_paths = ['lib']
14
+ s.required_ruby_version = '>= 2.5'
15
+
16
+ s.add_dependency 'activerecord'
17
+ s.add_dependency 'activesupport'
18
+
19
+ s.add_development_dependency 'bundler'
20
+ s.add_development_dependency 'rake'
21
+ s.add_development_dependency 'rspec'
22
+ s.add_development_dependency 'rubocop'
23
+ s.add_development_dependency 'sqlite3'
24
+ end
@@ -0,0 +1,86 @@
1
+ require File.expand_path('./spec_helper', __dir__)
2
+
3
+ describe ActiveRecord::SortableBy do
4
+ before do
5
+ c = ActiveRecord::Base.connection
6
+ c.tables.each do |t|
7
+ c.update "DELETE FROM #{t}"
8
+ end
9
+ end
10
+
11
+ it 'should have config' do
12
+ expect(Post._sortable_by_config._fields.keys).to match_array(%w[title created])
13
+ expect(Post._sortable_by_config._default).to eq('-created')
14
+ expect(SubPost._sortable_by_config._fields.keys).to match_array(%w[title created])
15
+ expect(SubPost._sortable_by_config._default).to eq('-created')
16
+
17
+ expect(App._sortable_by_config._fields.keys).to match_array(%w[name version])
18
+ expect(App._sortable_by_config._default).to eq('name')
19
+
20
+ expect(Shop._sortable_by_config._fields.keys).to be_empty
21
+ expect(Shop._sortable_by_config._default).to be_nil
22
+
23
+ expect(Product._sortable_by_config._fields.keys).to match_array(%w[name shop])
24
+ expect(Product._sortable_by_config._default).to eq('shop,name')
25
+ end
26
+
27
+ it 'should simply order' do
28
+ Post.create! title: 'A', created_at: Time.at(1515151500)
29
+ Post.create! title: 'b', created_at: Time.at(1515151600)
30
+ Post.create! title: 'C', created_at: Time.at(1515151400)
31
+
32
+ expect(Post.sorted_by(nil).pluck(:title)).to eq(%w[b A C])
33
+ expect(Post.sorted_by('').pluck(:title)).to eq(%w[b A C])
34
+ expect(Post.sorted_by('invalid').pluck(:title)).to eq(%w[b A C])
35
+
36
+ expect(Post.sorted_by('-created').pluck(:title)).to eq(%w[b A C])
37
+ expect(Post.sorted_by('created').pluck(:title)).to eq(%w[C A b])
38
+
39
+ expect(Post.sorted_by('title').pluck(:title)).to eq(%w[A C b])
40
+ expect(Post.sorted_by('-title').pluck(:title)).to eq(%w[b C A])
41
+ expect(Post.sorted_by(' title ').pluck(:title)).to eq(%w[A C b])
42
+ end
43
+
44
+ it 'should support STI inheritance and overrides' do
45
+ SubPost.create! title: 'A', created_at: Time.at(1515151700)
46
+ SubPost.create! title: 'b', created_at: Time.at(1515151600)
47
+ Post.create! title: 'C', created_at: Time.at(1515151400)
48
+ SubPost.create! title: 'D', created_at: Time.at(1515151500)
49
+
50
+ expect(Post.sorted_by(nil).pluck(:title)).to eq(%w[A b D C])
51
+ expect(SubPost.sorted_by(nil).pluck(:title)).to eq(%w[A b D])
52
+ expect(SubPost.sorted_by('-created').pluck(:title)).to eq(%w[A b D])
53
+ expect(SubPost.sorted_by('created').pluck(:title)).to eq(%w[D b A])
54
+
55
+ expect(Post.sorted_by('title').pluck(:title)).to eq(%w[A C D b])
56
+ expect(SubPost.sorted_by('title').pluck(:title)).to eq(%w[A b D])
57
+ end
58
+
59
+ it 'should support composition' do
60
+ App.create! name: 'E', major: 0, minor: 9, patch: 2
61
+ App.create! name: 'A', major: 1, minor: 0, patch: 1
62
+ App.create! name: 'D', major: 1, minor: 0, patch: 6
63
+ App.create! name: 'C', major: 1, minor: 1, patch: 0
64
+ App.create! name: 'B', major: 2, minor: 2, patch: 0
65
+
66
+ expect(App.sorted_by(nil).pluck(:name)).to eq(%w[A B C D E])
67
+ expect(App.sorted_by('version').pluck(:name)).to eq(%w[E A D C B])
68
+ expect(App.sorted_by('-version').pluck(:name)).to eq(%w[B C D A E])
69
+ end
70
+
71
+ it 'should support associations' do
72
+ y = Shop.create! name: 'Y'
73
+ x = Shop.create! name: 'X'
74
+
75
+ Product.create! name: 'a', shop_id: y.id
76
+ Product.create! name: 'B', shop_id: y.id, active: false
77
+ Product.create! name: 'c', shop_id: x.id
78
+ Product.create! name: 'D', shop_id: y.id
79
+ Product.create! name: 'e', shop_id: x.id
80
+ Product.create! name: 'f', shop_id: x.id, active: false
81
+
82
+ expect(Product.sorted_by(nil).pluck(:name)).to eq(%w[c e f a B D])
83
+ expect(Product.where(active: true).sorted_by(nil).pluck(:name)).to eq(%w[c e a D])
84
+ expect(Product.sorted_by('name').pluck(:name)).to eq(%w[a B c D e f])
85
+ end
86
+ end
@@ -0,0 +1,70 @@
1
+ ENV['RACK_ENV'] ||= 'test'
2
+ require 'sortable-by'
3
+ require 'rspec'
4
+
5
+ ActiveRecord::Base.configurations['test'] = {
6
+ 'adapter' => 'sqlite3',
7
+ 'database' => ':memory:',
8
+ }
9
+ ActiveRecord::Base.establish_connection :test
10
+
11
+ ActiveRecord::Base.connection.create_table :posts do |t|
12
+ t.string :type
13
+ t.string :title, null: false
14
+ t.timestamp :created_at, null: false
15
+ end
16
+
17
+ class Post < ActiveRecord::Base
18
+ sortable_by :title, default: '-created' do |s|
19
+ s.field :created, as: arel_table[:created_at]
20
+ end
21
+ end
22
+
23
+ class SubPost < Post
24
+ sortable_by do |s|
25
+ s.field :title, as: arel_table[:title].lower
26
+ end
27
+ end
28
+
29
+ # ---------------------------------------------------------------------
30
+
31
+ ActiveRecord::Base.connection.create_table :apps do |t|
32
+ t.string :name, null: false
33
+ t.integer :major, null: false
34
+ t.integer :minor, null: false
35
+ t.integer :patch, null: false
36
+ end
37
+
38
+ class App < ActiveRecord::Base
39
+ sortable_by :name do |s|
40
+ s.field :version, as: %i[major minor patch]
41
+ end
42
+ end
43
+
44
+ # ---------------------------------------------------------------------
45
+
46
+ ActiveRecord::Base.connection.create_table :shops do |t|
47
+ t.string :name, null: false
48
+ end
49
+
50
+ class Shop < ActiveRecord::Base
51
+ end
52
+
53
+ # ---------------------------------------------------------------------
54
+
55
+ ActiveRecord::Base.connection.create_table :products do |t|
56
+ t.string :name, null: false
57
+ t.integer :shop_id, null: false
58
+ t.boolean :active, null: false, default: true
59
+ t.foreign_key :shops
60
+ end
61
+
62
+ class Product < ActiveRecord::Base
63
+ belongs_to :shop
64
+
65
+ sortable_by do |s|
66
+ s.field :name, as: arel_table[:name].lower
67
+ s.field :shop, as: Shop.arel_table[:name].lower, eager_load: :shop
68
+ s.default 'shop,name'
69
+ end
70
+ end
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sortable-by
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.12.0
5
+ platform: ruby
6
+ authors:
7
+ - Dimitrij Denissenko
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-08-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: ActiveRecord plugin
112
+ email:
113
+ - dimitrij@blacksquaremedia.com
114
+ executables: []
115
+ extensions: []
116
+ extra_rdoc_files: []
117
+ files:
118
+ - ".gitignore"
119
+ - ".rubocop.yml"
120
+ - ".travis.yml"
121
+ - Gemfile
122
+ - Gemfile.lock
123
+ - LICENSE
124
+ - README.md
125
+ - Rakefile
126
+ - lib/sortable-by.rb
127
+ - lib/sortable_by.rb
128
+ - sortable-by.gemspec
129
+ - spec/sortable_by_spec.rb
130
+ - spec/spec_helper.rb
131
+ homepage: https://github.com/bsm/sortable-by
132
+ licenses:
133
+ - MIT
134
+ metadata: {}
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: '2.5'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubygems_version: 3.0.3
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Generate white-listed sort scopes from URL parameter values
154
+ test_files:
155
+ - spec/sortable_by_spec.rb
156
+ - spec/spec_helper.rb