datagrid 1.8.2 → 2.0.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.
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