module HamlLint::Utils
A miscellaneous set of utility functions.
Public Instance Methods
Returns whether a glob pattern (or any of a list of patterns) matches the specified file.
This is defined here so our file globbing options are consistent everywhere we perform globbing.
@param glob [String, Array] @param file [String] @return [Boolean]
# File lib/haml_lint/utils.rb, line 19 def any_glob_matches?(globs_or_glob, file) get_abs_and_rel_path(file).any? do |path| Array(globs_or_glob).any? do |glob| ::File.fnmatch?(glob, path, ::File::FNM_PATHNAME | # Wildcards don't match path separators ::File::FNM_DOTMATCH) # `*` wildcard matches dotfiles end end end
Converts a string containing underscores/hyphens/spaces into CamelCase.
@param str [String] @return [String]
# File lib/haml_lint/utils.rb, line 136 def camel_case(str) str.split(/_|-| /).map { |part| part.sub(/^\w/, &:upcase) }.join end
# File lib/haml_lint/utils.rb, line 240 def check_error_when_compiling_haml(haml_string) begin ruby_code = ::HamlLint::Adapter.detect_class.new(haml_string).precompile rescue StandardError => e return e end eval("BEGIN {return nil}; #{ruby_code}", binding, __FILE__, __LINE__) # rubocop:disable Security/Eval # The eval will return nil rescue ::SyntaxError $! end
Count the number of consecutive items satisfying the given {Proc}.
@param items [Array] @param offset [Fixnum] index to start searching from @yield [item] Passes item to the provided block. @yieldparam item [Object] Item to evaluate as matching criteria for
inclusion
@yieldreturn [Boolean] whether to include the item @return [Integer]
# File lib/haml_lint/utils.rb, line 177 def count_consecutive(items, offset = 0) count = 1 count += 1 while (offset + count < items.count) && yield(items[offset + count]) count end
Yields interpolated values within a block of text.
@param text [String] @yield Passes interpolated code and line number that code appears on in
the text.
@yieldparam interpolated_code [String] code that was interpolated @yieldparam line [Integer] line number code appears on in text
# File lib/haml_lint/utils.rb, line 55 def extract_interpolated_values(text) # rubocop:disable Metrics/AbcSize dumped_text = text.dump # Basically, match pairs of '\' and '\ followed by the letter 'n' quoted_regex_s = "(#{Regexp.quote('\\\\')}|#{Regexp.quote('\\n')})" newline_positions = extract_substring_positions(dumped_text, quoted_regex_s) # Filter the matches to only keep those ending in 'n'. # This way, escaped \n will not be considered newline_positions.select! do |pos| dumped_text[pos - 1] == 'n' end Haml::Util.handle_interpolation(dumped_text) do |scan| line = (newline_positions.find_index { |marker| scan.charpos <= marker } || newline_positions.size) + 1 escape_count = (scan[2].size - 1) / 2 break unless escape_count.even? dumped_interpolated_str = Haml::Util.balance(scan, '{', '}', 1)[0][0...-1] # Hacky way to turn a dumped string back into a regular string yield [eval('"' + dumped_interpolated_str + '"'), line] # rubocop:disable Security/Eval end end
Returns indexes of all occurrences of a substring within a string.
Note, this will not return overlapping substrings, so searching for “aa” in “aaa” will only find one substring, not two.
@param text [String] the text to search @param substr [String] the substring to search for @return [Array<Integer>] list of indexes where the substring occurs
# File lib/haml_lint/utils.rb, line 125 def extract_substring_positions(text, substr) positions = [] scanner = StringScanner.new(text) positions << scanner.charpos while scanner.scan(/(.*?)#{substr}/) positions end
Find all consecutive items satisfying the given block of a minimum size, yielding each group of consecutive items to the provided block.
@param items [Array] @param satisfies [Proc] function that takes an item and returns true/false @param min_consecutive [Fixnum] minimum number of consecutive items before
yielding the group
@yield Passes list of consecutive items all matching the criteria defined
by the `satisfies` {Proc} to the provided block
@yieldparam group [Array] List of consecutive items @yieldreturn [Boolean] block should return whether item matches criteria
for inclusion
# File lib/haml_lint/utils.rb, line 152 def for_consecutive_items(items, satisfies, min_consecutive = 2) current_index = -1 while (current_index += 1) < items.count next unless satisfies[items[current_index]] count = count_consecutive(items, current_index, &satisfies) next unless count >= min_consecutive # Yield the chunk of consecutive items yield items[current_index...(current_index + count)] current_index += count # Skip this patch of consecutive items to find more end end
Returns an array of two items, the first being the absolute path, the second the relative path.
The relative path is relative to the current working dir. The path passed can be either relative or absolute.
@param path [String] Path to get absolute and relative path of @return [Array<String>] Absolute and relative path
# File lib/haml_lint/utils.rb, line 37 def get_abs_and_rel_path(path) original_path = Pathname.new(path) root_dir_path = Pathname.new(File.expand_path(Dir.pwd)) if original_path.absolute? [path, original_path.relative_path_from(root_dir_path)] else [root_dir_path + original_path, path] end end
# File lib/haml_lint/utils.rb, line 82 def handle_interpolation_with_indexes(text) newline_indexes = extract_substring_positions(text, "\n") handle_interpolation_with_newline(text) do |scan| line_index = newline_indexes.find_index { |index| scan.charpos <= index } line_index ||= newline_indexes.size line_start_char_index = if line_index == 0 0 else newline_indexes[line_index - 1] end char_index = scan.charpos - line_start_char_index yield scan, line_index, char_index end end
Same as Haml::Util.handle_interpolation, but enables multiline mode on the regex
# File lib/haml_lint/utils.rb, line 103 def handle_interpolation_with_newline(str) scan = StringScanner.new(str) yield scan while scan.scan(/(.*?)(\\*)#([{@$])/m) scan.rest end
# File lib/haml_lint/utils.rb, line 215 def indent(string, nb_indent) if nb_indent < 0 string.gsub(/^ {1,#{-nb_indent}}/, '') else string.gsub(/^/, ' ' * nb_indent) end end
# File lib/haml_lint/utils.rb, line 194 def insert_after_indentation(code, insert) index = code.index(/\S/) "#{code[0...index]}#{insert}#{code[index..]}" end
Returns true if line is only whitespace. Note, this is not like blank? is rails. For nil, this returns false.
# File lib/haml_lint/utils.rb, line 236 def is_blank_line?(line) line && line.index(/\S/).nil? end
# File lib/haml_lint/utils.rb, line 230 def map_after_first!(array, &block) map_subset!(array, 1..-1, &block) end
# File lib/haml_lint/utils.rb, line 223 def map_subset!(array, range, &block) subset = array[range] return if subset.nil? || subset.empty? array[range] = subset.map(&block) end
Process ERB, providing some values for for versions to it
@param content [String] the (usually yaml) content to process @return [String]
# File lib/haml_lint/utils.rb, line 187 def process_erb(content) # Variables for use in the ERB's post-processing rubocop_version = HamlLint::VersionComparer.for_rubocop ERB.new(content).result(binding) end
# File lib/haml_lint/utils.rb, line 280 def regexp_for_parts(parts, join_regexp, prefix: nil, suffix: nil) regexp_code = parts.map { |c| Regexp.quote(c) }.join(join_regexp) regexp_code = "#{prefix}#{regexp_code}#{suffix}" Regexp.new(regexp_code) end
Overrides the global stdin, stdout and stderr while within the block, to push a string in stdin, and capture both stdout and stderr which are returned.
@param stdin_str [String] the string to push in as stdin @param _block [Block] the block to perform with the overridden std streams @return [String, String]
# File lib/haml_lint/utils.rb, line 258 def with_captured_streams(stdin_str, &_block) original_stdin = $stdin # The dup is needed so that stdin_data isn't altered (encoding-wise at least) $stdin = StringIO.new(stdin_str.dup) begin original_stdout = $stdout $stdout = StringIO.new begin original_stderr = $stderr $stderr = StringIO.new yield [$stdout.string, $stderr.string] ensure $stderr = original_stderr end ensure $stdout = original_stdout end ensure $stdin = original_stdin end
Calls a block of code with a modified set of environment variables, restoring them once the code has executed.
@param env [Hash] environment variables to set
# File lib/haml_lint/utils.rb, line 203 def with_environment(env) old_env = {} env.each do |var, value| old_env[var] = ENV[var.to_s] ENV[var.to_s] = value end yield ensure old_env.each { |var, value| ENV[var.to_s] = value } end