datagrid 0.2.0 → 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/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
|