sorted 0.2.2 → 0.3.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.
data/README.rdoc CHANGED
@@ -1,27 +1,46 @@
1
1
  = sorted
2
2
 
3
- This wee gem lets you sort tables (or somthing else) using a view helper and a scope.
3
+ Sorted is a simple object that will take an sql order string and a url sort string to let you sort large datasets over many pages (using {will_paginate}[http://github.com/mislav/will_paginate]) without loosing state.
4
4
 
5
- It will toggle your sort order for you and will even work across pages with {will_paginate}[http://github.com/mislav/will_paginate]
6
-
7
- == Requirements
8
-
9
- activerecord >= 3.0.0
5
+ Using Rails master it will create a `sorted` scope and a two view helpers
10
6
 
11
7
  == Example
12
8
 
13
- The view:
9
+ === The view:
14
10
 
15
11
  link_to_sorted "Email", :email
16
12
 
17
- The model:
13
+ This will make a url like this:
14
+
15
+ http://myapp/users?sort=email_asc
18
16
 
19
- @users = User.sorted(params[:order]).paginate(:page => params[:page])
17
+ Or on the next page load when you then sort by something else....
20
18
 
21
- This will make a url like this:
19
+ http://myapp/users?sort=name_asc!email_asc
20
+
21
+ === The model:
22
+
23
+ This will initially sort by email ascending:
24
+
25
+ @users = User.sorted(:order => "email ASC", :sort => params[:sort]).paginate(:page => params[:page])
26
+
27
+ == Rails 2.3.x
28
+
29
+ This gem works with rails 2.3.x but you will have to roll your own scope and view helper
30
+
31
+ Here is the named scope:
32
+
33
+ named_scope :sorted, lambda { |params|
34
+ { :order => Sorted::Sorter.new(params[:order], {:sort => params[:sort]}).to_sql }
35
+ }
22
36
 
23
- http://myapp/users?order=email_asc
37
+ And this in your application helper:
24
38
 
25
- Or this when you then sort by somthing else....
39
+ def sorted(order)
40
+ Sorted::Sorter.new(order, (request.get? && !params.nil?) ? params.dup : nil).toggle
41
+ end
26
42
 
27
- http://myapp/users?order=name_asc!email_desc
43
+ def link_to_sorted(name, order)
44
+ sorter = sorted(order)
45
+ link_to(name, sorter.params, {:class => sorter.css_class})
46
+ end
data/Rakefile CHANGED
@@ -6,12 +6,10 @@ begin
6
6
  Jeweler::Tasks.new do |gem|
7
7
  gem.name = "sorted"
8
8
  gem.summary = %Q{sort a table}
9
- gem.description = %Q{lets you sort tables (or somthing else) using a view helper and a custom scope}
9
+ gem.description = %Q{lets you sort large data sets using view helpers and a scope}
10
10
  gem.email = "rufuspost@gmail.com"
11
11
  gem.homepage = "http://github.com/mynameisrufus/sorted"
12
12
  gem.authors = ["Rufus Post"]
13
- gem.add_dependency "activerecord", ">= 3.0.0"
14
- gem.add_development_dependency "rspec", ">= 1.2.9"
15
13
  end
16
14
  Jeweler::GemcutterTasks.new
17
15
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.2
1
+ 0.3.0
data/lib/sorted.rb CHANGED
@@ -1,4 +1,114 @@
1
1
  module Sorted
2
+ class Sorter
3
+ def initialize(*args)
4
+ parse_order(args[0])
5
+ unless args[1].nil?
6
+ @params = args[1]
7
+ unless @params[:sort].nil?
8
+ parse_sort(@params[:sort])
9
+ end
10
+ end
11
+ self
12
+ end
13
+
14
+ def parse_sort(sort)
15
+ sort.split(/!/).each do |s|
16
+ if ps = parse_query(s)
17
+ sort_queue << ps
18
+ end
19
+ end
20
+ end
21
+
22
+ def parse_order(order)
23
+ order.to_s.split(/,/).each do |o|
24
+ if po = parse_sql(o)
25
+ order_queue << po
26
+ end
27
+ end
28
+ end
29
+
30
+ def parse_query(sort)
31
+ if m = sort.match(/(\w+)_(asc|desc)/)
32
+ [m[1],m[2]]
33
+ end
34
+ end
35
+
36
+ def parse_sql(sql)
37
+ if m = sql.match(/(([a-zA-Z._]+)\s([asc|ASC|desc|DESC]+)|[a-zA-Z._]+)/)
38
+ [(m[2].nil? ? m[1] : m[2]),(m[3].nil? ? "asc" : m[3].downcase)]
39
+ end
40
+ end
41
+
42
+ def toggle
43
+ @_array = []
44
+ order_queue.select do |os|
45
+ sort_queue.flatten.include?(os[0])
46
+ end.each do |os|
47
+ @_array << [os[0], (case sort_queue.assoc(os[0])[1]; when "asc"; "desc"; when "desc"; "asc" end)]
48
+ end
49
+ order_queue.select do |o|
50
+ !@_array.flatten.include?(o[0])
51
+ end.each do |o|
52
+ @_array << [o[0], o[1]]
53
+ end
54
+ sort_queue.select do |s|
55
+ !@_array.flatten.include?(s[0])
56
+ end.each do |s|
57
+ @_array << [s[0], s[1]]
58
+ end
59
+ self
60
+ end
61
+
62
+ def un_toggle
63
+ @_array = default
64
+ self
65
+ end
66
+
67
+ def to_hash
68
+ _array.inject({}){|h,a| h.merge(Hash[a[0],a[1]]) }
69
+ end
70
+
71
+ def to_sql
72
+ _array.map{|a| "#{a[0]} #{a[1].upcase}"}.join(', ')
73
+ end
74
+
75
+ def to_s
76
+ _array.map{|a| a.join('_')}.join('!')
77
+ end
78
+
79
+ def css_class
80
+ "sorted-#{_array[0][1]}"
81
+ end
82
+
83
+ def params
84
+ @params ||= {}
85
+ @params[:sort] = to_s unless _array.empty?
86
+ @params
87
+ end
88
+
89
+ def order_queue
90
+ @order_queue ||= []
91
+ end
92
+
93
+ def sort_queue
94
+ @sort_queue ||= []
95
+ end
96
+
97
+ private
98
+ def default
99
+ _default = sort_queue.dup
100
+ order_queue.each do |o|
101
+ unless _default.flatten.include?(o[0])
102
+ _default << [o[0], o[1]]
103
+ end
104
+ end
105
+ _default
106
+ end
107
+
108
+ def _array
109
+ @_array ||= default
110
+ end
111
+ end
2
112
  end
3
113
 
4
114
  if defined?(::Rails::Railtie)
@@ -1,62 +1,16 @@
1
1
  require 'action_view'
2
+ require 'sorted'
2
3
 
3
4
  module Sorted
4
5
  module ActionView
5
- def sorted_params(attribute)
6
- get_params = request.get? ? params.dup : {:order => nil}
7
- get_params[:order] = sorted_order(get_params[:order], attribute)
8
- get_params
6
+ def sorted(order)
7
+ ::Sorted::Sorter.new(order, (request.get? && !params.nil?) ? params.dup : nil).toggle
9
8
  end
10
9
 
11
- def link_to_sorted(name, attribute, options = nil)
12
- @sorted_params = sorted_params(attribute)
13
- if options.nil?
14
- options = {:class => sorted_css_class}
15
- elsif options[:class].nil?
16
- options.merge(:class => sorted_css_class)
17
- else
18
- options[:class] = "#{options[:class]} #{sorted_css_class}"
19
- end
20
- link_to(name, @sorted_params.merge(:order => sorted_to_string), options)
21
- end
22
-
23
- protected
24
-
25
- def sorted_css_class
26
- "sorted-#{@sorted_params[:order].first[1]}"
27
- end
28
-
29
- def sorted_order(sort_string, attribute, order_rest = {})
30
- order_first = {attribute => 'asc'}
31
- if sort_string.class == String
32
- sort_string.split(/!/).each do |order|
33
- order.match(/(\w+)_(asc|desc)/) do |match_data|
34
- if match_data[1] == attribute.to_s
35
- order_first = {attribute => sorted_sql_reverse(match_data[2])}
36
- else
37
- order_rest = order_rest.merge(match_data[1] => match_data[2])
38
- end
39
- end
40
- end
41
- end
42
- order_first.merge(order_rest).symbolize_keys
43
- end
44
-
45
- def sorted_to_string
46
- @sorted_params[:order].map do |order|
47
- order.join('_')
48
- end.join('!')
49
- end
50
-
51
- def sorted_sql_reverse(order)
52
- case order
53
- when 'asc'
54
- 'desc'
55
- when 'desc'
56
- 'asc'
57
- else
58
- 'asc'
59
- end
10
+ def link_to_sorted(name, order, options = {})
11
+ sorter = sorted(order)
12
+ options[:class] = options[:class].nil? ? sorter.css_class : "#{options[:class]} #{sorter.css_class}"
13
+ link_to(name, sorter.params, options)
60
14
  end
61
15
  end
62
16
  end
@@ -1,17 +1,11 @@
1
1
  require 'active_record'
2
+ require 'sorted'
2
3
 
3
4
  module Sorted
4
5
  module ActiveRecord
5
6
  def self.enable!
6
7
  ::ActiveRecord::Base.class_eval do
7
- scope :sorted, lambda{|params|
8
- return if params.nil?
9
- order = []
10
- params.split(/!/).each do |param|
11
- order << param.gsub(/_asc/, ' ASC').gsub(/_desc/, ' DESC')
12
- end
13
- {:order => order.join(', ')}
14
- }
8
+ scope :sorted, lambda { |params| Hash[:order, ::Sorted::Sorter.new(params[:order], {:sort => params[:sort]}).to_sql] }
15
9
  end
16
10
  end
17
11
  end
data/sorted.gemspec CHANGED
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{sorted}
8
- s.version = "0.2.2"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Rufus Post"]
12
- s.date = %q{2010-07-20}
13
- s.description = %q{lets you sort tables (or somthing else) using a view helper and a custom scope}
12
+ s.date = %q{2010-07-23}
13
+ s.description = %q{lets you sort large data sets using view helpers and a scope}
14
14
  s.email = %q{rufuspost@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
@@ -46,15 +46,9 @@ Gem::Specification.new do |s|
46
46
  s.specification_version = 3
47
47
 
48
48
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
- s.add_runtime_dependency(%q<activerecord>, [">= 3.0.0"])
50
- s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
51
49
  else
52
- s.add_dependency(%q<activerecord>, [">= 3.0.0"])
53
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
54
50
  end
55
51
  else
56
- s.add_dependency(%q<activerecord>, [">= 3.0.0"])
57
- s.add_dependency(%q<rspec>, [">= 1.2.9"])
58
52
  end
59
53
  end
60
54
 
data/spec/sorted_spec.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'action_controller'
3
+ require 'sorted'
3
4
 
4
5
  describe Sorted::ActiveRecord do
5
6
  before(:each) do
@@ -34,25 +35,93 @@ describe Sorted::ActionView do
34
35
  end
35
36
 
36
37
  it "should integrate with ActionView::Base" do
37
- ActionView::Base.new.should respond_to(:sorted_params)
38
+ ActionView::Base.new.should respond_to(:sorted)
38
39
  end
39
40
 
40
- it "should return a hash for url" do
41
- @controller.params = {:order => "name_desc"}
42
- ActionView::Base.new([], {}, @controller).sorted_params(:email).should == {:order => {:email => "asc", :name => "desc"}}
41
+ it "should return a nice hash from the order sql" do
42
+ sorter = Sorted::Sorter.new("email ASC, phone ASC, name DESC", {:sort => "email_desc!name_desc"})
43
+ sorter.order_queue.should == [["email", "asc"], ["phone", "asc"], ["name", "desc"]]
43
44
  end
44
45
 
45
- it "should return a hash for url" do
46
- @controller.params = {:order => "email_asc!name_desc"}
47
- ActionView::Base.new([], {}, @controller).sorted_params(:email).should == {:order => {:email => "desc", :name => "desc"}}
46
+ it "should return a nice hash from the sort params" do
47
+ sorter = Sorted::Sorter.new("email ASC, phone ASC, name DESC", {:sort => "email_desc!name_desc"})
48
+ sorter.sort_queue.should == [["email", "desc"], ["name", "desc"]]
49
+ end
50
+
51
+ it "should not toggle the sort order and include any sql orders not in sort params" do
52
+ sorter = Sorted::Sorter.new("email DESC, phone ASC, name DESC", {:sort => "email_desc!name_desc"})
53
+ sorter.to_hash.should == {"email" => "desc", "name" => "desc", "phone" => "asc"}
54
+ end
55
+
56
+ it "should toggle the sort order and include any sql orders not in sort params" do
57
+ sorter = Sorted::Sorter.new("email DESC, phone ASC, name DESC", {:sort => "email_desc!name_desc"})
58
+ sorter.toggle.to_hash.should == {"email" => "asc", "name" => "asc", "phone" => "asc"}
59
+ end
60
+
61
+ it "should not change the direction of name using view helper" do
62
+ @controller.params = {:sort => "name_desc!email_asc"}
63
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
64
+ sorter.toggle.to_hash.should == {"email" => "desc", "name" => "desc"}
65
+ end
66
+
67
+ it "should reverse email direction using view helper" do
68
+ @controller.params = {:sort => "email_asc!name_desc"}
69
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
70
+ sorter.toggle.to_hash.should == {"email" => "desc", "name" => "desc"}
71
+ end
72
+
73
+ it "should reverse email direction using view helper" do
74
+ @controller.params = {:sort => "phone_desc!name_desc!email_desc"}
75
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
76
+ sorter.toggle.params.should == {:sort => "email_asc!phone_desc!name_desc"}
77
+ @controller.params = sorter.params
78
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
79
+ sorter.toggle.params.should == {:sort => "email_desc!phone_desc!name_desc"}
80
+ @controller.params = sorter.params
81
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:phone)
82
+ sorter.toggle.params.should == {:sort => "phone_asc!email_desc!name_desc"}
83
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:name)
84
+ sorter.toggle.params.should == {:sort => "name_asc!email_desc!phone_desc"}
85
+ end
86
+
87
+ it "should should fail becasue the sort order is incorect" do
88
+ sorter = Sorted::Sorter.new(:jsci_complete, {:sort => "parent_id_desc!non_vocational_complete_desc!jsci_complete_desc"})
89
+ sorter.toggle
90
+ sorter.to_s.should_not == "parent_id_desc!non_vocational_complete_desc!jsci_complete_desc"
91
+ end
92
+
93
+ it "should return a hash of options for url builder with sorted query string" do
94
+ @controller.params = {:sort => "email_asc!name_desc", :page => 2}
95
+ ActionView::Base.new([], {}, @controller).sorted(:email).params.should == {:sort => "email_desc!name_desc", :page => 2}
96
+ end
97
+
98
+ it "should return an sql sort string" do
99
+ Sorted::Sorter.new(:email).to_sql.should == "email ASC"
100
+ Sorted::Sorter.new(:email, {:sort => "name_desc!email_desc"}).to_sql.should == "name DESC, email DESC"
101
+ end
102
+
103
+ it "should handle a large initial order string" do
104
+ sorter = Sorted::Sorter.new('email ASC, name DESC, phone ASC', {:sort => "email_desc!name_desc"})
105
+ sorter.to_sql.should == "email DESC, name DESC, phone ASC"
106
+ end
107
+
108
+ it "should handle a large initial order string" do
109
+ sorter = Sorted::Sorter.new('email ASC, phone DESC, name ASC', {:sort => "email_desc!name_desc"})
110
+ sorter.to_sql.should == "email DESC, name DESC, phone DESC"
111
+ end
112
+
113
+ it "should not die if params nil" do
114
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
115
+ sorter.params.should == {:sort => "email_asc"}
48
116
  end
49
117
 
50
- it "should return a query string for link options" do
51
- @controller.params = {:order => "email_asc!name_desc", :page => 2}
52
- ActionView::Base.new([], {}, @controller).sorted_params(:email).should == {:order => {:email => "desc", :name => "desc"}, :page => 2}
118
+ it "should have some roll your own methods" do
119
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
120
+ sorter.to_s.should == "email_asc"
53
121
  end
54
122
 
55
- it "should not care if params[:order] nil" do
56
- ActionView::Base.new([], {}, @controller).sorted_params({:email => "desc", :name => "desc"}).should_not be_nil
123
+ it "should return css class" do
124
+ sorter = ActionView::Base.new([], {}, @controller).sorted(:email)
125
+ sorter.css_class.should == "sorted-asc"
57
126
  end
58
127
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
8
- - 2
9
- version: 0.2.2
7
+ - 3
8
+ - 0
9
+ version: 0.3.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Rufus Post
@@ -14,40 +14,11 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-07-20 00:00:00 +10:00
17
+ date: 2010-07-23 00:00:00 +10:00
18
18
  default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: activerecord
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 3
30
- - 0
31
- - 0
32
- version: 3.0.0
33
- type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: rspec
37
- prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 1
45
- - 2
46
- - 9
47
- version: 1.2.9
48
- type: :development
49
- version_requirements: *id002
50
- description: lets you sort tables (or somthing else) using a view helper and a custom scope
19
+ dependencies: []
20
+
21
+ description: lets you sort large data sets using view helpers and a scope
51
22
  email: rufuspost@gmail.com
52
23
  executables: []
53
24