class Blufin::Files

Constants

JAVA_AUTO_GENERATED_EVERY_RUN
JAVA_AUTO_GENERATED_ONCE

Public Class Methods

create_directory(path) click to toggle source

Create a directory recursively (if it doesn't already exist). @return String

# File lib/core/files.rb, line 387
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) click to toggle source

Proxy function for the above. @return void

# File lib/core/files.rb, line 399
def self.create_path(path)
    raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
    create_directory(path)
end
delete_file(path_and_file) click to toggle source

Deletes a file (if exists) @return void

# File lib/core/files.rb, line 331
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) click to toggle source

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

# File lib/core/files.rb, line 413
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) click to toggle source

Get the path name ONLY (from a full path). @return string

# File lib/core/files.rb, line 406
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) click to toggle source

Returns TRUE or FALSE depending whether a path exists. @return void

# File lib/core/files.rb, line 345
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) click to toggle source

Get and array of directories in a directory. @return Array

# File lib/core/files.rb, line 366
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) click to toggle source

Get and array of files in a directory. @return Array

# File lib/core/files.rb, line 352
def self.get_files_in_dir(path, only_with_extension = nil)
    raise RuntimeError, "Expected String, instead got: #{path.class}" unless path.is_a?(String)
    unless only_with_extension.nil?
        raise RuntimeError, "Expected String, instead got: #{path.class}" unless only_with_extension.is_a?(String)
        raise RuntimeError, 'only_with_extension must be alphanumeric & lowercase (no periods)' unless only_with_extension =~ /[a-z0-9]/
    end
    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) click to toggle source

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

# File lib/core/files.rb, line 421
def self.is_empty(path_and_file)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    Blufin::Files::read_file(path_and_file).each do |line|
        line.strip!
        return false if line != ''
    end
    true
end
is_file(path_and_file) click to toggle source

Returns TRUE if path_and_file is a file, FALSE if it's a directory. File does not need to exist. @return bool

# File lib/core/files.rb, line 433
def self.is_file(path_and_file)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    path_and_file =~ /\.[a-z0-9]{1,10}$/i ? true : false
end
path_exists(path) click to toggle source

Returns TRUE or FALSE depending whether a path exists. @return void

# File lib/core/files.rb, line 338
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) click to toggle source

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

# File lib/core/files.rb, line 311
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) click to toggle source

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

# File lib/core/files.rb, line 284
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, write_empty_trailing_line: false) click to toggle source

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

# File lib/core/files.rb, line 186
def self.write_file(path_and_file, array_of_lines, write_empty_trailing_line: 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)
    # 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}") if line.to_s.strip != '' || write_empty_trailing_line
                else
                    file.write("#{line}\n")
                end
            end
            file.close
        }
    rescue Exception => e
        Blufin::Terminal::print_exception(e)
    end
    path_and_file
end
write_file_if_changed(path_and_file, array_of_lines, write_empty_trailing_line: false) click to toggle source

Writes a file (but only if content has changed). Returns true if file was overwritten, false if not. @return boolean

# File lib/core/files.rb, line 165
def self.write_file_if_changed(path_and_file, array_of_lines, write_empty_trailing_line: false)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    raise RuntimeError, "Expected Array, instead got: #{array_of_lines.class}" unless array_of_lines.is_a?(Array)
    # If file does not exist, writes it regardless and returns TRUE.
    unless Blufin::Files::file_exists(path_and_file)
        Blufin::Files::write_file(path_and_file, array_of_lines, write_empty_trailing_line: write_empty_trailing_line)
        return true
    end
    tmp_file = "/tmp/#{Blufin::Strings::random_string(2)}.txt"
    Blufin::Files::write_file(tmp_file, array_of_lines, write_empty_trailing_line: write_empty_trailing_line)
    target_file_hash = Digest::SHA1.hexdigest Blufin::Arrays::convert_line_array_to_string(Blufin::Files::read_file(path_and_file)).gsub(/\s/, '')
    tmp_file_hash    = Digest::SHA1.hexdigest Blufin::Arrays::convert_line_array_to_string(Blufin::Files::read_file(tmp_file)).gsub(/\s/, '')
    if target_file_hash != tmp_file_hash
        FileUtils.mv(tmp_file, path_and_file)
        return true
    end
    false
end
write_file_java(path_and_file, array_of_lines, auto_generated = JAVA_AUTO_GENERATED_EVERY_RUN, test_annotations = true) click to toggle source

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. @return String

# File lib/core/files.rb, line 15
def self.write_file_java(path_and_file, array_of_lines, auto_generated = JAVA_AUTO_GENERATED_EVERY_RUN, test_annotations = true)
    raise RuntimeError, "Expected String, instead got: #{path_and_file.class}" unless path_and_file.is_a?(String)
    auto_generated_valid = [nil, 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.nil? || auto_generated_valid.include?(auto_generated)
    raise RuntimeError, "Expected Boolean, instead got: #{test_annotations.class}" unless !!test_annotations == test_annotations
    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\._-]+;(\s*#.*)?$/
            # 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.gsub(/(\s*#.*)?$/, '').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+.*\{(\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;' unless auto_generated.nil?
    import_statements_one << 'import org.blufin.base.annotations.TestNotRequired;' if test_annotations
    import_statements_one << 'import org.blufin.base.annotations.helper.ON;' unless auto_generated.nil?
    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' if test_annotations
    annotations_two << ((auto_generated == JAVA_AUTO_GENERATED_EVERY_RUN) ? '@AutoGenerated(ON.EVERY_RUN)' : '@AutoGenerated(ON.CREATION_ONLY)') unless auto_generated.nil?
    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) click to toggle source

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

# File lib/core/files.rb, line 216
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) click to toggle source

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. @return void

# File lib/core/files.rb, line 236
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

Private Class Methods

prepare_for_file_write(path_and_file) click to toggle source

Creates path (if not exists) and deletes file (if exists). @return void

# File lib/core/files.rb, line 442
def self.prepare_for_file_write(path_and_file)
    FileUtils::mkdir_p(File.dirname(path_and_file)) unless path_exists(File.dirname(path_and_file))
    File.delete(path_and_file) if file_exists(path_and_file)
end