datagrid 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -1
- data/Readme.markdown +22 -7
- data/VERSION +1 -1
- data/datagrid.gemspec +4 -4
- data/lib/datagrid.rb +1 -0
- data/lib/datagrid/columns.rb +40 -72
- data/lib/datagrid/columns/column.rb +8 -6
- data/lib/datagrid/filters.rb +7 -63
- data/lib/datagrid/filters/base_filter.rb +4 -1
- data/lib/datagrid/filters/boolean_enum_filter.rb +0 -1
- data/lib/datagrid/filters/string_filter.rb +5 -0
- data/lib/datagrid/form_builder.rb +13 -2
- data/lib/datagrid/helper.rb +7 -7
- data/spec/datagrid/columns_spec.rb +35 -0
- data/spec/datagrid/filters_spec.rb +23 -0
- data/spec/datagrid/form_builder_spec.rb +36 -5
- data/spec/datagrid/helper_spec.rb +10 -1
- data/spec/datagrid_spec.rb +2 -2
- data/spec/spec_helper.rb +5 -2
- data/spec/support/equal_to_dom.rb +1 -1
- data/spec/support/schema.rb +2 -2
- data/spec/support/simple_report.rb +5 -3
- metadata +42 -95
data/Gemfile
CHANGED
@@ -17,7 +17,8 @@ group :development do
|
|
17
17
|
gem "bundler", "~> 1.0.0"
|
18
18
|
gem "jeweler", "~> 1.6.0"
|
19
19
|
gem "rcov", ">= 0"
|
20
|
-
gem "ruby-debug"
|
20
|
+
gem "ruby-debug", :platform => "mri_18"
|
21
|
+
#gem "ruby-debug19", :platform => "mri_19"
|
21
22
|
gem "sqlite3-ruby"
|
22
23
|
gem "fastercsv"
|
23
24
|
gem "nokogiri"
|
data/Readme.markdown
CHANGED
@@ -41,9 +41,9 @@ class SimpleReport
|
|
41
41
|
filter(:category, :enum, :select => ["first", "second"])
|
42
42
|
filter(:disabled, :eboolean)
|
43
43
|
filter(:confirmed, :boolean)
|
44
|
-
filter(:group_id, :multiple => true)
|
44
|
+
filter(:group_id, :integer, :multiple => true)
|
45
45
|
integer_range_filter(:logins_count, :integer)
|
46
|
-
filter(:group_name, :header => "Group") do |value|
|
46
|
+
filter(:group_name, :string, :header => "Group") do |value|
|
47
47
|
self.joins(:group).where(:groups => {:name => value})
|
48
48
|
end
|
49
49
|
|
@@ -66,7 +66,14 @@ end
|
|
66
66
|
Basic grid api:
|
67
67
|
|
68
68
|
``` ruby
|
69
|
-
report = SimpleReport.new(
|
69
|
+
report = SimpleReport.new(
|
70
|
+
:order => "group",
|
71
|
+
:descending => true,
|
72
|
+
:group_id => [1,2], :from_logins_count => 1,
|
73
|
+
:category => "first",
|
74
|
+
:order => :group,
|
75
|
+
:descending => true
|
76
|
+
)
|
70
77
|
|
71
78
|
report.assets # => Array of User instances:
|
72
79
|
# SELECT * FROM users WHERE users.group_id in (1,2) AND users.logins_count >= 1 AND users.category = 'first' ORDER BY groups.name DESC
|
@@ -85,7 +92,13 @@ report.to_csv # => Yes, it is
|
|
85
92
|
### Scope
|
86
93
|
|
87
94
|
Default scope of objects to filter and display.
|
88
|
-
In common case it is `ActiveRecord::Base` subclass with some generic scopes like in example above
|
95
|
+
In common case it is `ActiveRecord::Base` subclass with some generic scopes like in example above:
|
96
|
+
|
97
|
+
``` ruby
|
98
|
+
scope do
|
99
|
+
User.includes(:group)
|
100
|
+
end
|
101
|
+
```
|
89
102
|
|
90
103
|
### Filters
|
91
104
|
|
@@ -104,16 +117,18 @@ Datagrid supports different type of filters including:
|
|
104
117
|
* boolean
|
105
118
|
* eboolean - the select of "yes", "no" and any
|
106
119
|
* enum
|
120
|
+
* string
|
107
121
|
|
108
|
-
|
122
|
+
[More about filters](https://github.com/bogdan/datagrid/wiki/Filters)
|
109
123
|
|
110
124
|
|
111
125
|
### Columns
|
112
126
|
|
113
127
|
Each column is represented by name and code block to calculate the value.
|
114
|
-
|
128
|
+
Some formatting options are also available.
|
129
|
+
Each column is sortable.
|
115
130
|
|
116
|
-
More
|
131
|
+
[More about columns](https://github.com/bogdan/datagrid/wiki/Columns)
|
117
132
|
|
118
133
|
|
119
134
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/datagrid.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{datagrid}
|
8
|
-
s.version = "0.
|
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 = ["Bogdan Gusiev"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-07-01}
|
13
13
|
s.description = %q{This allows you to easily build datagrid aka data tables with sortable columns and filters}
|
14
14
|
s.email = %q{agresso@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -39,6 +39,7 @@ Gem::Specification.new do |s|
|
|
39
39
|
"lib/datagrid/filters/enum_filter.rb",
|
40
40
|
"lib/datagrid/filters/filter_eval.rb",
|
41
41
|
"lib/datagrid/filters/integer_filter.rb",
|
42
|
+
"lib/datagrid/filters/string_filter.rb",
|
42
43
|
"lib/datagrid/form_builder.rb",
|
43
44
|
"lib/datagrid/helper.rb",
|
44
45
|
"lib/datagrid/rspec.rb",
|
@@ -56,11 +57,10 @@ Gem::Specification.new do |s|
|
|
56
57
|
s.homepage = %q{http://github.com/bogdan/datagrid}
|
57
58
|
s.licenses = ["MIT"]
|
58
59
|
s.require_paths = ["lib"]
|
59
|
-
s.rubygems_version = %q{1.
|
60
|
+
s.rubygems_version = %q{1.6.2}
|
60
61
|
s.summary = %q{Ruby gem to create datagrids}
|
61
62
|
|
62
63
|
if s.respond_to? :specification_version then
|
63
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
64
64
|
s.specification_version = 3
|
65
65
|
|
66
66
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
data/lib/datagrid.rb
CHANGED
data/lib/datagrid/columns.rb
CHANGED
@@ -14,7 +14,24 @@ module Datagrid
|
|
14
14
|
|
15
15
|
include Datagrid::Core
|
16
16
|
|
17
|
-
datagrid_attribute :order
|
17
|
+
datagrid_attribute :order do |value|
|
18
|
+
unless value.blank?
|
19
|
+
value = value.to_sym
|
20
|
+
column = column_by_name(value)
|
21
|
+
unless column
|
22
|
+
order_unsupported(value, "no column #{value} in #{self.class}")
|
23
|
+
end
|
24
|
+
unless column.order
|
25
|
+
order_unsupported(
|
26
|
+
name, "#{self.class}##{name} don't support order"
|
27
|
+
)
|
28
|
+
end
|
29
|
+
value
|
30
|
+
else
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
18
35
|
datagrid_attribute :descending do |value|
|
19
36
|
Datagrid::Utils.booleanize(value)
|
20
37
|
end
|
@@ -30,69 +47,6 @@ module Datagrid
|
|
30
47
|
@columns ||= []
|
31
48
|
end
|
32
49
|
|
33
|
-
# Defines column that will be used to display data.
|
34
|
-
#
|
35
|
-
# Example:
|
36
|
-
#
|
37
|
-
# class UserGrid
|
38
|
-
# include Datagrid
|
39
|
-
#
|
40
|
-
# scope do
|
41
|
-
# User.order("users.created_at desc").includes(:group)
|
42
|
-
# end
|
43
|
-
#
|
44
|
-
# column(:name)
|
45
|
-
# column(:group, :order => "groups.name")
|
46
|
-
# self.group.name
|
47
|
-
# end
|
48
|
-
# column(:active, :header => "Activated") do |user|
|
49
|
-
# !user.disabled
|
50
|
-
# end
|
51
|
-
#
|
52
|
-
# end
|
53
|
-
#
|
54
|
-
# Each column will be used to generate data.
|
55
|
-
# In order to create grid that display all users:
|
56
|
-
#
|
57
|
-
# grid = UserGrid.new
|
58
|
-
# grid.rows
|
59
|
-
# grid.header # => ["Group", "Name", "Disabled"]
|
60
|
-
# grid.rows # => [
|
61
|
-
# # ["Steve", "Spammers", true],
|
62
|
-
# # [ "John", "Spoilers", true],
|
63
|
-
# # ["Berry", "Good people", false]
|
64
|
-
# # ]
|
65
|
-
# grid.data # => Header & Rows
|
66
|
-
#
|
67
|
-
# = Column value
|
68
|
-
#
|
69
|
-
# Column value can be defined by passing a block to <tt>#column</tt> method.
|
70
|
-
# If no block given column it is generated automatically by sending column name method to model.
|
71
|
-
# The block could have zero arguments(<tt>instance_eval</tt>) or one argument that is model object.
|
72
|
-
#
|
73
|
-
# = Column options
|
74
|
-
#
|
75
|
-
# The following options can be passed to column definition:
|
76
|
-
#
|
77
|
-
# * <tt>:order</tt> - an order SQL that should be used to sort by this column.
|
78
|
-
# Default: report column name if there is database column with this name.
|
79
|
-
# * <tt>:order_desc</tt> - descending order expression from this column. Default: "#{order} desc".
|
80
|
-
#
|
81
|
-
# TODO: frontend options description
|
82
|
-
#
|
83
|
-
# = Columns order
|
84
|
-
#
|
85
|
-
# Each column supports <tt>:order</tt> option that is used to specify SQL to sort data by the given column.
|
86
|
-
# In order to specify order the following attributes are used:
|
87
|
-
#
|
88
|
-
# * <tt>:order</tt> - column name to sort with as <tt>Symbol</tt>. Default: nil.
|
89
|
-
# * <tt>:descending</tt> - if true descending suffix is added to specified order. Default: false.
|
90
|
-
#
|
91
|
-
# Example:
|
92
|
-
#
|
93
|
-
# grid = UserGrid.new(:order => :group, :descending => true)
|
94
|
-
# grid.assets # => Return assets ordered by :group column descending
|
95
|
-
#
|
96
50
|
def column(name, options = {}, &block)
|
97
51
|
check_scope_defined!("Scope should be defined before columns")
|
98
52
|
block ||= lambda do |model|
|
@@ -101,25 +55,36 @@ module Datagrid
|
|
101
55
|
self.columns << Datagrid::Columns::Column.new(self, name, options, &block)
|
102
56
|
end
|
103
57
|
|
58
|
+
def order_unsupported(name, reason)
|
59
|
+
raise Datagrid::OrderUnsupported, "Can not sort #{self.inspect} by ##{name}: #{reason}"
|
60
|
+
end
|
104
61
|
|
62
|
+
def column_by_name(name)
|
63
|
+
self.columns.find do |col|
|
64
|
+
col.name.to_sym == name.to_sym
|
65
|
+
end
|
66
|
+
end
|
105
67
|
end # ClassMethods
|
106
68
|
|
107
69
|
module InstanceMethods
|
108
70
|
|
71
|
+
# Returns <tt>Array</tt> of human readable column names. See also "Localization" section
|
109
72
|
def header
|
110
73
|
self.class.columns.map(&:header)
|
111
74
|
end
|
112
75
|
|
76
|
+
# Returns <tt>Array</tt> column values for given asset
|
113
77
|
def row_for(asset)
|
114
78
|
self.class.columns.map do |column|
|
115
|
-
column.value(asset)
|
79
|
+
column.value(asset, self)
|
116
80
|
end
|
117
81
|
end
|
118
82
|
|
83
|
+
# Returns <tt>Hash</tt> where keys are column names and values are column values for the given asset
|
119
84
|
def hash_for(asset)
|
120
85
|
result = {}
|
121
86
|
self.class.columns.each do |column|
|
122
|
-
result[column.name] = column.value(asset)
|
87
|
+
result[column.name] = column.value(asset, self)
|
123
88
|
end
|
124
89
|
result
|
125
90
|
end
|
@@ -144,15 +109,20 @@ module Datagrid
|
|
144
109
|
result = super
|
145
110
|
if self.order
|
146
111
|
column = column_by_name(self.order)
|
147
|
-
raise Datagrid::OrderUnsupported, "Can not sort #{self.inspect} by #{name.inspect}" unless column
|
148
112
|
result = result.order(self.descending ? column.desc_order : column.order)
|
149
113
|
end
|
150
114
|
result
|
151
115
|
end
|
152
116
|
|
153
117
|
def to_csv(options = {})
|
154
|
-
|
155
|
-
|
118
|
+
klass = if RUBY_VERSION >= "1.9"
|
119
|
+
require 'csv'
|
120
|
+
CSV
|
121
|
+
else
|
122
|
+
require "fastercsv"
|
123
|
+
FasterCSV
|
124
|
+
end
|
125
|
+
klass.generate(
|
156
126
|
{:headers => self.header, :write_headers => true}.merge(options)
|
157
127
|
) do |csv|
|
158
128
|
self.rows.each do |row|
|
@@ -166,9 +136,7 @@ module Datagrid
|
|
166
136
|
end
|
167
137
|
|
168
138
|
def column_by_name(name)
|
169
|
-
self.
|
170
|
-
col.name.to_sym == name.to_sym
|
171
|
-
end
|
139
|
+
self.class.column_by_name(name)
|
172
140
|
end
|
173
141
|
|
174
142
|
end # InstanceMethods
|
@@ -10,15 +10,17 @@ class Datagrid::Columns::Column
|
|
10
10
|
self.block = block
|
11
11
|
end
|
12
12
|
|
13
|
-
def value(
|
14
|
-
value_for(
|
13
|
+
def value(model, report)
|
14
|
+
value_for(model, report)
|
15
15
|
end
|
16
16
|
|
17
|
-
def value_for(
|
17
|
+
def value_for(model, report)
|
18
18
|
if self.block.arity == 1
|
19
|
-
self.block.call(
|
19
|
+
self.block.call(model)
|
20
|
+
elsif self.block.arity == 2
|
21
|
+
self.block.call(model, report)
|
20
22
|
else
|
21
|
-
|
23
|
+
model.instance_eval(&self.block)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -32,7 +34,7 @@ class Datagrid::Columns::Column
|
|
32
34
|
|
33
35
|
def header
|
34
36
|
self.options[:header] ||
|
35
|
-
I18n.translate(self.name, :scope => "reports.#{self.grid}.columns", :default => self.name.to_s.humanize )
|
37
|
+
I18n.translate(self.name, :scope => "reports.#{self.grid.param_name}.columns", :default => self.name.to_s.humanize )
|
36
38
|
end
|
37
39
|
|
38
40
|
def order
|
data/lib/datagrid/filters.rb
CHANGED
@@ -10,10 +10,11 @@ module Datagrid
|
|
10
10
|
require "datagrid/filters/filter_eval"
|
11
11
|
require "datagrid/filters/integer_filter"
|
12
12
|
require "datagrid/filters/composite_filters"
|
13
|
+
require "datagrid/filters/string_filter"
|
13
14
|
|
14
15
|
FILTER_TYPES = {
|
15
16
|
:date => Filters::DateFilter,
|
16
|
-
:string => Filters::
|
17
|
+
:string => Filters::StringFilter,
|
17
18
|
:default => Filters::DefaultFilter,
|
18
19
|
:eboolean => Filters::BooleanEnumFilter ,
|
19
20
|
:boolean => Filters::BooleanFilter ,
|
@@ -45,62 +46,9 @@ module Datagrid
|
|
45
46
|
end
|
46
47
|
|
47
48
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
# Example:
|
52
|
-
#
|
53
|
-
# class UserGrid
|
54
|
-
# include Datagrid
|
55
|
-
#
|
56
|
-
# scope do
|
57
|
-
# User.order("users.created_at desc")
|
58
|
-
# end
|
59
|
-
#
|
60
|
-
# filter(:name)
|
61
|
-
# filter(:posts_count, :integer) do |value|
|
62
|
-
# self.where(["posts_count >= ?", value])
|
63
|
-
# end
|
64
|
-
#
|
65
|
-
# end
|
66
|
-
#
|
67
|
-
# Each filter becomes grid attribute.
|
68
|
-
# In order to create grid that display all users with name 'John' that have more than zero posts:
|
69
|
-
#
|
70
|
-
# grid = UserGrid.new(:posts_count => 1, :name => "John")
|
71
|
-
# grid.assets # SELECT * FROM users WHERE users.posts_count > 1 AND name = 'John'
|
72
|
-
#
|
73
|
-
# Important! Take care about non-breaking the filter chain and force objects loading in filter.
|
74
|
-
# The filter block should always return a <tt>ActiveRecord::Scope</tt> rather than <tt>Array</tt>
|
75
|
-
#
|
76
|
-
# = Default filter block
|
77
|
-
#
|
78
|
-
# If no block given filter is generated automatically as simple select by filter name from scope.
|
79
|
-
#
|
80
|
-
# = Filter types
|
81
|
-
#
|
82
|
-
# Filter does types conversion automatically.
|
83
|
-
# The following filter types are supported:
|
84
|
-
#
|
85
|
-
# * <tt>:default</tt> (default) - leave value as is
|
86
|
-
# * <tt>:date</tt> - converts value to date using date parser
|
87
|
-
# * <tt>:enum</tt> - designed to be collection select. Additional options for easy form generation:
|
88
|
-
# * <tt>:select</tt> (required) - collection of values to match against.
|
89
|
-
# * <tt>:boolean</tt> - converts value to true or false depending on whether it looks truly or not
|
90
|
-
# * <tt>:integer</tt> - converts given value to integer.
|
91
|
-
# * <tt>:eboolean</tt> - subtype of enum filter that provides select of "Yes", "No" and "Any". Could be useful.
|
92
|
-
#
|
93
|
-
# = Default filter options
|
94
|
-
#
|
95
|
-
# Options that could be passed to any filter type:
|
96
|
-
#
|
97
|
-
# * <tt>:header</tt> - human readable name of the filter. Default: generated from the filter name.
|
98
|
-
# * <tt>:default</tt> - default value of the filter. Default: nil.
|
99
|
-
# * <tt>:multiple</tt> - if true multiple values can be assigned to this filter. Default: false.
|
100
|
-
# * <tt>:allow_nil</tt> - determines if filter should be called if filter value is nil. Default: false.
|
101
|
-
# * <tt>:allow_blank</tt> - determines if filter should be called if filter value is #blank?. Default: false.
|
102
|
-
#
|
103
|
-
def filter(attribute, type = :string, options = {}, &block)
|
49
|
+
def filter(attribute, *args, &block)
|
50
|
+
options = args.extract_options!
|
51
|
+
type = args.shift || :default
|
104
52
|
|
105
53
|
klass = type.is_a?(Class) ? type : FILTER_TYPES[type]
|
106
54
|
raise ConfigurationError, "filter class #{type.inspect} not found" unless klass
|
@@ -119,12 +67,8 @@ module Datagrid
|
|
119
67
|
protected
|
120
68
|
def default_filter(attribute)
|
121
69
|
check_scope_defined!("Scope should be defined before filters")
|
122
|
-
|
123
|
-
|
124
|
-
self.scoped(:conditions => {attribute => value})
|
125
|
-
end
|
126
|
-
else
|
127
|
-
raise ConfigurationError, "Not able to generate default filter. No column '#{attribute}' in #{self.scope.table_name}."
|
70
|
+
lambda do |value|
|
71
|
+
self.scoped(:conditions => {attribute => value})
|
128
72
|
end
|
129
73
|
end
|
130
74
|
|
@@ -22,6 +22,9 @@ class Datagrid::Filters::BaseFilter
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def format_values(value)
|
25
|
+
if !self.multiple && value.is_a?(Array)
|
26
|
+
raise Datagrid::ArgumentError, "#{grid.class}.#{name} filter can not accept Array argument. Use :multiple option."
|
27
|
+
end
|
25
28
|
values = Array(value)
|
26
29
|
values.map! do |value|
|
27
30
|
self.format(value)
|
@@ -31,7 +34,7 @@ class Datagrid::Filters::BaseFilter
|
|
31
34
|
|
32
35
|
def header
|
33
36
|
options[:header] ||
|
34
|
-
I18n.translate(self.name, :scope => "datagrid.#{grid.
|
37
|
+
I18n.translate(self.name, :scope => "datagrid.#{grid.param_name}.filters", :default => self.name.to_s.humanize)
|
35
38
|
end
|
36
39
|
|
37
40
|
def default
|
@@ -5,7 +5,6 @@ class Datagrid::Filters::BooleanEnumFilter < Datagrid::Filters::EnumFilter
|
|
5
5
|
VALUES = {YES => true, NO => false}
|
6
6
|
|
7
7
|
def initialize(report, attribute, options = {}, &block)
|
8
|
-
options[:allow_blank] = true unless options.has_key?(:allow_blank)
|
9
8
|
options[:select] = VALUES.keys
|
10
9
|
super(report, attribute, options, &block)
|
11
10
|
end
|
@@ -36,11 +36,22 @@ module Datagrid
|
|
36
36
|
|
37
37
|
def datagrid_enum_filter(attribute_or_filter, options = {})
|
38
38
|
filter = get_filter(attribute_or_filter)
|
39
|
-
|
39
|
+
if !options.has_key?(:multiple) && filter.multiple
|
40
|
+
options[:multiple] = true
|
41
|
+
end
|
42
|
+
select filter.name, filter.select || [], {:include_blank => filter.include_blank}, options
|
40
43
|
end
|
41
44
|
|
42
45
|
def datagrid_integer_filter(attribute_or_filter, options = {})
|
43
|
-
|
46
|
+
filter = get_filter(attribute_or_filter)
|
47
|
+
if filter.multiple && self.object[filter.name].blank?
|
48
|
+
options[:value] = ""
|
49
|
+
end
|
50
|
+
text_field filter.name, options
|
51
|
+
end
|
52
|
+
|
53
|
+
def datagrid_string_filter(attribute_or_filter, options = {})
|
54
|
+
datagrid_default_filter(attribute_or_filter, options)
|
44
55
|
end
|
45
56
|
|
46
57
|
def get_attribute(attribute_or_filter)
|
data/lib/datagrid/helper.rb
CHANGED
@@ -3,8 +3,8 @@ require "action_view"
|
|
3
3
|
module Datagrid
|
4
4
|
module Helper
|
5
5
|
|
6
|
-
def datagrid_format_value(column, asset)
|
7
|
-
value = column.value(asset)
|
6
|
+
def datagrid_format_value(report, column, asset)
|
7
|
+
value = column.value(asset, report)
|
8
8
|
if column.options[:url]
|
9
9
|
link_to(value, column.options[:url].call(asset))
|
10
10
|
else
|
@@ -24,11 +24,10 @@ module Datagrid
|
|
24
24
|
assets = report.assets
|
25
25
|
paginate = options[:paginate]
|
26
26
|
assets = assets.paginate(paginate) if paginate
|
27
|
-
content = content_tag(:tr, datagrid_header(report, options)) + datagrid_rows(report
|
27
|
+
content = content_tag(:tr, datagrid_header(report, options)) + datagrid_rows(report, assets, options)
|
28
28
|
content_tag(:table, content, html)
|
29
29
|
end
|
30
30
|
|
31
|
-
protected
|
32
31
|
|
33
32
|
def datagrid_header(grid, options = {})
|
34
33
|
header = empty_string
|
@@ -43,12 +42,13 @@ module Datagrid
|
|
43
42
|
header
|
44
43
|
end
|
45
44
|
|
46
|
-
def datagrid_rows(
|
45
|
+
def datagrid_rows(report, assets, options)
|
46
|
+
columns = report.columns
|
47
47
|
result = assets.map do |asset|
|
48
48
|
content = columns.map do |column|
|
49
|
-
content_tag(:td, datagrid_format_value(column, asset))
|
49
|
+
content_tag(:td, datagrid_format_value(report, column, asset))
|
50
50
|
end.join(empty_string)
|
51
|
-
content_tag(:tr, _safe(content), :class => cycle(
|
51
|
+
content_tag(:tr, _safe(content), :class => options[:cycle] && cycle(*options[:cycle]))
|
52
52
|
end.join(empty_string)
|
53
53
|
_safe(result)
|
54
54
|
end
|
@@ -27,4 +27,39 @@ describe Datagrid::Columns do
|
|
27
27
|
it "should support csv export" do
|
28
28
|
subject.to_csv.should == "Group,Name\nPop,Star\n"
|
29
29
|
end
|
30
|
+
|
31
|
+
it "should support columns with model and report arguments" do
|
32
|
+
report = test_report(:category => "foo") do
|
33
|
+
scope {Entry.order(:category)}
|
34
|
+
filter(:category) do |value|
|
35
|
+
where("category LIKE '%#{value}%'")
|
36
|
+
end
|
37
|
+
|
38
|
+
column(:exact_category) do |entry, report|
|
39
|
+
entry.category == report.category
|
40
|
+
end
|
41
|
+
end
|
42
|
+
Entry.create!(:category => "foo")
|
43
|
+
Entry.create!(:category => "foobar")
|
44
|
+
report.rows.first.first.should be_true
|
45
|
+
report.rows.last.first.should be_false
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "should raise error if ordered by not existing column" do
|
50
|
+
lambda {
|
51
|
+
test_report(:order => :hello)
|
52
|
+
}.should raise_error(Datagrid::OrderUnsupported)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should raise error if ordered by column without order" do
|
56
|
+
lambda {
|
57
|
+
test_report(:order => :category) do
|
58
|
+
filter(:category, :default, :order => false) do |value|
|
59
|
+
self
|
60
|
+
end
|
61
|
+
end
|
62
|
+
}.should raise_error(Datagrid::OrderUnsupported)
|
63
|
+
end
|
64
|
+
|
30
65
|
end
|
@@ -8,5 +8,28 @@ describe Datagrid::Filters do
|
|
8
8
|
filter(:created_at, :date, :default => proc { Date.today } )
|
9
9
|
end.created_at.should == Date.today
|
10
10
|
end
|
11
|
+
|
12
|
+
it "should not support array argument for not multiple filter" do
|
13
|
+
report = test_report do
|
14
|
+
scope {Entry}
|
15
|
+
filter(:group_id, :integer)
|
16
|
+
end
|
17
|
+
lambda {
|
18
|
+
report.group_id = [1,2]
|
19
|
+
}.should raise_error(Datagrid::ArgumentError)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
it "should initialize report Scope table not exists" do
|
24
|
+
class ModelWithoutTable < ActiveRecord::Base; end
|
25
|
+
class TheReport
|
26
|
+
include Datagrid
|
27
|
+
|
28
|
+
scope {ModelWithoutTable}
|
29
|
+
|
30
|
+
filter(:name)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
11
34
|
|
12
35
|
end
|
@@ -36,7 +36,7 @@ describe Datagrid::FormBuilder do
|
|
36
36
|
context "with enum filter type" do
|
37
37
|
let(:_filter) { :category }
|
38
38
|
it { should equal_to_dom(
|
39
|
-
'<select class="category enum_filter" id="report_category" name="report[category]
|
39
|
+
'<select class="category enum_filter" id="report_category" name="report[category]"><option value=""></option>
|
40
40
|
<option value="first">first</option>
|
41
41
|
<option value="second">second</option></select>'
|
42
42
|
)}
|
@@ -45,7 +45,7 @@ describe Datagrid::FormBuilder do
|
|
45
45
|
grid.category = "first"
|
46
46
|
end
|
47
47
|
it { should equal_to_dom(
|
48
|
-
'<select class="category enum_filter" id="report_category" name="report[category]
|
48
|
+
'<select class="category enum_filter" id="report_category" name="report[category]"><option value=""></option>
|
49
49
|
<option value="first" selected="true">first</option>
|
50
50
|
<option value="second">second</option></select>'
|
51
51
|
)}
|
@@ -55,11 +55,39 @@ describe Datagrid::FormBuilder do
|
|
55
55
|
context "with eboolean filter type" do
|
56
56
|
let(:_filter) { :disabled }
|
57
57
|
it { should equal_to_dom(
|
58
|
-
'<select class="disabled boolean_enum_filter" id="report_disabled" name="report[disabled]
|
59
|
-
<option value="
|
60
|
-
<option value="
|
58
|
+
'<select class="disabled boolean_enum_filter" id="report_disabled" name="report[disabled]"><option value=""></option>
|
59
|
+
<option value="YES">YES</option>
|
60
|
+
<option value="NO">NO</option></select>'
|
61
61
|
)}
|
62
62
|
end
|
63
|
+
context "with string filter" do
|
64
|
+
let(:grid) do
|
65
|
+
test_report do
|
66
|
+
scope {Entry}
|
67
|
+
filter(:name, :string)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
let(:_filter) { :name }
|
72
|
+
|
73
|
+
it {should equal_to_dom('<input class="name string_filter" id="report_name" name="report[name]" size="30" type="text">')}
|
74
|
+
end
|
75
|
+
|
76
|
+
context "with non multiple filter" do
|
77
|
+
let(:grid) do
|
78
|
+
test_report do
|
79
|
+
scope {Entry}
|
80
|
+
filter(
|
81
|
+
:name, :enum,
|
82
|
+
:include_blank => false,
|
83
|
+
:multiple => false,
|
84
|
+
:select => []
|
85
|
+
)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
let(:_filter) { :name }
|
89
|
+
it {should equal_to_dom('<select class="name enum_filter" id="report_name" name="report[name]"></select>')}
|
90
|
+
end
|
63
91
|
end
|
64
92
|
|
65
93
|
describe ".datagrid_label" do
|
@@ -69,6 +97,9 @@ describe Datagrid::FormBuilder do
|
|
69
97
|
)
|
70
98
|
end
|
71
99
|
end
|
100
|
+
|
101
|
+
|
102
|
+
|
72
103
|
end
|
73
104
|
|
74
105
|
|
@@ -34,12 +34,21 @@ describe Datagrid::Helper do
|
|
34
34
|
</th>
|
35
35
|
</tr>
|
36
36
|
|
37
|
-
<tr
|
37
|
+
<tr>
|
38
38
|
<td>Pop</td>
|
39
39
|
<td>Star</td>
|
40
40
|
</tr>
|
41
41
|
</table>')
|
42
42
|
end
|
43
|
+
|
44
|
+
it "should support cycle option" do
|
45
|
+
subject.datagrid_rows(grid, [entry], :cycle => ["odd", "even"]).should equal_to_dom(
|
46
|
+
'<tr class="odd">
|
47
|
+
<td>Pop</td>
|
48
|
+
<td>Star</td>
|
49
|
+
</tr>'
|
50
|
+
)
|
51
|
+
end
|
43
52
|
end
|
44
53
|
|
45
54
|
|
data/spec/datagrid_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -10,11 +10,14 @@ end
|
|
10
10
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
11
11
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
12
12
|
|
13
|
-
require 'rspec'
|
14
13
|
require "active_record"
|
15
14
|
require "will_paginate"
|
16
15
|
require 'datagrid'
|
17
|
-
|
16
|
+
begin
|
17
|
+
#require 'ruby-debug'
|
18
|
+
rescue
|
19
|
+
end
|
20
|
+
require 'rspec'
|
18
21
|
|
19
22
|
|
20
23
|
RSpec.configure do |config|
|
data/spec/support/schema.rb
CHANGED
@@ -17,8 +17,8 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
17
17
|
t.integer :group_id
|
18
18
|
t.string :name
|
19
19
|
t.string :category
|
20
|
-
t.boolean :disabled, :null => false, :default =>
|
21
|
-
t.boolean :confirmed, :null => false, :default =>
|
20
|
+
t.boolean :disabled, :null => false, :default => false
|
21
|
+
t.boolean :confirmed, :null => false, :default => false
|
22
22
|
t.timestamps
|
23
23
|
end
|
24
24
|
|
@@ -1,12 +1,14 @@
|
|
1
1
|
|
2
2
|
|
3
|
-
def test_report(&block)
|
3
|
+
def test_report(attributes = {}, &block)
|
4
4
|
klass = Class.new
|
5
5
|
klass.class_eval do
|
6
6
|
include Datagrid
|
7
7
|
end
|
8
|
-
|
9
|
-
|
8
|
+
if block
|
9
|
+
klass.class_eval(&block)
|
10
|
+
end
|
11
|
+
klass.new(attributes)
|
10
12
|
end
|
11
13
|
|
12
14
|
class SimpleReport
|
metadata
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datagrid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 2
|
9
|
-
- 0
|
10
|
-
version: 0.2.0
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.0
|
11
6
|
platform: ruby
|
12
7
|
authors:
|
13
8
|
- Bogdan Gusiev
|
@@ -15,187 +10,141 @@ autorequire:
|
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
12
|
|
18
|
-
date: 2011-
|
13
|
+
date: 2011-07-01 00:00:00 +03:00
|
19
14
|
default_executable:
|
20
15
|
dependencies:
|
21
16
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
17
|
+
name: rails
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
19
|
none: false
|
24
20
|
requirements:
|
25
21
|
- - ">="
|
26
22
|
- !ruby/object:Gem::Version
|
27
|
-
hash: 3
|
28
|
-
segments:
|
29
|
-
- 0
|
30
23
|
version: "0"
|
31
|
-
requirement: *id001
|
32
24
|
type: :runtime
|
33
|
-
name: rails
|
34
25
|
prerelease: false
|
26
|
+
version_requirements: *id001
|
35
27
|
- !ruby/object:Gem::Dependency
|
36
|
-
|
28
|
+
name: rake
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
30
|
none: false
|
38
31
|
requirements:
|
39
32
|
- - "="
|
40
33
|
- !ruby/object:Gem::Version
|
41
|
-
hash: 49
|
42
|
-
segments:
|
43
|
-
- 0
|
44
|
-
- 8
|
45
|
-
- 7
|
46
34
|
version: 0.8.7
|
47
|
-
requirement: *id002
|
48
35
|
type: :development
|
49
|
-
name: rake
|
50
36
|
prerelease: false
|
37
|
+
version_requirements: *id002
|
51
38
|
- !ruby/object:Gem::Dependency
|
52
|
-
|
39
|
+
name: mocha
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
41
|
none: false
|
54
42
|
requirements:
|
55
43
|
- - ">="
|
56
44
|
- !ruby/object:Gem::Version
|
57
|
-
hash: 3
|
58
|
-
segments:
|
59
|
-
- 0
|
60
45
|
version: "0"
|
61
|
-
requirement: *id003
|
62
46
|
type: :development
|
63
|
-
name: mocha
|
64
47
|
prerelease: false
|
48
|
+
version_requirements: *id003
|
65
49
|
- !ruby/object:Gem::Dependency
|
66
|
-
|
50
|
+
name: rspec
|
51
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
52
|
none: false
|
68
53
|
requirements:
|
69
54
|
- - "="
|
70
55
|
- !ruby/object:Gem::Version
|
71
|
-
hash: 23
|
72
|
-
segments:
|
73
|
-
- 2
|
74
|
-
- 6
|
75
|
-
- 0
|
76
56
|
version: 2.6.0
|
77
|
-
requirement: *id004
|
78
57
|
type: :development
|
79
|
-
name: rspec
|
80
58
|
prerelease: false
|
59
|
+
version_requirements: *id004
|
81
60
|
- !ruby/object:Gem::Dependency
|
82
|
-
|
61
|
+
name: bundler
|
62
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
83
63
|
none: false
|
84
64
|
requirements:
|
85
65
|
- - ~>
|
86
66
|
- !ruby/object:Gem::Version
|
87
|
-
hash: 23
|
88
|
-
segments:
|
89
|
-
- 1
|
90
|
-
- 0
|
91
|
-
- 0
|
92
67
|
version: 1.0.0
|
93
|
-
requirement: *id005
|
94
68
|
type: :development
|
95
|
-
name: bundler
|
96
69
|
prerelease: false
|
70
|
+
version_requirements: *id005
|
97
71
|
- !ruby/object:Gem::Dependency
|
98
|
-
|
72
|
+
name: jeweler
|
73
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
99
74
|
none: false
|
100
75
|
requirements:
|
101
76
|
- - ~>
|
102
77
|
- !ruby/object:Gem::Version
|
103
|
-
hash: 15
|
104
|
-
segments:
|
105
|
-
- 1
|
106
|
-
- 6
|
107
|
-
- 0
|
108
78
|
version: 1.6.0
|
109
|
-
requirement: *id006
|
110
79
|
type: :development
|
111
|
-
name: jeweler
|
112
80
|
prerelease: false
|
81
|
+
version_requirements: *id006
|
113
82
|
- !ruby/object:Gem::Dependency
|
114
|
-
|
83
|
+
name: rcov
|
84
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
115
85
|
none: false
|
116
86
|
requirements:
|
117
87
|
- - ">="
|
118
88
|
- !ruby/object:Gem::Version
|
119
|
-
hash: 3
|
120
|
-
segments:
|
121
|
-
- 0
|
122
89
|
version: "0"
|
123
|
-
requirement: *id007
|
124
90
|
type: :development
|
125
|
-
name: rcov
|
126
91
|
prerelease: false
|
92
|
+
version_requirements: *id007
|
127
93
|
- !ruby/object:Gem::Dependency
|
128
|
-
|
94
|
+
name: ruby-debug
|
95
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
129
96
|
none: false
|
130
97
|
requirements:
|
131
98
|
- - ">="
|
132
99
|
- !ruby/object:Gem::Version
|
133
|
-
hash: 3
|
134
|
-
segments:
|
135
|
-
- 0
|
136
100
|
version: "0"
|
137
|
-
requirement: *id008
|
138
101
|
type: :development
|
139
|
-
name: ruby-debug
|
140
102
|
prerelease: false
|
103
|
+
version_requirements: *id008
|
141
104
|
- !ruby/object:Gem::Dependency
|
142
|
-
|
105
|
+
name: sqlite3-ruby
|
106
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
143
107
|
none: false
|
144
108
|
requirements:
|
145
109
|
- - ">="
|
146
110
|
- !ruby/object:Gem::Version
|
147
|
-
hash: 3
|
148
|
-
segments:
|
149
|
-
- 0
|
150
111
|
version: "0"
|
151
|
-
requirement: *id009
|
152
112
|
type: :development
|
153
|
-
name: sqlite3-ruby
|
154
113
|
prerelease: false
|
114
|
+
version_requirements: *id009
|
155
115
|
- !ruby/object:Gem::Dependency
|
156
|
-
|
116
|
+
name: fastercsv
|
117
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
157
118
|
none: false
|
158
119
|
requirements:
|
159
120
|
- - ">="
|
160
121
|
- !ruby/object:Gem::Version
|
161
|
-
hash: 3
|
162
|
-
segments:
|
163
|
-
- 0
|
164
122
|
version: "0"
|
165
|
-
requirement: *id010
|
166
123
|
type: :development
|
167
|
-
name: fastercsv
|
168
124
|
prerelease: false
|
125
|
+
version_requirements: *id010
|
169
126
|
- !ruby/object:Gem::Dependency
|
170
|
-
|
127
|
+
name: nokogiri
|
128
|
+
requirement: &id011 !ruby/object:Gem::Requirement
|
171
129
|
none: false
|
172
130
|
requirements:
|
173
131
|
- - ">="
|
174
132
|
- !ruby/object:Gem::Version
|
175
|
-
hash: 3
|
176
|
-
segments:
|
177
|
-
- 0
|
178
133
|
version: "0"
|
179
|
-
requirement: *id011
|
180
134
|
type: :development
|
181
|
-
name: nokogiri
|
182
135
|
prerelease: false
|
136
|
+
version_requirements: *id011
|
183
137
|
- !ruby/object:Gem::Dependency
|
184
|
-
|
138
|
+
name: will_paginate
|
139
|
+
requirement: &id012 !ruby/object:Gem::Requirement
|
185
140
|
none: false
|
186
141
|
requirements:
|
187
142
|
- - "="
|
188
143
|
- !ruby/object:Gem::Version
|
189
|
-
hash: 29
|
190
|
-
segments:
|
191
|
-
- 2
|
192
|
-
- 3
|
193
|
-
- 15
|
194
144
|
version: 2.3.15
|
195
|
-
requirement: *id012
|
196
145
|
type: :development
|
197
|
-
name: will_paginate
|
198
146
|
prerelease: false
|
147
|
+
version_requirements: *id012
|
199
148
|
description: This allows you to easily build datagrid aka data tables with sortable columns and filters
|
200
149
|
email: agresso@gmail.com
|
201
150
|
executables: []
|
@@ -228,6 +177,7 @@ files:
|
|
228
177
|
- lib/datagrid/filters/enum_filter.rb
|
229
178
|
- lib/datagrid/filters/filter_eval.rb
|
230
179
|
- lib/datagrid/filters/integer_filter.rb
|
180
|
+
- lib/datagrid/filters/string_filter.rb
|
231
181
|
- lib/datagrid/form_builder.rb
|
232
182
|
- lib/datagrid/helper.rb
|
233
183
|
- lib/datagrid/rspec.rb
|
@@ -255,7 +205,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
205
|
requirements:
|
256
206
|
- - ">="
|
257
207
|
- !ruby/object:Gem::Version
|
258
|
-
hash:
|
208
|
+
hash: -315143401371934304
|
259
209
|
segments:
|
260
210
|
- 0
|
261
211
|
version: "0"
|
@@ -264,14 +214,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
264
214
|
requirements:
|
265
215
|
- - ">="
|
266
216
|
- !ruby/object:Gem::Version
|
267
|
-
hash: 3
|
268
|
-
segments:
|
269
|
-
- 0
|
270
217
|
version: "0"
|
271
218
|
requirements: []
|
272
219
|
|
273
220
|
rubyforge_project:
|
274
|
-
rubygems_version: 1.
|
221
|
+
rubygems_version: 1.6.2
|
275
222
|
signing_key:
|
276
223
|
specification_version: 3
|
277
224
|
summary: Ruby gem to create datagrids
|