datagrid 0.6.4 → 0.7.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.
@@ -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) {