Class AutomateIt::EditManager::EditSession
In: lib/automateit/edit_manager.rb
Parent: AutomateIt::Common

EditSession

EditSession provides a way to edit files and strings.

For example, here‘s how to edit a string from the Interpreter:

  edit(:text => "# hello") do
    uncomment "llo"
    append "world"
  end
  # => "hello\nworld"

The above example edits a text string containing "# hello". The editing session uncomments the line containing "llo" and then appends a line with the word "world". The edited result is returned, containing two lines: "hello" and "world".

The edit session only makes changes if they‘re needed. In the above example, once the "hello" line is uncommented, the "uncomment" command won‘t do anything. Similarly, once the word "world" has been appended, it won‘t be appended again. So if you re-edit the resulting string, it won‘t be changed because it‘s already in the desired state.

This approach simplifies editing because you only need to specify the commands that are needed to change the file, and the session will figure out which ones to run.

Methods

_backup   _exists?   _read   _readable?   _write   append   comment   comment_style   contains?   delete   different?   edit   manipulate   new   prepend   replace   uncomment  

Attributes

comment_prefix  [RW]  Comment prefix, e.g., "/*"
comment_suffix  [RW]  Comment suffix, e.g., "*/"
contents  [RW]  Current contents of the editing buffer.
filename  [RW]  File that was read for editing.
original_contents  [RW]  Original contents of the editing buffer before any changes were made.
params  [RW]  Hash of parameters to make available to the editing session.

Public Class methods

Create an EditSession.

Options:

  • :interpreter — AutomateIt Interpreter, required. Will be automatically set if you use AutomateIt::Interpreter#edit.

[Source]

# File lib/automateit/edit_manager.rb, line 70
  def initialize(*args)
    super(*args)
    interpreter.add_method_missing_to(self)
  end

Public Instance methods

Append line to the bottom of the buffer, but only if it‘s not in this file already.

Options:

  • :unless — Look for this String or Regexp instead and don‘t append if it matches.

See example for prepend.

[Source]

# File lib/automateit/edit_manager.rb, line 202
  def append(line, opts={})
    query = opts[:unless] || line
    if query.is_a?(String)
      query = Regexp.new(Regexp.escape(query))
    end
    return if contains?(query)
    @contents = "%s\n%s\n" % [@contents.chomp, line]
  end

Comment out lines matching the String or Regexp query.

[Source]

# File lib/automateit/edit_manager.rb, line 235
  def comment(line, opts={})
    query = line.is_a?(String) ? Regexp.escape(line) : line
    query = Regexp.new("^(?!#{comment_prefix})([^\n]*%s[^\n]*)(\n*)" % query)
    return false unless @contents.match(query)
    @contents.gsub!(query, "%s%s%s%s" % [@comment_prefix, $1, @comment_suffix, $2])
  end

Specify the comment style‘s prefix and suffix.

Example:

  # C style comments
  comment_style "/*", "*/"

[Source]

# File lib/automateit/edit_manager.rb, line 229
  def comment_style(prefix, suffix="")
    @comment_prefix = prefix
    @comment_suffix = suffix
  end

Does the buffer contain anything that matches the String or Regexp query?

[Source]

# File lib/automateit/edit_manager.rb, line 212
  def contains?(line)
    query = line.is_a?(String) ? Regexp.new(Regexp.escape(line)) : line
    ! @contents.match(query).nil?
  end

Delete lines matching the String or Regexp query

[Source]

# File lib/automateit/edit_manager.rb, line 218
  def delete(line, opts={})
    query = line.is_a?(String) ? Regexp.escape(line) : line
    query = Regexp.new("^[^\n]*%s[^\n]*\n?" % query)
    @contents.gsub!(query, "")
  end

Is the buffer currently different than its original contents?

[Source]

# File lib/automateit/edit_manager.rb, line 268
  def different?
    @contents != @original_contents
  end

Edit a file or string.

Requires a filename argument or options hash — e.g.,. edit("foo") and edit(:file => "foo") will both edit a file called foo.

Options:

  • :file — File to edit.
  • :text — String to edit.
  • :params — Hash to make available to editor session.
  • :create — Create the file if it doesn‘t exist? Defaults to false.
  • :mode, :user, :group — Set permissions on generated file, see ShellManager#chperm
  • :backup — Make a backup of original file? Defaults to true.

Edit a string:

  edit(:text => "foo") do
    replace "o", "@"
  end
  # => "f@@"

Edit a file and pass parameters to the editing session:

  edit(:file => "myfile", :params => {:greet => "world"} do
    prepend "MyHeader"
    append "Hello "+params[:greet]
  end

Edit a file, create it and set permissions if necessary:

  edit("/tmp/foo", :create => true, :mode => 0600, :user => :root) do
    prepend "Hello world!"
  end

[Source]

# File lib/automateit/edit_manager.rb, line 108
  def edit(*a, &block)
    args, opts = args_and_opts(*a)
    if args.first
      @filename = args.first
    else
      raise ArgumentError.new("no file or text specified for editing") unless opts[:file] or opts[:text]
      @filename = opts[:file]
      @contents = opts[:text]
    end
    @params = opts[:params] || {}
    @is_backup = opts[:backup].nil? ? true : opts[:backup]
    @comment_prefix = "# "
    @comment_suffix = ""
    begin
      @contents ||= _read || ""
    rescue Errno::ENOENT => e
      if opts[:create]
        @contents = ""
      else
        raise e
      end
    end
    @original_contents = @contents.clone

    raise ArgumentError.new("no block given") unless block
    instance_eval(&block)
    if @filename
      if different?
        _backup if @is_backup
        _write
      end

      chperm_opts = {}
      for key in [:owner, :user, :group, :mode]
        chperm_opts[key] = opts[key] if opts[key]
      end
      chperm(@filename, chperm_opts) unless chperm_opts.empty?

      return different?
    else
      return contents
    end
  end

Manipulate the buffer. The result of your block will replace the buffer. This is very useful for complex edits.

Example:

  manipulate do |buffer|
    buffer.gsub(/foo/, "bar")
  end

[Source]

# File lib/automateit/edit_manager.rb, line 263
  def manipulate(&block) # :yields: buffer
    @contents = block.call(@contents)
  end

Prepend line to the top of the buffer, but only if it‘s not in this file already.

Options:

  • :unless — Look for this String or Regexp instead and don‘t prepend if it matches.

Example:

  # Buffer's contents are 'add    this line'

  # This will prepend a line because they're not identical.
  prepend("add this line")

  # Won't prepend line because Regexp matches exisint line in buffer.
  prepend("add this line", :unless => /add\s*this\*line/)

[Source]

# File lib/automateit/edit_manager.rb, line 185
  def prepend(line, opts={})
    query = opts[:unless] || line
    if query.is_a?(String)
      query = Regexp.new(Regexp.escape(query))
    end
    return if contains?(query)
    @contents = "%s\n%s" % [line.chomp, @contents]
  end

Replace contents matching the String or Regexp query with the string.

[Source]

# File lib/automateit/edit_manager.rb, line 251
  def replace(line, string, opts={})
    query = line.is_a?(String) ? Regexp.new(Regexp.escape(line)) : line
    @contents.gsub!(query, string)
  end

Uncomment lines matching the String or Regexp query.

[Source]

# File lib/automateit/edit_manager.rb, line 243
  def uncomment(line, opts={})
    query = line.is_a?(String) ? Regexp.escape(line) : line
    query = Regexp.new("^(%s)([^\n]*%s[^\n]*)(%s)(\n*)" % [@comment_prefix, query, @comment_suffix])
    return false unless @contents.match(query)
    @contents.gsub!(query, "%s%s" % [$2, $4])
  end

Protected Instance methods

Backup the original file.

[Source]

# File lib/automateit/edit_manager.rb, line 301
  def _backup
    return false unless @filename and File.exists?(@filename)
    result = nil
    log.silence(Logger::WARN) do
      result = backup(@filename)
    end
    log.debug(PNOTE+"Saved '#{@filename}' to '#{result}'")
  end

Does the file exist?

[Source]

# File lib/automateit/edit_manager.rb, line 311
  def _exists?
    File.exists?(@filename)
  end

Read contents from filename. Called by the edit command to load text into the buffer.

[Source]

# File lib/automateit/edit_manager.rb, line 276
  def _read
    @contents = \
      if writing? or (preview? and @filename and _exists? and _readable?)
        File.read(@filename)
      elsif preview? and not _readable?
        log.info(PNOTE+"Not allowed to read file, previewing edits as if it doesn't exist: #{@filename}")
        nil
      else
        nil
      end
  end

Is the file readable?

[Source]

# File lib/automateit/edit_manager.rb, line 316
  def _readable?
    FileTest.readable?(@filename)
  end

Write contents to filename. Used by the edit command to write the buffer to a file.

[Source]

# File lib/automateit/edit_manager.rb, line 290
  def _write
    return false unless @filename
    log.info(PNOTE+"Edited '#{@filename}'")
    if preview?
      true
    else
      File.open(@filename, "w+"){|writer| writer.write(@contents)}
    end
  end

[Validate]