chronicle-etl 0.2.4 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.rubocop.yml +3 -0
  4. data/README.md +20 -13
  5. data/chronicle-etl.gemspec +11 -8
  6. data/lib/chronicle/etl/cli/connectors.rb +19 -7
  7. data/lib/chronicle/etl/cli/jobs.rb +24 -18
  8. data/lib/chronicle/etl/cli/main.rb +10 -2
  9. data/lib/chronicle/etl/config.rb +1 -1
  10. data/lib/chronicle/etl/exceptions.rb +12 -1
  11. data/lib/chronicle/etl/extraction.rb +12 -0
  12. data/lib/chronicle/etl/extractors/csv_extractor.rb +43 -36
  13. data/lib/chronicle/etl/extractors/extractor.rb +9 -1
  14. data/lib/chronicle/etl/extractors/file_extractor.rb +15 -33
  15. data/lib/chronicle/etl/extractors/helpers/filesystem_reader.rb +104 -0
  16. data/lib/chronicle/etl/extractors/json_extractor.rb +45 -0
  17. data/lib/chronicle/etl/extractors/stdin_extractor.rb +6 -1
  18. data/lib/chronicle/etl/job.rb +30 -29
  19. data/lib/chronicle/etl/job_definition.rb +45 -7
  20. data/lib/chronicle/etl/job_log.rb +10 -0
  21. data/lib/chronicle/etl/job_logger.rb +23 -20
  22. data/lib/chronicle/etl/loaders/csv_loader.rb +4 -0
  23. data/lib/chronicle/etl/loaders/loader.rb +1 -1
  24. data/lib/chronicle/etl/loaders/rest_loader.rb +5 -1
  25. data/lib/chronicle/etl/loaders/stdout_loader.rb +6 -1
  26. data/lib/chronicle/etl/loaders/table_loader.rb +57 -7
  27. data/lib/chronicle/etl/logger.rb +48 -0
  28. data/lib/chronicle/etl/models/attachment.rb +14 -0
  29. data/lib/chronicle/etl/models/base.rb +23 -7
  30. data/lib/chronicle/etl/models/entity.rb +9 -3
  31. data/lib/chronicle/etl/registry/connector_registration.rb +61 -0
  32. data/lib/chronicle/etl/registry/registry.rb +52 -0
  33. data/lib/chronicle/etl/registry/self_registering.rb +25 -0
  34. data/lib/chronicle/etl/runner.rb +57 -7
  35. data/lib/chronicle/etl/serializers/jsonapi_serializer.rb +25 -0
  36. data/lib/chronicle/etl/serializers/serializer.rb +27 -0
  37. data/lib/chronicle/etl/transformers/image_file_transformer.rb +253 -0
  38. data/lib/chronicle/etl/transformers/null_transformer.rb +10 -1
  39. data/lib/chronicle/etl/transformers/transformer.rb +39 -9
  40. data/lib/chronicle/etl/utils/binary_attachments.rb +21 -0
  41. data/lib/chronicle/etl/utils/progress_bar.rb +3 -1
  42. data/lib/chronicle/etl/utils/text_recognition.rb +15 -0
  43. data/lib/chronicle/etl/version.rb +1 -1
  44. data/lib/chronicle/etl.rb +7 -2
  45. metadata +96 -44
  46. data/Gemfile.lock +0 -91
  47. data/lib/chronicle/etl/catalog.rb +0 -108
  48. data/lib/chronicle/etl/utils/jsonapi.rb +0 -28
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chronicle-etl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Louis
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-09-23 00:00:00.000000000 Z
11
+ date: 2022-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: chronic_duration
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '0.20'
33
+ version: 0.10.6
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '0.20'
40
+ version: 0.10.6
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: colorize
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -39,33 +53,61 @@ dependencies:
39
53
  - !ruby/object:Gem::Version
40
54
  version: 0.8.1
41
55
  - !ruby/object:Gem::Dependency
42
- name: tty-table
56
+ name: marcel
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '0.11'
61
+ version: 1.0.2
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '0.11'
68
+ version: 1.0.2
55
69
  - !ruby/object:Gem::Dependency
56
- name: tty-progressbar
70
+ name: mini_exiftool
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: '0.17'
75
+ version: '2.10'
62
76
  type: :runtime
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: '0.17'
82
+ version: '2.10'
83
+ - !ruby/object:Gem::Dependency
84
+ name: nokogiri
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.13'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.13'
97
+ - !ruby/object:Gem::Dependency
98
+ name: runcom
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '6.2'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '6.2'
69
111
  - !ruby/object:Gem::Dependency
70
112
  name: sequel
71
113
  requirement: !ruby/object:Gem::Requirement
@@ -81,117 +123,117 @@ dependencies:
81
123
  - !ruby/object:Gem::Version
82
124
  version: '5.35'
83
125
  - !ruby/object:Gem::Dependency
84
- name: deep_merge
126
+ name: sqlite3
85
127
  requirement: !ruby/object:Gem::Requirement
86
128
  requirements:
87
129
  - - "~>"
88
130
  - !ruby/object:Gem::Version
89
- version: '1.2'
131
+ version: '1.4'
90
132
  type: :runtime
91
133
  prerelease: false
92
134
  version_requirements: !ruby/object:Gem::Requirement
93
135
  requirements:
94
136
  - - "~>"
95
137
  - !ruby/object:Gem::Version
96
- version: '1.2'
138
+ version: '1.4'
97
139
  - !ruby/object:Gem::Dependency
98
- name: bundler
140
+ name: thor
99
141
  requirement: !ruby/object:Gem::Requirement
100
142
  requirements:
101
143
  - - "~>"
102
144
  - !ruby/object:Gem::Version
103
- version: '2.1'
104
- type: :development
145
+ version: '0.20'
146
+ type: :runtime
105
147
  prerelease: false
106
148
  version_requirements: !ruby/object:Gem::Requirement
107
149
  requirements:
108
150
  - - "~>"
109
151
  - !ruby/object:Gem::Version
110
- version: '2.1'
152
+ version: '0.20'
111
153
  - !ruby/object:Gem::Dependency
112
- name: rake
154
+ name: tty-progressbar
113
155
  requirement: !ruby/object:Gem::Requirement
114
156
  requirements:
115
157
  - - "~>"
116
158
  - !ruby/object:Gem::Version
117
- version: '13.0'
118
- type: :development
159
+ version: '0.17'
160
+ type: :runtime
119
161
  prerelease: false
120
162
  version_requirements: !ruby/object:Gem::Requirement
121
163
  requirements:
122
164
  - - "~>"
123
165
  - !ruby/object:Gem::Version
124
- version: '13.0'
166
+ version: '0.17'
125
167
  - !ruby/object:Gem::Dependency
126
- name: rspec
168
+ name: tty-table
127
169
  requirement: !ruby/object:Gem::Requirement
128
170
  requirements:
129
171
  - - "~>"
130
172
  - !ruby/object:Gem::Version
131
- version: '3.9'
132
- type: :development
173
+ version: '0.11'
174
+ type: :runtime
133
175
  prerelease: false
134
176
  version_requirements: !ruby/object:Gem::Requirement
135
177
  requirements:
136
178
  - - "~>"
137
179
  - !ruby/object:Gem::Version
138
- version: '3.9'
180
+ version: '0.11'
139
181
  - !ruby/object:Gem::Dependency
140
- name: pry-byebug
182
+ name: bundler
141
183
  requirement: !ruby/object:Gem::Requirement
142
184
  requirements:
143
185
  - - "~>"
144
186
  - !ruby/object:Gem::Version
145
- version: '3.9'
187
+ version: '2.1'
146
188
  type: :development
147
189
  prerelease: false
148
190
  version_requirements: !ruby/object:Gem::Requirement
149
191
  requirements:
150
192
  - - "~>"
151
193
  - !ruby/object:Gem::Version
152
- version: '3.9'
194
+ version: '2.1'
153
195
  - !ruby/object:Gem::Dependency
154
- name: runcom
196
+ name: pry-byebug
155
197
  requirement: !ruby/object:Gem::Requirement
156
198
  requirements:
157
199
  - - "~>"
158
200
  - !ruby/object:Gem::Version
159
- version: '6.2'
201
+ version: '3.9'
160
202
  type: :development
161
203
  prerelease: false
162
204
  version_requirements: !ruby/object:Gem::Requirement
163
205
  requirements:
164
206
  - - "~>"
165
207
  - !ruby/object:Gem::Version
166
- version: '6.2'
208
+ version: '3.9'
167
209
  - !ruby/object:Gem::Dependency
168
- name: redcarpet
210
+ name: rake
169
211
  requirement: !ruby/object:Gem::Requirement
170
212
  requirements:
171
213
  - - "~>"
172
214
  - !ruby/object:Gem::Version
173
- version: '3.5'
215
+ version: '13.0'
174
216
  type: :development
175
217
  prerelease: false
176
218
  version_requirements: !ruby/object:Gem::Requirement
177
219
  requirements:
178
220
  - - "~>"
179
221
  - !ruby/object:Gem::Version
180
- version: '3.5'
222
+ version: '13.0'
181
223
  - !ruby/object:Gem::Dependency
182
- name: sqlite3
224
+ name: rspec
183
225
  requirement: !ruby/object:Gem::Requirement
184
226
  requirements:
185
227
  - - "~>"
186
228
  - !ruby/object:Gem::Version
187
- version: '1.4'
229
+ version: '3.9'
188
230
  type: :development
189
231
  prerelease: false
190
232
  version_requirements: !ruby/object:Gem::Requirement
191
233
  requirements:
192
234
  - - "~>"
193
235
  - !ruby/object:Gem::Version
194
- version: '1.4'
236
+ version: '3.9'
195
237
  description: Chronicle-ETL allows you to extract personal data from a variety of services,
196
238
  transformer it, and load it.
197
239
  email:
@@ -209,7 +251,6 @@ files:
209
251
  - ".yardopts"
210
252
  - CODE_OF_CONDUCT.md
211
253
  - Gemfile
212
- - Gemfile.lock
213
254
  - LICENSE.txt
214
255
  - README.md
215
256
  - Rakefile
@@ -218,16 +259,18 @@ files:
218
259
  - chronicle-etl.gemspec
219
260
  - exe/chronicle-etl
220
261
  - lib/chronicle/etl.rb
221
- - lib/chronicle/etl/catalog.rb
222
262
  - lib/chronicle/etl/cli/connectors.rb
223
263
  - lib/chronicle/etl/cli/jobs.rb
224
264
  - lib/chronicle/etl/cli/main.rb
225
265
  - lib/chronicle/etl/cli/subcommand_base.rb
226
266
  - lib/chronicle/etl/config.rb
227
267
  - lib/chronicle/etl/exceptions.rb
268
+ - lib/chronicle/etl/extraction.rb
228
269
  - lib/chronicle/etl/extractors/csv_extractor.rb
229
270
  - lib/chronicle/etl/extractors/extractor.rb
230
271
  - lib/chronicle/etl/extractors/file_extractor.rb
272
+ - lib/chronicle/etl/extractors/helpers/filesystem_reader.rb
273
+ - lib/chronicle/etl/extractors/json_extractor.rb
231
274
  - lib/chronicle/etl/extractors/stdin_extractor.rb
232
275
  - lib/chronicle/etl/job.rb
233
276
  - lib/chronicle/etl/job_definition.rb
@@ -238,16 +281,25 @@ files:
238
281
  - lib/chronicle/etl/loaders/rest_loader.rb
239
282
  - lib/chronicle/etl/loaders/stdout_loader.rb
240
283
  - lib/chronicle/etl/loaders/table_loader.rb
284
+ - lib/chronicle/etl/logger.rb
241
285
  - lib/chronicle/etl/models/activity.rb
286
+ - lib/chronicle/etl/models/attachment.rb
242
287
  - lib/chronicle/etl/models/base.rb
243
288
  - lib/chronicle/etl/models/entity.rb
244
289
  - lib/chronicle/etl/models/generic.rb
290
+ - lib/chronicle/etl/registry/connector_registration.rb
291
+ - lib/chronicle/etl/registry/registry.rb
292
+ - lib/chronicle/etl/registry/self_registering.rb
245
293
  - lib/chronicle/etl/runner.rb
294
+ - lib/chronicle/etl/serializers/jsonapi_serializer.rb
295
+ - lib/chronicle/etl/serializers/serializer.rb
296
+ - lib/chronicle/etl/transformers/image_file_transformer.rb
246
297
  - lib/chronicle/etl/transformers/null_transformer.rb
247
298
  - lib/chronicle/etl/transformers/transformer.rb
299
+ - lib/chronicle/etl/utils/binary_attachments.rb
248
300
  - lib/chronicle/etl/utils/hash_utilities.rb
249
- - lib/chronicle/etl/utils/jsonapi.rb
250
301
  - lib/chronicle/etl/utils/progress_bar.rb
302
+ - lib/chronicle/etl/utils/text_recognition.rb
251
303
  - lib/chronicle/etl/version.rb
252
304
  homepage: https://github.com/chronicle-app
253
305
  licenses:
@@ -256,7 +308,7 @@ metadata:
256
308
  homepage_uri: https://github.com/chronicle-app
257
309
  source_code_uri: https://github.com/chronicle-app/chronicle-etl
258
310
  changelog_uri: https://github.com/chronicle-app/chronicle-etl/blob/master/CHANGELOG.md
259
- post_install_message:
311
+ post_install_message:
260
312
  rdoc_options: []
261
313
  require_paths:
262
314
  - lib
@@ -272,7 +324,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
324
  version: '0'
273
325
  requirements: []
274
326
  rubygems_version: 3.1.2
275
- signing_key:
327
+ signing_key:
276
328
  specification_version: 4
277
329
  summary: ETL tool for personal data
278
330
  test_files: []
data/Gemfile.lock DELETED
@@ -1,91 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- chronicle-etl (0.2.4)
5
- colorize (~> 0.8.1)
6
- deep_merge (~> 1.2)
7
- sequel (~> 5.35)
8
- thor (~> 0.20)
9
- tty-progressbar (~> 0.17)
10
- tty-table (~> 0.11)
11
-
12
- GEM
13
- remote: https://rubygems.org/
14
- specs:
15
- byebug (11.1.3)
16
- coderay (1.1.3)
17
- colorize (0.8.1)
18
- deep_merge (1.2.1)
19
- diff-lcs (1.4.4)
20
- equatable (0.6.1)
21
- method_source (1.0.0)
22
- necromancer (0.6.0)
23
- pastel (0.7.4)
24
- equatable (~> 0.6)
25
- tty-color (~> 0.5)
26
- pry (0.13.1)
27
- coderay (~> 1.1)
28
- method_source (~> 1.0)
29
- pry-byebug (3.9.0)
30
- byebug (~> 11.0)
31
- pry (~> 0.13.0)
32
- rake (13.0.1)
33
- redcarpet (3.5.0)
34
- refinements (7.7.0)
35
- rspec (3.9.0)
36
- rspec-core (~> 3.9.0)
37
- rspec-expectations (~> 3.9.0)
38
- rspec-mocks (~> 3.9.0)
39
- rspec-core (3.9.2)
40
- rspec-support (~> 3.9.3)
41
- rspec-expectations (3.9.2)
42
- diff-lcs (>= 1.2.0, < 2.0)
43
- rspec-support (~> 3.9.0)
44
- rspec-mocks (3.9.1)
45
- diff-lcs (>= 1.2.0, < 2.0)
46
- rspec-support (~> 3.9.0)
47
- rspec-support (3.9.3)
48
- runcom (6.2.0)
49
- refinements (~> 7.4)
50
- xdg (~> 4.0)
51
- sequel (5.36.0)
52
- sqlite3 (1.4.2)
53
- strings (0.1.8)
54
- strings-ansi (~> 0.1)
55
- unicode-display_width (~> 1.5)
56
- unicode_utils (~> 1.4)
57
- strings-ansi (0.1.0)
58
- thor (0.20.3)
59
- tty-color (0.5.2)
60
- tty-cursor (0.7.1)
61
- tty-progressbar (0.17.0)
62
- strings-ansi (~> 0.1.0)
63
- tty-cursor (~> 0.7)
64
- tty-screen (~> 0.7)
65
- unicode-display_width (~> 1.6)
66
- tty-screen (0.8.1)
67
- tty-table (0.11.0)
68
- equatable (~> 0.6)
69
- necromancer (~> 0.5)
70
- pastel (~> 0.7.2)
71
- strings (~> 0.1.5)
72
- tty-screen (~> 0.7)
73
- unicode-display_width (1.7.0)
74
- unicode_utils (1.4.0)
75
- xdg (4.2.0)
76
-
77
- PLATFORMS
78
- ruby
79
-
80
- DEPENDENCIES
81
- bundler (~> 2.1)
82
- chronicle-etl!
83
- pry-byebug (~> 3.9)
84
- rake (~> 13.0)
85
- redcarpet (~> 3.5)
86
- rspec (~> 3.9)
87
- runcom (~> 6.2)
88
- sqlite3 (~> 1.4)
89
-
90
- BUNDLED WITH
91
- 2.1.4
@@ -1,108 +0,0 @@
1
- module Chronicle
2
- module ETL
3
- # Utility methods to catalogue which Extractor, Transformer, and
4
- # Loader connector classes are available to chronicle-etl
5
- module Catalog
6
- PHASES = [:extractor, :transformer, :loader]
7
- PLUGINS = ['email', 'bash']
8
- BUILTIN = {
9
- extractor: ['stdin', 'json', 'csv', 'file'],
10
- transformer: ['null'],
11
- loader: ['stdout', 'csv', 'table', 'rest']
12
- }.freeze
13
-
14
- # Return which ETL connectors are available, both built in and externally-defined
15
- def self.available_classes
16
- # TODO: have a registry of plugins
17
-
18
- # Attempt to load each chronicle plugin that we might know about so
19
- # that we can later search for subclasses to build our list of
20
- # available classes
21
- PLUGINS.each do |plugin|
22
- require "chronicle/#{plugin}"
23
- rescue LoadError
24
- # this will happen if the gem isn't available globally
25
- end
26
-
27
- parent_klasses = [
28
- ::Chronicle::ETL::Extractor,
29
- ::Chronicle::ETL::Transformer,
30
- ::Chronicle::ETL::Loader
31
- ]
32
- klasses = []
33
- parent_klasses.map do |parent|
34
- klasses += ::ObjectSpace.each_object(::Class).select { |klass| klass < parent }
35
- end
36
-
37
- klasses.map do |klass|
38
- {
39
- name: klass.name,
40
- built_in: klass.built_in?,
41
- provider: klass.provider,
42
- phase: klass.phase
43
- }
44
- end
45
- end
46
-
47
- # Take a phase (e, t, or l) and an identifier and return the right class
48
- def self.phase_and_identifier_to_klass(phase, identifier)
49
- Chronicle::ETL::Catalog.identifier_to_klass(phase: phase, identifier: identifier)
50
- end
51
-
52
- # For a given connector identifier, return the class (either builtin, or from a
53
- # external chronicle gem)
54
- def self.identifier_to_klass(identifier:, phase:)
55
- if BUILTIN[phase].include? identifier
56
- load_builtin_klass(name: identifier, phase: phase)
57
- else
58
- provider, name = identifier.split(':')
59
- name ||= ''
60
- load_provider_klass(provider: provider, name: name, phase: phase)
61
- end
62
- end
63
-
64
- # Returns whether a class is an Extractor, Transformer, or Loader
65
- def phase
66
- ancestors = self.ancestors
67
- return :extractor if ancestors.include? Chronicle::ETL::Extractor
68
- return :transformer if ancestors.include? Chronicle::ETL::Transformer
69
- return :loader if ancestors.include? Chronicle::ETL::Loader
70
- end
71
-
72
- # Returns which third-party provider this connector is associated wtih
73
- def provider
74
- # TODO: needs better convention for a gem reporting its provider name
75
- provider = to_s.split('::')[1].downcase
76
- provider == 'etl' ? 'chronicle' : provider
77
- end
78
-
79
- # Returns whether this connector is a built-in one
80
- def built_in?
81
- to_s.include? 'Chronicle::ETL'
82
- end
83
-
84
- private
85
-
86
- def self.load_builtin_klass(name:, phase:)
87
- klass_str = "Chronicle::ETL::#{name.capitalize}#{phase.capitalize}"
88
- begin
89
- Object.const_get(klass_str)
90
- rescue NameError => e
91
- raise ConnectorNotAvailableError.new("Connector not found", name: name)
92
- end
93
- end
94
-
95
- def self.load_provider_klass(name: '', phase:, provider:)
96
- begin
97
- require "chronicle/#{provider}"
98
- klass_str = "Chronicle::#{provider.capitalize}::#{name.capitalize}#{phase.capitalize}"
99
- Object.const_get(klass_str)
100
- rescue LoadError => e
101
- raise ProviderNotAvailableError.new("Provider '#{provider.capitalize}' could not be loaded", provider: provider)
102
- rescue NameError => e
103
- raise ProviderConnectorNotAvailableError.new("Connector '#{name}' in '#{provider}' could not be found", provider: provider, name: name)
104
- end
105
- end
106
- end
107
- end
108
- end
@@ -1,28 +0,0 @@
1
- module Chronicle
2
- module ETL
3
- module Utils
4
- module JSONAPI
5
- # For a given Chronicle::ETL::Model, serialize it as jsonapi
6
- def self.serialize(record)
7
- return unless record.is_a? Chronicle::ETL::Models::Base
8
-
9
- obj = record.identifier_hash
10
- obj[:attributes] = record.attributes
11
-
12
- relationships = Hash[record.associations.map do |k, v|
13
- if v.is_a?(Array)
14
- data = { data: v.map{ |association| serialize(association) } }
15
- else
16
- data = { data: serialize(v) }
17
- end
18
-
19
- [k, data]
20
- end]
21
-
22
- obj[:relationships] = relationships if relationships.any?
23
- obj
24
- end
25
- end
26
- end
27
- end
28
- end