tallty_import_export 1.1.0 → 1.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72c586f1a3e13625520d1ce6378e478ee8dc6cf0055a16528f63ead86c20794f
4
- data.tar.gz: 857a44c2a36c69347a2baed91855d943a16581427bdd1b562dd02e54d4a7d97c
3
+ metadata.gz: 284928193ebed0e079f44ba98ee7a2f0d51c05f0c1ea5100dd68973940f56369
4
+ data.tar.gz: 75dbf1351c7a08ce445b508ea60aba31da811fcfc87e9355c5f8c710f66be47a
5
5
  SHA512:
6
- metadata.gz: 9ae472d4119ebb57fe5066615d49001ba99a417a067d0586f25010338e7bba1d5fdda737cf8a7892483e68b079af065e21862e87225409f3a7f2e7e0683f8d5f
7
- data.tar.gz: fd6af86be0af8b552d2d5170e86b807a301550e7b7f3e604fa0cef539fe6f4630083a4117a494071bc734f83fb29950425f6cdb147b82e130b978c0a2fc8af6f
6
+ metadata.gz: 8d335d50b6059608dcdb41cc3f44e16f75746d900d698ff1ea3960de8d2541b0fdfadf9b7fceeadef33f70906a3c4673f8247c6aa9406195826f0b45a9977d5e
7
+ data.tar.gz: e72f4ddf2a9bb43f00d031aa74c56723870b63ce0b548110d6c3112a0945dbd21f789759a88834fb1101f24c61e30ce179bd14dea19001c2e4bb81f5e7721c9e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- tallty_import_export (1.0.35)
4
+ tallty_import_export (1.1.1)
5
5
  activesupport
6
6
  attr_json
7
7
  caxlsx
@@ -27,27 +27,31 @@ GEM
27
27
  tzinfo (~> 2.0)
28
28
  attr_json (1.4.0)
29
29
  activerecord (>= 5.0.0, < 7.1)
30
- caxlsx (3.2.0)
30
+ caxlsx (3.3.0)
31
31
  htmlentities (~> 4.3, >= 4.3.4)
32
32
  marcel (~> 1.0)
33
33
  nokogiri (~> 1.10, >= 1.10.4)
34
34
  rubyzip (>= 1.3.0, < 3)
35
35
  concurrent-ruby (1.1.10)
36
+ connection_pool (2.3.0)
36
37
  diff-lcs (1.4.4)
37
38
  htmlentities (4.3.4)
38
- i18n (1.10.0)
39
+ i18n (1.12.0)
39
40
  concurrent-ruby (~> 1.0)
40
41
  marcel (1.0.2)
41
42
  mini_portile2 (2.8.0)
42
- minitest (5.15.0)
43
- nokogiri (1.13.4)
43
+ minitest (5.16.3)
44
+ nokogiri (1.13.9)
44
45
  mini_portile2 (~> 2.8.0)
45
46
  racc (~> 1.4)
46
47
  racc (1.6.0)
47
48
  rake (12.3.3)
48
- redis (4.6.0)
49
- redis-objects (1.5.1)
50
- redis (~> 4.2)
49
+ redis (5.0.5)
50
+ redis-client (>= 0.9.0)
51
+ redis-client (0.10.0)
52
+ connection_pool
53
+ redis-objects (1.7.0)
54
+ redis
51
55
  roo (2.9.0)
52
56
  nokogiri (~> 1)
53
57
  rubyzip (>= 1.3.0, < 3.0.0)
@@ -77,7 +81,7 @@ GEM
77
81
  activesupport (>= 5.0)
78
82
  tallty_form (1.0.0)
79
83
  tallty_duck_record
80
- tzinfo (2.0.4)
84
+ tzinfo (2.0.5)
81
85
  concurrent-ruby (~> 1.0)
82
86
  zip-zip (0.3)
83
87
  rubyzip (>= 1.0.0)
@@ -14,7 +14,7 @@ module TalltyImportExport
14
14
  attr_json :json, :string
15
15
  attr_json :select, ActiveModel::Type::Value.new, array: true
16
16
  attr_json :source, :boolean
17
- attr_json :proc, ActiveModel::Type::Value.new, array: true
17
+ attr_json :proc, ActiveModel::Type::Value.new
18
18
  attr_json :children, self.to_type, array: true
19
19
 
20
20
  attr_accessor :depth, :parent_path, :seq
@@ -6,14 +6,14 @@ module TalltyImportExport
6
6
  end
7
7
 
8
8
  module ClassMethods
9
- def model_headers **args
9
+ def model_headers(**args)
10
10
  columns.map do |column|
11
11
  {
12
12
  key: column.name,
13
13
  name: column.comment || column.name,
14
14
  attr_type: column.type,
15
15
  format: column.type == :string ? :string : nil,
16
- primary_key: column.name == 'id' ? true : false
16
+ primary_key: column.name == 'id',
17
17
  }
18
18
  end
19
19
  end
@@ -2,6 +2,7 @@ module TalltyImportExport
2
2
  class Excel
3
3
  require 'redis-objects'
4
4
  require 'roo'
5
+ require 'roo-xls'
5
6
 
6
7
  attr_reader :uid, :cache
7
8
 
@@ -2,7 +2,7 @@ module TalltyImportExport
2
2
  class Export
3
3
  attr_reader :klass, :context
4
4
 
5
- def initialize klass
5
+ def initialize(klass)
6
6
  @klass = klass
7
7
  @context = Context.new({})
8
8
  end
@@ -34,7 +34,7 @@ module TalltyImportExport
34
34
  # proc: proc或者lamda,支持call,传入 record 和 context
35
35
  # list: 对于list布局的,进行嵌套,生成子表格
36
36
 
37
- def export_xlsx records, **options
37
+ def export_xlsx(records, **options)
38
38
  records = with_scope records
39
39
  process_options(options)
40
40
 
@@ -46,14 +46,16 @@ module TalltyImportExport
46
46
 
47
47
  if @group_by.present?
48
48
  if records.is_a?(Array)
49
- records.group_by { |record| record.send(@group_by)}.each do |key, group_records|
49
+ records.group_by { |record| record.send(@group_by) }.each do |key, group_records|
50
50
  next unless key.present?
51
+
51
52
  @group_key = key
52
53
  export_workbook workbook, group_records, **options
53
54
  end
54
55
  else
55
56
  records.group(@group_by).count.keys.each do |key|
56
57
  next unless key.present?
58
+
57
59
  @group_key = key
58
60
  export_workbook workbook, records.ransack("#{@group_where}" => key).result, **options
59
61
  end
@@ -72,16 +74,16 @@ module TalltyImportExport
72
74
  end
73
75
  end
74
76
 
75
- def export_workbook workbook, association_records, **options
77
+ def export_workbook(workbook, association_records, **options)
76
78
  # excel导出样式
77
79
  alignment = { vertical: :center, horizontal: :center }
78
80
  border = { color: '969696', style: :thin }
79
81
  title1 = workbook.styles.add_style(alignment: alignment, border: border, sz: 12, b: true)
80
- title2 = workbook.styles.add_style(alignment: alignment, border: border, bg_color: "2a5caa", sz: 12, fg_color: "fffffb")
82
+ title2 = workbook.styles.add_style(alignment: alignment, border: border, bg_color: '2a5caa', sz: 12, fg_color: 'fffffb')
81
83
  title3 = workbook.styles.add_style(alignment: alignment.merge(wrap_text: true), border: border, sz: 10)
82
- headers = export_headers_result **options
84
+ headers = export_headers_result(**options)
83
85
 
84
- _sheet_name = respond_to?(:sheet_name) ? self.sheet_name : nil
86
+ _sheet_name = respond_to?(:sheet_name) ? sheet_name : nil
85
87
 
86
88
  workbook.add_worksheet(name: _sheet_name) do |sheet|
87
89
  if respond_to?(:first_header)
@@ -90,7 +92,7 @@ module TalltyImportExport
90
92
  sheet.add_row [first_header], style: title1, height: 30
91
93
  end
92
94
 
93
- sheet.add_row headers.map{|header| header[:name]}, style: title2, height: 25
95
+ sheet.add_row headers.map { |header| header[:name] }, style: title2, height: 25
94
96
 
95
97
  last_row = nil
96
98
  merge_column_hash = {}
@@ -133,12 +135,12 @@ module TalltyImportExport
133
135
  merge_column_hash.each do |col_index, row_arr|
134
136
  row_arr.each do |arr|
135
137
  sheet.merge_cells(
136
- Axlsx::cell_r(col_index, arr.first) + ':' + Axlsx::cell_r(col_index, arr.last)
138
+ Axlsx.cell_r(col_index, arr.first) + ':' + Axlsx.cell_r(col_index, arr.last),
137
139
  )
138
140
  end
139
141
  end
140
142
  end
141
- sheet.column_widths(*headers.map{|header| (header[:width] || @width).to_f})
143
+ sheet.column_widths(*headers.map { |header| (header[:width] || @width).to_f })
142
144
  end
143
145
  end
144
146
 
@@ -147,7 +149,7 @@ module TalltyImportExport
147
149
  {}
148
150
  end
149
151
 
150
- def process_options options = {}
152
+ def process_options(options = {})
151
153
  options = export_options.merge(options).with_indifferent_access
152
154
 
153
155
  @row_height ||= options.delete(:row_height) || 25
@@ -161,30 +163,30 @@ module TalltyImportExport
161
163
  context.params = @params
162
164
  end
163
165
 
164
- def with_scope records
166
+ def with_scope(records)
165
167
  records
166
168
  end
167
169
 
168
- def export_headers_result **options
170
+ def export_headers_result(**options)
169
171
  if @headers.present? && @group_key.blank?
170
172
  headers_hash = @headers.to_h { |header| [header.with_indifferent_access[:key], header] }.with_indifferent_access
171
173
  export_headers(**options.symbolize_keys).select do |_header|
172
174
  _header.with_indifferent_access[:key].to_s.in?(headers_hash.keys)
173
175
  end.map do |_header|
174
176
  _header = _header.with_indifferent_access
175
- _header.merge(headers_hash[_header[:key]].delete_if { |k, v| v.blank? })
177
+ _header.merge(headers_hash[_header[:key]].delete_if { |_k, v| v.blank? })
176
178
  end
177
179
  else
178
180
  @headers = export_headers(**options.symbolize_keys)
179
181
  end
180
182
  end
181
183
 
182
- def export_headers **args
184
+ def export_headers(**args)
183
185
  @headers || klass.try(:headers) || klass.try(:model_headers)
184
186
  end
185
187
 
186
188
  # 处理一个记录的数据
187
- def handle_data record, header, index=0, **opts
189
+ def handle_data(record, header, index = 0, **opts)
188
190
  data =
189
191
  if header[:key] == '_index'
190
192
  index
@@ -200,28 +202,36 @@ module TalltyImportExport
200
202
  data = handle_format(data, header, **opts)
201
203
  data = handle_data_type(data, **opts)
202
204
  data = handle_select(data, header, **opts)
203
- rescue
205
+ rescue StandardError
204
206
  ''
205
207
  end
206
208
 
207
- def try_chain record, arr
209
+ def try_chain(record, arr)
208
210
  arr.reduce(record) do |r, m|
209
211
  if r.is_a?(Array)
210
212
  r.try(m) || r.try(:[], m.to_i)
211
213
  else
212
- r.try(:[], m) || r.try(:[], m.to_sym) || r.try(m)
214
+ begin
215
+ r.try(:[], m)
216
+ rescue StandardError
217
+ nil
218
+ end || begin
219
+ r.try(:[], m.to_sym)
220
+ rescue StandardError
221
+ nil
222
+ end || r.try(m)
213
223
  end
214
224
  end
215
225
  end
216
226
 
217
- def try_method record, method, prefix: nil
227
+ def try_method(record, method, prefix: nil)
218
228
  prefix_arr = prefix.to_s.split(/\./)
219
229
  arr = method.to_s.split(/\./)
220
230
  try_chain record, prefix_arr + arr
221
231
  end
222
232
 
223
233
  # 根据数据类型 attr_type 进行数据的格式化
224
- def handle_format data, header, **opts
234
+ def handle_format(data, header, **opts)
225
235
  case header[:attr_type].to_s
226
236
  when 'string'
227
237
  data.to_s
@@ -234,7 +244,7 @@ module TalltyImportExport
234
244
  end
235
245
  end
236
246
 
237
- def handle_data_type data, **opts
247
+ def handle_data_type(data, **opts)
238
248
  if data.is_a?(Time)
239
249
  data.in_time_zone.strftime('%F %H:%M')
240
250
  elsif data.is_a?(Date)
@@ -257,7 +267,7 @@ module TalltyImportExport
257
267
  end
258
268
  end
259
269
 
260
- def handle_select data, header, **opts
270
+ def handle_select(data, header, **opts)
261
271
  if header[:select].present?
262
272
  select_option = header[:select].find { |option| option[:value].to_s == data.to_s }
263
273
  select_option.present? ? select_option[:label] : data
@@ -126,7 +126,7 @@ module TalltyImportExport
126
126
 
127
127
  def export_headers_result **options
128
128
  @headers = options.symbolize_keys[:headers]
129
- super(**options)
129
+ @headers = super(**options)
130
130
  @headers = TalltyImportExport::Attr::ExportHeader.new({ items: @headers })
131
131
  end
132
132
 
@@ -1,9 +1,10 @@
1
1
  module TalltyImportExport
2
2
  class Import
3
3
  require 'roo'
4
+ require 'roo-xls'
4
5
  attr_reader :klass, :context, :primary_keys, :associations
5
6
 
6
- def initialize klass
7
+ def initialize(klass)
7
8
  @klass = klass
8
9
  @context = Context.new({})
9
10
  end
@@ -20,13 +21,41 @@ module TalltyImportExport
20
21
  # skip: 用来综合使用的数据,但是不导入
21
22
 
22
23
  # xlsx_file 为 file path or file object or TalltyImportExport::Excel.new
23
- def import_xlsx xlsx_file, associations, **options
24
+ def import_xlsx(xlsx_file, associations, **options)
24
25
  process_xlsx_line_info(xlsx_file, associations, **options) do |line_info, associations|
25
26
  process_line_info(line_info, associations)
26
27
  end
27
28
  end
28
29
 
29
- def exchange_to_ids xlsx_file, associations, **options
30
+ # 导出excel的空模版
31
+ def export_template_xlsx(**options)
32
+ origin_options = options.dup
33
+ process_options(options)
34
+
35
+ Axlsx::Package.new do |pack|
36
+ pack.use_shared_strings = true
37
+ workbook = pack.workbook
38
+
39
+ export_workbook workbook, **origin_options
40
+
41
+ file_path = File.join(Rails.root, 'public', 'import')
42
+ FileUtils.mkdir_p(file_path) unless Dir.exist?(file_path)
43
+ file_name = "#{Time.now.strftime('%Y%m%d%H%M%S')}#{@filename}.xlsx"
44
+ file_path_with_name = File.join(file_path, file_name)
45
+ pack.serialize(file_path_with_name)
46
+ return file_path_with_name
47
+ end
48
+ end
49
+
50
+ def export_workbook(workbook, **options)
51
+ export_instance = TalltyImportExport::Export.new(@klass)
52
+ opts = options.symbolize_keys.merge({ headers: @headers })
53
+ Rails.logger.info opts
54
+ export_instance.process_options(opts)
55
+ export_instance.export_workbook(workbook, [], **opts)
56
+ end
57
+
58
+ def exchange_to_ids(xlsx_file, associations, **options)
30
59
  errors = []
31
60
  ids = []
32
61
  process_xlsx_line_info(xlsx_file, associations, **options) do |line_info, associations|
@@ -37,33 +66,34 @@ module TalltyImportExport
37
66
  error_msg = errors.map do |line_info|
38
67
  "【#{@primary_keys.map { |key| line_info[key] }.join(' - ')}】"
39
68
  end.join(' ')
40
- raise RecordNotFountError.new("以下内容未找到: #{error_msg}")
69
+ raise RecordNotFountError, "以下内容未找到: #{error_msg}"
41
70
  end
42
- return ids.compact.uniq
71
+ ids.compact.uniq
43
72
  end
44
73
 
45
- def process_xlsx_line_info xlsx_file, associations, **options
74
+ def process_xlsx_line_info(xlsx_file, associations, **options)
46
75
  @associations = associations
47
76
  # 先处理获取出来Excel每行的数据, line_info
48
77
  process_options(options)
49
78
 
50
- if TalltyImportExport::Excel === xlsx_file
79
+ if xlsx_file.is_a?(TalltyImportExport::Excel)
51
80
  xlsx_file.rows.each_with_excel_hash(@excel_hash) do |line_info|
52
81
  yield line_info.with_indifferent_access, associations
53
82
  end
54
83
  else
55
84
  file_path = xlsx_file.is_a?(String) ? xlsx_file : xlsx_file.path
56
- xlsx = ::Roo::Excelx.new(file_path)
85
+ xlsx = ::Roo::Spreadsheet.open(file_path, extension: File.extname(file_path) == '.xls' ? :xls : :xlsx)
57
86
  xlsx.each_with_pagename do |_sheetname, sheet|
58
87
  sheet.each(**@excel_hash).with_index do |line_info, index|
59
88
  next if index == 0
89
+
60
90
  yield line_info.with_indifferent_access, associations
61
91
  end
62
92
  end
63
93
  end
64
94
  end
65
95
 
66
- def import_data data, associations, **options
96
+ def import_data(data, associations, **options)
67
97
  process_options(options)
68
98
  TalltyImportExport::Excel::Rows.new(data).each_with_excel_hash(@excel_hash) do |line_info|
69
99
  process_line_info(line_info.with_indifferent_access, associations)
@@ -74,25 +104,25 @@ module TalltyImportExport
74
104
  TalltyImportExport::Excel
75
105
  end
76
106
 
77
- def process_options options
107
+ def process_options(options)
78
108
  options = import_options.merge(options).with_indifferent_access
79
- @headers = options.delete(:headers) || import_headers
109
+ @headers = options.delete(:headers) || import_headers(**options)
80
110
  @primary_keys = options.delete(:primary_keys) || @headers.map { |header| header[:primary_key] ? header[:key].to_sym : nil }.compact
81
111
  @skip_keys = options.delete(:skip_keys) || @headers.map { |header| header[:skip] ? header[:key].to_sym : nil }.compact
82
112
  @params = options
83
113
  context.params = @params
84
114
 
85
- @excel_hash = @headers.reduce({}) do |h, header|
115
+ @excel_hash = @headers.each_with_object({}) do |header, h|
86
116
  h[header[:key].to_sym] = header[:name]
87
- h
88
117
  end
89
118
 
90
119
  options
91
120
  end
92
121
 
93
- def process_line_info line_info, associations
122
+ def process_line_info(line_info, associations)
94
123
  # 去除空行内容
95
124
  return unless line_info.values.any?(&:present?)
125
+
96
126
  context.line_info = line_info
97
127
  # 转换处理导入的数据格式
98
128
  line_info = convert_data(line_info)
@@ -104,14 +134,16 @@ module TalltyImportExport
104
134
  context.last_line_info = line_info
105
135
  end
106
136
 
107
- def convert_data line_info
137
+ def convert_data(line_info)
108
138
  info = line_info.with_indifferent_access
109
- import_headers_result.reduce({}) do |h, header|
139
+ import_headers_result.each_with_object({}.with_indifferent_access) do |header, h|
110
140
  k = header[:key]
141
+ k_arr = k.to_s.split(/\./)
111
142
  v = info[k]
112
143
  # header[:convert] = handle_xxx
113
144
  # handle_xxx(val, processing_line_info, raw_line_info)
114
145
  val = header[:convert] ? send(header[:convert], v, h, info) : v
146
+ val.strip! if val.is_a?(String)
115
147
  if header[:json]
116
148
  h[header[:json]] ||= {}
117
149
  h[header[:json]][k] = val
@@ -120,15 +152,20 @@ module TalltyImportExport
120
152
  elsif header[:finder]
121
153
  # $SAFE = 2
122
154
  h[k.to_sym] = eval header[:finder]
155
+ elsif k_arr.size > 1
156
+ # hash设置
157
+ attr = k_arr.first
158
+ val = { k_arr[1..-1].join('.') => v }.to_nested_hash
159
+ h[attr.to_sym] ||= {}
160
+ h[attr.to_sym].merge! val
123
161
  else
124
162
  h[k.to_sym] = val
125
163
  end
126
- h
127
164
  end.with_indifferent_access
128
165
  end
129
166
 
130
167
  # 通过转换后,数据是否合法,如果不合法,则直接跳过不处理这个数据
131
- def valid? line_info
168
+ def valid?(line_info)
132
169
  true
133
170
  end
134
171
 
@@ -141,12 +178,12 @@ module TalltyImportExport
141
178
  _header.with_indifferent_access[:key].to_s.in?(headers_hash.keys)
142
179
  end.map do |_header|
143
180
  _header = _header.with_indifferent_access
144
- _header.merge(headers_hash[_header[:key]].delete_if { |k, v| v.blank? })
181
+ _header.merge(headers_hash[_header[:key]].delete_if { |_k, v| v.blank? })
145
182
  end
146
183
  else
147
- @headers = import_headers(**options.symbolize_keys)
184
+ @headers = import_headers
148
185
  end
149
- rescue
186
+ rescue StandardError
150
187
  @headers
151
188
  end
152
189
 
@@ -154,8 +191,8 @@ module TalltyImportExport
154
191
  {}
155
192
  end
156
193
 
157
- def import_headers **args
158
- @headers || klass.try(:headers) || klass.try(:model_headers) || (raise ArgumentError.new('missing import_headers'))
194
+ def import_headers(**args)
195
+ @headers || klass.try(:headers) || klass.try(:model_headers) || (raise ArgumentError, 'missing import_headers')
159
196
  end
160
197
 
161
198
  # # 只保留 key, name, json, 合并到 import_header
@@ -182,12 +219,12 @@ module TalltyImportExport
182
219
  # @headers = result
183
220
  # end
184
221
 
185
- def skip val, processing_line_info, raw_line_info
222
+ def skip(val, processing_line_info, raw_line_info)
186
223
  # do nothing there, use for header[:convert]
187
224
  end
188
225
 
189
226
  ### 这个方法是可以由复杂业务进行重载的 ###
190
- def import_record line_info, associations
227
+ def import_record(line_info, associations)
191
228
  if primary_keys.present?
192
229
  _record = associations.find_or_initialize_by(line_info.clone.extract!(*primary_keys))
193
230
  _record.update!(line_info.clone.except!(*primary_keys, *@skip_keys))
@@ -196,23 +233,26 @@ module TalltyImportExport
196
233
  end
197
234
  end
198
235
 
199
- def exchange_line_info_to_id line_info, associations, errors
236
+ def exchange_line_info_to_id(line_info, associations, errors)
200
237
  # 去除空行内容
201
238
  return unless line_info.values.any?(&:present?)
239
+
202
240
  context.line_info = line_info
203
241
 
204
242
  return unless primary_keys.present?
243
+
205
244
  ids = associations.where(line_info.clone.extract!(*primary_keys)).pluck(:id)
206
245
 
207
246
  context.last_line_info = line_info
208
247
 
209
248
  errors << line_info unless ids[0]
210
- return ids[0]
249
+ ids[0]
211
250
  end
212
251
 
213
252
  class RecordNotFountError < StandardError
214
253
  attr_accessor :message
215
- def initialize message
254
+
255
+ def initialize(message)
216
256
  @message = message
217
257
  super()
218
258
  end
@@ -28,6 +28,10 @@ module TalltyImportExport
28
28
  def exchange_to_ids xlsx_file, associations, **options
29
29
  import_instance.exchange_to_ids(xlsx_file, associations, **options)
30
30
  end
31
+
32
+ def export_template_xlsx **options
33
+ import_instance.export_template_xlsx(**options)
34
+ end
31
35
  end
32
36
  end
33
37
  end
@@ -1,3 +1,3 @@
1
1
  module TalltyImportExport
2
- VERSION = "1.1.0"
2
+ VERSION = '1.1.3'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tallty_import_export
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - liyijie
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-05-10 00:00:00.000000000 Z
11
+ date: 2022-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: zip-zip