activesorting 0.5.0

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.
@@ -0,0 +1,163 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ activesorting (0.5.0)
5
+ activerecord (>= 4.0.0)
6
+ railties (>= 4.0.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actioncable (5.0.0.beta3)
12
+ actionpack (= 5.0.0.beta3)
13
+ nio4r (~> 1.2)
14
+ websocket-driver (~> 0.6.1)
15
+ actionmailer (5.0.0.beta3)
16
+ actionpack (= 5.0.0.beta3)
17
+ actionview (= 5.0.0.beta3)
18
+ activejob (= 5.0.0.beta3)
19
+ mail (~> 2.5, >= 2.5.4)
20
+ rails-dom-testing (~> 1.0, >= 1.0.5)
21
+ actionpack (5.0.0.beta3)
22
+ actionview (= 5.0.0.beta3)
23
+ activesupport (= 5.0.0.beta3)
24
+ rack (~> 2.x)
25
+ rack-test (~> 0.6.3)
26
+ rails-dom-testing (~> 1.0, >= 1.0.5)
27
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
+ actionview (5.0.0.beta3)
29
+ activesupport (= 5.0.0.beta3)
30
+ builder (~> 3.1)
31
+ erubis (~> 2.7.0)
32
+ rails-dom-testing (~> 1.0, >= 1.0.5)
33
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
34
+ activejob (5.0.0.beta3)
35
+ activesupport (= 5.0.0.beta3)
36
+ globalid (>= 0.3.6)
37
+ activemodel (5.0.0.beta3)
38
+ activesupport (= 5.0.0.beta3)
39
+ activerecord (5.0.0.beta3)
40
+ activemodel (= 5.0.0.beta3)
41
+ activesupport (= 5.0.0.beta3)
42
+ arel (~> 7.0)
43
+ activesupport (5.0.0.beta3)
44
+ concurrent-ruby (~> 1.0)
45
+ i18n (~> 0.7)
46
+ minitest (~> 5.1)
47
+ tzinfo (~> 1.1)
48
+ appraisal (2.1.0)
49
+ bundler
50
+ rake
51
+ thor (>= 0.14.0)
52
+ arel (7.0.0)
53
+ builder (3.2.2)
54
+ concurrent-ruby (1.0.1)
55
+ coveralls (0.8.13)
56
+ json (~> 1.8)
57
+ simplecov (~> 0.11.0)
58
+ term-ansicolor (~> 1.3)
59
+ thor (~> 0.19.1)
60
+ tins (~> 1.6.0)
61
+ diff-lcs (1.2.5)
62
+ docile (1.1.5)
63
+ erubis (2.7.0)
64
+ globalid (0.3.6)
65
+ activesupport (>= 4.1.0)
66
+ i18n (0.7.0)
67
+ json (1.8.3)
68
+ loofah (2.0.3)
69
+ nokogiri (>= 1.5.9)
70
+ mail (2.6.4)
71
+ mime-types (>= 1.16, < 4)
72
+ method_source (0.8.2)
73
+ mime-types (3.0)
74
+ mime-types-data (~> 3.2015)
75
+ mime-types-data (3.2016.0221)
76
+ mini_portile2 (2.0.0)
77
+ minitest (5.8.4)
78
+ nio4r (1.2.1)
79
+ nokogiri (1.6.7.2)
80
+ mini_portile2 (~> 2.0.0.rc2)
81
+ rack (2.0.0.alpha)
82
+ json
83
+ rack-test (0.6.3)
84
+ rack (>= 1.0)
85
+ rails (5.0.0.beta3)
86
+ actioncable (= 5.0.0.beta3)
87
+ actionmailer (= 5.0.0.beta3)
88
+ actionpack (= 5.0.0.beta3)
89
+ actionview (= 5.0.0.beta3)
90
+ activejob (= 5.0.0.beta3)
91
+ activemodel (= 5.0.0.beta3)
92
+ activerecord (= 5.0.0.beta3)
93
+ activesupport (= 5.0.0.beta3)
94
+ bundler (>= 1.3.0, < 2.0)
95
+ railties (= 5.0.0.beta3)
96
+ sprockets-rails (>= 2.0.0)
97
+ rails-deprecated_sanitizer (1.0.3)
98
+ activesupport (>= 4.2.0.alpha)
99
+ rails-dom-testing (1.0.7)
100
+ activesupport (>= 4.2.0.beta, < 5.0)
101
+ nokogiri (~> 1.6.0)
102
+ rails-deprecated_sanitizer (>= 1.0.1)
103
+ rails-html-sanitizer (1.0.3)
104
+ loofah (~> 2.0)
105
+ railties (5.0.0.beta3)
106
+ actionpack (= 5.0.0.beta3)
107
+ activesupport (= 5.0.0.beta3)
108
+ method_source
109
+ rake (>= 0.8.7)
110
+ thor (>= 0.18.1, < 2.0)
111
+ rake (10.5.0)
112
+ rspec (3.4.0)
113
+ rspec-core (~> 3.4.0)
114
+ rspec-expectations (~> 3.4.0)
115
+ rspec-mocks (~> 3.4.0)
116
+ rspec-core (3.4.4)
117
+ rspec-support (~> 3.4.0)
118
+ rspec-expectations (3.4.0)
119
+ diff-lcs (>= 1.2.0, < 2.0)
120
+ rspec-support (~> 3.4.0)
121
+ rspec-mocks (3.4.1)
122
+ diff-lcs (>= 1.2.0, < 2.0)
123
+ rspec-support (~> 3.4.0)
124
+ rspec-support (3.4.1)
125
+ simplecov (0.11.2)
126
+ docile (~> 1.1.0)
127
+ json (~> 1.8)
128
+ simplecov-html (~> 0.10.0)
129
+ simplecov-html (0.10.0)
130
+ sprockets (3.5.2)
131
+ concurrent-ruby (~> 1.0)
132
+ rack (> 1, < 3)
133
+ sprockets-rails (3.0.4)
134
+ actionpack (>= 4.0)
135
+ activesupport (>= 4.0)
136
+ sprockets (>= 3.0.0)
137
+ sqlite3 (1.3.11)
138
+ term-ansicolor (1.3.2)
139
+ tins (~> 1.0)
140
+ thor (0.19.1)
141
+ thread_safe (0.3.5)
142
+ tins (1.6.0)
143
+ tzinfo (1.2.2)
144
+ thread_safe (~> 0.1)
145
+ websocket-driver (0.6.3)
146
+ websocket-extensions (>= 0.1.0)
147
+ websocket-extensions (0.1.2)
148
+
149
+ PLATFORMS
150
+ ruby
151
+
152
+ DEPENDENCIES
153
+ appraisal
154
+ bundler (~> 1.11)
155
+ coveralls
156
+ rails (= 5.0.0.beta3)
157
+ rake (~> 10.0)
158
+ rspec
159
+ sqlite3
160
+ activesorting!
161
+
162
+ BUNDLED WITH
163
+ 1.11.2
@@ -0,0 +1,7 @@
1
+ module ActiveSorting
2
+ class Engine < Rails::Engine # :nodoc:
3
+ ActiveSupport.on_load(:active_record) do
4
+ ActiveRecord::Base.send(:include, ActiveSorting::Model)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,159 @@
1
+ module ActiveSorting
2
+ module Model # :nodoc:
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ end
6
+
7
+ # Patches ActiveRecord models
8
+ module ClassMethods
9
+ # Track all sortable arguments
10
+ attr_accessor :active_sorting_options
11
+
12
+ # Sets the sortable options
13
+ #
14
+ # +name+ sortable field name
15
+ # Accepts a Hash of options:
16
+ # +order+ sorting direction, defaults to :asc
17
+ # +step+ stepping value, defaults to 500
18
+ # +scope+ scope field name, defaults to []
19
+ def sortable(name, opts = {})
20
+ self.active_sorting_options = active_sorting_default_options.merge(opts)
21
+ active_sorting_options[:name] = name
22
+ active_sorting_check_options
23
+ validates active_sorting_options[:name], presence: true
24
+ before_validation :active_sorting_callback_before_validation
25
+ end
26
+
27
+ # Default sorting options
28
+ def active_sorting_default_options
29
+ {
30
+ order: :asc,
31
+ step: 500,
32
+ scope: []
33
+ }
34
+ end
35
+
36
+ # Check provided options
37
+ def active_sorting_check_options
38
+ unless columns_hash[active_sorting_field.to_s].type == :integer
39
+ raise ArgumentError, 'Sortable field should be of type Integer'
40
+ end
41
+ unless active_sorting_step.is_a?(Fixnum)
42
+ raise ArgumentError, 'Sortable step should be of type Fixnum'
43
+ end
44
+ end
45
+
46
+ # Calculate the least possible changes required to
47
+ # reorder items in +old_list+ to match +new_list+ order
48
+ # by comparing two proposals from
49
+ # +active_sorting_calculate_changes+
50
+ def active_sorting_changes_required(old_list, new_list)
51
+ changes = []
52
+ if old_list.count != new_list.count
53
+ raise ArgumentError, "Size mismatch between new (#{new_list.count}) and old (#{old_list.count}) array of items"
54
+ end
55
+ proposal1 = active_sorting_calculate_changes(old_list.dup, new_list.dup)
56
+ if proposal1.count >= (new_list.count / 4)
57
+ proposal2 = active_sorting_calculate_changes(old_list.reverse, new_list.reverse)
58
+ changes = proposal1.count < proposal2.count ? proposal1 : proposal2
59
+ else
60
+ changes = proposal1
61
+ end
62
+ changes
63
+ end
64
+
65
+ # Calculate the possible changes required to
66
+ # reorder items in +old_list+ to match +new_list+ order
67
+ def active_sorting_calculate_changes(old_list, new_list, changes = [])
68
+ new_list.each_with_index do |id, index|
69
+ next unless old_list[index] != id
70
+ # This item has changed
71
+ changes << id
72
+ # Remove it from both lists, rinse and repeat
73
+ new_list.delete(id)
74
+ old_list.delete(id)
75
+ # Recur...
76
+ active_sorting_calculate_changes(old_list, new_list, changes)
77
+ break
78
+ end
79
+ changes
80
+ end
81
+
82
+ # Commit changes to database
83
+ def active_sorting_make_changes(new_list, changes)
84
+ new_list.each_with_index do |id, index|
85
+ next unless changes.include?(id)
86
+ if index == new_list.count.pred
87
+ # We're moving an item to last position,
88
+ # increase the count of last item's position
89
+ # by the step
90
+ n1 = find(index.pred).active_sorting_value
91
+ n2 = n1 + active_sorting_step
92
+ elsif index == 0
93
+ # We're moving an item to first position
94
+ # Calculate the gap between following 2 items
95
+ n1 = find(index.next).active_sorting_value
96
+ n2 = find(index.next.next).active_sorting_value
97
+ else
98
+ # We're moving a non-terminal item
99
+ n1 = find(index.pred).active_sorting_value
100
+ n2 = find(index.next).active_sorting_value
101
+ end
102
+ find(id).active_sorting_center_item(n1, n2)
103
+ end
104
+ end
105
+
106
+ def active_sorting_field
107
+ active_sorting_options[:name]
108
+ end
109
+
110
+ def active_sorting_step
111
+ active_sorting_options[:step]
112
+ end
113
+
114
+ def active_sorting_order
115
+ active_sorting_options[:order]
116
+ end
117
+ end
118
+
119
+ def active_sorting_value
120
+ send(self.class.active_sorting_field)
121
+ end
122
+
123
+ def active_sorting_value=(new_value)
124
+ send("#{self.class.active_sorting_field}=", new_value)
125
+ end
126
+
127
+ # Centers an item between the given two positions
128
+ def active_sorting_center_item(n1, n2)
129
+ delta = (n1 - n2).abs
130
+ smaller = [n1, n2].min
131
+ if delta == 1
132
+ new_position = smaller + delta
133
+ elsif delta > 1
134
+ new_position = smaller + (delta / 2)
135
+ end
136
+ self.active_sorting_value = new_position
137
+ save!
138
+ self
139
+ end
140
+
141
+ # Generate the next stepping
142
+ def active_sorting_next_step
143
+ # Get the maximum value for the sortable field name
144
+ # TODO: scopes
145
+ max = self.class.unscoped.maximum(self.class.active_sorting_field)
146
+ # First value will always be 0
147
+ return 0 if max.nil?
148
+ # Increment by the step value configured
149
+ max + self.class.active_sorting_step
150
+ end
151
+
152
+ ## Callbacks
153
+ # Generates a new code based on given options
154
+ def active_sorting_callback_before_validation
155
+ field_name = self.class.active_sorting_field
156
+ send("#{field_name}=", active_sorting_next_step) if send(field_name).nil?
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,3 @@
1
+ module ActiveSorting
2
+ VERSION = '0.5.0'.freeze
3
+ end
@@ -0,0 +1,5 @@
1
+ require 'rails/engine'
2
+ require 'active_record'
3
+ require 'active_sorting/version'
4
+ require 'active_sorting/model'
5
+ require 'active_sorting/engine'
@@ -0,0 +1 @@
1
+ require 'active_sorting'
metadata ADDED
@@ -0,0 +1,183 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: activesorting
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Omar Abdel-Wahab
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-04-14 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.11'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.11'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
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: sqlite3
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: coveralls
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: appraisal
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: activerecord
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 4.0.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 4.0.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: railties
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: 4.0.0
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: 4.0.0
125
+ description:
126
+ email:
127
+ - owahab@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".codeclimate.yml"
133
+ - ".coveralls.yml"
134
+ - ".gitignore"
135
+ - ".rubocop.yml"
136
+ - ".travis.yml"
137
+ - Appraisals
138
+ - CONTRIBUTING.md
139
+ - Gemfile
140
+ - LICENSE
141
+ - README.md
142
+ - Rakefile
143
+ - activesorting.gemspec
144
+ - bin/console
145
+ - bin/setup
146
+ - gemfiles/40.gemfile
147
+ - gemfiles/40.gemfile.lock
148
+ - gemfiles/41.gemfile
149
+ - gemfiles/41.gemfile.lock
150
+ - gemfiles/42.gemfile
151
+ - gemfiles/42.gemfile.lock
152
+ - gemfiles/50.gemfile
153
+ - gemfiles/50.gemfile.lock
154
+ - lib/active_sorting.rb
155
+ - lib/active_sorting/engine.rb
156
+ - lib/active_sorting/model.rb
157
+ - lib/active_sorting/version.rb
158
+ - lib/activesorting.rb
159
+ homepage: http://github.com/owahab/active_sorting
160
+ licenses:
161
+ - MIT
162
+ metadata: {}
163
+ post_install_message:
164
+ rdoc_options: []
165
+ require_paths:
166
+ - lib
167
+ required_ruby_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ required_rubygems_version: !ruby/object:Gem::Requirement
173
+ requirements:
174
+ - - ">="
175
+ - !ruby/object:Gem::Version
176
+ version: '0'
177
+ requirements: []
178
+ rubyforge_project:
179
+ rubygems_version: 2.4.5
180
+ signing_key:
181
+ specification_version: 4
182
+ summary: Adds ability to sort models using a custom field
183
+ test_files: []