sorted 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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