easy_exports 0.1.2 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +138 -1
- data/lib/easy_exports/data_attributes_resolver.rb +32 -5
- data/lib/easy_exports/data_loader.rb +12 -23
- data/lib/easy_exports/exportable_attribute_formatters_configurations.rb +48 -0
- data/lib/easy_exports/exportable_attribute_resolvers.rb +9 -1
- data/lib/easy_exports/exportable_attributes.rb +10 -2
- data/lib/easy_exports/exports_generable.rb +8 -4
- data/lib/easy_exports/version.rb +1 -1
- data/lib/easy_exports.rb +41 -0
- metadata +4 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99d64117b05b63ec1f0cd4ef5b8b6a7ec3d653087678d9b4831edb87c8dd61c4
|
|
4
|
+
data.tar.gz: 884619c1077d8ff642ceb1466f4c9ffcbb50bac95277b5bf7765303f53d666f3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e843ce5e1aa5edab56616992a16d989952c52343a854619d0fb46715617af59a2e4ca641d69bb8dc243d2aea63b7bdae42a164e2e39e3ce9784e471ff04f3054
|
|
7
|
+
data.tar.gz: 4915abc76083e2e755e954699b788e4d5debaef66cd764c42af7d85eb2dc56dafff68589ca81c38a71fbdb64962c8a891c1291781f8591af20702f4be8f463a4
|
data/README.md
CHANGED
|
@@ -58,11 +58,12 @@ Retrieve exportable attributes using the `exportable_attributes` method. This me
|
|
|
58
58
|
|
|
59
59
|
### Generating Exports from Exportable Attributes
|
|
60
60
|
|
|
61
|
-
To generate exports, use the `generate_exports(exportable_attributes, ids)` method.
|
|
61
|
+
To generate exports, use the `generate_exports(exportable_attributes, ids, order:)` method.
|
|
62
62
|
|
|
63
63
|
- The `exportable_attributes` argument specifies the chosen attributes from the exportable attributes list.
|
|
64
64
|
- The `ids` argument is optional; provide IDs to export data for specific records.
|
|
65
65
|
- Omitting `ids` will trigger exports for all records of the given model.
|
|
66
|
+
- The `order:` keyword argument is optional; see [Ordering Exports](#ordering-exports) for details.
|
|
66
67
|
|
|
67
68
|
The method returns an `EasyExports::Export` object containing hash data from the records and a `csv_string` that can be written to a CSV file.
|
|
68
69
|
|
|
@@ -107,6 +108,142 @@ Exported CSV showcases data for:
|
|
|
107
108
|
- The main CSV header includes association names and attribute names.
|
|
108
109
|
|
|
109
110
|
|
|
111
|
+
### Ordering Exports
|
|
112
|
+
|
|
113
|
+
Control the order of rows in the generated export using the `order:` keyword argument on `generate_exports`.
|
|
114
|
+
|
|
115
|
+
- `order:` accepts any value ActiveRecord's `order` accepts — a hash, string, symbol, or array.
|
|
116
|
+
- When `order:` is omitted and the model has a `created_at` column, exports default to newest first (`created_at DESC`).
|
|
117
|
+
- When `order:` is omitted and no `created_at` column exists, no ordering is applied.
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
# Example: explicit ordering
|
|
121
|
+
|
|
122
|
+
# Order by first_name ascending
|
|
123
|
+
User.generate_exports(user_exportable_attributes, [], order: { first_name: :asc })
|
|
124
|
+
|
|
125
|
+
# Order by a raw SQL fragment
|
|
126
|
+
User.generate_exports(user_exportable_attributes, [], order: 'last_name DESC, id ASC')
|
|
127
|
+
|
|
128
|
+
# Default ordering (newest first when created_at exists)
|
|
129
|
+
User.generate_exports(user_exportable_attributes)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
For performance, records are fetched in batches of 1,000 internally while preserving the requested order across the full result set. The batch size is configurable — see [Configuration](#configuration).
|
|
133
|
+
|
|
134
|
+
### Configuration
|
|
135
|
+
|
|
136
|
+
Configure gem-wide defaults using `EasyExports.configure`.
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
# config/initializers/easy_exports.rb
|
|
140
|
+
EasyExports.configure do |c|
|
|
141
|
+
c.batch_size = 500 # default: 1000
|
|
142
|
+
c.sensitive_attributes += %w[internal_note ssn] # extends the default list
|
|
143
|
+
c.type_formatters[:datetime] = ->(v) { v.strftime('%d/%m/%Y') }
|
|
144
|
+
c.csv_header_formatter = ->(key) { key.humanize.upcase } # or set to nil to disable
|
|
145
|
+
end
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- `batch_size` — number of records fetched per database round trip during export. Override per call with `generate_exports(..., batch_size: 2_000)`.
|
|
149
|
+
- `sensitive_attributes` — attributes auto-excluded from every export. See [Sensitive Attributes](#sensitive-attributes) for the default list and per-model opt-out.
|
|
150
|
+
- `type_formatters` — per-type value formatters applied before a raw value is written to CSV. See [Type Formatters](#type-formatters).
|
|
151
|
+
- `csv_header_formatter` — callable applied to every header in the CSV row. Defaults to `humanize.titleize` (e.g. `registration_email` → `Registration Email`). Set to `nil` to keep raw snake_case headers.
|
|
152
|
+
|
|
153
|
+
### Sensitive Attributes
|
|
154
|
+
|
|
155
|
+
EasyExports automatically excludes commonly sensitive attributes from all exports. The default list is:
|
|
156
|
+
|
|
157
|
+
```ruby
|
|
158
|
+
%w[
|
|
159
|
+
password_digest
|
|
160
|
+
encrypted_password
|
|
161
|
+
remember_token
|
|
162
|
+
reset_password_token
|
|
163
|
+
confirmation_token
|
|
164
|
+
session_token
|
|
165
|
+
api_key
|
|
166
|
+
secret_token
|
|
167
|
+
]
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
To include these on a specific model (e.g. for admin-only exports), opt in at the class level:
|
|
171
|
+
|
|
172
|
+
```ruby
|
|
173
|
+
class AdminLogin < ApplicationRecord
|
|
174
|
+
self.include_sensitive_exportable_attributes = true
|
|
175
|
+
end
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Extend or replace the default list through [Configuration](#configuration).
|
|
179
|
+
|
|
180
|
+
### Type Formatters
|
|
181
|
+
|
|
182
|
+
EasyExports applies type-based formatters automatically, so you don't have to write a lambda for every boolean or timestamp column.
|
|
183
|
+
|
|
184
|
+
| Type | Matches | Shipped formatter | Example output |
|
|
185
|
+
|------|---------|-------------------|----------------|
|
|
186
|
+
| `boolean` | `true` / `false` | `->(v) { v ? 'Yes' : 'No' }` | `Yes`, `No` |
|
|
187
|
+
| `datetime` | `Date`, `Time`, `DateTime`, `ActiveSupport::TimeWithZone` | `->(v) { v.strftime('%A, %B %-d, %Y %H:%M') }` | `Sunday, January 5, 2025 09:17` |
|
|
188
|
+
| `leading_zero_string` | `String` starting with `0` | `->(v) { "'#{v}" }` | `'0244867596` (preserves leading zero in spreadsheets) |
|
|
189
|
+
| `string` | `String` not containing `@` | *(none — opt in per model)* | — |
|
|
190
|
+
|
|
191
|
+
`nil` values always pass through untouched.
|
|
192
|
+
|
|
193
|
+
**Turn off a type formatter for a specific model:**
|
|
194
|
+
|
|
195
|
+
```ruby
|
|
196
|
+
class Transaction < ApplicationRecord
|
|
197
|
+
disable_exportable_type_formatter :datetime # one type
|
|
198
|
+
disable_exportable_type_formatter :boolean, :datetime # multiple types
|
|
199
|
+
end
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Replace a type formatter for a specific model** — apply a different format to *all* values of that type on this one model:
|
|
203
|
+
|
|
204
|
+
```ruby
|
|
205
|
+
class Registration < ApplicationRecord
|
|
206
|
+
# Every datetime on Registration renders as "January 5, 2025" — no time portion
|
|
207
|
+
format_exportable_type :datetime, ->(v) { v.strftime('%B %-d, %Y') }
|
|
208
|
+
|
|
209
|
+
# Capitalize the first letter of every plain string (emails are skipped automatically)
|
|
210
|
+
format_exportable_type :string, ->(v) { v.sub(/^./, &:upcase) }
|
|
211
|
+
|
|
212
|
+
# Block form
|
|
213
|
+
format_exportable_type(:boolean) { |v| v ? '✓' : '✗' }
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
**Change or disable a type formatter globally** — see [Configuration](#configuration).
|
|
218
|
+
|
|
219
|
+
### Custom Value Formatters
|
|
220
|
+
|
|
221
|
+
For a specific attribute, override the default with your own formatter using `format_exportable_attribute`.
|
|
222
|
+
|
|
223
|
+
- Declare it on the class that owns the attribute. It applies whenever that attribute is exported, whether from the owner model directly or through an association.
|
|
224
|
+
- Accepts either a callable (lambda/proc) or a block.
|
|
225
|
+
- A custom formatter takes precedence over any default formatter for that attribute.
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
class Registration < ApplicationRecord
|
|
229
|
+
# Override the global datetime default with a shorter format for this attribute
|
|
230
|
+
format_exportable_attribute :registered_on, ->(v) { v&.strftime('%Y-%m-%d') }
|
|
231
|
+
|
|
232
|
+
# Override the global boolean default with custom glyphs
|
|
233
|
+
format_exportable_attribute :is_archived, ->(v) { v ? '✓' : '' }
|
|
234
|
+
|
|
235
|
+
# Block form
|
|
236
|
+
format_exportable_attribute(:status) { |v| v.to_s.titleize }
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Precedence** (top wins):
|
|
241
|
+
1. Per-attribute `format_exportable_attribute`
|
|
242
|
+
2. Per-model `disable_default_formatter` (if disabled → raw value)
|
|
243
|
+
3. Per-model `override_default_formatter` (if overridden → override wins)
|
|
244
|
+
4. Global `EasyExports.default_formatters[:type]`
|
|
245
|
+
5. Raw value
|
|
246
|
+
|
|
110
247
|
### Exportable Attributes Aliases
|
|
111
248
|
|
|
112
249
|
Configure an alternative association name for exportable attributes using the `exportable_association_aliases(aliases)` model method.
|
|
@@ -26,15 +26,42 @@ module EasyExports
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def resolve_attributes(attribute, objects)
|
|
29
|
-
|
|
29
|
+
return [nil] if objects.empty?
|
|
30
|
+
|
|
31
|
+
objects.map do |object|
|
|
32
|
+
raw_value = object.send(attribute)
|
|
33
|
+
format_value_for_export(object.class, attribute, raw_value)
|
|
34
|
+
end.flatten
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def format_value_for_export(klass, attribute, value)
|
|
38
|
+
custom = exportable_attribute_formatter_for(klass, attribute)
|
|
39
|
+
return custom.call(value) if custom
|
|
40
|
+
return value if value.nil?
|
|
41
|
+
|
|
42
|
+
type_formatter = type_formatter_for(klass, value)
|
|
43
|
+
type_formatter ? type_formatter.call(value) : value
|
|
30
44
|
end
|
|
31
45
|
|
|
32
|
-
def
|
|
33
|
-
|
|
46
|
+
def exportable_attribute_formatter_for(klass, attribute)
|
|
47
|
+
store = exportable_attribute_formatters_store[klass.name.underscore.downcase]
|
|
48
|
+
store && store[attribute.to_s]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def type_formatter_for(klass, value)
|
|
52
|
+
klass_key = klass.name.underscore.downcase
|
|
53
|
+
disabled = disabled_type_formatters_store[klass_key] || []
|
|
54
|
+
overrides = overridden_type_formatters_store[klass_key] || {}
|
|
34
55
|
|
|
35
|
-
|
|
56
|
+
EasyExports::TYPE_MATCHERS.each do |type, matcher|
|
|
57
|
+
next if disabled.include?(type)
|
|
58
|
+
next unless matcher.call(value)
|
|
59
|
+
|
|
60
|
+
formatter = overrides[type] || EasyExports.type_formatters[type]
|
|
61
|
+
return formatter if formatter
|
|
62
|
+
end
|
|
36
63
|
|
|
37
|
-
|
|
64
|
+
nil
|
|
38
65
|
end
|
|
39
66
|
|
|
40
67
|
def objects_for_attribute(association_name, record)
|
|
@@ -7,34 +7,23 @@ module EasyExports
|
|
|
7
7
|
class_methods do
|
|
8
8
|
private
|
|
9
9
|
|
|
10
|
-
def fetch_records(ids, selected_attributes)
|
|
10
|
+
def fetch_records(ids, selected_attributes, order = nil, batch_size = EasyExports.batch_size)
|
|
11
11
|
validate_association_attributes(selected_attributes, 'to_exported_data')
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def association_attributes(association_name)
|
|
17
|
-
association_name = if association_name == underscored_self_name
|
|
18
|
-
association_name.classify
|
|
19
|
-
else
|
|
20
|
-
reflect_on_all_associations.find do |association|
|
|
21
|
-
association.name.to_s == association_name
|
|
22
|
-
end&.class_name
|
|
23
|
-
end
|
|
13
|
+
scope = ids.blank? ? all : where(id: ids)
|
|
14
|
+
ordered_ids = apply_export_order(scope, order).pluck(:id)
|
|
15
|
+
associations_to_preload = selected_attributes.keys - [underscored_self_name]
|
|
24
16
|
|
|
25
|
-
|
|
17
|
+
ordered_ids.each_slice(batch_size).flat_map do |id_slice|
|
|
18
|
+
batch = apply_export_order(where(id: id_slice), order).to_a
|
|
19
|
+
ActiveRecord::Associations::Preloader.new(records: batch, associations: associations_to_preload).call
|
|
20
|
+
batch
|
|
21
|
+
end
|
|
26
22
|
end
|
|
27
23
|
|
|
28
|
-
def
|
|
29
|
-
records
|
|
30
|
-
|
|
31
|
-
associations_to_preload = selected_attributes.keys
|
|
32
|
-
associations_to_preload.delete(underscored_self_name)
|
|
33
|
-
|
|
34
|
-
ActiveRecord::Associations::Preloader.new(
|
|
35
|
-
records: records,
|
|
36
|
-
associations: associations_to_preload
|
|
37
|
-
).call
|
|
24
|
+
def apply_export_order(records, order)
|
|
25
|
+
return records.order(order) if order.present?
|
|
26
|
+
return records.order(created_at: :desc) if column_names.include?('created_at')
|
|
38
27
|
|
|
39
28
|
records
|
|
40
29
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module EasyExports
|
|
4
|
+
module ExportableAttributeFormattersConfigurations
|
|
5
|
+
extend ActiveSupport::Concern
|
|
6
|
+
|
|
7
|
+
class_methods do
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def format_exportable_attribute(attribute, formatter = nil, &block)
|
|
11
|
+
formatter ||= block
|
|
12
|
+
unless formatter.respond_to?(:call)
|
|
13
|
+
raise ArgumentError, 'format_exportable_attribute requires a callable (proc or block)'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
exportable_attribute_formatters_store[underscored_self_name] ||= {}
|
|
17
|
+
exportable_attribute_formatters_store[underscored_self_name][attribute.to_s] = formatter
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def disable_exportable_type_formatter(*types)
|
|
21
|
+
validate_known_type_formatter!(types, 'disable_exportable_type_formatter')
|
|
22
|
+
|
|
23
|
+
disabled_type_formatters_store[underscored_self_name] ||= []
|
|
24
|
+
disabled_type_formatters_store[underscored_self_name] |= types.map(&:to_sym)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def format_exportable_type(type, formatter = nil, &block)
|
|
28
|
+
formatter ||= block
|
|
29
|
+
unless formatter.respond_to?(:call)
|
|
30
|
+
raise ArgumentError, 'format_exportable_type requires a callable (proc or block)'
|
|
31
|
+
end
|
|
32
|
+
validate_known_type_formatter!([type], 'format_exportable_type')
|
|
33
|
+
|
|
34
|
+
overridden_type_formatters_store[underscored_self_name] ||= {}
|
|
35
|
+
overridden_type_formatters_store[underscored_self_name][type.to_sym] = formatter
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def validate_known_type_formatter!(types, method)
|
|
39
|
+
invalid = types.map(&:to_sym) - EasyExports::TYPE_MATCHERS.keys
|
|
40
|
+
return if invalid.empty?
|
|
41
|
+
|
|
42
|
+
raise ArgumentError,
|
|
43
|
+
"#{method} unknown type(s): #{invalid.join(', ')}. " \
|
|
44
|
+
"Known types: #{EasyExports::TYPE_MATCHERS.keys.join(', ')}"
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -20,7 +20,15 @@ module EasyExports
|
|
|
20
20
|
|
|
21
21
|
def resolve_attributes_for_association(association)
|
|
22
22
|
association_attributes = association.class_name.constantize.attribute_names
|
|
23
|
-
association_attributes -
|
|
23
|
+
association_attributes -
|
|
24
|
+
resolve_excluded_exportable_attributes(association.name.to_s.downcase) -
|
|
25
|
+
resolve_sensitive_attributes_to_exclude
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def resolve_sensitive_attributes_to_exclude
|
|
29
|
+
return [] if include_sensitive_exportable_attributes
|
|
30
|
+
|
|
31
|
+
EasyExports.sensitive_attributes.map(&:to_s)
|
|
24
32
|
end
|
|
25
33
|
|
|
26
34
|
def resolve_associations_names_aliases(association_name)
|
|
@@ -8,17 +8,21 @@ module EasyExports
|
|
|
8
8
|
cattr_accessor :excluded_exportable_attributes_store, default: {}, instance_writer: false
|
|
9
9
|
cattr_accessor :associations_aliases_store, default: {}, instance_writer: false
|
|
10
10
|
cattr_accessor :associations_to_exclude_store, default: {}, instance_writer: false
|
|
11
|
-
|
|
11
|
+
cattr_accessor :exportable_attribute_formatters_store, default: {}, instance_writer: false
|
|
12
|
+
cattr_accessor :disabled_type_formatters_store, default: {}, instance_writer: false
|
|
13
|
+
cattr_accessor :overridden_type_formatters_store, default: {}, instance_writer: false
|
|
14
|
+
cattr_accessor :include_sensitive_exportable_attributes, default: false, instance_writer: false
|
|
12
15
|
|
|
13
16
|
include EasyExports::ExportableAssociationAliasesConfigurations
|
|
14
17
|
include EasyExports::ExportableAttributeResolvers
|
|
15
18
|
include EasyExports::ExcludeExportableAttributesConfigurations
|
|
19
|
+
include EasyExports::ExportableAttributeFormattersConfigurations
|
|
16
20
|
include EasyExports::ExportsGenerable
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
class_methods do
|
|
20
24
|
def exportable_attributes
|
|
21
|
-
self_with_associations.each_with_object({}) do |association, attributes|
|
|
25
|
+
@exportable_attributes ||= self_with_associations.each_with_object({}) do |association, attributes|
|
|
22
26
|
association_name = association.name.to_s.downcase
|
|
23
27
|
next if associations_to_exclude_store[underscored_self_name]&.include? association_name
|
|
24
28
|
|
|
@@ -29,6 +33,10 @@ module EasyExports
|
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
36
|
+
def reset_exportable_attributes_cache!
|
|
37
|
+
@exportable_attributes = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
32
40
|
private
|
|
33
41
|
|
|
34
42
|
def self_with_associations
|
|
@@ -10,7 +10,7 @@ module EasyExports
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
class_methods do
|
|
13
|
-
def generate_exports(fields_to_export = {}, ids = [])
|
|
13
|
+
def generate_exports(fields_to_export = {}, ids = [], order: nil, batch_size: nil)
|
|
14
14
|
validate_exclude_exportable_attributes_argument(fields_to_export, 'generate_exports')
|
|
15
15
|
|
|
16
16
|
selected_exportable_attributes = revert_transformed_names(fields_to_export)
|
|
@@ -19,7 +19,7 @@ module EasyExports
|
|
|
19
19
|
export_row_template = generate_export_row_template(selected_exportable_attributes)
|
|
20
20
|
|
|
21
21
|
selected_attributes = revert_exportable_attributes_aliases(selected_exportable_attributes)
|
|
22
|
-
records = fetch_records(ids, selected_attributes)
|
|
22
|
+
records = fetch_records(ids, selected_attributes, order, batch_size || EasyExports.batch_size)
|
|
23
23
|
|
|
24
24
|
exported_data = records.each_with_object([]) do |record, hash_to_export|
|
|
25
25
|
hash_to_export << value_from_selected_attributes(selected_attributes, record, export_row_template.dup)
|
|
@@ -31,8 +31,12 @@ module EasyExports
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def write_exported_data_to_csv(exported_data, export_row_template)
|
|
34
|
+
header_formatter = EasyExports.csv_header_formatter
|
|
35
|
+
keys = export_row_template.keys
|
|
36
|
+
headers = header_formatter ? keys.map { |k| header_formatter.call(k) } : keys
|
|
37
|
+
|
|
34
38
|
CSV.generate(headers: true) do |csv|
|
|
35
|
-
csv <<
|
|
39
|
+
csv << headers
|
|
36
40
|
|
|
37
41
|
exported_data.each do |data|
|
|
38
42
|
csv << data.values
|
|
@@ -60,7 +64,7 @@ module EasyExports
|
|
|
60
64
|
def generate_export_row_template(selected_attributes)
|
|
61
65
|
selected_attributes.each_with_object({}) do |(association_name, attributes), export_row|
|
|
62
66
|
attributes.each do |attribute|
|
|
63
|
-
export_row.merge!(
|
|
67
|
+
export_row.merge!(export_header(association_name, attribute) => nil)
|
|
64
68
|
end
|
|
65
69
|
end
|
|
66
70
|
end
|
data/lib/easy_exports/version.rb
CHANGED
data/lib/easy_exports.rb
CHANGED
|
@@ -1,13 +1,54 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
|
4
|
+
|
|
3
5
|
require 'easy_exports/version'
|
|
4
6
|
require 'easy_exports/railtie'
|
|
5
7
|
require 'easy_exports/exportable_attribute_resolvers'
|
|
6
8
|
require 'easy_exports/exclude_associations_configurations'
|
|
7
9
|
require 'easy_exports/exclude_exportable_attributes_configurations'
|
|
8
10
|
require 'easy_exports/exportable_association_aliases_configurations'
|
|
11
|
+
require 'easy_exports/exportable_attribute_formatters_configurations'
|
|
9
12
|
require 'easy_exports/export'
|
|
10
13
|
require 'easy_exports/data_loader'
|
|
11
14
|
require 'easy_exports/data_attributes_resolver'
|
|
12
15
|
require 'easy_exports/exports_generable'
|
|
13
16
|
require 'easy_exports/exportable_attributes'
|
|
17
|
+
|
|
18
|
+
module EasyExports
|
|
19
|
+
DEFAULT_BATCH_SIZE = 1_000
|
|
20
|
+
DEFAULT_SENSITIVE_ATTRIBUTES = %w[
|
|
21
|
+
password_digest
|
|
22
|
+
encrypted_password
|
|
23
|
+
remember_token
|
|
24
|
+
reset_password_token
|
|
25
|
+
confirmation_token
|
|
26
|
+
session_token
|
|
27
|
+
api_key
|
|
28
|
+
secret_token
|
|
29
|
+
].freeze
|
|
30
|
+
|
|
31
|
+
TYPE_MATCHERS = {
|
|
32
|
+
boolean: ->(v) { v == true || v == false },
|
|
33
|
+
datetime: ->(v) { v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime) || v.is_a?(ActiveSupport::TimeWithZone) },
|
|
34
|
+
leading_zero_string: ->(v) { v.is_a?(String) && v.start_with?('0') },
|
|
35
|
+
string: ->(v) { v.is_a?(String) && !v.include?('@') }
|
|
36
|
+
}.freeze
|
|
37
|
+
|
|
38
|
+
TYPE_FORMATTERS = {
|
|
39
|
+
boolean: ->(v) { v ? 'Yes' : 'No' },
|
|
40
|
+
datetime: ->(v) { v.strftime('%A, %B %-d, %Y %H:%M') },
|
|
41
|
+
leading_zero_string: ->(v) { "'#{v}" }
|
|
42
|
+
}.freeze
|
|
43
|
+
|
|
44
|
+
DEFAULT_CSV_HEADER_FORMATTER = ->(key) { key.to_s.humanize.titleize }
|
|
45
|
+
|
|
46
|
+
mattr_accessor :batch_size, default: DEFAULT_BATCH_SIZE
|
|
47
|
+
mattr_accessor :sensitive_attributes, default: DEFAULT_SENSITIVE_ATTRIBUTES.dup
|
|
48
|
+
mattr_accessor :type_formatters, default: TYPE_FORMATTERS.dup
|
|
49
|
+
mattr_accessor :csv_header_formatter, default: DEFAULT_CSV_HEADER_FORMATTER
|
|
50
|
+
|
|
51
|
+
def self.configure
|
|
52
|
+
yield self
|
|
53
|
+
end
|
|
54
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: easy_exports
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dapilah Sydney
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rails
|
|
@@ -112,6 +111,7 @@ files:
|
|
|
112
111
|
- lib/easy_exports/exclude_exportable_attributes_configurations.rb
|
|
113
112
|
- lib/easy_exports/export.rb
|
|
114
113
|
- lib/easy_exports/exportable_association_aliases_configurations.rb
|
|
114
|
+
- lib/easy_exports/exportable_attribute_formatters_configurations.rb
|
|
115
115
|
- lib/easy_exports/exportable_attribute_resolvers.rb
|
|
116
116
|
- lib/easy_exports/exportable_attributes.rb
|
|
117
117
|
- lib/easy_exports/exports_generable.rb
|
|
@@ -126,7 +126,6 @@ metadata:
|
|
|
126
126
|
homepage_uri: https://github.com/SydDaps/easy_exports
|
|
127
127
|
source_code_uri: https://github.com/SydDaps/easy_exports
|
|
128
128
|
changelog_uri: https://rubygems.org/
|
|
129
|
-
post_install_message:
|
|
130
129
|
rdoc_options: []
|
|
131
130
|
require_paths:
|
|
132
131
|
- lib
|
|
@@ -141,8 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
141
140
|
- !ruby/object:Gem::Version
|
|
142
141
|
version: '0'
|
|
143
142
|
requirements: []
|
|
144
|
-
rubygems_version: 3.2
|
|
145
|
-
signing_key:
|
|
143
|
+
rubygems_version: 3.7.2
|
|
146
144
|
specification_version: 4
|
|
147
145
|
summary: Streamline data retrieval from Rails models
|
|
148
146
|
test_files: []
|