table_sortable 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.idea/.rakeTasks +7 -0
  4. data/.idea/encodings.xml +6 -0
  5. data/.idea/inspectionProfiles/Project_Default.xml +6 -0
  6. data/.idea/misc.xml +4 -0
  7. data/.idea/modules.xml +8 -0
  8. data/.idea/table_sortable.iml +190 -0
  9. data/.idea/vcs.xml +6 -0
  10. data/.rspec +1 -0
  11. data/.travis.yml +5 -0
  12. data/CODE_OF_CONDUCT.md +74 -0
  13. data/Gemfile +4 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +137 -0
  16. data/Rakefile +10 -0
  17. data/app/helpers/table_sortable_helper.rb +15 -0
  18. data/app/views/table_sortable/_columns.slim +3 -0
  19. data/app/views/table_sortable/_field.slim +1 -0
  20. data/app/views/table_sortable/_header.slim +2 -0
  21. data/app/views/table_sortable/_headers.slim +3 -0
  22. data/app/views/table_sortable/_pager.slim +42 -0
  23. data/bin/console +14 -0
  24. data/bin/setup +8 -0
  25. data/lib/table_sortable/column/filter.rb +19 -0
  26. data/lib/table_sortable/column/sorter.rb +20 -0
  27. data/lib/table_sortable/column.rb +30 -0
  28. data/lib/table_sortable/columns.rb +26 -0
  29. data/lib/table_sortable/concerns/proc.rb +49 -0
  30. data/lib/table_sortable/controller.rb +93 -0
  31. data/lib/table_sortable/version.rb +3 -0
  32. data/lib/table_sortable.rb +25 -0
  33. data/spec/concerns/proc_class_spec.rb +13 -0
  34. data/spec/controllers/test_controller_spec.rb +17 -0
  35. data/spec/lib/table_sortable/column/filter_spec.rb +3 -0
  36. data/spec/lib/table_sortable/column/sorter_spec.rb +3 -0
  37. data/spec/lib/table_sortable/concerns/proc_spec.rb +82 -0
  38. data/spec/lib/table_sortable/controller_spec.rb +51 -0
  39. data/spec/spec_helper.rb +109 -0
  40. data/spec/support/controller_macros.rb +7 -0
  41. data/spec/support/matchers/have_filters.rb +6 -0
  42. data/spec/support/shared_stuff.rb +22 -0
  43. data/table_sortable.gemspec +37 -0
  44. metadata +173 -0
@@ -0,0 +1,19 @@
1
+ module TableSortable
2
+ class Column
3
+ class Filter
4
+ include TableSortable::Concerns::Proc
5
+
6
+ def initialize(*options)
7
+ super :filter, *options
8
+ end
9
+
10
+ def array_proc
11
+ -> (value, col=nil) { select{|record| value.downcase.in? col.value(record).to_s.downcase} }
12
+ end
13
+
14
+ def sql_proc
15
+ -> (value, col=nil) { where("? LIKE (?)", filter.to_s.underscore, "%#{value}%") }
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module TableSortable
2
+ class Column
3
+ class Sorter
4
+ include TableSortable::Concerns::Proc
5
+
6
+ def initialize(*options)
7
+ super :sort, *options
8
+ end
9
+
10
+ def array_proc
11
+ -> (col=nil) { sort{ |a,b| col.value(a) <=> col.value(b) }}
12
+ end
13
+
14
+ def sql_proc
15
+ -> (col=nil) { order(sorter) }
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,30 @@
1
+ module TableSortable
2
+ class Column
3
+
4
+ attr_reader :name, :label, :filter, :sorter, :template, :placeholder
5
+
6
+ def initialize(col_name, *options)
7
+
8
+ options = options.extract_options!
9
+ value = options[:value] || col_name
10
+ label = options[:label] || (options[:label] == false ? '' : col_name.to_s.titleize)
11
+ placeholder = options[:placeholder] || (options[:placeholder] == false ? false : label)
12
+ template = options[:template] || col_name
13
+
14
+ @name = col_name
15
+ @value = value.is_a?(Proc) ? value : -> (record) { record.send(value) }
16
+ @label = label
17
+ @placeholder = placeholder
18
+ @template = template
19
+ @filter = TableSortable::Column::Filter.new(options.merge(:column_name => @name) )
20
+ @sorter = TableSortable::Column::Sorter.new(options.merge(:column_name => @name) )
21
+
22
+ end
23
+
24
+ def value(record)
25
+ record.instance_eval(&@value) unless @value.nil?
26
+ end
27
+
28
+ end
29
+
30
+ end
@@ -0,0 +1,26 @@
1
+ module TableSortable
2
+ class Columns
3
+
4
+ def initialize
5
+ @columns = []
6
+ end
7
+
8
+ def add(col_name, *options)
9
+ options = options.extract_options!
10
+ @columns << TableSortable::Column.new(col_name, options)
11
+ end
12
+
13
+ def sort_by(sort_key)
14
+ if sort_key
15
+ sort_key.map{|c| @columns.find{|col| (c.is_a?(String) ? (col.label == c) : col.name == c)}}
16
+ else
17
+ @columns
18
+ end
19
+ end
20
+
21
+ def sort(&sort_proc)
22
+ @columns.sort(&sort_proc)
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,49 @@
1
+ module TableSortable
2
+ module Concerns
3
+ module Proc
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ attr_reader :proc, :method
8
+ end
9
+
10
+ def initialize(option_name, *options)
11
+ options = options.extract_options!
12
+ unless options[option_name] == false
13
+ filter = options[option_name] || options[:column_name]
14
+ @method = options["#{option_name.to_s}_method".to_sym] || :array
15
+ if filter.respond_to? :call
16
+ @proc = -> (records, col=nil) { instance_exec(records, &filter) }
17
+ @method = detect_method(@proc)
18
+ elsif !filter.nil?
19
+ case @method
20
+ when :array
21
+ @proc = array_proc
22
+ when :sql
23
+ @proc = sql_proc
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def detect_method(proc)
30
+ method = [].instance_exec('', &proc) rescue :failed
31
+ method == :failed ? :sql : :array
32
+ end
33
+
34
+ def disabled?
35
+ method.nil?
36
+ end
37
+
38
+ def array_proc
39
+ raise NotImplementedError
40
+ end
41
+
42
+ def sql_proc
43
+ raise NotImplementedError
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+
@@ -0,0 +1,93 @@
1
+ module TableSortable
2
+ module Controller
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ helper_method :columns
8
+ prepend_before_action :initialize_table_sortable
9
+ end
10
+
11
+ module ClassMethods
12
+ def define_columns(*args)
13
+ options = args.extract_options!
14
+ column_offset = options[:offset] || 0
15
+ columns = args
16
+ before_action(options) do
17
+ columns.each do |column|
18
+ define_column column
19
+ end
20
+ self.column_offset = column_offset
21
+ end
22
+ end
23
+
24
+ def define_column(*args)
25
+ before_action do
26
+ define_column *args
27
+ end
28
+ end
29
+ end
30
+
31
+ def define_column(col_name, *options)
32
+ options = options.extract_options!
33
+ @columns.add(col_name, options)
34
+ end
35
+
36
+ private
37
+
38
+ def filter_and_sort(scope)
39
+ cols = @columns.sort_by(display_order)
40
+
41
+ page = params[:page]
42
+ page_size = params[:pagesize]
43
+ sort_by_col_data = params[SCOL] ? params[SCOL].keys.first : column_offset
44
+ sort_order = params[SCOL] ? params[SCOL].values.first : SORT_ASC
45
+
46
+ sort_column = cols.at(sort_by_col_data.to_i - column_offset)
47
+ sort_proc = ->(records) { records.instance_exec(sort_column, &sort_column.sorter.proc)}
48
+ ordered_sort_proc = ->(records) {sort_order == SORT_ASC ? sort_proc.call(records) : sort_proc.call(records).reverse}
49
+
50
+ filters = [->(records) { ordered_sort_proc.call(records) }]
51
+
52
+ # a filter exists
53
+ if params[FCOL]
54
+ @columns.sort_by(filter_order.reverse).each_with_index do |col, i|
55
+ column_index = cols.index(col) + column_offset
56
+ filter_value = params[FCOL][column_index.to_s]
57
+ filters << ->(records){ filter_value.nil? ? filters[i].call(records) : filters[i].call(records.instance_exec(filter_value, col, &col.filter.proc)) }
58
+ end
59
+ end
60
+ scope = filters.last.call(scope)
61
+ if page
62
+ scope = Kaminari.paginate_array(scope)
63
+ scope = scope.page(page.to_i + 1).per(page_size)
64
+ end
65
+ scope
66
+ end
67
+
68
+ def initialize_table_sortable
69
+
70
+ @columns ||= TableSortable::Columns.new
71
+ self.column_offset = 0
72
+
73
+ end
74
+
75
+ def columns(record = nil)
76
+ @columns.sort_by(display_order)
77
+ end
78
+
79
+ def filter_order
80
+ @filter_order || @columns.sort{ |a,b| a.filter.method && b.filter.method ? b.filter.method <=> a.filter.method : a.filter.method ? 1 : -1 }.compact.map{|col| col.name}
81
+ end
82
+
83
+ def sort_order
84
+ @sort_order || @columns.sort{ |a,b| a.sorter.method && b.sorter.method ? b.sorter.method <=> a.sorter.method : a.filter.method ? 1 : -1 }.compact.map{|col| col.name}
85
+ end
86
+
87
+ public
88
+
89
+ attr_writer :filter_order, :sort_order
90
+ attr_accessor :display_order, :column_offset
91
+
92
+ end
93
+ end
@@ -0,0 +1,3 @@
1
+ module TableSortable
2
+ VERSION = "0.1.2"
3
+ end
@@ -0,0 +1,25 @@
1
+ require 'rails/engine'
2
+ require 'active_support/concern'
3
+ require 'action_controller'
4
+
5
+ module TableSortable
6
+
7
+ FCOL = 'fcol'
8
+ SCOL = 'scol'
9
+ SORT_ASC = '0'
10
+ SORT_DESC = '1'
11
+
12
+ class Engine < Rails::Engine; end
13
+
14
+ end
15
+
16
+
17
+ class TableSortableError < StandardError; end
18
+
19
+ require 'table_sortable/concerns/proc'
20
+ require 'table_sortable/column/sorter'
21
+ require 'table_sortable/column/filter'
22
+ require 'table_sortable/column'
23
+ require 'table_sortable/columns'
24
+ require 'table_sortable/version'
25
+ require 'table_sortable/controller'
@@ -0,0 +1,13 @@
1
+ shared_examples_for 'proc_class' do |parameter_name|
2
+ include_context 'shared stuff'
3
+
4
+ let(:dummy_class) { described_class.new(parameter_name => ->(x) {x}) }
5
+
6
+ it 'includes TableSortable::Concerns::Proc' do
7
+ expect(described_class.included_modules).to include TableSortable::Concerns::Proc
8
+ end
9
+ it 'defines array_proc and sql_proc that return a proc' do
10
+ expect(dummy_class.array_proc).to respond_to :call
11
+ expect(dummy_class.sql_proc).to respond_to :call
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ module Test
2
+ class Controller < ActionController::Base
3
+
4
+ include TableSortable::Controller
5
+
6
+ def index
7
+ end
8
+ end
9
+ end
10
+
11
+ describe Test::Controller, type: :controller do
12
+
13
+ let(:controller) { Test::Controller.new }
14
+
15
+ it { has_before_filters(:initialize_table_sortable) }
16
+
17
+ end
@@ -0,0 +1,3 @@
1
+ describe TableSortable::Column::Filter do
2
+ it_behaves_like 'proc_class', :filter
3
+ end
@@ -0,0 +1,3 @@
1
+ describe TableSortable::Column::Sorter do
2
+ it_behaves_like 'proc_class', :sort
3
+ end
@@ -0,0 +1,82 @@
1
+ describe TableSortable::Concerns::Proc do
2
+ include_context 'shared stuff'
3
+
4
+ let :proc_class do
5
+ Class.new do
6
+ include TableSortable::Concerns::Proc
7
+
8
+ def array_proc
9
+ -> (x) {x * 2}
10
+ end
11
+
12
+ def sql_proc
13
+ -> (x) {x * 3}
14
+ end
15
+ end
16
+ end
17
+
18
+ let :dummy_proc do
19
+ proc_class.new(:proc, proc: dummy_col)
20
+ end
21
+
22
+ context 'on initialization' do
23
+ context 'given a proc' do
24
+ it 'should keep it' do
25
+ example_proc = -> (x) { x * 100 }
26
+ proc = proc_class.new(:proc, proc: example_proc )
27
+ expect(5.instance_eval(&proc.proc)).to eq 500
28
+ end
29
+ context 'it is an sql proc' do
30
+ it 'should detect it as sql' do
31
+ proc = proc_class.new(:proc, proc: -> (value) { where(name: value) } )
32
+ expect(proc.method).to eq :sql
33
+ end
34
+ end
35
+ context 'it is an array proc' do
36
+ it 'should detect it as array' do
37
+ proc = proc_class.new(:proc, proc: -> (value) { select{|record| record.name == value} } )
38
+ expect(proc.method).to eq :array
39
+ end
40
+ end
41
+ end
42
+ context 'given no proc' do
43
+ it 'should use array proc' do
44
+ expect(dummy_proc.method).to eq :array
45
+ end
46
+ context '_method: option' do
47
+ context 'not provided' do
48
+ it 'should replace it with array_proc' do
49
+ expect(5.instance_eval(&dummy_proc.proc)).to eq 5.instance_eval(&dummy_proc.array_proc)
50
+ end
51
+ end
52
+ context '== :sql' do
53
+ it 'should replace it with sql_proc' do
54
+ dummy_proc = proc_class.new(:proc, column_name: :proc, proc_method: :sql)
55
+ expect(5.instance_eval(&dummy_proc.proc)).to eq 5.instance_eval(&dummy_proc.sql_proc)
56
+ end
57
+ end
58
+ context '== :array' do
59
+ it 'should replace it with sql_proc' do
60
+ dummy_proc = proc_class.new(:proc, column_name: :proc, proc_method: :array)
61
+ expect(5.instance_eval(&dummy_proc.proc)).to eq 5.instance_eval(&dummy_proc.array_proc)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ context 'detect method' do
69
+ context 'given a proc containing an sql method' do
70
+ it 'should detect it as sql' do
71
+ proc_to_detect = -> (filter_value) { where(name: filter_value) }
72
+ expect(dummy_proc.detect_method(proc_to_detect)).to eq :sql
73
+ end
74
+ end
75
+ context 'given a proc containing an array method' do
76
+ it 'should detect it as array' do
77
+ proc_to_detect = -> (filter_value) { select{|record| record.name == filter_value} }
78
+ expect(dummy_proc.detect_method(proc_to_detect)).to eq :array
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,51 @@
1
+ describe TableSortable::Controller do
2
+
3
+ let :controller do
4
+ controller = ActionController::Base.new
5
+ controller.class.include TableSortable::Controller
6
+ controller.instance_eval('initialize_table_sortable')
7
+ controller
8
+ end
9
+ let :populated_controller do
10
+ controller.send(:define_column,
11
+ :column_with_sql_procs_a,
12
+ filter: -> (value) { where(column: value)},
13
+ sort: -> { order(:column)})
14
+ controller.send(:define_column,
15
+ :column_with_array_procs,
16
+ filter: -> (value) { select{|record| record == value}},
17
+ sort: -> (col) { sort{ |a,b| col.value(a) <=> col.value(b) }})
18
+ controller.send(:define_column,
19
+ :column_with_sql_procs_b,
20
+ filter: -> (value) { where(last_name: value)},
21
+ sort: -> { order(:column)})
22
+ controller
23
+ end
24
+
25
+ context 'initialization' do
26
+ it 'creates a columns collection' do
27
+ expect(controller.instance_eval('@columns')).to be_a TableSortable::Columns
28
+ end
29
+ end
30
+
31
+ context 'define_column' do
32
+ it 'adds a new column at the end of the collection' do
33
+ controller.send(:define_column, :name)
34
+ controller.send(:define_column, :another_name)
35
+ expect(controller.send(:columns).first.name).to eq :name
36
+ expect(controller.send(:columns).last.name).to eq :another_name
37
+ end
38
+ end
39
+
40
+ context 'filter_order' do
41
+ it 'orders sql filters before array filters' do
42
+ expect(populated_controller.send(:filter_order)).to eq [:column_with_sql_procs_a, :column_with_sql_procs_b, :column_with_array_procs]
43
+ end
44
+ end
45
+
46
+ context 'sort_order' do
47
+ it 'orders sql filters before array filters' do
48
+ expect(populated_controller.send(:sort_order)).to eq [:column_with_sql_procs_a, :column_with_sql_procs_b, :column_with_array_procs]
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,109 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
4
+ # this file to always be loaded, without a need to explicitly require it in any
5
+ # files.
6
+ #
7
+ # Given that it is always loaded, you are encouraged to keep this file as
8
+ # light-weight as possible. Requiring heavyweight dependencies from this file
9
+ # will add to the boot time of your test suite on EVERY test run, even for an
10
+ # individual file that may not need all of that loaded. Instead, consider making
11
+ # a separate helper file that requires the additional dependencies and performs
12
+ # the additional setup, and require it from the spec files that actually need
13
+ # it.
14
+ #
15
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
16
+
17
+ require 'table_sortable'
18
+ require 'support/controller_macros'
19
+ require 'support/matchers/have_filters'
20
+ require 'support/shared_stuff'
21
+
22
+ RSpec.configure do |config|
23
+
24
+ config.include ControllerMacros, type: :controller
25
+
26
+ # rspec-expectations config goes here. You can use an alternate
27
+ # assertion/expectation library such as wrong or the stdlib/minitest
28
+ # assertions if you prefer.
29
+ config.expect_with :rspec do |expectations|
30
+ # This option will default to `true` in RSpec 4. It makes the `description`
31
+ # and `failure_message` of custom matchers include text for helper methods
32
+ # defined using `chain`, e.g.:
33
+ # be_bigger_than(2).and_smaller_than(4).description
34
+ # # => "be bigger than 2 and smaller than 4"
35
+ # ...rather than:
36
+ # # => "be bigger than 2"
37
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
38
+ end
39
+
40
+ # rspec-mocks config goes here. You can use an alternate test double
41
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
42
+ config.mock_with :rspec do |mocks|
43
+ # Prevents you from mocking or stubbing a method that does not exist on
44
+ # a real object. This is generally recommended, and will default to
45
+ # `true` in RSpec 4.
46
+ mocks.verify_partial_doubles = true
47
+ end
48
+
49
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
50
+ # have no way to turn it off -- the option exists only for backwards
51
+ # compatibility in RSpec 3). It causes shared context metadata to be
52
+ # inherited by the metadata hash of host groups and examples, rather than
53
+ # triggering implicit auto-inclusion in groups with matching metadata.
54
+ config.shared_context_metadata_behavior = :apply_to_host_groups
55
+
56
+ # The settings below are suggested to provide a good initial experience
57
+ # with RSpec, but feel free to customize to your heart's content.
58
+ =begin
59
+ # This allows you to limit a spec run to individual examples or groups
60
+ # you care about by tagging them with `:focus` metadata. When nothing
61
+ # is tagged with `:focus`, all examples get run. RSpec also provides
62
+ # aliases for `it`, `describe`, and `context` that include `:focus`
63
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
64
+ config.filter_run_when_matching :focus
65
+
66
+ # Allows RSpec to persist some state between runs in order to support
67
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
68
+ # you configure your source control system to ignore this file.
69
+ config.example_status_persistence_file_path = "spec/examples.txt"
70
+
71
+ # Limits the available syntax to the non-monkey patched syntax that is
72
+ # recommended. For more details, see:
73
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
74
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
75
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
76
+ config.disable_monkey_patching!
77
+
78
+ # This setting enables warnings. It's recommended, but in some cases may
79
+ # be too noisy due to issues in dependencies.
80
+ config.warnings = true
81
+
82
+ # Many RSpec users commonly either run the entire suite or an individual
83
+ # file, and it's useful to allow more verbose output when running an
84
+ # individual spec file.
85
+ if config.files_to_run.one?
86
+ # Use the documentation formatter for detailed output,
87
+ # unless a formatter has already been configured
88
+ # (e.g. via a command-line flag).
89
+ config.default_formatter = "doc"
90
+ end
91
+
92
+ # Print the 10 slowest examples and example groups at the
93
+ # end of the spec run, to help surface which specs are running
94
+ # particularly slow.
95
+ config.profile_examples = 10
96
+
97
+ # Run specs in random order to surface order dependencies. If you find an
98
+ # order dependency and want to debug it, you can fix the order by providing
99
+ # the seed, which is printed after each run.
100
+ # --seed 1234
101
+ config.order = :random
102
+
103
+ # Seed global randomization in this process using the `--seed` CLI option.
104
+ # Setting this allows you to use `--seed` to deterministically reproduce
105
+ # test failures related to randomization by passing the same `--seed` value
106
+ # as the one that triggered the failure.
107
+ Kernel.srand config.seed
108
+ =end
109
+ end
@@ -0,0 +1,7 @@
1
+ # spec/support/controller_macros.rb
2
+
3
+ module ControllerMacros
4
+ def has_before_filters *names
5
+ expect(controller).to have_filters(:before, *names)
6
+ end
7
+ end
@@ -0,0 +1,6 @@
1
+ RSpec::Matchers.define :have_filters do |kind, *names|
2
+ match do |controller|
3
+ filters = controller._process_action_callbacks.select{ |f| f.kind == kind }.map(&:filter)
4
+ names.all?{ |name| filters.include?(name) }
5
+ end
6
+ end
@@ -0,0 +1,22 @@
1
+ RSpec.configure do |rspec|
2
+ # This config option will be enabled by default on RSpec 4,
3
+ # but for reasons of backwards compatibility, you have to
4
+ # set it on RSpec 3.
5
+ #
6
+ # It causes the host group and examples to inherit metadata
7
+ # from the shared context.
8
+ rspec.shared_context_metadata_behavior = :apply_to_host_groups
9
+ end
10
+
11
+ RSpec.shared_context "shared stuff", :shared_context => :metadata do
12
+
13
+ let :dummy_col do
14
+ TableSortable::Column.new(:dummy_col)
15
+ end
16
+
17
+ end
18
+
19
+
20
+ RSpec.configure do |rspec|
21
+ rspec.include_context "shared stuff", :include_shared => true
22
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "table_sortable/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "table_sortable"
8
+ spec.version = TableSortable::VERSION
9
+ spec.authors = ["Oded Davidov"]
10
+ spec.email = ["davidovoded@gmail.com"]
11
+
12
+ spec.summary = 'Use jquery-tablesorter.js with server side filtering, pagination and sorting'
13
+ spec.description = 'Use jquery-tablesorter.js with server side filtering, pagination and sorting'
14
+ # spec.homepage = "TODO: Put your gem's website or public repo URL here."
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ # spec.metadata["allowed_push_host"] = "localhost"
21
+ else
22
+ raise "RubyGems 2.0 or newer is required to protect against " \
23
+ "public gem pushes."
24
+ end
25
+
26
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
27
+ f.match(%r{^(test|spec|features)/})
28
+ end
29
+ spec.test_files = `git ls-files -- spec/*`.split("\n")
30
+ spec.require_paths = ["lib"]
31
+
32
+ spec.add_development_dependency "bundler", "~> 1.15"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "rspec", "~> 3.4"
35
+ spec.add_dependency "kaminari", '~> 0.17.0'
36
+ spec.add_dependency "rails", '~> 5.1', '>= 5.1.1'
37
+ end