datagrid 0.6.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -31,8 +31,8 @@ module Datagrid
31
31
  end
32
32
 
33
33
  def datagrid_column_classes(grid, column)
34
- order_class = grid.order == column.name ? ["ordered", grid.descending ? "desc" : "asc"] : nil
35
- [column.name, order_class].compact.join(" ")
34
+ order_class = grid.order == column.name ? ["ordered", grid.descending ? "desc" : "asc"] : nil
35
+ [column.name, order_class, column.options[:class]].compact.join(" ")
36
36
  end
37
37
  end
38
38
  end
@@ -50,8 +50,8 @@ module Datagrid
50
50
 
51
51
  def assets
52
52
  result = super
53
- if self.order
54
- column = column_by_name(self.order)
53
+ if order
54
+ column = column_by_name(order)
55
55
  result = apply_order(result, column)
56
56
  end
57
57
  result
@@ -60,19 +60,49 @@ module Datagrid
60
60
  private
61
61
 
62
62
  def apply_order(assets, column)
63
-
64
- order = column.order
65
- if self.descending?
63
+ if descending?
66
64
  if column.order_desc
67
- driver.asc(assets, column.order_desc)
65
+ apply_asc_order(assets, column.order_desc)
68
66
  else
69
- driver.desc(assets, order)
67
+ apply_desc_order(assets, column.order)
70
68
  end
69
+ else
70
+ apply_asc_order(assets, column.order)
71
+ end
72
+ end
73
+
74
+ def apply_asc_order(assets, order)
75
+ if order.respond_to?(:call)
76
+ apply_block_order(assets, order)
71
77
  else
72
78
  driver.asc(assets, order)
73
79
  end
74
80
  end
75
81
 
82
+ def apply_desc_order(assets, order)
83
+ if order.respond_to?(:call)
84
+ reverse_order(apply_asc_order(assets, order))
85
+ else
86
+ driver.desc(assets, order)
87
+ end
88
+ end
89
+
90
+ def reverse_order(assets)
91
+ driver.reverse_order(assets)
92
+ rescue NotImplementedError
93
+ self.class.order_unsupported("Your ORM do not support reverse order: please specify :order_desc option manually")
94
+ end
95
+
96
+ def apply_block_order(assets, order)
97
+ case order.arity
98
+ when -1, 0
99
+ assets.instance_eval(&order)
100
+ when 1
101
+ order.call(assets)
102
+ else
103
+ self.class.order_unsupported("Order option proc can not handle more than one argument")
104
+ end
105
+ end
76
106
  end # InstanceMethods
77
107
 
78
108
  end
@@ -12,15 +12,24 @@ module Datagrid
12
12
  end
13
13
 
14
14
  def format_value(grid, column, asset)
15
+
15
16
  value = if column.html?
16
- if column.block.arity > 1
17
- @template.instance_exec(asset, grid, &column.block)
18
- else
19
- @template.instance_exec(asset, &column.block)
17
+ args = []
18
+ remaining_arity = column.html_block.arity
19
+
20
+ if column.data?
21
+ args << column.value(asset,grid)
22
+ remaining_arity -= 1
20
23
  end
24
+
25
+ args << asset if remaining_arity > 0
26
+ args << grid if remaining_arity > 1
27
+
28
+ @template.instance_exec(*args, &column.html_block)
21
29
  else
22
- column.value(asset, grid)
30
+ column.value(asset,grid)
23
31
  end
32
+
24
33
  url = column.options[:url] && column.options[:url].call(asset)
25
34
  if url
26
35
  @template.link_to(value, url)
@@ -2,6 +2,7 @@ module Datagrid
2
2
  module Utils
3
3
  class << self
4
4
 
5
+
5
6
  TRUTH = [true, 1, "1", "true", "yes", "on"]
6
7
 
7
8
  def booleanize(value)
@@ -17,6 +18,21 @@ module Datagrid
17
18
  @warnings[message] = true
18
19
  end
19
20
  end
21
+
22
+ def add_html_classes(options, *classes)
23
+ options = options.clone
24
+ options[:class] ||= ""
25
+ if options[:class].is_a?(Array)
26
+ options[:class] += classes
27
+ else
28
+ # suppose that it is a String
29
+ options[:class] += " " unless options[:class].blank?
30
+ options[:class] += classes.join(" ")
31
+ end
32
+ options
33
+ end
34
+
35
+
20
36
  end
21
37
  end
22
38
  end
@@ -11,17 +11,23 @@ describe Datagrid::Columns do
11
11
  describe "basic methods" do
12
12
 
13
13
  let!(:entry) { Entry.create!(
14
- :group => group, :name => "Star", :disabled => false, :confirmed => false, :category => "first"
14
+ :group => group,
15
+ :name => "Star",
16
+ :disabled => false,
17
+ :confirmed => false,
18
+ :category => "first",
19
+ :access_level => 'admin',
20
+ :pet => 'rottweiler'
15
21
  ) }
16
22
 
17
23
  it "should have data columns without html columns" do
18
24
  subject.data_columns.size.should == subject.columns.size - 1
19
25
  end
20
26
  it "should build rows of data" do
21
- subject.rows.should == [["Pop", "Star"]]
27
+ subject.rows.should == [["Pop", "Star", "admin", "ROTTWEILER"]]
22
28
  end
23
29
  it "should generate header" do
24
- subject.header.should == ["Group", "Name"]
30
+ subject.header.should == ["Group", "Name", "Access level", "Pet"]
25
31
  end
26
32
 
27
33
  it "should generate table data" do
@@ -34,12 +40,18 @@ describe Datagrid::Columns do
34
40
  it "should generate hash for given asset" do
35
41
  subject.hash_for(entry).should == {
36
42
  :group => "Pop",
37
- :name => "Star"
43
+ :name => "Star",
44
+ :access_level => 'admin',
45
+ :pet => 'ROTTWEILER'
38
46
  }
39
47
  end
40
48
 
41
49
  it "should support csv export" do
42
- subject.to_csv.should == "Group,Name\nPop,Star\n"
50
+ subject.to_csv.should == "Group,Name,Access level,Pet\nPop,Star,admin,ROTTWEILER\n"
51
+ end
52
+
53
+ it "should support csv export of particular columns" do
54
+ subject.to_csv(:name).should == "Name\nStar\n"
43
55
  end
44
56
  end
45
57
 
@@ -50,8 +62,8 @@ describe Datagrid::Columns do
50
62
  where("category LIKE '%#{value}%'")
51
63
  end
52
64
 
53
- column(:exact_category) do |entry, report|
54
- entry.category == report.category
65
+ column(:exact_category) do |entry, grid|
66
+ entry.category == grid.category
55
67
  end
56
68
  end
57
69
  Entry.create!(:category => "foo")
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe Datagrid::Filters::DateFilter do
4
+
5
+ it "should support date range argument" do
6
+ e1 = Entry.create!(:created_at => 7.days.ago)
7
+ e2 = Entry.create!(:created_at => 4.days.ago)
8
+ e3 = Entry.create!(:created_at => 1.day.ago)
9
+ report = test_report(:created_at => 5.day.ago..3.days.ago) do
10
+ scope { Entry }
11
+ filter(:created_at, :date)
12
+ end
13
+ report.assets.should_not include(e1)
14
+ report.assets.should include(e2)
15
+ report.assets.should_not include(e3)
16
+ end
17
+
18
+ it "should support date range given as array argument" do
19
+ e1 = Entry.create!(:created_at => 7.days.ago)
20
+ e2 = Entry.create!(:created_at => 4.days.ago)
21
+ e3 = Entry.create!(:created_at => 1.day.ago)
22
+ report = test_report(:created_at => [5.day.ago.to_date.to_s, 3.days.ago.to_date.to_s]) do
23
+ scope { Entry }
24
+ filter(:created_at, :date, :range => true)
25
+ end
26
+ report.assets.should_not include(e1)
27
+ report.assets.should include(e2)
28
+ report.assets.should_not include(e3)
29
+ end
30
+
31
+ it "should support minimum date argument" do
32
+ e1 = Entry.create!(:created_at => 7.days.ago)
33
+ e2 = Entry.create!(:created_at => 4.days.ago)
34
+ e3 = Entry.create!(:created_at => 1.day.ago)
35
+ report = test_report(:created_at => [5.day.ago.to_date.to_s, nil]) do
36
+ scope { Entry }
37
+ filter(:created_at, :date, :range => true)
38
+ end
39
+ report.assets.should_not include(e1)
40
+ report.assets.should include(e2)
41
+ report.assets.should include(e3)
42
+ end
43
+
44
+ it "should support maximum date argument" do
45
+ e1 = Entry.create!(:created_at => 7.days.ago)
46
+ e2 = Entry.create!(:created_at => 4.days.ago)
47
+ e3 = Entry.create!(:created_at => 1.day.ago)
48
+ report = test_report(:created_at => [nil, 3.days.ago.to_date.to_s]) do
49
+ scope { Entry }
50
+ filter(:created_at, :date, :range => true)
51
+ end
52
+ report.assets.should include(e1)
53
+ report.assets.should include(e2)
54
+ report.assets.should_not include(e3)
55
+ end
56
+
57
+ it "should find something in one day interval" do
58
+
59
+ e1 = Entry.create!(:created_at => 7.days.ago)
60
+ e2 = Entry.create!(:created_at => 4.days.ago)
61
+ e3 = Entry.create!(:created_at => 1.day.ago)
62
+ report = test_report(:created_at => (4.days.ago.to_date..4.days.ago.to_date)) do
63
+ scope { Entry }
64
+ filter(:created_at, :date, :range => true)
65
+ end
66
+ report.assets.should_not include(e1)
67
+ report.assets.should include(e2)
68
+ report.assets.should_not include(e3)
69
+ end
70
+ it "should support invalid range" do
71
+
72
+ e1 = Entry.create!(:created_at => 7.days.ago)
73
+ e2 = Entry.create!(:created_at => 4.days.ago)
74
+ e3 = Entry.create!(:created_at => 1.day.ago)
75
+ report = test_report(:created_at => (1.days.ago.to_date..7.days.ago.to_date)) do
76
+ scope { Entry }
77
+ filter(:created_at, :date, :range => true)
78
+ end
79
+ report.assets.should_not include(e1)
80
+ report.assets.should_not include(e2)
81
+ report.assets.should_not include(e3)
82
+ end
83
+
84
+
85
+ it "should support block" do
86
+ report = test_report(:created_at => Date.today) do
87
+ scope { Entry }
88
+ filter(:created_at, :date, :range => true) do |value|
89
+ where("created_at >= ?", value)
90
+ end
91
+ end
92
+ report.assets.should_not include(Entry.create!(:created_at => 1.day.ago))
93
+ report.assets.should include(Entry.create!(:created_at => DateTime.now))
94
+ end
95
+
96
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+
3
+ describe Datagrid::Filters::IntegerFilter do
4
+
5
+ it "should support integer range argument" do
6
+ e1 = Entry.create!(:group_id => 1)
7
+ e2 = Entry.create!(:group_id => 4)
8
+ e3 = Entry.create!(:group_id => 7)
9
+ report = test_report(:group_id => 3..5) do
10
+ scope { Entry }
11
+ filter(:group_id, :integer)
12
+ end
13
+ report.assets.should_not include(e1)
14
+ report.assets.should include(e2)
15
+ report.assets.should_not include(e3)
16
+ end
17
+
18
+ it "should support integer range given as array argument" do
19
+ e1 = Entry.create!(:group_id => 7)
20
+ e2 = Entry.create!(:group_id => 4)
21
+ e3 = Entry.create!(:group_id => 1)
22
+ report = test_report(:group_id => [3.to_s, 5.to_s]) do
23
+ scope { Entry }
24
+ filter(:group_id, :integer, :range => true)
25
+ end
26
+ report.assets.should_not include(e1)
27
+ report.assets.should include(e2)
28
+ report.assets.should_not include(e3)
29
+ end
30
+
31
+ it "should support minimum integer argument" do
32
+ e1 = Entry.create!(:group_id => 1)
33
+ e2 = Entry.create!(:group_id => 4)
34
+ e3 = Entry.create!(:group_id => 7)
35
+ report = test_report(:group_id => [5.to_s, nil]) do
36
+ scope { Entry }
37
+ filter(:group_id, :integer, :range => true)
38
+ end
39
+ report.assets.should_not include(e1)
40
+ report.assets.should_not include(e2)
41
+ report.assets.should include(e3)
42
+ end
43
+
44
+ it "should support maximum integer argument" do
45
+ e1 = Entry.create!(:group_id => 1)
46
+ e2 = Entry.create!(:group_id => 4)
47
+ e3 = Entry.create!(:group_id => 7)
48
+ report = test_report(:group_id => [nil, 5.to_s]) do
49
+ scope { Entry }
50
+ filter(:group_id, :integer, :range => true)
51
+ end
52
+ report.assets.should include(e1)
53
+ report.assets.should include(e2)
54
+ report.assets.should_not include(e3)
55
+ end
56
+
57
+ it "should find something in one integer interval" do
58
+
59
+ e1 = Entry.create!(:group_id => 7)
60
+ e2 = Entry.create!(:group_id => 4)
61
+ e3 = Entry.create!(:group_id => 1)
62
+ report = test_report(:group_id => (4..4)) do
63
+ scope { Entry }
64
+ filter(:group_id, :integer, :range => true)
65
+ end
66
+ report.assets.should_not include(e1)
67
+ report.assets.should include(e2)
68
+ report.assets.should_not include(e3)
69
+ end
70
+ it "should support invalid range" do
71
+
72
+ e1 = Entry.create!(:group_id => 7)
73
+ e2 = Entry.create!(:group_id => 4)
74
+ e3 = Entry.create!(:group_id => 1)
75
+ report = test_report(:group_id => (7..1)) do
76
+ scope { Entry }
77
+ filter(:group_id, :integer, :range => true)
78
+ end
79
+ report.assets.should_not include(e1)
80
+ report.assets.should_not include(e2)
81
+ report.assets.should_not include(e3)
82
+ end
83
+
84
+
85
+ it "should support block" do
86
+ report = test_report(:group_id => 5) do
87
+ scope { Entry }
88
+ filter(:group_id, :integer, :range => true) do |value|
89
+ where("group_id >= ?", value)
90
+ end
91
+ end
92
+ report.assets.should_not include(Entry.create!(:group_id => 1))
93
+ report.assets.should include(Entry.create!(:group_id => 5))
94
+ end
95
+
96
+ end
@@ -51,8 +51,9 @@ describe Datagrid::Filters do
51
51
  scope {ModelWithoutTable}
52
52
 
53
53
  filter(:name)
54
+ filter(:limit)
54
55
  end
55
- TheReport.new(:name => 'hello')
56
+ TheReport.new(:name => 'hello').should_not be_nil
56
57
  end
57
58
 
58
59
  it "should support inheritence" do
@@ -50,6 +50,98 @@ describe Datagrid::FormBuilder do
50
50
  '<input class="group_id integer_filter" id="report_group_id" name="report[group_id]" size="30" type="text"/>'
51
51
  )}
52
52
  end
53
+
54
+ context "with date filter type" do
55
+ let(:_filter) { :created_at }
56
+ let(:_grid) {
57
+ test_report do
58
+ scope {Entry}
59
+ filter(:created_at, :date)
60
+ end
61
+ }
62
+ it { should equal_to_dom(
63
+ '<input class="created_at date_filter" id="report_created_at" name="report[created_at]" size="30" type="text"/>'
64
+ )}
65
+ end
66
+
67
+ context "with integer filter type and range option" do
68
+ let(:_filter) { :group_id }
69
+ let(:_grid) {
70
+ test_report(:group_id => _range) do
71
+ scope {Entry}
72
+ filter(:group_id, :integer, :range => true)
73
+ end
74
+ }
75
+ context "with only left bound" do
76
+
77
+ let(:_range) { [10, nil]}
78
+ it { should equal_to_dom(
79
+ '<input class="group_id integer_filter from" id="report_group_id" multiple name="report[group_id][]" size="30" type="text" value="10"/>' +
80
+ '<span class="separator integer"> - </span>' +
81
+ '<input class="group_id integer_filter to" id="report_group_id" multiple name="report[group_id][]" size="30" type="text"/>'
82
+ )}
83
+ it { should be_html_safe }
84
+ end
85
+ context "with only right bound" do
86
+
87
+ let(:_range) { [nil, 10]}
88
+ it { should equal_to_dom(
89
+ '<input class="group_id integer_filter from" id="report_group_id" multiple name="report[group_id][]" size="30" type="text"/>' +
90
+ '<span class="separator integer"> - </span>' +
91
+ '<input class="group_id integer_filter to" id="report_group_id" multiple name="report[group_id][]" size="30" type="text" value="10"/>'
92
+ )}
93
+ it { should be_html_safe }
94
+ end
95
+
96
+ context "with invalid range value" do
97
+ let(:_range) { 2..1 }
98
+ it { should equal_to_dom(
99
+ '<input class="group_id integer_filter from" id="report_group_id" multiple name="report[group_id][]" size="30" type="text" value="2"/>' +
100
+ '<span class="separator integer"> - </span>' +
101
+ '<input class="group_id integer_filter to" id="report_group_id" multiple name="report[group_id][]" size="30" type="text" value="1"/>'
102
+ )}
103
+ end
104
+ end
105
+
106
+
107
+ context "with date filter type and range option" do
108
+ let(:_filter) { :created_at }
109
+ let(:_grid) {
110
+ test_report(:created_at => _range) do
111
+ scope {Entry}
112
+ filter(:created_at, :date, :range => true)
113
+ end
114
+ }
115
+ context "with only left bound" do
116
+
117
+ let(:_range) { ["2012-01-03", nil]}
118
+ it { should equal_to_dom(
119
+ '<input class="created_at date_filter from" id="report_created_at" multiple name="report[created_at][]" size="30" type="text" value="2012-01-03"/>' +
120
+ '<span class="separator date"> - </span>' +
121
+ '<input class="created_at date_filter to" id="report_created_at" multiple name="report[created_at][]" size="30" type="text"/>'
122
+ )}
123
+ it { should be_html_safe }
124
+ end
125
+ context "with only right bound" do
126
+
127
+ let(:_range) { [nil, "2012-01-03"]}
128
+ it { should equal_to_dom(
129
+ '<input class="created_at date_filter from" id="report_created_at" multiple name="report[created_at][]" size="30" type="text"/>' +
130
+ '<span class="separator date"> - </span>' +
131
+ '<input class="created_at date_filter to" id="report_created_at" multiple name="report[created_at][]" size="30" type="text" value="2012-01-03"/>'
132
+ )}
133
+ it { should be_html_safe }
134
+ end
135
+
136
+ context "with invalid range value" do
137
+ let(:_range) { Date.parse('2012-01-02')..Date.parse('2012-01-01') }
138
+ it { should equal_to_dom(
139
+ '<input class="created_at date_filter from" id="report_created_at" multiple name="report[created_at][]" size="30" type="text" value="2012-01-02"/>' +
140
+ '<span class="separator date"> - </span>' +
141
+ '<input class="created_at date_filter to" id="report_created_at" multiple name="report[created_at][]" size="30" type="text" value="2012-01-01"/>'
142
+ )}
143
+ end
144
+ end
53
145
  context "with enum filter type" do
54
146
  let(:_filter) { :category }
55
147
  let(:_grid) {