datagrid 0.9.0 → 0.9.2
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/Readme.markdown +4 -3
- data/VERSION +1 -1
- data/app/views/datagrid/_head.html.erb +1 -1
- data/app/views/datagrid/_row.html.erb +1 -1
- data/datagrid.gemspec +2 -2
- data/lib/datagrid/column_names_attribute.rb +2 -1
- data/lib/datagrid/columns.rb +100 -7
- data/lib/datagrid/columns/column.rb +76 -26
- data/lib/datagrid/core.rb +16 -6
- data/lib/datagrid/filters.rb +26 -2
- data/lib/datagrid/filters/base_filter.rb +4 -4
- data/lib/datagrid/filters/date_filter.rb +1 -1
- data/lib/datagrid/filters/enum_filter.rb +6 -4
- data/lib/datagrid/form_builder.rb +3 -3
- data/lib/datagrid/helper.rb +2 -4
- data/lib/datagrid/renderer.rb +7 -24
- data/lib/datagrid/utils.rb +13 -0
- data/spec/datagrid/columns_spec.rb +45 -6
- data/spec/datagrid/core_spec.rb +32 -8
- data/spec/datagrid/filters/enum_filter_spec.rb +13 -0
- data/spec/datagrid/filters_spec.rb +24 -1
- data/spec/datagrid/form_builder_spec.rb +39 -8
- data/spec/datagrid/helper_spec.rb +30 -1
- data/spec/support/simple_report.rb +16 -9
- metadata +3 -3
data/Readme.markdown
CHANGED
@@ -13,6 +13,7 @@ Ruby library that helps you to build and represent table-like data with:
|
|
13
13
|
* ActiveRecord
|
14
14
|
* Mongoid
|
15
15
|
* MongoMapper
|
16
|
+
* Array (slow but possible)
|
16
17
|
|
17
18
|
[Create an issue](https://github.com/bogdan/datagrid/issues/new) if you want more.
|
18
19
|
|
@@ -40,8 +41,8 @@ class SimpleReport
|
|
40
41
|
filter(:disabled, :eboolean)
|
41
42
|
filter(:confirmed, :boolean)
|
42
43
|
filter(:group_id, :integer, :multiple => true)
|
43
|
-
filter(:logins_count, :integer, :range => true)
|
44
|
-
filter(:group_name, :string, :header => "Group") do |value|
|
44
|
+
filter(:logins_count, :integer, :range => true, :before => :group_id)
|
45
|
+
filter(:group_name, :string, :header => "Group", :after => :category_id) do |value|
|
45
46
|
self.joins(:group).where(:groups => {:name => value})
|
46
47
|
end
|
47
48
|
|
@@ -129,7 +130,7 @@ Datagrid supports different type of filters including:
|
|
129
130
|
Each column is represented by name and code block to calculate the value.
|
130
131
|
|
131
132
|
``` ruby
|
132
|
-
column(:activated, :header => "Active", :order => "activated") do
|
133
|
+
column(:activated, :header => "Active", :order => "activated", :after => :name) do
|
133
134
|
self.activated?
|
134
135
|
end
|
135
136
|
```
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.2
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<tr>
|
2
|
-
<% grid.
|
2
|
+
<% grid.html_columns(*options[:columns]).each do |column| %>
|
3
3
|
<th class="<%= datagrid_column_classes(grid, column) %>">
|
4
4
|
<%= column.header %>
|
5
5
|
<%= datagrid_order_for(grid, column) if column.order && options[:order]%>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
<tr class="<%= options[:cycle] && cycle(*options[:cycle]) %>">
|
2
|
-
<% grid.
|
2
|
+
<% grid.html_columns(*options[:columns]).each do |column| %>
|
3
3
|
<td class="<%= datagrid_column_classes(grid, column) %>"><%= datagrid_format_value(grid, column, asset) %></td>
|
4
4
|
<% end %>
|
5
5
|
</tr>
|
data/datagrid.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "datagrid"
|
8
|
-
s.version = "0.9.
|
8
|
+
s.version = "0.9.2"
|
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 = "2013-
|
12
|
+
s.date = "2013-08-23"
|
13
13
|
s.description = "This allows you to easily build datagrid aka data tables with sortable columns and filters"
|
14
14
|
s.email = "agresso@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,6 +17,7 @@ module Datagrid
|
|
17
17
|
end
|
18
18
|
|
19
19
|
module ClassMethods
|
20
|
+
# Adds a filter that acts like a column selection
|
20
21
|
def column_names_filter
|
21
22
|
filter(:column_names, :enum, :select => proc { |grid| grid.class.columns.map {|c| [c.header, c.name] }}, :multiple => true ) do |value|
|
22
23
|
scoped
|
@@ -24,7 +25,7 @@ module Datagrid
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
def columns(*args)
|
28
|
+
def columns(*args) #:nodoc:
|
28
29
|
options = args.extract_options!
|
29
30
|
column_names = selected_column_names(*args)
|
30
31
|
column_names << options
|
data/lib/datagrid/columns.rb
CHANGED
@@ -32,17 +32,36 @@ module Datagrid
|
|
32
32
|
args.compact!
|
33
33
|
args.map!(&:to_sym)
|
34
34
|
columns_array.select do |column|
|
35
|
-
(!options[:data] || column.data?) && (args.empty? || args.include?(column.name))
|
35
|
+
(!options[:data] || column.data?) && (!options[:html] || column.html?)&& (args.empty? || args.include?(column.name))
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
39
|
# Defines new datagrid column
|
40
|
+
#
|
41
|
+
# Arguments:
|
42
|
+
#
|
43
|
+
# * <tt>name</tt> - column name
|
44
|
+
# * <tt>options</tt> - hash of options
|
45
|
+
# * <tt>block</tt> - proc to calculate a column value
|
46
|
+
#
|
47
|
+
# Available options:
|
48
|
+
#
|
49
|
+
# * <tt>:html</tt> - determines if current column should be present in html table and how is it formatted
|
50
|
+
# * <tt>:order</tt> - determines if this column could be sortable and how
|
51
|
+
# * <tt>:order_desc</tt> - determines a descending order for given column (only in case when <tt>:order</tt> can not be easily inverted
|
52
|
+
# * <tt>:url</tt> - a proc with one argument, pass this option to easily convert the value into an URL
|
53
|
+
# * <tt>:before</tt> - determines the position of this column, by adding it before the column passed here
|
54
|
+
# * <tt>:after</tt> - determines the position of this column, by adding it after the column passed here
|
55
|
+
#
|
56
|
+
# See: https://github.com/bogdan/datagrid/wiki/Columns for examples
|
40
57
|
def column(name, options = {}, &block)
|
41
58
|
check_scope_defined!("Scope should be defined before columns")
|
42
59
|
block ||= lambda do |model|
|
43
60
|
model.send(name)
|
44
61
|
end
|
45
|
-
|
62
|
+
position = Datagrid::Utils.extract_position_from_options(columns_array, options)
|
63
|
+
column = Datagrid::Columns::Column.new(self, name, options, &block)
|
64
|
+
columns_array.insert(position, column)
|
46
65
|
end
|
47
66
|
|
48
67
|
# Returns column definition with given name
|
@@ -52,6 +71,30 @@ module Datagrid
|
|
52
71
|
end
|
53
72
|
end
|
54
73
|
|
74
|
+
# Returns an array of all defined column names
|
75
|
+
def column_names
|
76
|
+
columns.map(&:name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def respond_to(&block) #:nodoc:
|
80
|
+
Datagrid::Columns::Column::ResponseFormat.new(&block)
|
81
|
+
end
|
82
|
+
|
83
|
+
def format(value, &block)
|
84
|
+
if block_given?
|
85
|
+
respond_to do |f|
|
86
|
+
f.data { value }
|
87
|
+
f.html do
|
88
|
+
instance_exec(value, &block)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
else
|
92
|
+
# Ruby Object#format exists.
|
93
|
+
# We don't want to change the behaviour and overwrite it.
|
94
|
+
super
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
55
98
|
def inherited(child_class) #:nodoc:
|
56
99
|
super(child_class)
|
57
100
|
child_class.columns_array = self.columns_array.clone
|
@@ -62,14 +105,22 @@ module Datagrid
|
|
62
105
|
module InstanceMethods
|
63
106
|
|
64
107
|
# Returns <tt>Array</tt> of human readable column names. See also "Localization" section
|
108
|
+
#
|
109
|
+
# Arguments:
|
110
|
+
#
|
111
|
+
# * <tt>column_names</tt> - list of column names if you want to limit data only to specified columns
|
65
112
|
def header(*column_names)
|
66
113
|
data_columns(*column_names).map(&:header)
|
67
114
|
end
|
68
115
|
|
69
116
|
# Returns <tt>Array</tt> column values for given asset
|
117
|
+
#
|
118
|
+
# Arguments:
|
119
|
+
#
|
120
|
+
# * <tt>column_names</tt> - list of column names if you want to limit data only to specified columns
|
70
121
|
def row_for(asset, *column_names)
|
71
122
|
data_columns(*column_names).map do |column|
|
72
|
-
column.
|
123
|
+
column.data_value(asset, self)
|
73
124
|
end
|
74
125
|
end
|
75
126
|
|
@@ -77,12 +128,16 @@ module Datagrid
|
|
77
128
|
def hash_for(asset)
|
78
129
|
result = {}
|
79
130
|
self.data_columns.each do |column|
|
80
|
-
result[column.name] = column.
|
131
|
+
result[column.name] = column.data_value(asset, self)
|
81
132
|
end
|
82
133
|
result
|
83
134
|
end
|
84
135
|
|
85
136
|
# Returns Array of Arrays with data for each row in datagrid assets without header.
|
137
|
+
#
|
138
|
+
# Arguments:
|
139
|
+
#
|
140
|
+
# * <tt>column_names</tt> - list of column names if you want to limit data only to specified columns
|
86
141
|
def rows(*column_names)
|
87
142
|
#TODO: find in batches
|
88
143
|
self.assets.map do |asset|
|
@@ -91,12 +146,30 @@ module Datagrid
|
|
91
146
|
end
|
92
147
|
|
93
148
|
# Returns Array of Arrays with data for each row in datagrid assets with header.
|
94
|
-
|
95
|
-
|
149
|
+
#
|
150
|
+
# Arguments:
|
151
|
+
#
|
152
|
+
# * <tt>column_names</tt> - list of column names if you want to limit data only to specified columns
|
153
|
+
def data(*column_names)
|
154
|
+
self.rows(*column_names).unshift(self.header(*column_names))
|
96
155
|
end
|
97
156
|
|
98
157
|
# Return Array of Hashes where keys are column names and values are column values
|
99
158
|
# for each row in datagrid <tt>#assets</tt>
|
159
|
+
#
|
160
|
+
# Example:
|
161
|
+
#
|
162
|
+
# class MyGrid
|
163
|
+
# scope { Model }
|
164
|
+
# column(:id)
|
165
|
+
# column(:name)
|
166
|
+
# end
|
167
|
+
#
|
168
|
+
# Model.create!(:name => "One")
|
169
|
+
# Model.create!(:name => "Two")
|
170
|
+
#
|
171
|
+
# MyGrid.new.data_hash # => [{:name => "One"}, {:name => "Two"}]
|
172
|
+
#
|
100
173
|
def data_hash
|
101
174
|
self.assets.map do |asset|
|
102
175
|
hash_for(asset)
|
@@ -139,12 +212,13 @@ module Datagrid
|
|
139
212
|
#
|
140
213
|
# MyGrid.new.columns # => all defined columns
|
141
214
|
# grid = MyGrid.new(:column_names => [:id, :name])
|
142
|
-
# grid.columns # => id and name
|
215
|
+
# grid.columns # => id and name columns
|
143
216
|
# grid.columns(:id, :category) # => id and category column
|
144
217
|
def columns(*args)
|
145
218
|
self.class.columns(*args)
|
146
219
|
end
|
147
220
|
|
221
|
+
# Returns all columns that can be represented in plain data(non-html) way
|
148
222
|
def data_columns(*names)
|
149
223
|
options = names.extract_options!
|
150
224
|
options[:data] = true
|
@@ -152,9 +226,28 @@ module Datagrid
|
|
152
226
|
self.columns(*names)
|
153
227
|
end
|
154
228
|
|
229
|
+
# Returns all columns that can be represented in HTML table
|
230
|
+
def html_columns(*names)
|
231
|
+
options = names.extract_options!
|
232
|
+
options[:html] = true
|
233
|
+
names << options
|
234
|
+
self.columns(*names)
|
235
|
+
end
|
236
|
+
|
237
|
+
# Finds a column by name
|
155
238
|
def column_by_name(name)
|
156
239
|
self.class.column_by_name(name)
|
157
240
|
end
|
241
|
+
|
242
|
+
|
243
|
+
def format(value, &block)
|
244
|
+
if block_given?
|
245
|
+
self.class.format(value, &block)
|
246
|
+
else
|
247
|
+
super
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
158
251
|
end # InstanceMethods
|
159
252
|
|
160
253
|
end
|
@@ -1,41 +1,52 @@
|
|
1
1
|
class Datagrid::Columns::Column
|
2
2
|
|
3
|
-
|
3
|
+
class ResponseFormat # :nodoc:
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
attr_accessor :data_block, :html_block
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
yield(self)
|
9
|
+
end
|
10
|
+
|
11
|
+
def data(&block)
|
12
|
+
self.data_block = block
|
13
|
+
end
|
14
|
+
|
15
|
+
def html(&block)
|
16
|
+
self.html_block = block
|
17
|
+
end
|
18
|
+
|
19
|
+
def data_value
|
20
|
+
data_block.call
|
21
|
+
end
|
22
|
+
|
23
|
+
def html_value(context)
|
24
|
+
context.instance_eval(&html_block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_accessor :grid_class, :options, :data_block, :name, :html_block
|
29
|
+
|
30
|
+
def initialize(grid_class, name, options = {}, &block)
|
31
|
+
self.grid_class = grid_class
|
7
32
|
self.name = name.to_sym
|
8
33
|
self.options = options
|
9
34
|
if options[:html] == true
|
10
35
|
self.html_block = block
|
11
36
|
else
|
37
|
+
self.data_block = block
|
38
|
+
|
12
39
|
if options[:html].is_a? Proc
|
13
40
|
self.html_block = options[:html]
|
14
41
|
end
|
15
|
-
self.block = block
|
16
|
-
end
|
17
|
-
if format
|
18
|
-
::Datagrid::Utils.warn_once(":format column option is deprecated. Use :url or :html option instead.")
|
19
42
|
end
|
20
43
|
end
|
21
44
|
|
22
|
-
def
|
23
|
-
|
45
|
+
def data_value(model, grid)
|
46
|
+
result = generic_value(model,grid)
|
47
|
+
result.is_a?(ResponseFormat) ? result.data_value : result
|
24
48
|
end
|
25
49
|
|
26
|
-
def value_for(model, grid)
|
27
|
-
if self.block.arity == 1
|
28
|
-
self.block.call(model)
|
29
|
-
elsif self.block.arity == 2
|
30
|
-
self.block.call(model, grid)
|
31
|
-
else
|
32
|
-
model.instance_eval(&self.block)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def format
|
37
|
-
self.options[:format]
|
38
|
-
end
|
39
50
|
|
40
51
|
def label
|
41
52
|
self.options[:label]
|
@@ -43,14 +54,14 @@ class Datagrid::Columns::Column
|
|
43
54
|
|
44
55
|
def header
|
45
56
|
self.options[:header] ||
|
46
|
-
I18n.translate(self.name, :scope => "datagrid.#{self.
|
57
|
+
I18n.translate(self.name, :scope => "datagrid.#{self.grid_class.param_name}.columns", :default => self.name.to_s.humanize )
|
47
58
|
end
|
48
59
|
|
49
60
|
def order
|
50
61
|
if options.has_key?(:order)
|
51
62
|
self.options[:order]
|
52
63
|
else
|
53
|
-
|
64
|
+
grid_class.driver.default_order(grid_class.scope, name)
|
54
65
|
end
|
55
66
|
end
|
56
67
|
|
@@ -60,11 +71,50 @@ class Datagrid::Columns::Column
|
|
60
71
|
end
|
61
72
|
|
62
73
|
def html?
|
63
|
-
|
74
|
+
options[:html] != false
|
64
75
|
end
|
65
76
|
|
66
77
|
def data?
|
67
|
-
self.
|
78
|
+
self.data_block != nil
|
79
|
+
end
|
80
|
+
|
81
|
+
def html_value(context, asset, grid)
|
82
|
+
if html? && html_block
|
83
|
+
value_from_html_block(context, asset, grid)
|
84
|
+
else
|
85
|
+
result = generic_value(asset,grid)
|
86
|
+
result.is_a?(ResponseFormat) ? result.html_value(context) : result
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def value_from_html_block(context, asset, grid)
|
91
|
+
args = []
|
92
|
+
remaining_arity = html_block.arity
|
93
|
+
|
94
|
+
if data?
|
95
|
+
args << data_value(asset,grid)
|
96
|
+
remaining_arity -= 1
|
97
|
+
end
|
98
|
+
|
99
|
+
args << asset if remaining_arity > 0
|
100
|
+
args << grid if remaining_arity > 1
|
101
|
+
|
102
|
+
return context.instance_exec(*args, &html_block)
|
103
|
+
end
|
104
|
+
|
105
|
+
def block
|
106
|
+
Datagrid::Utils.warn_once("Datagrid::Columns::Column#block is deprecated. Use #html_block or #data_block instead")
|
107
|
+
data_block
|
108
|
+
end
|
109
|
+
|
110
|
+
def generic_value(model, grid)
|
111
|
+
if self.data_block.arity == 1
|
112
|
+
self.data_block.call(model)
|
113
|
+
elsif self.data_block.arity == 2
|
114
|
+
self.data_block.call(model, grid)
|
115
|
+
else
|
116
|
+
model.instance_eval(&self.data_block)
|
117
|
+
end
|
68
118
|
end
|
69
119
|
|
70
120
|
end
|
data/lib/datagrid/core.rb
CHANGED
@@ -16,7 +16,7 @@ module Datagrid
|
|
16
16
|
|
17
17
|
module ClassMethods
|
18
18
|
|
19
|
-
def datagrid_attribute(name, &block)
|
19
|
+
def datagrid_attribute(name, &block) #:nodoc:
|
20
20
|
unless datagrid_attributes.include?(name)
|
21
21
|
block ||= lambda do |value|
|
22
22
|
value
|
@@ -32,6 +32,7 @@ module Datagrid
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
# Defines a scope at class level
|
35
36
|
def scope(&block)
|
36
37
|
if block
|
37
38
|
self.scope_value = block
|
@@ -41,7 +42,7 @@ module Datagrid
|
|
41
42
|
end
|
42
43
|
end
|
43
44
|
|
44
|
-
def driver
|
45
|
+
def driver #:nodoc:
|
45
46
|
@driver ||= Drivers::AbstractDriver.guess_driver(scope).new
|
46
47
|
end
|
47
48
|
|
@@ -60,12 +61,16 @@ module Datagrid
|
|
60
61
|
|
61
62
|
module InstanceMethods
|
62
63
|
|
63
|
-
def initialize(attributes = nil)
|
64
|
+
def initialize(attributes = nil, &block)
|
64
65
|
super()
|
65
66
|
|
66
67
|
if attributes
|
67
68
|
self.attributes = attributes
|
68
69
|
end
|
70
|
+
|
71
|
+
if block_given?
|
72
|
+
self.scope_value = block
|
73
|
+
end
|
69
74
|
end
|
70
75
|
|
71
76
|
def attributes
|
@@ -88,11 +93,14 @@ module Datagrid
|
|
88
93
|
driver.to_scope(scope)
|
89
94
|
end
|
90
95
|
|
91
|
-
|
96
|
+
|
97
|
+
def assign_attributes(attributes)
|
92
98
|
attributes.each do |name, value|
|
93
99
|
self[name] = value
|
94
100
|
end
|
101
|
+
self
|
95
102
|
end
|
103
|
+
alias attributes= assign_attributes
|
96
104
|
|
97
105
|
def as_query
|
98
106
|
attributes = self.attributes.clone
|
@@ -111,17 +119,19 @@ module Datagrid
|
|
111
119
|
if block_given?
|
112
120
|
self.scope_value = block
|
113
121
|
self
|
122
|
+
elsif scope_value
|
123
|
+
scope_value.call
|
114
124
|
else
|
115
125
|
check_scope_defined!
|
116
126
|
scope_value.call
|
117
127
|
end
|
118
128
|
end
|
119
129
|
|
120
|
-
def driver
|
130
|
+
def driver #:nodoc:
|
121
131
|
self.class.driver
|
122
132
|
end
|
123
133
|
|
124
|
-
def check_scope_defined!(message = nil)
|
134
|
+
def check_scope_defined!(message = nil) #:nodoc:
|
125
135
|
self.class.send :check_scope_defined!, message
|
126
136
|
end
|
127
137
|
|
data/lib/datagrid/filters.rb
CHANGED
@@ -46,6 +46,25 @@ module Datagrid
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
+
# Defines new datagrid filter
|
50
|
+
#
|
51
|
+
# Arguments:
|
52
|
+
#
|
53
|
+
# * <tt>name</tt> - filter name
|
54
|
+
# * <tt>options</tt> - hash of options
|
55
|
+
# * <tt>block</tt> - proc to apply the filter
|
56
|
+
#
|
57
|
+
# Available options:
|
58
|
+
#
|
59
|
+
# * <tt>:header</tt> - determines the header of the filter
|
60
|
+
# * <tt>:default</tt> - the default filter value
|
61
|
+
# * <tt>:multiple</tt> - determines if more than one option can be selected
|
62
|
+
# * <tt>:allow_nil</tt> - determines if the value can be nil
|
63
|
+
# * <tt>:allow_blank</tt> - determines if the value can be blank
|
64
|
+
# * <tt>:before</tt> - determines the position of this filter, by adding it before the filter passed here (when using datagrid_form_for helper)
|
65
|
+
# * <tt>:after</tt> - determines the position of this filter, by adding it after the filter passed here (when using datagrid_form_for helper)
|
66
|
+
#
|
67
|
+
# See: https://github.com/bogdan/datagrid/wiki/Columns for examples
|
49
68
|
def filter(attribute, *args, &block)
|
50
69
|
options = args.extract_options!
|
51
70
|
type = args.shift || :default
|
@@ -53,9 +72,9 @@ module Datagrid
|
|
53
72
|
klass = type.is_a?(Class) ? type : FILTER_TYPES[type]
|
54
73
|
raise ConfigurationError, "filter class #{type.inspect} not found" unless klass
|
55
74
|
|
56
|
-
|
75
|
+
position = Datagrid::Utils.extract_position_from_options(self.filters, options)
|
57
76
|
filter = klass.new(self, attribute, options, &block)
|
58
|
-
self.filters
|
77
|
+
self.filters.insert(position, filter)
|
59
78
|
|
60
79
|
datagrid_attribute(attribute) do |value|
|
61
80
|
filter.parse_values(value)
|
@@ -97,6 +116,11 @@ module Datagrid
|
|
97
116
|
self[filter.name]
|
98
117
|
end
|
99
118
|
|
119
|
+
# Returns filter object with the given name
|
120
|
+
def filter_by_name(name)
|
121
|
+
self.class.filter_by_name(name)
|
122
|
+
end
|
123
|
+
|
100
124
|
end # InstanceMethods
|
101
125
|
|
102
126
|
end
|
@@ -3,10 +3,10 @@ end
|
|
3
3
|
|
4
4
|
class Datagrid::Filters::BaseFilter
|
5
5
|
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :grid_class, :options, :block, :name
|
7
7
|
|
8
8
|
def initialize(grid_class, name, options = {}, &block)
|
9
|
-
self.
|
9
|
+
self.grid_class = grid_class
|
10
10
|
self.name = name
|
11
11
|
self.options = options
|
12
12
|
self.block = block || default_filter_block
|
@@ -33,7 +33,7 @@ class Datagrid::Filters::BaseFilter
|
|
33
33
|
|
34
34
|
def parse_values(value)
|
35
35
|
if !self.multiple && value.is_a?(Array)
|
36
|
-
raise Datagrid::ArgumentError, "#{
|
36
|
+
raise Datagrid::ArgumentError, "#{grid_class}##{name} filter can not accept Array argument. Use :multiple option."
|
37
37
|
end
|
38
38
|
values = Array.wrap(value)
|
39
39
|
values.map! do |v|
|
@@ -44,7 +44,7 @@ class Datagrid::Filters::BaseFilter
|
|
44
44
|
|
45
45
|
def header
|
46
46
|
options[:header] ||
|
47
|
-
I18n.translate(self.name, :scope => "datagrid.#{
|
47
|
+
I18n.translate(self.name, :scope => "datagrid.#{grid_class.param_name}.filters", :default => self.name.to_s.humanize)
|
48
48
|
end
|
49
49
|
|
50
50
|
def default
|
@@ -11,11 +11,13 @@ class Datagrid::Filters::EnumFilter < Datagrid::Filters::BaseFilter
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def select(object = nil)
|
14
|
-
|
15
|
-
if
|
16
|
-
|
14
|
+
select = self.options[:select]
|
15
|
+
if select.is_a?(Symbol)
|
16
|
+
object.send(select)
|
17
|
+
elsif select.respond_to?(:call)
|
18
|
+
select.arity == 1 ? select.call(object) : select.call
|
17
19
|
else
|
18
|
-
|
20
|
+
select
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
@@ -94,13 +94,13 @@ module Datagrid
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def datagrid_get_attribute(attribute_or_filter)
|
97
|
-
|
97
|
+
Utils.string_like?(attribute_or_filter) ? attribute_or_filter : attribute_or_filter.name
|
98
98
|
end
|
99
99
|
|
100
100
|
def datagrid_get_filter(attribute_or_filter)
|
101
|
-
if
|
101
|
+
if Utils.string_like?(attribute_or_filter)
|
102
102
|
object.class.filter_by_name(attribute_or_filter) ||
|
103
|
-
raise(Error, "filter #{attribute_or_filter} not found")
|
103
|
+
raise(Error, "Datagrid filter #{attribute_or_filter} not found")
|
104
104
|
else
|
105
105
|
attribute_or_filter
|
106
106
|
end
|
data/lib/datagrid/helper.rb
CHANGED
@@ -21,8 +21,6 @@ module Datagrid
|
|
21
21
|
# * <tt>:html</tt> - hash of attributes for <table> tag
|
22
22
|
# * <tt>:order</tt> - If false do not generate ordering controlls.
|
23
23
|
# Default: true.
|
24
|
-
# * <tt>:cycle</tt> - Used as arguments for cycle for each row.
|
25
|
-
# Default: false. Example: <tt>["odd", "even"]</tt>.
|
26
24
|
# * <tt>:columns</tt> - Array of column names to display.
|
27
25
|
# Used in case when same grid class is used in different places
|
28
26
|
# and needs different columns. Default: all defined columns.
|
@@ -57,7 +55,7 @@ module Datagrid
|
|
57
55
|
datagrid_renderer.form_for(grid, options)
|
58
56
|
end
|
59
57
|
|
60
|
-
# Provides access to datagrid
|
58
|
+
# Provides access to datagrid columns data.
|
61
59
|
#
|
62
60
|
# <%= datagrid_row(grid, user) do |row| %>
|
63
61
|
# <tr>
|
@@ -66,7 +64,7 @@ module Datagrid
|
|
66
64
|
# </tr>
|
67
65
|
# <% end %>
|
68
66
|
#
|
69
|
-
# Used in case you want to build
|
67
|
+
# Used in case you want to build html table completelly manually
|
70
68
|
def datagrid_row(grid, asset, &block)
|
71
69
|
HtmlRow.new(self, grid, asset).tap do |row|
|
72
70
|
if block_given?
|
data/lib/datagrid/renderer.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require "action_view"
|
2
2
|
|
3
3
|
module Datagrid
|
4
|
-
class Renderer
|
4
|
+
class Renderer #:nodoc:
|
5
5
|
|
6
6
|
def self.for(template)
|
7
7
|
new(template)
|
@@ -16,33 +16,13 @@ module Datagrid
|
|
16
16
|
column = grid.column_by_name(column)
|
17
17
|
end
|
18
18
|
|
19
|
-
value =
|
20
|
-
args = []
|
21
|
-
remaining_arity = column.html_block.arity
|
22
|
-
|
23
|
-
if column.data?
|
24
|
-
args << column.value(asset,grid)
|
25
|
-
remaining_arity -= 1
|
26
|
-
end
|
27
|
-
|
28
|
-
args << asset if remaining_arity > 0
|
29
|
-
args << grid if remaining_arity > 1
|
30
|
-
|
31
|
-
@template.instance_exec(*args, &column.html_block)
|
32
|
-
else
|
33
|
-
column.value(asset,grid)
|
34
|
-
end
|
19
|
+
value = column.html_value(@template, asset, grid)
|
35
20
|
|
36
21
|
url = column.options[:url] && column.options[:url].call(asset)
|
37
22
|
if url
|
38
23
|
@template.link_to(value, url)
|
39
24
|
else
|
40
|
-
|
41
|
-
when :url
|
42
|
-
@template.link_to(column.label ? asset.send(column.label) : I18n.t("datagrid.table.url_label", :default => "URL"), value)
|
43
|
-
else
|
44
|
-
_safe(value)
|
45
|
-
end
|
25
|
+
_safe(value)
|
46
26
|
end
|
47
27
|
end
|
48
28
|
|
@@ -57,10 +37,13 @@ module Datagrid
|
|
57
37
|
options = args.extract_options!
|
58
38
|
options[:html] ||= {}
|
59
39
|
options[:html][:class] ||= "datagrid #{html_class(grid)}"
|
40
|
+
if options[:cycle]
|
41
|
+
::Datagrid::Utils.warn_once("datagrid_table cycle option is deprecated. Use css to stylee odd/even rows instead.")
|
42
|
+
end
|
60
43
|
assets = args.any? ? args.shift : grid.assets
|
61
44
|
paginate = options[:paginate]
|
62
45
|
if paginate
|
63
|
-
::Datagrid::Utils.warn_once(":paginate option is deprecated.
|
46
|
+
::Datagrid::Utils.warn_once(":paginate option is deprecated. Look to https://github.com/bogdan/datagrid/wiki/Frontend.")
|
64
47
|
assets = assets.paginate(paginate)
|
65
48
|
end
|
66
49
|
|
data/lib/datagrid/utils.rb
CHANGED
@@ -32,7 +32,20 @@ module Datagrid
|
|
32
32
|
options
|
33
33
|
end
|
34
34
|
|
35
|
+
def string_like?(value)
|
36
|
+
value.is_a?(Symbol) || value.is_a?(String)
|
37
|
+
end
|
35
38
|
|
39
|
+
def extract_position_from_options(array, options)
|
40
|
+
position = options.extract!(:before, :after)
|
41
|
+
if position[:before]
|
42
|
+
array.index {|c| c.name.to_sym == position[:before].to_sym }
|
43
|
+
elsif position[:after]
|
44
|
+
array.index {|c| c.name.to_sym == position[:after].to_sym } + 1
|
45
|
+
else
|
46
|
+
-1
|
47
|
+
end
|
48
|
+
end
|
36
49
|
end
|
37
50
|
end
|
38
51
|
end
|
@@ -17,17 +17,40 @@ describe Datagrid::Columns do
|
|
17
17
|
:confirmed => false,
|
18
18
|
:category => "first",
|
19
19
|
:access_level => 'admin',
|
20
|
-
:pet => 'rottweiler'
|
20
|
+
:pet => 'rottweiler',
|
21
|
+
:shipping_date => Date.new(2013, 8, 1)
|
21
22
|
) }
|
23
|
+
let(:date) { Date.new(2013, 8, 1) }
|
22
24
|
|
23
25
|
it "should have data columns without html columns" do
|
24
26
|
subject.data_columns.size.should == subject.columns.size - 1
|
25
27
|
end
|
26
28
|
it "should build rows of data" do
|
27
|
-
subject.rows.should == [["Pop", "Star", "admin", "ROTTWEILER"]]
|
29
|
+
subject.rows.should == [[date, "Pop", "Star", "admin", "ROTTWEILER"]]
|
28
30
|
end
|
29
31
|
it "should generate header" do
|
30
|
-
subject.header.should == ["Group", "Name", "Access level", "Pet"]
|
32
|
+
subject.header.should == ["Shipping date", "Group", "Name", "Access level", "Pet"]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should return html_columns" do
|
36
|
+
report = test_report do
|
37
|
+
scope {Entry}
|
38
|
+
column(:id)
|
39
|
+
column(:name, :html => false)
|
40
|
+
end
|
41
|
+
report.html_columns.map(&:name).should == [:id]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return html_columns when column definition has 2 arguments" do
|
45
|
+
report = test_report(:name => "Hello") do
|
46
|
+
scope {Entry}
|
47
|
+
filter(:name)
|
48
|
+
column(:id)
|
49
|
+
column(:name, :html => false) do |model, grid|
|
50
|
+
"'#{model.name}' filtered by '#{grid.name}'"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
report.row_for(Entry.create!(:name => "Hello World")).should == [8, "'Hello World' filtered by 'Hello'"]
|
31
54
|
end
|
32
55
|
|
33
56
|
it "should generate table data" do
|
@@ -42,12 +65,13 @@ describe Datagrid::Columns do
|
|
42
65
|
:group => "Pop",
|
43
66
|
:name => "Star",
|
44
67
|
:access_level => 'admin',
|
45
|
-
:pet => 'ROTTWEILER'
|
68
|
+
:pet => 'ROTTWEILER',
|
69
|
+
:shipping_date => date
|
46
70
|
}
|
47
71
|
end
|
48
72
|
|
49
73
|
it "should support csv export" do
|
50
|
-
subject.to_csv.should == "Group,Name,Access level,Pet\
|
74
|
+
subject.to_csv.should == "Shipping date,Group,Name,Access level,Pet\n#{date},Pop,Star,admin,ROTTWEILER\n"
|
51
75
|
end
|
52
76
|
|
53
77
|
it "should support csv export of particular columns" do
|
@@ -55,7 +79,7 @@ describe Datagrid::Columns do
|
|
55
79
|
end
|
56
80
|
|
57
81
|
it "should support csv export options" do
|
58
|
-
subject.to_csv(:col_sep => ";").should == "Group;Name;Access level;Pet\
|
82
|
+
subject.to_csv(:col_sep => ";").should == "Shipping date;Group;Name;Access level;Pet\n#{date};Pop;Star;admin;ROTTWEILER\n"
|
59
83
|
end
|
60
84
|
end
|
61
85
|
|
@@ -121,4 +145,19 @@ describe Datagrid::Columns do
|
|
121
145
|
|
122
146
|
end
|
123
147
|
|
148
|
+
|
149
|
+
context "when grid has formatted column" do
|
150
|
+
it "should output correct data" do
|
151
|
+
report = test_report do
|
152
|
+
scope {Entry}
|
153
|
+
column(:name) do |entry|
|
154
|
+
format(entry.name) do |value|
|
155
|
+
"<strong>#{value}</strong"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
Entry.create!(:name => "Hello World")
|
160
|
+
report.rows.should == [["Hello World"]]
|
161
|
+
end
|
162
|
+
end
|
124
163
|
end
|
data/spec/datagrid/core_spec.rb
CHANGED
@@ -1,15 +1,39 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Datagrid::Core do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
4
|
+
|
5
|
+
context 'with 2 persisted entries' do
|
6
|
+
before { 2.times { Entry.create } }
|
7
|
+
|
8
|
+
let(:limit) { Entry.limit(1) }
|
9
|
+
let(:report_class) do
|
10
|
+
test_report_class do
|
11
|
+
scope { Entry }
|
12
|
+
end
|
8
13
|
end
|
9
|
-
|
10
|
-
|
14
|
+
|
15
|
+
describe '#scope' do
|
16
|
+
context 'in the class' do
|
17
|
+
let(:report) { report_class.new }
|
18
|
+
|
19
|
+
it { expect(report.scope).to have(2).item }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'changes scope on the fly' do
|
23
|
+
let(:report) do
|
24
|
+
report_class.new.tap do |r|
|
25
|
+
r.scope { limit }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it { expect(report.scope).to have(1).item }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'changes scope by initializer' do
|
33
|
+
let(:report) { report_class.new { limit } }
|
34
|
+
|
35
|
+
it { expect(report.scope).to have(1).item }
|
36
|
+
end
|
11
37
|
end
|
12
|
-
2.times { Entry.create }
|
13
|
-
report.assets.to_a.size.should == 1
|
14
38
|
end
|
15
39
|
end
|
@@ -33,4 +33,17 @@ describe Datagrid::Filters::EnumFilter do
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
|
37
|
+
it "should support select given as symbol" do
|
38
|
+
report = test_report do
|
39
|
+
scope {Entry}
|
40
|
+
filter(:group_id, :enum, :select => :selectable_group_ids)
|
41
|
+
def selectable_group_ids
|
42
|
+
[1,3,5]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
report.filter_by_name(:group_id).select(report).should == [1,3,5]
|
47
|
+
end
|
48
|
+
|
36
49
|
end
|
@@ -127,6 +127,29 @@ describe Datagrid::Filters do
|
|
127
127
|
end
|
128
128
|
grid.assets.should_not be_empty
|
129
129
|
end
|
130
|
-
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "positioning filter before another" do
|
134
|
+
it "should insert the filter before the specified element" do
|
135
|
+
grid = test_report do
|
136
|
+
scope {Entry}
|
137
|
+
filter(:limit)
|
138
|
+
filter(:name, :before => :limit)
|
139
|
+
end
|
140
|
+
grid.filters.index {|f| f.name == :name}.should == 0
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "positioning filter after another" do
|
145
|
+
it "should insert the filter before the specified element" do
|
146
|
+
grid = test_report do
|
147
|
+
scope {Entry}
|
148
|
+
filter(:limit)
|
149
|
+
filter(:name)
|
150
|
+
filter(:group_id, :after => :limit)
|
151
|
+
end
|
152
|
+
grid.filters.index {|f| f.name == :group_id}.should == 1
|
153
|
+
end
|
131
154
|
end
|
132
155
|
end
|
@@ -163,6 +163,19 @@ describe Datagrid::FormBuilder do
|
|
163
163
|
'<input class="created_at date_filter to" multiple name="report[created_at][]" size="30" type="text" value="2012-01-01"/>'
|
164
164
|
)}
|
165
165
|
end
|
166
|
+
context "with blank range value" do
|
167
|
+
around(:each) do |example|
|
168
|
+
with_date_format do
|
169
|
+
example.run
|
170
|
+
end
|
171
|
+
end
|
172
|
+
let(:_range) { [nil, nil] }
|
173
|
+
it { should equal_to_dom(
|
174
|
+
'<input class="created_at date_filter from" multiple name="report[created_at][]" size="30" type="text"/>' +
|
175
|
+
'<span class="separator date"> - </span>' +
|
176
|
+
'<input class="created_at date_filter to" multiple name="report[created_at][]" size="30" type="text"/>'
|
177
|
+
)}
|
178
|
+
end
|
166
179
|
end
|
167
180
|
context "with enum filter type" do
|
168
181
|
let(:_filter) { :category }
|
@@ -271,11 +284,21 @@ describe Datagrid::FormBuilder do
|
|
271
284
|
end
|
272
285
|
end
|
273
286
|
let(:_filter) { :group_id }
|
274
|
-
|
287
|
+
let(:expected_html) do
|
288
|
+
if ActionPack::VERSION::MAJOR == 3 && ActionPack::VERSION::MINOR < 2
|
289
|
+
<<-HTML
|
290
|
+
<select class="group_id enum_filter" id="report_group_id" multiple name="report[group_id][]">
|
291
|
+
<option value="hello">hello</option></select>
|
292
|
+
HTML
|
293
|
+
else
|
294
|
+
<<-HTML
|
275
295
|
<input name="report[group_id][]" type="hidden" value=""><select class="group_id enum_filter" id="report_group_id" multiple name="report[group_id][]">
|
276
296
|
<option value="hello">hello</option></select>
|
277
|
-
HTML
|
297
|
+
HTML
|
298
|
+
end
|
299
|
+
end
|
278
300
|
|
301
|
+
it { should equal_to_dom(expected_html) }
|
279
302
|
end
|
280
303
|
|
281
304
|
context "with column names filter" do
|
@@ -291,11 +314,23 @@ HTML
|
|
291
314
|
end
|
292
315
|
end
|
293
316
|
let(:_filter) { :column_names }
|
294
|
-
|
317
|
+
let(:expected_html) do
|
318
|
+
if ActionPack::VERSION::MAJOR == 3 && ActionPack::VERSION::MINOR < 2
|
319
|
+
<<-HTML
|
320
|
+
<select class="column_names enum_filter" id="report_column_names" multiple name="report[column_names][]"><option value="id" selected>Id</option>
|
321
|
+
<option value="name" selected>Name</option>
|
322
|
+
<option value="category">Category</option></select>
|
323
|
+
HTML
|
324
|
+
else
|
325
|
+
<<-HTML
|
295
326
|
<input name="report[column_names][]" type="hidden" value=""><select class="column_names enum_filter" id="report_column_names" multiple name="report[column_names][]"><option value="id" selected>Id</option>
|
296
327
|
<option value="name" selected>Name</option>
|
297
328
|
<option value="category">Category</option></select>
|
298
|
-
HTML
|
329
|
+
HTML
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
it { should equal_to_dom(expected_html) }
|
299
334
|
end
|
300
335
|
end
|
301
336
|
|
@@ -318,7 +353,3 @@ HTML
|
|
318
353
|
end
|
319
354
|
end
|
320
355
|
end
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
@@ -7,13 +7,14 @@ require 'datagrid/renderer'
|
|
7
7
|
describe Datagrid::Helper do
|
8
8
|
subject do
|
9
9
|
template = ActionView::Base.new
|
10
|
+
template.stub(:protect_against_forgery?).and_return(false)
|
10
11
|
template.view_paths << File.expand_path("../../../app/views", __FILE__)
|
11
12
|
template.view_paths << File.expand_path("../../support/test_partials", __FILE__)
|
12
13
|
template
|
13
14
|
end
|
14
15
|
|
15
16
|
before(:each) do
|
16
|
-
subject.stub
|
17
|
+
subject.stub(:params).and_return({})
|
17
18
|
subject.stub(:url_for) do |options|
|
18
19
|
options.to_param
|
19
20
|
end
|
@@ -95,6 +96,7 @@ describe Datagrid::Helper do
|
|
95
96
|
"table.datagrid td.group" => 0
|
96
97
|
)
|
97
98
|
end
|
99
|
+
|
98
100
|
context "with column_names attribute" do
|
99
101
|
let(:grid) do
|
100
102
|
test_report(:column_names => "name") do
|
@@ -279,6 +281,22 @@ describe Datagrid::Helper do
|
|
279
281
|
)
|
280
282
|
end
|
281
283
|
|
284
|
+
context "when grid has complicated columns" do
|
285
|
+
let(:grid) do
|
286
|
+
test_report(:name => 'Hello') do
|
287
|
+
scope {Entry}
|
288
|
+
filter(:name)
|
289
|
+
column(:name) do |model, grid|
|
290
|
+
"'#{model.name}' filtered by '#{grid.name}'"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
it "should ignore them" do
|
295
|
+
subject.datagrid_rows(grid, [entry]).should match_css_pattern(
|
296
|
+
"td.name" => 1
|
297
|
+
)
|
298
|
+
end
|
299
|
+
end
|
282
300
|
end
|
283
301
|
|
284
302
|
describe ".datagrid_order_for" do
|
@@ -361,5 +379,16 @@ describe Datagrid::Helper do
|
|
361
379
|
end
|
362
380
|
subject.datagrid_format_value(report, :name, entry).should == "<b>Star</b>"
|
363
381
|
end
|
382
|
+
it "should support format in column" do
|
383
|
+
report = test_report do
|
384
|
+
scope {Entry}
|
385
|
+
column(:name) do |e|
|
386
|
+
format(e.name) do |value|
|
387
|
+
link_to value, "/profile"
|
388
|
+
end
|
389
|
+
end
|
390
|
+
end
|
391
|
+
subject.datagrid_format_value(report, :name, entry).should == "<a href=\"/profile\">Star</a>"
|
392
|
+
end
|
364
393
|
end
|
365
394
|
end
|
@@ -1,16 +1,21 @@
|
|
1
1
|
|
2
2
|
|
3
3
|
def test_report(attributes = {}, &block)
|
4
|
-
klass =
|
5
|
-
klass.class_eval do
|
6
|
-
include Datagrid
|
7
|
-
end
|
8
|
-
if block
|
9
|
-
klass.class_eval(&block)
|
10
|
-
end
|
4
|
+
klass = test_report_class(&block)
|
11
5
|
klass.new(attributes)
|
12
6
|
end
|
13
7
|
|
8
|
+
def test_report_class(&block)
|
9
|
+
Class.new.tap do |klass|
|
10
|
+
klass.class_eval do
|
11
|
+
include Datagrid
|
12
|
+
end
|
13
|
+
if block
|
14
|
+
klass.class_eval(&block)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
14
19
|
class SimpleReport
|
15
20
|
|
16
21
|
include Datagrid
|
@@ -40,12 +45,14 @@ class SimpleReport
|
|
40
45
|
render :partial => "actions", :locals => {:model => model}
|
41
46
|
end
|
42
47
|
|
43
|
-
column(:access_level, :html => lambda {|data| content_tag :h1, data})
|
44
|
-
|
45
48
|
column(:pet, :html => lambda {|data| content_tag :em, data}) do
|
46
49
|
self.pet.try(:upcase)
|
47
50
|
end
|
48
51
|
|
52
|
+
column(:shipping_date, :before => :group)
|
53
|
+
|
54
|
+
column(:access_level, :html => lambda {|data| content_tag :h1, data}, :after => :actions)
|
55
|
+
|
49
56
|
def param_name
|
50
57
|
:report
|
51
58
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: datagrid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.9.
|
4
|
+
version: 0.9.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -337,7 +337,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
337
337
|
version: '0'
|
338
338
|
segments:
|
339
339
|
- 0
|
340
|
-
hash:
|
340
|
+
hash: 3747985271557157131
|
341
341
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
342
342
|
none: false
|
343
343
|
requirements:
|