Class: Blufin::Files

Inherits:
Object
  • Object
show all
Defined in:
lib/core/files.rb

Constant Summary collapse

JAVA_AUTO_GENERATED_EVERY_RUN =
'java_auto_generated_every_run'
JAVA_AUTO_GENERATED_ONCE =
'java_auto_generated_once'

Class Method Summary collapse

Class Method Details

.create_directory(path) ⇒ Object

Create a directory recursively (if it doesn’t already exist).

Returns:

  • String



359
360
361
362
363
364
365
366
367
# File 'lib/core/files.rb', line 359

def self.create_directory(path)
    begin
        path = File.expand_path(path)
        FileUtils.mkpath(path) unless path_exists(path)
        path
    rescue => e
        Blufin::Terminal::print_exception(e)
    end
end

.create_path(path) ⇒ Object

Proxy function for the above.

Returns:

  • void



371
372
373
# File 'lib/core/files.rb', line 371

def self.create_path(path)
    create_directory(path)
end

.delete_file(path_and_file) ⇒ Object

Deletes a file (if exists)

Returns:

  • void

Raises:

  • (RuntimeError)


307
308
309
310
# File 'lib/core/files.rb', line 307

def self.delete_file(path_and_file)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    FileUtils.rm(File.expand_path(path_and_file)) if file_exists(path_and_file)
end

.extract_file_name(path_and_file, include_extension = true) ⇒ Object

Get the file name ONLY (from a full path).

Returns:

  • string

Raises:

  • (RuntimeError)


384
385
386
387
388
# File 'lib/core/files.rb', line 384

def self.extract_file_name(path_and_file, include_extension = true)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    return File.basename(File.expand_path(path_and_file)) if include_extension
    return File.basename(File.expand_path(path_and_file), '*') unless include_extension
end

.extract_path_name(path_and_file) ⇒ Object

Get the path name ONLY (from a full path).

Returns:

  • string

Raises:

  • (RuntimeError)


377
378
379
380
# File 'lib/core/files.rb', line 377

def self.extract_path_name(path_and_file)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    File.dirname(File.expand_path(path_and_file))
end

.file_exists(path_and_file) ⇒ Object

Returns TRUE or FALSE depending whether a path exists.

Returns:

  • void

Raises:

  • (RuntimeError)


321
322
323
324
# File 'lib/core/files.rb', line 321

def self.file_exists(path_and_file)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    File.exist?(File.expand_path(path_and_file))
end

.get_dirs_in_dir(path, recursive = false) ⇒ Object

Get and array of directories in a directory.

Returns:

  • Array

Raises:

  • (RuntimeError)


338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/core/files.rb', line 338

def self.get_dirs_in_dir(path, recursive = false)
    raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
    path = "/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}"
    raise RuntimeError, "Directory doesn't exist: #{path}" unless path_exists(path)
    dirs = Dir.glob("#{path}/**/*/")
    unless recursive
        root_dirs   = []
        root_length = path.split('/').length
        dirs.each do |dir|
            root_dirs << dir if dir.split('/').length == root_length + 1
        end
        dirs = root_dirs
    end
    dirs.map! { |value| value.gsub(/\/\z/, '') }
    dirs.uniq!
    dirs.sort!
    dirs
end

.get_files_in_dir(path, only_with_extension = nil) ⇒ Object

Get and array of files in a directory.

Returns:

  • Array

Raises:

  • (RuntimeError)


328
329
330
331
332
333
334
# File 'lib/core/files.rb', line 328

def self.get_files_in_dir(path, only_with_extension = nil)
    raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
    path = "/#{Blufin::Strings.remove_surrounding_slashes(File.expand_path(path))}"
    raise RuntimeError, "Directory doesn't exist: #{path}" unless path_exists(path)
    files = Dir.glob("#{path}/**/*.#{only_with_extension.nil? ? '*' : only_with_extension}")
    files.uniq.sort
end

.is_empty(path_and_file) ⇒ Object

Returns TRUE if file is empty. Ignores spaces and new-line characters.

Returns:

  • bool



392
393
394
395
396
397
398
# File 'lib/core/files.rb', line 392

def self.is_empty(path_and_file)
    Blufin::Files::read_file(path_and_file).each do |line|
        line.strip!
        return false if line != ''
    end
    true
end

.path_exists(path) ⇒ Object

Returns TRUE or FALSE depending whether a path exists.

Returns:

  • void

Raises:

  • (RuntimeError)


314
315
316
317
# File 'lib/core/files.rb', line 314

def self.path_exists(path)
    raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
    File.directory?(File.expand_path(path))
end

.read_file(path_and_file, start_line = nil, end_line = nil) ⇒ Object

Get content of a file as an “Array of Lines”

Returns:

  • Array

Raises:

  • (RuntimeError)


287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
# File 'lib/core/files.rb', line 287

def self.read_file(path_and_file, start_line = nil, end_line = nil)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    line_count    = 0
    path_and_file = File.expand_path(path_and_file)
    raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file)
    raise RuntimeError, "start_line (#{start_line}) cannot be bigger than end_line (#{end_line})." if (!start_line.nil? && !end_line.nil?) && (start_line > end_line)
    file_content = []
    file         = File.open(path_and_file).read
    file.gsub!(/\r\n?/, "\n")
    file.each_line do |line|
        line_count += 1
        next if !start_line.nil? && start_line > line_count
        next if !end_line.nil? && end_line < line_count
        file_content << line
    end
    file_content
end

.remove_line_from_file(path_and_file, regex, multiple_occurrences = false) ⇒ Object

Removes a line from a file. multiple_occurrences -> If set to TRUE, will remove ALL occurrences from file.

Returns:

  • void

Raises:

  • (RuntimeError)


260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/core/files.rb', line 260

def self.remove_line_from_file(path_and_file, regex, multiple_occurrences = false)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    path_and_file = File.expand_path(path_and_file)
    raise RuntimeError, "Expected Regexp to match to line, instead got: #{regex.class}" unless regex.is_a? Regexp
    raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file)
    new_lines    = []
    line_removed = false
    read_file(path_and_file).each do |line_content|
        line_content.gsub!(/\n\z/, '')
        line_content_to_match = line_content.strip
        if line_content_to_match =~ regex
            if multiple_occurrences
                next
            else
                unless line_removed
                    line_removed = true
                    next
                end
            end
        end
        new_lines << line_content
    end
    write_file(path_and_file, new_lines)
end

.write_file(path_and_file, array_of_lines) ⇒ Object

Write an “Array of Lines” to a file – overwrites file if exists!

Returns:

  • String

Raises:

  • (RuntimeError)


162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/core/files.rb', line 162

def self.write_file(path_and_file, array_of_lines)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    path_and_file = File.expand_path(path_and_file)
    # If this comes in as a string, convert it to an Array of lines.
    if array_of_lines.is_a?(String)
        array_of_lines_new = []
        array_of_lines.split("\n").each { |line| array_of_lines_new << line.gsub("\n", '') }
        array_of_lines = array_of_lines_new
    end
    raise RuntimeError, "Expected an array of lines to write to file, instead got: #{array_of_lines.class}" unless array_of_lines.is_a? Array
    prepare_for_file_write(path_and_file)
    begin
        File.open(path_and_file, 'w') { |file|
            array_of_lines.each_with_index do |line, index|
                if index == array_of_lines.size - 1
                    file.write("#{line}") unless line.to_s.strip == ''
                else
                    file.write("#{line}\n")
                end
            end
            file.close
        }
    rescue Exception => e
        Blufin::Terminal::print_exception(e)
    end
    path_and_file
end

.write_file_java(path_and_file, array_of_lines, auto_generated = JAVA_AUTO_GENERATED_EVERY_RUN) ⇒ Object

Same as write_file() but for Java files. If arrange_imports = TRUE (default) it will sort the import statements in the same order as IntelliJ would.

Returns:

  • String

Raises:

  • (RuntimeError)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/core/files.rb', line 14

def self.write_file_java(path_and_file, array_of_lines, auto_generated = JAVA_AUTO_GENERATED_EVERY_RUN)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    auto_generated_valid = [JAVA_AUTO_GENERATED_EVERY_RUN, JAVA_AUTO_GENERATED_ONCE]
    raise RuntimeError, "Expected .java file, instead got: #{path_and_file}" unless path_and_file =~ /\.java\z/
    raise RuntimeError, "auto_generated must be one of the following: #{auto_generated_valid.join(', ')}" unless auto_generated_valid.include?(auto_generated)
    package               = nil
    import_statements_one = []
    import_statements_two = []
    previous_was_blank    = false
    annotations_one       = []
    annotations_two       = []
    contents              = []
    array_of_lines.each do |line|
        if contents.any?
            next if line.strip == '' && previous_was_blank
            previous_was_blank = false
            contents << line
            previous_was_blank = true if line.strip == ''
            next
        end
        if package.nil? && line.strip =~ /^package\s+[A-Za-z0-9\._-]+;$/
            # Get package.
            raise RuntimeError, "Package has a hyphen in it \xe2\x86\x92 \x1B[38;5;184m#{line.strip}\x1B[0m. When this file's contents were generated you forgot a .gsub() statement to replace it." if line.strip =~ /-/
            package = line.strip
            next
        elsif line.strip =~ /^import\s+[A-Za-z0-9\.*_-]+;$/ || line.strip =~ /^import\s+static\s+[A-Za-z0-9\.*_-]+;$/
            # Get import statements.
            raise RuntimeError, "Import has a hyphen in it \xe2\x86\x92 \x1B[38;5;184m#{line.strip}\x1B[0m. When this file's contents were generated you forgot a .gsub() statement to replace it." if line.strip =~ /-/
            import_statements_one << line.strip
            next
        elsif !contents.any? && line.strip =~ /^@(.)+$/
            annotations_one << line.strip
        elsif !contents.any? && line.strip =~ /^(public|private|protected)\s+.*(class|enum)\s+.*\{$/
            contents << line.strip
            next
        end
    end
    raise RuntimeError, "Couldn't parse content for: #{path_and_file}" unless contents.any?
    # Add @AutoGenerated + @TestNotRequired stuff.
    import_statements_one << 'import org.blufin.base.annotations.AutoGenerated;'
    import_statements_one << 'import org.blufin.base.annotations.TestNotRequired;'
    import_statements_one << 'import org.blufin.base.annotations.helper.ON;'
    annotations_one.each do |annotation|
        next if %w(@TestNotRequired @AutoGenerated @AutoGenerated(ON.EVERY_RUN) @AutoGenerated(ON.CREATION_ONLY)).include?(annotation)
        annotations_two << annotation
    end
    annotations_two << '@TestNotRequired'
    annotations_two << ((auto_generated == JAVA_AUTO_GENERATED_EVERY_RUN) ? '@AutoGenerated(ON.EVERY_RUN)' : '@AutoGenerated(ON.CREATION_ONLY)')
    annotations_two.uniq!
    import_statements_one.uniq!
    import_statements_one.sort!
    package_path = package.gsub(/package\s/, '').gsub(/;/, '').strip

    # Figure out which import statements to "keep" -- IE: Are they being used?
    import_statements_one.each do |import_statement|

        import_statement_path  = []
        import_statement_split = import_statement.gsub(/import\s/, '').gsub(/;/, '').strip.split('.')
        import_statement_split.each_with_index { |n, idx| import_statement_path << n unless idx == (import_statement_split.length - 1) }

        # Skip import if we're in the same package.
        next if import_statement_path.join('.') == package_path

        found = false
        is    = import_statement.split('.')
        is    = is[is.length - 1].gsub(';', '').strip
        if is == '*'
            import_statements_two << import_statement
            next
        end
        annotations_two.each do |annotation|
            if annotation =~ /@#{is}/ || annotation =~ /[\(\.]#{is}[\)\.]/
                found = true
                break
            end
        end
        unless found
            contents.each do |content_line|
                if content_line =~ /[<\(\s{]#{is}[\.<>,\s\(\)]/ || content_line =~ /@#{is}[\(]?/
                    found = true
                    break
                end
            end
        end
        import_statements_two << import_statement if found
    end
    import_statement_counter = {}
    import_statement_tracker = {}
    # Convert multiple imports to .*
    import_statements_two.each do |import_statement|
        is                           = import_statement.split('.')
        is                           = is.first(is.length - 1).join('.')
        import_statement_counter[is] = 0 if import_statement_counter[is].nil?
        import_statement_counter[is] += 1
        import_statement_tracker[is] = [] if import_statement_tracker[is].nil?
        import_statement_tracker[is] << import_statement
    end
    import_statements_one = []
    import_statements_two.each do |import_statement|
        is = import_statement.split('.')
        is = is.first(is.length - 1).join('.')
        if import_statement_counter[is] > 5
            import_statements_one << "#{is}.*;"
        else
            import_statements_one << import_statement
        end
    end
    import_statements_one.uniq!
    import_statements_one.sort!
    # Re-assemble the file.
    final_written_java_non = 0
    final_written_java     = 0
    final_contents         = [package, '']
    # Write NON-JAVA statements.
    import_statements_one.each do |import_statement|
        unless import_statement =~ /^import\s+java/ || import_statement =~ /^import\s+static/
            final_contents << import_statement
            final_written_java_non += 1
        end
    end
    static_statement_found = false
    # Write STATIC statements.
    import_statements_one.each do |import_statement|
        if import_statement =~ /^import\s+static/
            unless static_statement_found
                final_contents << ''
                static_statement_found = true
            end
            final_contents << import_statement
            final_written_java += 1
        end
    end
    final_contents << '' if final_written_java_non > 0
    # Write JAVA statements.
    import_statements_one.each do |import_statement|
        if import_statement =~ /^import\s+java/
            final_contents << import_statement
            final_written_java += 1
        end
    end
    final_contents << '' if final_written_java > 0
    annotations_two.each { |line| final_contents << line } if annotations_two.any?
    contents.each { |line| final_contents << line } if contents.any?
    return self.write_file(path_and_file, final_contents)
end

.write_file_string(path_and_file, content) ⇒ Object

Write a “String” to a file – overwrites file if exists!

Returns:

  • void

Raises:

  • (RuntimeError)


192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/core/files.rb', line 192

def self.write_file_string(path_and_file, content)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    path_and_file = File.expand_path(path_and_file)
    raise RuntimeError, "Expected String to write to file, instead got: #{content.class}" unless content.is_a? String
    prepare_for_file_write(path_and_file)
    begin
        File.open(path_and_file, 'w') { |file|
            file.write("#{content}")
            file.close
        }
    rescue Exception => e
        Blufin::Terminal::print_exception(e)
    end
end

.write_line_to_file(path_and_file, line, regex = nil, only_if_not_exists = true, replace = false) ⇒ Object

Writes a line to a file. regex -> If a value exists the program checks for this regex and writes on the line AFTER match(es). if nil (or not found), writes at the end of file. only_if_not_exists -> If TRUE, will add line only if it doesn’t already exist. replace -> If TRUE, will replace file rather than writing on next line after regex.

Returns:

  • void

Raises:

  • (RuntimeError)


212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/core/files.rb', line 212

def self.write_line_to_file(path_and_file, line, regex = nil, only_if_not_exists = true, replace = false)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    path_and_file = File.expand_path(path_and_file)
    raise RuntimeError, "File not found: #{path_and_file}" unless file_exists(path_and_file)
    raise RuntimeError, "Expected String to write to file, instead got: #{line.class}" unless line.is_a? String
    raise RuntimeError, "Expected Regexp to match to line, instead got: #{regex.class}" unless regex.nil? || regex.is_a?(Regexp)
    raise RuntimeError, 'Cannot set replace to TRUE when regex is nil.' if regex.nil? && replace
    raise RuntimeError, 'only_if_not_exists must be set to FALSE when replace is TRUE.' if only_if_not_exists && replace
    new_lines = []
    if only_if_not_exists
        line_found = false
        read_file(path_and_file).each do |line_content|
            line_content.gsub!(/\n\z/, '')
            line_found = true if line_content == line
        end
        return if line_found
    end
    if !regex.nil? && !replace
        regex_found   = false
        line_inserted = false
        read_file(path_and_file).each do |line_content|
            line_content.gsub!(/\n\z/, '')
            regex_found = true if line_content =~ regex
            if regex_found && line_content !~ regex && !line_inserted
                new_lines << line
                line_inserted = true
            end
            new_lines << line_content
        end
        new_lines << line unless line_inserted
    elsif !regex.nil? && replace
        regex_found = false
        read_file(path_and_file).each do |line_content|
            line_content.gsub!(/\n\z/, '')
            if !regex_found && line_content =~ regex
                regex_found = true
                new_lines << line
            else
                new_lines << line_content
            end
        end
    end
    write_file(path_and_file, new_lines)
end