combine_pdf 0.2.21 → 0.2.27

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.
@@ -5,223 +5,382 @@
5
5
  ## is subject to the same license.
6
6
  ########################################################
7
7
 
8
-
9
-
10
-
11
-
12
-
13
8
  module CombinePDF
14
-
15
-
16
- class PDF
17
-
18
- protected
19
-
20
- include Renderer
21
-
22
- # @private
23
- # Some PDF objects contain references to other PDF objects.
24
- #
25
- # this function adds the references contained in "object", but DOESN'T add the object itself.
26
- #
27
- # this is used for internal operations, such as injectng data using the << operator.
28
- def add_referenced(object, dup_pages = true)
29
- # add references but not root
30
- case
31
- when object.is_a?(Array)
32
- object.each {|it| add_referenced(it, dup_pages)}
33
- return true
34
- when object.is_a?(Hash)
35
- # first if statement is actually a workaround for a bug in Acrobat Reader, regarding duplicate pages.
36
- if dup_pages && object[:is_reference_only] && object[:referenced_object] && object[:referenced_object].is_a?(Hash) && object[:referenced_object][:Type] == :Page
37
- if @objects.find_index object[:referenced_object]
38
- @objects << (object[:referenced_object] = object[:referenced_object].dup)
39
- else
40
- @objects << object[:referenced_object]
41
- end
42
- elsif object[:is_reference_only] && object[:referenced_object]
43
- found_at = @objects.find_index object[:referenced_object]
44
- if found_at
45
- #if the objects are equal, they might still be different objects!
46
- # so, we need to make sure they are the same object for the pointers to effect id numbering
47
- # and formatting operations.
48
- object[:referenced_object] = @objects[found_at]
49
- # stop this path, there is no need to run over the Hash's keys and values
50
- return true
51
- else
52
- # stop if page propegation is false
53
- return true if !dup_pages && object[:referenced_object][:Type] == :Page
54
- # @objects.include? object[:referenced_object] is bound to be false
55
- # the object wasn't found - add it to the @objects array
56
- @objects << object[:referenced_object]
57
- end
58
-
59
- end
60
- object.each do |k, v|
61
- add_referenced(v, dup_pages) unless k == :Parent
62
- end
63
- else
64
- return false
65
- end
66
- true
67
- end
68
-
69
- # @private
70
- def rebuild_catalog(*with_pages)
71
- # # build page list v.1 Slow but WORKS
72
- # # Benchmark testing value: 26.708394
73
- # old_catalogs = @objects.select {|obj| obj.is_a?(Hash) && obj[:Type] == :Catalog}
74
- # old_catalogs ||= []
75
- # page_list = []
76
- # PDFOperations._each_object(old_catalogs,false) { |p| page_list << p if p.is_a?(Hash) && p[:Type] == :Page }
77
-
78
- # build page list v.2 faster, better, and works
79
- # Benchmark testing value: 0.215114
80
- page_list = pages
81
-
82
- # add pages to catalog, if requested
83
- page_list.push(*with_pages) unless with_pages.empty?
84
-
85
- # build new Pages object
86
- pages_object = {Type: :Pages, Count: page_list.length, Kids: page_list.map {|p| {referenced_object: p, is_reference_only: true} } }
87
-
88
- # rebuild/rename the names dictionary
89
- rebuild_names
90
- # build new Catalog object
91
- catalog_object = {Type: :Catalog, Pages: {referenced_object: pages_object, is_reference_only: true}, Names: {referenced_object: @names, is_reference_only: true}}
92
- catalog_object[:ViewerPreferences] = @viewer_preferences unless @viewer_preferences.empty?
93
-
94
- # rebuild/rename the forms dictionary
95
- if @forms_data.nil? || @forms_data.empty?
96
- @forms_data = nil
97
- else
98
- @forms_data = {referenced_object: actual_value(@forms_data), is_reference_only: true}
99
- catalog_object[:AcroForm] = @forms_data
100
- end
101
-
102
-
103
- # point old Pages pointers to new Pages object
104
- ## first point known pages objects - enough?
105
- pages.each {|p| p[:Parent] = { referenced_object: pages_object, is_reference_only: true} }
106
- ## or should we, go over structure? (fails)
107
- # each_object {|obj| obj[:Parent][:referenced_object] = pages_object if obj.is_a?(Hash) && obj[:Parent].is_a?(Hash) && obj[:Parent][:referenced_object] && obj[:Parent][:referenced_object][:Type] == :Pages}
108
-
109
- # remove old catalog and pages objects
110
- @objects.reject! {|obj| obj.is_a?(Hash) && (obj[:Type] == :Catalog || obj[:Type] == :Pages) }
111
-
112
- # inject new catalog and pages objects
113
- @objects << pages_object
114
- @objects << catalog_object
115
-
116
- catalog_object
117
- end
118
-
119
- def names_object
120
- @names
121
- end
122
- def forms_data
123
- @forms_data
124
- end
125
-
126
- # @private
127
- # this is an alternative to the rebuild_catalog catalog method
128
- # this method is used by the to_pdf method, for streamlining the PDF output.
129
- # there is no point is calling the method before preparing the output.
130
- def rebuild_catalog_and_objects
131
- catalog = rebuild_catalog
132
- @objects.clear
133
- @objects << @info
134
- add_referenced @info
135
- @objects << catalog
136
- add_referenced catalog[:Pages]
137
- add_referenced catalog[:Names], false
138
- catalog
139
- end
140
-
141
- def get_existing_catalogs
142
- (@objects.select {|obj| obj.is_a?(Hash) && obj[:Type] == :Catalog}) || (@objects.select {|obj| obj.is_a?(Hash) && obj[:Type] == :Page})
143
- end
144
-
145
-
146
-
147
- # end
148
- # @private
149
- def renumber_object_ids(start = nil)
150
- @set_start_id = start || @set_start_id
151
- start = @set_start_id
152
- history = {}
153
- @objects.each do |obj|
154
- obj[:indirect_reference_id] = start
155
- start += 1
156
- end
157
- end
158
- def remove_old_ids
159
- @objects.each {|obj| obj.delete(:indirect_reference_id); obj.delete(:indirect_generation_number)}
160
- end
161
-
162
- def rebuild_names name_tree = nil, base = "CombinePDF_0000000"
163
- if name_tree
164
- dic = []
165
- case name_tree
166
- when Array
167
- if name_tree[0].is_a? String
168
- (name_tree.length/2).times do |i|
169
- dic << (name_tree[i*2].clear << base.next!)
170
- dic << name_tree[(i*2) + 1]
171
- end
172
- else
173
- name_tree.each {|kid| dic.concat rebuild_names(kid, base) }
174
- end
175
- when Hash
176
- if name_tree[:Kids]
177
- dic.concat rebuild_names(name_tree[:Kids], base)
178
- elsif name_tree[:Names]
179
- dic.concat rebuild_names(name_tree[:Names], base)
180
- elsif name_tree[:referenced_object]
181
- dic.concat rebuild_names(name_tree[:referenced_object], base)
182
- end
183
- end
184
- return dic
185
- end
186
- @names.keys.each do |k|
187
- @names[k] = {referenced_object: { Names: rebuild_names(@names[k], base) } , is_reference_only: true} unless k == :Type
188
- end
189
- end
190
-
191
- # @private
192
- # this method reviews a Hash an updates it by merging Hash data,
193
- # preffering the new over the old.
194
- def self.hash_merge_new_no_page key, old_data, new_data
195
- if old_data.is_a? Hash
196
- return old_data if old_data[:Type] == :Page
197
- old_data.merge( new_data, &( @hash_merge_new_no_page_proc ||= self.method(:hash_merge_new_no_page) ) )
198
- elsif old_data.is_a? Array
199
- old_data + new_data
200
- else
201
- new_data
202
- end
203
- end
204
-
205
-
206
- private
207
-
208
- def renaming_dictionary object = nil, dictionary = {}
209
- object ||= @names
210
- case object
211
- when Array
212
- object.length.times {|i| object[i].is_a?(String) ? (dictionary[object[i]] = (dictionary.last || "Random_0001").next) : renaming_dictionary(object[i], dictionary) }
213
- when Hash
214
- object.values.each {|v| renaming_dictionary v, dictionary }
215
- end
216
- end
217
-
218
- def rename_object object, dictionary
219
- case object
220
- when Array
221
- object.length.times {|i| }
222
- when Hash
223
- end
224
- end
225
-
226
- end
9
+ class PDF
10
+ protected
11
+
12
+ include Renderer
13
+
14
+ # RECORSIVE_PROTECTION = { Parent: true, Last: true}.freeze
15
+
16
+ # @private
17
+ # Some PDF objects contain references to other PDF objects.
18
+ #
19
+ # this function adds the references contained in `@objects`.
20
+ #
21
+ # this is used for internal operations, such as injectng data using the << operator.
22
+ def add_referenced
23
+ # add references but not root
24
+ should_resolve = @objects.dup
25
+ dup_pages = nil
26
+ resolved = [].to_set
27
+ while should_resolve.any?
28
+ obj = should_resolve.pop
29
+ if obj.is_a?(Hash)
30
+ next if resolved.include? obj.object_id
31
+ resolved << obj.object_id
32
+ if obj[:referenced_object]
33
+ tmp = @objects.find_index(obj[:referenced_object])
34
+ if tmp
35
+ tmp = @objects[tmp]
36
+ obj[:referenced_object] = tmp
37
+ else
38
+ tmp = obj[:referenced_object]
39
+ should_resolve << tmp
40
+ @objects << tmp
41
+ end
42
+ else
43
+ obj.keys.each { |k| should_resolve << obj[k] unless k == :Parent || resolved.include?(obj[k].object_id) || !obj[k].is_a?(Enumerable) }
44
+ end
45
+ elsif obj.is_a?(Array)
46
+ next if resolved.include? obj.object_id
47
+ resolved << obj.object_id
48
+ should_resolve.concat obj
49
+ end
50
+ end
51
+ resolved.clear
52
+ end
53
+
54
+ # # @private
55
+ # # Some PDF objects contain references to other PDF objects.
56
+ # #
57
+ # # this function adds the references contained in "object", but DOESN'T add the object itself.
58
+ # #
59
+ # # this is used for internal operations, such as injectng data using the << operator.
60
+ # def add_referenced(object, dup_pages = true)
61
+ # # add references but not root
62
+ # if object.is_a?(Array)
63
+ # object.each { |it| add_referenced(it, dup_pages) }
64
+ # return true
65
+ # elsif object.is_a?(Hash)
66
+ # # first if statement is actually a workaround for a bug in Acrobat Reader, regarding duplicate pages.
67
+ # if dup_pages && object[:is_reference_only] && object[:referenced_object] && object[:referenced_object].is_a?(Hash) && object[:referenced_object][:Type] == :Page
68
+ # if @objects.find_index object[:referenced_object]
69
+ # @objects << (object[:referenced_object] = object[:referenced_object].dup)
70
+ # else
71
+ # @objects << object[:referenced_object]
72
+ # end
73
+ # elsif object[:is_reference_only] && object[:referenced_object]
74
+ # found_at = @objects.find_index object[:referenced_object]
75
+ # if found_at
76
+ # # if the objects are equal, they might still be different objects!
77
+ # # so, we need to make sure they are the same object for the pointers to effect id numbering
78
+ # # and formatting operations.
79
+ # object[:referenced_object] = @objects[found_at]
80
+ # # stop this path, there is no need to run over the Hash's keys and values
81
+ # return true
82
+ # else
83
+ # # stop if page propegation is false
84
+ # return true if !dup_pages && object[:referenced_object][:Type] == :Page
85
+ # # @objects.include? object[:referenced_object] is bound to be false
86
+ # # the object wasn't found - add it to the @objects array
87
+ # @objects << object[:referenced_object]
88
+ # end
89
+ #
90
+ # end
91
+ # object.each do |k, v|
92
+ # add_referenced(v, dup_pages) unless RECORSIVE_PROTECTION[k]
93
+ # end
94
+ # else
95
+ # return false
96
+ # end
97
+ # true
98
+ # end
99
+
100
+ # @private
101
+ def rebuild_catalog(*with_pages)
102
+ # # build page list v.1 Slow but WORKS
103
+ # # Benchmark testing value: 26.708394
104
+ # old_catalogs = @objects.select {|obj| obj.is_a?(Hash) && obj[:Type] == :Catalog}
105
+ # old_catalogs ||= []
106
+ # page_list = []
107
+ # PDFOperations._each_object(old_catalogs,false) { |p| page_list << p if p.is_a?(Hash) && p[:Type] == :Page }
108
+
109
+ # build page list v.2 faster, better, and works
110
+ # Benchmark testing value: 0.215114
111
+ page_list = pages
112
+
113
+ # add pages to catalog, if requested
114
+ page_list.concat(with_pages) unless with_pages.empty?
115
+
116
+ # build new Pages object
117
+ pages_object = { Type: :Pages, Count: page_list.length, Kids: page_list.map { |p| { referenced_object: p, is_reference_only: true } } }
118
+
119
+ # rebuild/rename the names dictionary
120
+ rebuild_names
121
+ # build new Catalog object
122
+ catalog_object = { Type: :Catalog,
123
+ Pages: { referenced_object: pages_object, is_reference_only: true },
124
+ Names: { referenced_object: @names, is_reference_only: true },
125
+ Outlines: { referenced_object: @outlines, is_reference_only: true } }
126
+ catalog_object[:ViewerPreferences] = @viewer_preferences unless @viewer_preferences.empty?
127
+
128
+ # rebuild/rename the forms dictionary
129
+ if @forms_data.nil? || @forms_data.empty?
130
+ @forms_data = nil
131
+ else
132
+ @forms_data = { referenced_object: (@forms_data[:referenced_object] || @forms_data), is_reference_only: true }
133
+ catalog_object[:AcroForm] = @forms_data
134
+ end
135
+
136
+ # point old Pages pointers to new Pages object
137
+ ## first point known pages objects - enough?
138
+ pages.each { |p| p[:Parent] = { referenced_object: pages_object, is_reference_only: true } }
139
+ ## or should we, go over structure? (fails)
140
+ # each_object {|obj| obj[:Parent][:referenced_object] = pages_object if obj.is_a?(Hash) && obj[:Parent].is_a?(Hash) && obj[:Parent][:referenced_object] && obj[:Parent][:referenced_object][:Type] == :Pages}
141
+
142
+ # remove old catalog and pages objects
143
+ @objects.reject! { |obj| obj.is_a?(Hash) && (obj[:Type] == :Catalog || obj[:Type] == :Pages) }
144
+
145
+ # inject new catalog and pages objects
146
+ @objects << pages_object
147
+ @objects << catalog_object
148
+
149
+ catalog_object
150
+ end
151
+
152
+ def names_object
153
+ @names
154
+ end
155
+
156
+ def outlines_object
157
+ @outlines
158
+ end
159
+ # def forms_data
160
+ # @forms_data
161
+ # end
162
+
163
+ # @private
164
+ # this is an alternative to the rebuild_catalog catalog method
165
+ # this method is used by the to_pdf method, for streamlining the PDF output.
166
+ # there is no point is calling the method before preparing the output.
167
+ def rebuild_catalog_and_objects
168
+ catalog = rebuild_catalog
169
+ @objects.clear
170
+ @objects << @info
171
+ @objects << catalog
172
+ # fix Acrobat Reader issue with page reference uniqueness (must be unique or older Acrobat Reader fails)
173
+ catalog[:Pages][:referenced_object][:Kids].each do |page|
174
+ tmp = page[:referenced_object]
175
+ tmp = page[:referenced_object] = tmp.dup if @objects.include? tmp
176
+ @objects << tmp
177
+ end
178
+ # adds every referenced object to the @objects (root), addition is performed as pointers rather then copies
179
+ # puts (Benchmark.measure do
180
+ add_referenced
181
+ # end)
182
+ # @objects << @info
183
+ # add_referenced @info
184
+ # add_referenced catalog
185
+ # add_referenced catalog[:Pages]
186
+ # add_referenced catalog[:Names], false
187
+ # add_referenced catalog[:Outlines], false
188
+ # add_referenced catalog[:AcroForm], false
189
+ catalog
190
+ end
191
+
192
+ def get_existing_catalogs
193
+ (@objects.select { |obj| obj.is_a?(Hash) && obj[:Type] == :Catalog }) || (@objects.select { |obj| obj.is_a?(Hash) && obj[:Type] == :Page })
194
+ end
195
+
196
+ # end
197
+ # @private
198
+ def renumber_object_ids(start = nil)
199
+ @set_start_id = start || @set_start_id
200
+ start = @set_start_id
201
+ history = {}
202
+ @objects.each do |obj|
203
+ obj[:indirect_reference_id] = start
204
+ start += 1
205
+ end
206
+ end
207
+
208
+ def remove_old_ids
209
+ @objects.each { |obj| obj.delete(:indirect_reference_id); obj.delete(:indirect_generation_number) }
210
+ end
211
+
212
+ POSSIBLE_NAME_TREES = [:Dests, :AP, :Pages, :IDS, :Templates, :URLS, :Pages].to_set.freeze
213
+
214
+ def rebuild_names(name_tree = nil, base = 'CombinePDF_0000000')
215
+ if name_tree
216
+ return nil unless name_tree.is_a?(Hash)
217
+ name_tree = name_tree[:referenced_object] || name_tree
218
+ dic = []
219
+ # map a names tree and return a valid name tree. Do not recourse.
220
+ should_resolve = [name_tree[:Kids], name_tree[:Names]]
221
+ resolved = [].to_set
222
+ while should_resolve.any?
223
+ pos = should_resolve.pop
224
+ if pos.is_a? Array
225
+ next if resolved.include?(pos.object_id)
226
+ if pos[0].is_a? String
227
+ (pos.length / 2).times do |i|
228
+ dic << (pos[i * 2].clear << base.next!)
229
+ dic << (pos[(i * 2) + 1].is_a?(Array) ? { is_reference_only: true, referenced_object: { indirect_without_dictionary: pos[(i * 2) + 1] } } : pos[(i * 2) + 1])
230
+ # dic << pos[(i * 2) + 1]
231
+ end
232
+ else
233
+ should_resolve.concat pos
234
+ end
235
+ elsif pos.is_a? Hash
236
+ pos = pos[:referenced_object] || pos
237
+ next if resolved.include?(pos.object_id)
238
+ should_resolve << pos[:Kids] if pos[:Kids]
239
+ should_resolve << pos[:Names] if pos[:Names]
240
+ end
241
+ resolved << pos.object_id
242
+ end
243
+ return { referenced_object: { Names: dic }, is_reference_only: true }
244
+ end
245
+ @names ||= @names[:referenced_object]
246
+ new_names = { Type: :Names }.dup
247
+ POSSIBLE_NAME_TREES.each do |ntree|
248
+ if @names[ntree]
249
+ new_names[ntree] = rebuild_names(@names[ntree], base)
250
+ @names[ntree].clear
251
+ end
252
+ end
253
+ @names.clear
254
+ @names = new_names
255
+ end
256
+
257
+ # @private
258
+ # this method reviews a Hash an updates it by merging Hash data,
259
+ # preffering the new over the old.
260
+ def self.hash_merge_new_no_page(_key, old_data, new_data)
261
+ if old_data.is_a? Hash
262
+ return old_data if old_data[:Type] == :Page
263
+ old_data.merge(new_data, &(@hash_merge_new_no_page_proc ||= method(:hash_merge_new_no_page)))
264
+ elsif old_data.is_a? Array
265
+ old_data + new_data
266
+ else
267
+ new_data
268
+ end
269
+ end
270
+
271
+ # Merges 2 outlines by appending one to the end or start of the other.
272
+ # old_data - the main outline, which is also the one that will be used in the resulting PDF.
273
+ # new_data - the outline to be appended
274
+ # position - an integer representing the position where a PDF is being inserted.
275
+ # This method only differentiates between inserted at the beginning, or not.
276
+ # Not at the beginning, means the new outline will be added to the end of the original outline.
277
+ # An outline base node (tree base) has :Type, :Count, :First, :Last
278
+ # Every node within the outline base node's :First or :Last can have also have the following pointers to other nodes:
279
+ # :First or :Last (only if the node has a subtree / subsection)
280
+ # :Parent (the node's parent)
281
+ # :Prev, :Next (previous and next node)
282
+ # Non-node-pointer data in these nodes:
283
+ # :Title - the node's title displayed in the PDF outline
284
+ # :Count - Number of nodes in it's subtree (0 if no subtree)
285
+ # :Dest - node link destination (if the node is linking to something)
286
+ def merge_outlines(old_data, new_data, position)
287
+ old_data = actual_object(old_data)
288
+ new_data = actual_object(new_data)
289
+ if old_data.nil? || old_data.empty? || old_data[:First].nil?
290
+ # old_data is a reference to the actual object,
291
+ # so if we update old_data, we're done, no need to take any further action
292
+ old_data.update new_data
293
+ elsif new_data.nil? || new_data.empty? || new_data[:First].nil?
294
+ return old_data
295
+ else
296
+ new_data = new_data.dup # avoid old data corruption
297
+ # number of outline nodes, after the merge
298
+ old_data[:Count] = old_data[:Count].to_i + new_data[:Count].to_i
299
+ # walk the Hash here ...
300
+ # I'm just using the start / end insert-position for now...
301
+ # first - is going to be the start of the outline base node's :First, after the merge
302
+ # last - is going to be the end of the outline base node's :Last, after the merge
303
+ # median - the start of what will be appended to the end of the outline base node's :First
304
+ # parent - the outline base node of the resulting merged outline
305
+ # FIXME implement the possibility to insert somewhere in the middle of the outline
306
+ prev = nil
307
+ pos = first = actual_object(((position != 0) ? old_data : new_data)[:First])
308
+ last = actual_object(((position != 0) ? new_data : old_data)[:Last])
309
+ median = { is_reference_only: true, referenced_object: actual_object(((position != 0) ? new_data : old_data)[:First]) }
310
+ old_data[:First] = { is_reference_only: true, referenced_object: first }
311
+ old_data[:Last] = { is_reference_only: true, referenced_object: last }
312
+ parent = { is_reference_only: true, referenced_object: old_data }
313
+ while pos
314
+ # walking through old_data here and updating the :Parent as we go,
315
+ # this updates the inserted new_data :Parent's as well once it is appended and the
316
+ # loop keeps walking the appended data.
317
+ pos[:Parent] = parent if pos[:Parent]
318
+ # connect the two outlines
319
+ # if there is no :Next, the end of the outline base node's :First is reached and this is
320
+ # where the new data gets appended, the same way you would append to a two-way linked list.
321
+ if pos[:Next].nil?
322
+ median[:referenced_object][:Prev] = { is_reference_only: true, referenced_object: prev } if median
323
+ pos[:Next] = median
324
+ # midian becomes 'nil' because this loop keeps going after the appending is done,
325
+ # to update the parents of the appended tree and we wouldn't want to keep appending it infinitely.
326
+ median = nil
327
+ end
328
+ # iterating over the outlines main nodes (this is not going into subtrees)
329
+ # while keeping every rotations previous node saved
330
+ prev = pos
331
+ pos = actual_object(pos[:Next])
332
+ end
333
+ # make sure the last object doesn't have the :Next and the first no :Prev property
334
+ prev.delete :Next
335
+ actual_object(old_data[:First]).delete :Prev
336
+ end
337
+ end
338
+
339
+ # Prints the whole outline hash to a file,
340
+ # with basic indentation and replacing raw streams with "RAW STREAM"
341
+ # (subbing doesn't allways work that great for big streams)
342
+ # outline - outline hash
343
+ # file - "filename.filetype" string
344
+ def print_outline_to_file(outline, file)
345
+ outline_subbed_str = outline.to_s.gsub(/\:raw_stream_content=\>"(?:(?!"}).)*+"\}\}/, ':raw_stream_content=> RAW STREAM}}')
346
+ brace_cnt = 0
347
+ formatted_outline_str = ''
348
+ outline_subbed_str.each_char do |c|
349
+ if c == '{'
350
+ formatted_outline_str << "\n" << "\t" * brace_cnt << c
351
+ brace_cnt += 1
352
+ elsif c == '}'
353
+ brace_cnt -= 1
354
+ brace_cnt = 0 if brace_cnt < 0
355
+ formatted_outline_str << c << "\n" << "\t" * brace_cnt
356
+ elsif c == '\n'
357
+ formatted_outline_str << c << "\t" * brace_cnt
358
+ else
359
+ formatted_outline_str << c
360
+ end
361
+ end
362
+ formatted_outline_str << "\n" * 10
363
+ File.open(file, 'w') { |file| file.write(formatted_outline_str) }
364
+ end
365
+
366
+ private
367
+
368
+ def renaming_dictionary(object = nil, dictionary = {})
369
+ object ||= @names
370
+ case object
371
+ when Array
372
+ object.length.times { |i| object[i].is_a?(String) ? (dictionary[object[i]] = (dictionary.last || 'Random_0001').next) : renaming_dictionary(object[i], dictionary) }
373
+ when Hash
374
+ object.values.each { |v| renaming_dictionary v, dictionary }
375
+ end
376
+ end
377
+
378
+ def rename_object(object, _dictionary)
379
+ case object
380
+ when Array
381
+ object.length.times { |i| }
382
+ when Hash
383
+ end
384
+ end
385
+ end
227
386
  end