datagrid 1.8.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -0
  3. data/CHANGELOG.md +11 -1
  4. data/{Readme.markdown → README.md} +44 -29
  5. data/app/assets/stylesheets/datagrid.css +145 -0
  6. data/app/views/datagrid/_enum_checkboxes.html.erb +5 -3
  7. data/app/views/datagrid/_form.html.erb +4 -4
  8. data/app/views/datagrid/_head.html.erb +26 -3
  9. data/app/views/datagrid/_range_filter.html.erb +5 -3
  10. data/app/views/datagrid/_row.html.erb +12 -1
  11. data/app/views/datagrid/_table.html.erb +4 -4
  12. data/datagrid.gemspec +8 -7
  13. data/lib/datagrid/active_model.rb +9 -17
  14. data/lib/datagrid/base.rb +39 -0
  15. data/lib/datagrid/column_names_attribute.rb +9 -11
  16. data/lib/datagrid/columns/column.rb +155 -133
  17. data/lib/datagrid/columns.rb +325 -115
  18. data/lib/datagrid/configuration.rb +33 -4
  19. data/lib/datagrid/core.rb +89 -54
  20. data/lib/datagrid/deprecated_object.rb +20 -0
  21. data/lib/datagrid/drivers/abstract_driver.rb +12 -23
  22. data/lib/datagrid/drivers/active_record.rb +24 -26
  23. data/lib/datagrid/drivers/array.rb +22 -14
  24. data/lib/datagrid/drivers/mongo_mapper.rb +15 -14
  25. data/lib/datagrid/drivers/mongoid.rb +15 -17
  26. data/lib/datagrid/drivers/sequel.rb +14 -19
  27. data/lib/datagrid/drivers.rb +2 -1
  28. data/lib/datagrid/engine.rb +11 -3
  29. data/lib/datagrid/filters/base_filter.rb +166 -143
  30. data/lib/datagrid/filters/boolean_filter.rb +19 -5
  31. data/lib/datagrid/filters/date_filter.rb +33 -35
  32. data/lib/datagrid/filters/date_time_filter.rb +24 -16
  33. data/lib/datagrid/filters/default_filter.rb +9 -3
  34. data/lib/datagrid/filters/dynamic_filter.rb +151 -105
  35. data/lib/datagrid/filters/enum_filter.rb +43 -19
  36. data/lib/datagrid/filters/extended_boolean_filter.rb +39 -31
  37. data/lib/datagrid/filters/float_filter.rb +15 -5
  38. data/lib/datagrid/filters/integer_filter.rb +21 -10
  39. data/lib/datagrid/filters/ranged_filter.rb +66 -45
  40. data/lib/datagrid/filters/select_options.rb +58 -49
  41. data/lib/datagrid/filters/string_filter.rb +9 -4
  42. data/lib/datagrid/filters.rb +204 -79
  43. data/lib/datagrid/form_builder.rb +116 -128
  44. data/lib/datagrid/generators/scaffold.rb +184 -0
  45. data/lib/datagrid/generators/views.rb +20 -0
  46. data/lib/datagrid/helper.rb +436 -69
  47. data/lib/datagrid/ordering.rb +26 -29
  48. data/lib/datagrid/rspec.rb +6 -10
  49. data/lib/datagrid/utils.rb +37 -30
  50. data/lib/datagrid/version.rb +3 -1
  51. data/lib/datagrid.rb +8 -28
  52. data/templates/base.rb.erb +6 -4
  53. data/templates/grid.rb.erb +1 -1
  54. metadata +17 -17
  55. data/app/assets/stylesheets/datagrid.sass +0 -134
  56. data/lib/datagrid/filters/composite_filters.rb +0 -49
  57. data/lib/datagrid/renderer.rb +0 -157
  58. data/lib/datagrid/scaffold.rb +0 -129
  59. data/lib/tasks/datagrid_tasks.rake +0 -15
  60. data/templates/controller.rb.erb +0 -6
  61. data/templates/index.html.erb +0 -5
@@ -1,14 +1,43 @@
1
- module Datagrid
1
+ # frozen_string_literal: true
2
2
 
3
+ module Datagrid
4
+ # @return [Configuration] current Datagrid configuration
3
5
  def self.configuration
4
6
  @configuration ||= Configuration.new
5
7
  end
6
8
 
7
- def self.configure
8
- yield(configuration)
9
+ # @yield block to configure
10
+ # @yieldparam [Configuration] configuration
11
+ # @yieldreturn [void]
12
+ # @return [void] configure datagrid
13
+ # @see Datagrid::Configuration
14
+ def self.configure(&block)
15
+ block.call(configuration)
9
16
  end
10
17
 
11
- # Datagrid configuration object
18
+ # ## Configuration
19
+ #
20
+ # Datagrid provides several configuration options.
21
+ #
22
+ # Here is the API reference and a description of the available options:
23
+ #
24
+ # ``` ruby
25
+ # Datagrid.configure do |config|
26
+ # # Defines date formats that can be used to parse dates.
27
+ # # Note: Multiple formats can be specified. The first format is used to format dates as strings,
28
+ # # while other formats are used only for parsing dates
29
+ # # from strings (e.g., if your app supports multiple formats).
30
+ # config.date_formats = "%m/%d/%Y", "%Y-%m-%d"
31
+ #
32
+ # # Defines timestamp formats that can be used to parse timestamps.
33
+ # # Note: Multiple formats can be specified. The first format is used to format timestamps as strings,
34
+ # # while other formats are used only for parsing timestamps
35
+ # # from strings (e.g., if your app supports multiple formats).
36
+ # config.datetime_formats = ["%m/%d/%Y %h:%M", "%Y-%m-%d %h:%M:%s"]
37
+ # end
38
+ # ```
39
+ #
40
+ # These options can be set globally in your application to customize Datagrid’s behavior.
12
41
  class Configuration
13
42
  # @return [Array<String>] Date parsing formats
14
43
  attr_accessor :date_formats
data/lib/datagrid/core.rb CHANGED
@@ -1,8 +1,47 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "datagrid/drivers"
2
4
  require "active_support/core_ext/class/attribute"
3
5
  require "active_model/attribute_assignment"
4
6
 
5
7
  module Datagrid
8
+ # Simple example of using Datagrid scope as the assets source to be queried from the database.
9
+ #
10
+ # In most cases, the scope is a model class with some default ORM scopes, like `order` or `includes`:
11
+ #
12
+ # The scope is also used to:
13
+ # - Choose an ORM driver (e.g., Mongoid, ActiveRecord, etc.).
14
+ # - Association preloading
15
+ # - Columns Providing default order
16
+ #
17
+ # You can set the scope at class level or instance level.
18
+ # Both having appropriate use cases
19
+ #
20
+ # @example Defining a scope in a grid class
21
+ # class ProjectsGrid
22
+ # include Datagrid
23
+ # scope { Project.includes(:category) }
24
+ # end
25
+ #
26
+ # @example Setting a scope at the instance level
27
+ # grid = ProjectsGrid.new(grid_params) do |scope|
28
+ # scope.where(owner_id: current_user.id)
29
+ # end
30
+ #
31
+ # grid.assets # => SELECT * FROM projects WHERE projects.owner_id = ? AND [other filtering conditions]
32
+ #
33
+ # @example Retrieving and redefining the scope
34
+ # grid.scope # => SELECT * FROM projects WHERE projects.user_id = ?
35
+ # grid.redefined_scope? # => true
36
+ #
37
+ # # Reset scope to default class value
38
+ # grid.reset_scope
39
+ # grid.assets # => SELECT * FROM projects
40
+ # grid.redefined_scope? # => false
41
+ #
42
+ # # Overwriting the scope (ignoring previously defined)
43
+ # grid.scope { current_user.projects }
44
+ # grid.redefined_scope? # => true
6
45
  module Core
7
46
  include ::ActiveModel::AttributeAssignment
8
47
 
@@ -18,25 +57,21 @@ module Datagrid
18
57
  end
19
58
 
20
59
  module ClassMethods
21
-
22
60
  # @!visibility private
23
61
  def datagrid_attribute(name, &block)
24
- unless datagrid_attributes.include?(name)
25
- block ||= lambda do |value|
26
- value
27
- end
28
- datagrid_attributes << name
29
- define_method name do
30
- instance_variable_get("@#{name}")
31
- end
62
+ return if datagrid_attributes.include?(name)
32
63
 
33
- define_method :"#{name}=" do |value|
34
- instance_variable_set("@#{name}", instance_exec(value, &block))
35
- end
64
+ datagrid_attributes << name
65
+ define_method name do
66
+ instance_variable_get("@#{name}")
67
+ end
68
+
69
+ define_method :"#{name}=" do |value|
70
+ instance_variable_set("@#{name}", block ? instance_exec(value, &block) : value)
36
71
  end
37
72
  end
38
73
 
39
- # Defines a scope at class level
74
+ # Defines a relation scope of database models to be filtered
40
75
  # @return [void]
41
76
  # @example
42
77
  # scope { User }
@@ -109,57 +144,57 @@ module Datagrid
109
144
  end
110
145
  end
111
146
 
112
- protected
113
-
147
+ # @!visibility private
114
148
  def check_scope_defined!(message = nil)
115
149
  message ||= "#{self}.scope is not defined"
116
150
  raise(Datagrid::ConfigurationError, message) unless scope_value
117
151
  end
118
152
 
153
+ protected
154
+
155
+ # @!visibility private
119
156
  def inherited(child_class)
120
- super(child_class)
121
- child_class.datagrid_attributes = self.datagrid_attributes.clone
157
+ super
158
+ child_class.datagrid_attributes = datagrid_attributes.clone
122
159
  end
123
-
124
160
  end
125
161
 
162
+ # @param [Hash{String, Symbol => Object}] attributes a hash of attributes to initialize the object
163
+ # @yield [block] an optional block that is passed to the scope method for further customization
164
+ # @return [void] Initializes a new instance with optional attributes and an optional block.
126
165
  def initialize(attributes = nil, &block)
127
166
  super()
128
167
 
129
- if attributes
130
- self.attributes = attributes
131
- end
168
+ self.attributes = attributes if attributes
132
169
 
133
170
  instance_eval(&dynamic_block) if dynamic_block
134
- if block_given?
135
- self.scope(&block)
136
- end
137
- end
171
+ return unless block_given?
138
172
 
173
+ scope(&block)
174
+ end
139
175
 
140
- # @return [Hash<Symbol, Object>] grid attributes including filter values and ordering values
176
+ # @return [Hash{Symbol => Object}] grid attributes including filter values and ordering values
177
+ # @example
178
+ # class UsersGrid < ApplicationGrid
179
+ # scope { User }
180
+ # filter(:first_name, :string)
181
+ # filter(:last_name, :string)
182
+ # end
183
+ #
184
+ # grid = UsersGrid.new(first_name: 'John', last_name: 'Smith')
185
+ # grid.attributes # => {first_name: 'John', last_name: 'Smith', order: nil, descending: nil}
141
186
  def attributes
142
187
  result = {}
143
- self.datagrid_attributes.each do |name|
188
+ datagrid_attributes.each do |name|
144
189
  result[name] = self[name]
145
190
  end
146
191
  result
147
192
  end
148
193
 
149
- # Updates datagrid attributes with a passed hash argument
150
- # @param attributes [Hash<Symbol, Object>]
151
- # @example
152
- # grid = MyGrid.new
153
- # grid.attributes = {first_name: 'John', last_name: 'Smith'}
154
- # grid.first_name # => 'John'
155
- # grid.last_name # => 'Smith'
156
- def attributes=(attributes)
157
- super(attributes)
158
- end
159
-
194
+ # @param [String, Symbol] attribute attribute name
160
195
  # @return [Object] Any datagrid attribute value
161
196
  def [](attribute)
162
- self.public_send(attribute)
197
+ public_send(attribute)
163
198
  end
164
199
 
165
200
  # Assigns any datagrid attribute
@@ -167,7 +202,7 @@ module Datagrid
167
202
  # @param value [Object] Datagrid attribute value
168
203
  # @return [void]
169
204
  def []=(attribute, value)
170
- self.public_send(:"#{attribute}=", value)
205
+ public_send(:"#{attribute}=", value)
171
206
  end
172
207
 
173
208
  # @return [Object] a scope relation (e.g ActiveRecord::Relation) with all applied filters
@@ -175,7 +210,7 @@ module Datagrid
175
210
  scope
176
211
  end
177
212
 
178
- # Returns serializable query arguments skipping all nil values
213
+ # @return [Hash{Symbol => Object}] serializable query arguments skipping all nil values
179
214
  # @example
180
215
  # grid = ProductsGrid.new(category: 'dresses', available: true)
181
216
  # grid.as_query # => {category: 'dresses', available: true}
@@ -187,7 +222,7 @@ module Datagrid
187
222
  attributes
188
223
  end
189
224
 
190
- # @return [Hash<Symbol, Hash<Symbol, Object>>] query parameters to link this grid from a page
225
+ # @return [Hash{Symbol => Hash{Symbol => Object}}] query parameters to link this grid from a page
191
226
  # @example
192
227
  # grid = ProductsGrid.new(category: 'dresses', available: true)
193
228
  # Rails.application.routes.url_helpers.products_path(grid.query_params)
@@ -196,7 +231,7 @@ module Datagrid
196
231
  { param_name.to_sym => as_query.merge(attributes) }
197
232
  end
198
233
 
199
- # Redefines scope at instance level
234
+ # @return [void] redefines scope at instance level
200
235
  # @example
201
236
  # class MyGrid
202
237
  # scope { Article.order('created_at desc') }
@@ -224,12 +259,11 @@ module Datagrid
224
259
 
225
260
  # @!visibility private
226
261
  def original_scope
227
- check_scope_defined!
262
+ self.class.check_scope_defined!
228
263
  scope_value.call
229
264
  end
230
265
 
231
- # Resets current instance scope to default scope defined in a class
232
- # @return [void]
266
+ # @return [void] Resets current instance scope to default scope defined in a class
233
267
  def reset_scope
234
268
  self.scope_value = self.class.scope_value
235
269
  end
@@ -244,11 +278,6 @@ module Datagrid
244
278
  self.class.driver
245
279
  end
246
280
 
247
- # @!visibility private
248
- def check_scope_defined!(message = nil)
249
- self.class.send :check_scope_defined!, message
250
- end
251
-
252
281
  # @return [String] a datagrid attributes and their values in inspection form
253
282
  def inspect
254
283
  attrs = attributes.map do |key, value|
@@ -263,15 +292,21 @@ module Datagrid
263
292
  scope == other.scope
264
293
  end
265
294
 
266
- # Resets loaded assets and column values cache
267
- # @return [void]
295
+ # @return [void] Resets loaded assets and column values cache
268
296
  def reset
269
297
  assets.reset
270
298
  end
271
299
 
272
300
  protected
301
+
273
302
  def sanitize_for_mass_assignment(attributes)
274
- forbidden_attributes_protection ? super(attributes) : attributes
303
+ if forbidden_attributes_protection
304
+ super
305
+ elsif defined?(ActionController::Parameters) && attributes.is_a?(ActionController::Parameters)
306
+ attributes.to_unsafe_h
307
+ else
308
+ attributes
309
+ end
275
310
  end
276
311
  end
277
312
  end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datagrid
4
+ # @!visibility private
5
+ class DeprecatedObject < BasicObject
6
+ def initialize(real_object, &block)
7
+ @real_object = real_object
8
+ @block = block
9
+ end
10
+
11
+ def method_missing(method_name, ...)
12
+ @block.call
13
+ @real_object.public_send(method_name, ...)
14
+ end
15
+
16
+ def respond_to_missing?(method_name, include_private = false)
17
+ @real_object.respond_to?(method_name, include_private)
18
+ end
19
+ end
20
+ end
@@ -1,19 +1,20 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Datagrid
2
4
  module Drivers
3
5
  # @!visibility private
4
6
  class AbstractDriver
5
-
6
- TIMESTAMP_CLASSES = [DateTime, Time, ActiveSupport::TimeWithZone]
7
+ TIMESTAMP_CLASSES = [DateTime, Time, ActiveSupport::TimeWithZone].freeze
7
8
 
8
9
  class_attribute :subclasses, default: []
9
10
 
10
11
  def self.inherited(base)
11
- super(base)
12
- self.subclasses << base
12
+ super
13
+ subclasses << base
13
14
  end
14
15
 
15
16
  def self.guess_driver(scope)
16
- self.subclasses.find do |driver_class|
17
+ subclasses.find do |driver_class|
17
18
  driver_class.match?(scope)
18
19
  end || raise(Datagrid::ConfigurationError, "ORM Driver not found for scope: #{scope.inspect}.")
19
20
  end
@@ -54,7 +55,7 @@ module Datagrid
54
55
  raise NotImplementedError
55
56
  end
56
57
 
57
- def has_column?(scope, column_name)
58
+ def scope_has_column?(scope, column_name)
58
59
  raise NotImplementedError
59
60
  end
60
61
 
@@ -62,7 +63,7 @@ module Datagrid
62
63
  raise NotImplementedError
63
64
  end
64
65
 
65
- def is_timestamp?(scope, field)
66
+ def timestamp_column?(scope, field)
66
67
  normalized_column_type(scope, field) == :timestamp
67
68
  end
68
69
 
@@ -83,28 +84,15 @@ module Datagrid
83
84
  end
84
85
 
85
86
  def append_column_queries(assets, columns)
86
- if columns.present?
87
- raise NotImplementedError
88
- else
89
- assets
90
- end
87
+ raise NotImplementedError if columns.present?
88
+
89
+ assets
91
90
  end
92
91
 
93
92
  def default_cache_key(asset)
94
93
  raise NotImplementedError
95
94
  end
96
95
 
97
- def where_by_timestamp_gotcha(scope, name, value)
98
- value = Datagrid::Utils.format_date_as_timestamp(value)
99
- if value.first
100
- scope = greater_equal(scope, name, value.first)
101
- end
102
- if value.last
103
- scope = less_equal(scope, name, value.last)
104
- end
105
- scope
106
- end
107
-
108
96
  def default_preload(scope, value)
109
97
  raise NotImplementedError
110
98
  end
@@ -114,6 +102,7 @@ module Datagrid
114
102
  end
115
103
 
116
104
  protected
105
+
117
106
  def timestamp_class?(klass)
118
107
  TIMESTAMP_CLASSES.include?(klass)
119
108
  end
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Datagrid
2
4
  module Drivers
3
5
  # @!visibility private
4
6
  class ActiveRecord < AbstractDriver
5
-
6
7
  def self.match?(scope)
7
8
  return false unless defined?(::ActiveRecord)
9
+
8
10
  if scope.is_a?(Class)
9
11
  scope.ancestors.include?(::ActiveRecord::Base)
10
12
  else
@@ -14,6 +16,7 @@ module Datagrid
14
16
 
15
17
  def to_scope(scope)
16
18
  return scope if scope.is_a?(::ActiveRecord::Relation)
19
+
17
20
  # Model class or Active record association
18
21
  # ActiveRecord association class hides itself under an Array
19
22
  # We can only reveal it by checking if it respond to some specific
@@ -29,10 +32,8 @@ module Datagrid
29
32
 
30
33
  def append_column_queries(assets, columns)
31
34
  if columns.present?
32
- if assets.select_values.empty?
33
- assets = assets.select(Arel.respond_to?(:star) ? assets.klass.arel_table[Arel.star] : "#{assets.quoted_table_name}.*")
34
- end
35
- columns = columns.map {|c| "#{c.query} AS #{c.name}"}
35
+ assets = assets.select(assets.klass.arel_table[Arel.star]) if assets.select_values.empty?
36
+ columns = columns.map { |c| "#{c.query} AS #{c.name}" }
36
37
  assets = assets.select(*columns)
37
38
  end
38
39
  assets
@@ -61,7 +62,7 @@ module Datagrid
61
62
  end
62
63
 
63
64
  def default_order(scope, column_name)
64
- has_column?(scope, column_name) ? prefix_table_name(scope, column_name) : nil
65
+ scope_has_column?(scope, column_name) ? prefix_table_name(scope, column_name) : nil
65
66
  end
66
67
 
67
68
  def greater_equal(scope, field, value)
@@ -72,7 +73,7 @@ module Datagrid
72
73
  scope.where(["#{prefix_table_name(scope, field)} <= ?", value])
73
74
  end
74
75
 
75
- def has_column?(scope, column_name)
76
+ def scope_has_column?(scope, column_name)
76
77
  scope.column_names.include?(column_name.to_s)
77
78
  rescue ::ActiveRecord::StatementInvalid
78
79
  false
@@ -88,15 +89,16 @@ module Datagrid
88
89
  end
89
90
 
90
91
  def normalized_column_type(scope, field)
91
- return nil unless has_column?(scope, field)
92
+ return nil unless scope_has_column?(scope, field)
93
+
92
94
  builtin_type = scope.columns_hash[field.to_s].type
93
95
  {
94
- [:string, :text, :time, :binary] => :string,
95
- [:integer, :primary_key] => :integer,
96
- [:float, :decimal] => :float,
96
+ %i[string text time binary] => :string,
97
+ %i[integer primary_key] => :integer,
98
+ %i[float decimal] => :float,
97
99
  [:date] => :date,
98
- [:datetime, :timestamp] => :timestamp,
99
- [:boolean] => :boolean
100
+ %i[datetime timestamp] => :timestamp,
101
+ [:boolean] => :boolean,
100
102
  }.each do |keys, value|
101
103
  return value if keys.include?(builtin_type)
102
104
  end
@@ -106,6 +108,7 @@ module Datagrid
106
108
  if scope.limit_value
107
109
  raise Datagrid::ConfigurationError, "ActiveRecord can not use batches in combination with SQL limit"
108
110
  end
111
+
109
112
  options = batch_size ? { batch_size: batch_size } : {}
110
113
  scope.find_each(**options, &block)
111
114
  end
@@ -119,28 +122,23 @@ module Datagrid
119
122
  end
120
123
 
121
124
  def can_preload?(scope, association)
122
- !! scope.klass.reflect_on_association(association)
125
+ !!scope.klass.reflect_on_association(association)
123
126
  end
124
127
 
125
128
  protected
126
129
 
127
130
  def prefix_table_name(scope, field)
128
- has_column?(scope, field) ? [scope.table_name, field].join(".") : field
131
+ scope_has_column?(scope, field) ? [scope.table_name, field].join(".") : field
129
132
  end
130
133
 
131
134
  def contains_predicate
132
- defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) &&
133
- ::ActiveRecord::Base.connection.is_a?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) ?
134
- 'ilike' : 'like'
135
+ if defined?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter) &&
136
+ ::ActiveRecord::Base.connection.is_a?(::ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)
137
+ "ilike"
138
+ else
139
+ "like"
140
+ end
135
141
  end
136
142
  end
137
143
  end
138
144
  end
139
-
140
- if defined?(ActiveRecord::Base)
141
- ActiveRecord::Base.class_eval do
142
- def self.datagrid_where_by_timestamp(column, value)
143
- Datagrid::Drivers::ActiveRecord.new.where_by_timestamp_gotcha(self, column, value)
144
- end
145
- end
146
- end
@@ -1,8 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Datagrid
2
4
  module Drivers
3
5
  # @!visibility private
4
6
  class Array < AbstractDriver
5
-
6
7
  def self.match?(scope)
7
8
  !Datagrid::Drivers::ActiveRecord.match?(scope) && (
8
9
  scope.is_a?(::Array) || scope.is_a?(Enumerator) ||
@@ -16,15 +17,16 @@ module Datagrid
16
17
 
17
18
  def where(scope, attribute, value)
18
19
  scope.select do |object|
19
- object.public_send(attribute) == value
20
+ get(object, attribute) == value
20
21
  end
21
22
  end
22
23
 
23
24
  def asc(scope, order)
24
25
  return scope unless order
25
26
  return scope if order.empty?
27
+
26
28
  scope.sort_by do |object|
27
- object.public_send(order)
29
+ get(object, order)
28
30
  end
29
31
  end
30
32
 
@@ -32,7 +34,7 @@ module Datagrid
32
34
  asc(scope, order).reverse
33
35
  end
34
36
 
35
- def default_order(scope, column_name)
37
+ def default_order(_scope, column_name)
36
38
  column_name
37
39
  end
38
40
 
@@ -42,36 +44,36 @@ module Datagrid
42
44
 
43
45
  def greater_equal(scope, field, value)
44
46
  scope.select do |object|
45
- object.public_send(field) >= value
47
+ get(object, field) >= value
46
48
  end
47
49
  end
48
50
 
49
51
  def less_equal(scope, field, value)
50
52
  scope.select do |object|
51
- object.public_send(field) <= value
53
+ get(object, field) <= value
52
54
  end
53
55
  end
54
56
 
55
- def has_column?(scope, column_name)
57
+ def scope_has_column?(scope, column_name)
56
58
  scope.any? && scope.first.respond_to?(column_name)
57
59
  end
58
60
 
59
- def is_timestamp?(scope, column_name)
60
- has_column?(scope, column_name) &&
61
- timestamp_class?(scope.first.public_send(column_name).class)
61
+ def timestamp_column?(scope, column_name)
62
+ scope_has_column?(scope, column_name) &&
63
+ timestamp_class?(get(scope.first, column_name).class)
62
64
  end
63
65
 
64
66
  def contains(scope, field, value)
65
67
  scope.select do |object|
66
- object.public_send(field).to_s.include?(value)
68
+ get(object, field).to_s.include?(value)
67
69
  end
68
70
  end
69
71
 
70
- def column_names(scope)
72
+ def column_names(_scope)
71
73
  []
72
74
  end
73
75
 
74
- def batch_each(scope, batch_size, &block)
76
+ def batch_each(scope, _batch_size, &block)
75
77
  scope.each(&block)
76
78
  end
77
79
 
@@ -79,9 +81,15 @@ module Datagrid
79
81
  asset
80
82
  end
81
83
 
82
- def can_preload?(scope, association)
84
+ def can_preload?(_scope, _association)
83
85
  false
84
86
  end
87
+
88
+ protected
89
+
90
+ def get(object, property)
91
+ object.is_a?(Hash) ? object[property] : object.public_send(property)
92
+ end
85
93
  end
86
94
  end
87
95
  end