class PoiseFile::Resources::PoiseFile::Content

File content class for `poise_file`.

@api private @see Resource

Public Instance Methods

file_for_provider() click to toggle source

Required abstract method for ContentBase. Builds the new content of file in a tempfile or returns nil to not touch the file content.

@return [Chef::FileContentManagement::Tempfile, nil]

# File lib/poise_file/resources/poise_file.rb, line 111
def file_for_provider
  if @new_resource.content
    if @new_resource.pattern && @new_resource.format.to_s != 'text'
      raise ArgumentError.new("Cannot use `pattern` property and `format` property together")
    end

    tempfile = Chef::FileContentManagement::Tempfile.new(@new_resource).tempfile
    content = if @new_resource.pattern
      content_for_pattern
    else
      content_for_format
    end
    tempfile.write(content)
    tempfile.close
    tempfile
  else
    nil
  end
end

Private Instance Methods

content_for_format() click to toggle source

Build the content when using format mode (i.e. when not using the edit-in-place mode).

@api private @return [String]

# File lib/poise_file/resources/poise_file.rb, line 210
def content_for_format
  case @new_resource.format.to_s
  when 'json'
    require 'chef/json_compat'
    # Make sure we include the trailing newline because YAML has one.
    Chef::JSONCompat.to_json_pretty(@new_resource.content) + "\n"
  when 'yaml'
    require 'yaml'
    YAML.dump(@new_resource.content)
  when 'text'
    @new_resource.content
  else
    raise ArgumentError.new("Unknown file format #{@new_resource.format.inspect}")
  end
end
content_for_pattern() click to toggle source

Build the content when using the edit-in-place mode.

@api private @return [String]

# File lib/poise_file/resources/poise_file.rb, line 137
def content_for_pattern
  # Get the base content to start from.
  existing_content = if ::File.exist?(@new_resource.path)
    IO.read(@new_resource.path)
  else
    # Pretend the file is empty if it doesn't already exist.
    ''
  end

  # If we were given a proc, use it.
  if @new_resource.pattern.is_a?(Proc)
    return @new_resource.pattern.call(existing_content, @new_resource)
  end

  # Build the pattern.
  pattern = if @new_resource.pattern.is_a?(Regexp)
    # Should this dup the pattern because weird tracking stuff?
    @new_resource.pattern
  else
    # Deal with newlines at the end of a line because $ matches before
    # newline, not after.
    pattern_string = if @new_resource.content.end_with?("\n")
      @new_resource.pattern.gsub(/\$\Z/, "$\n?")
    else
      @new_resource.pattern
    end
    # Ruby will show a warning if trying to add options to an existing
    # Regexp instance so only use that if it's a string.
    Regexp.new(pattern_string, Regexp::MULTILINE)
  end

  # Run the pattern operation.
  case @new_resource.pattern_location.to_s
  when 'replace'
    # Overwrite the matched section.
    existing_content.gsub!(pattern, @new_resource.content) || existing_content
  when 'replace_or_add'
    # Overwrite the pattern if it matches otherwise append.
    existing_content.gsub!(pattern, @new_resource.content) || (existing_content << @new_resource.content)
  when 'before'
    # Insert the content before the pattern if it doesn't already exist.
    match = pattern.match(existing_content)
    if match
      if match.pre_match.end_with?(@new_resource.content)
        existing_content
      else
        '' << match.pre_match << @new_resource.content << match[0] << match.post_match
      end
    else
      existing_content
    end
  when 'after'
    # Insert the content after the pattern if it doesn't already exist.
    match = pattern.match(existing_content)
    if match
      if match.post_match.start_with?(@new_resource.content)
        existing_content
      else
        '' << match.pre_match << match[0] << @new_resource.content << match.post_match
      end
    else
      existing_content
    end
  else
    raise ArgumentError.new("Unknown file pattern location #{@new_resource.pattern_location.inspect}")
  end
end