[Japanese] [English]


Index


Title: RCtool - rcfiles update tool

RCtool is a small tool which makes/updates rcfiles automatically.

Latest Version 1.1.1

1 What's new

1.1 [2005/12/11] 1.1.1 released

`set_filenames' bugfix on Windows.

1.2 [2005/11/15] 1.1.0 released

New methodology to incorporate RCtool.

2 Abstract

RCtool is a small tool which makes/updates rcfiles automatically.

There is a rcfile in software each. For example, it is .zshrc in zsh, .emacs in Emacs and so on.

Please think about the scene which introduces a new EmacsLisp program into Emacs. You copy a .el file in the directory which is in load-path. You have to write setting in .emacs last.

I think that update of .emacs is easy if you introduce it once. However, please imagine a scene upgrading an EmacsLisp program. When the EmacsLisp code is largely modified, and setting did not have compatibility either, a user must modify .emacs by hand one by one. Changing .emacs by hand is boring and error-prone; changing .emacs automatically without any notification is extremely rude.

RCtool takes over this troublesome work. RCtool does the following work separately.

A user understands which part changed clearly.

A developer modifies the definition script and can offer appropriate rcfiles to a user.

3 Environment

RCtool needs Ruby. RCtool works in Debian GNU/Linux and WINE. I think RCtool works in any Unices and Windows.

4 Usage (for a user)

It is very easy to use RCtool as a user. A necessary tool is only Ruby.

It is assumed that a software RCtool is incorporated is installed and there is a definition script `foo-rctool' in that.

Prepare to modify rcfiles

foo-rctool -p

Output difference points (need `diff' command)

foo-rctool -d

Reflect changes of rcfiles (installation)

foo-rctool -i

Cancel changes (uninstallation)

foo-rctool -u

Display options

foo-rctool

That's all!

4.1 WARNING

You MUST NOT MODIFY the block(a region between `Beginning of the foo block:' and `End of the foo block.') including the comment. A change result is lost if you have modified the block when you invoke RCtool again. When you want to change an initial value, please overwrite with a value below the block.

But you can MOVE A BLOCK ENTIRELY in an arbitrary place. When you do not like a place of a block inserted in RCtool, please move to an appropriate part. When you invoke RCtool next time, RCtool finds the block and modify it adequately.

5 Usage (for a developer)

If you develop a program with rcfiles, let's incorporate RCtool.

5.1 Download / Untar

Please execute the following commands.

ruby -ropen-uri -e 'URI("http://www.rubyist.net/~rubikitch/archive/rctool-1.1.1.tar.gz").read.display' > rctool-1.1.1.tar.gz
tar xzvf rctool-1.1.1.tar.gz

When you failed, please download it from the next link.

5.2 Installation

Execute setup.rb to install RCtool.

ruby setup.rb  

5.3 How to Incorporate RCtool

Since version 1.1.0, RCtool uses new methodology to incorporate into your system.

It is assumed the following situation.

mkrctool generates an integrated script.

mkrctool foo-rctool.rb > bin/foo-rctool

Of course if you modify `foo-rctool.rb', you must update `bin/foo-rctool'. Make or Rake takes over such a cumbersome task.

5.4 Basic Concepts

In explanation of RCtool, I define the following concepts.

Code piece

Here, I decide to point at one part of contents of rcfiles.

Block

I call a code piece added/updated by invoking RCtool a block. When a name of a block is foo, a block begins from

Beginning of the foo block:

and ends after

End of the foo block.
Template

When there is not an rcfile, RCtool creates an rcfile. It is a template that define contents of front and back of a block. A block is expressed with "%s" in the template inside. (IO#printf is called)

User-setting area

A part under a block is a user-setting area. It is used to override the setting defined by a block.

RCtool Patch

RCtool Patch is an information that contains an rcfile name and a block and a template. RCtool Patch is unrelated to a diff/patch command. Please think that RCtool patches an rcfile by an original method.

5.5 Definition Script

Next, write a RCtool "definition script" if you installed RCtool. A definition script is a pure Ruby script.

It is 2 of next to do in a definition script.

  1. Make an RCtool object.
  2. Define RCtool patches.
RCtool.new(params)

This method makes an RCtool object. params is a Hash. A key of params and correspondence of a value are as follows. By normal use: you are enough if you define even :name.

name the block name
backup_dir path to the backup directory [default = "backup" ]
home_dir path to the directory to put the rcfiles [default = ENV['HOME'] ]
RCtool#define_patch(file, block, comment_start, template="%s", where=:append)

This method defines an RCtool patch to an rcfile file. comment_start is a comment start character string. A block is put at the end of a file if where == :append. A block is put at the top of a file if where == :prepend.

The private methods that RCtool defines are only these. It is work of a definition script that computes a default value of setting (in other words, contents of a block).

5.6 Example

About concrete how to use RCtool, it is early to watch an example of a program introducing RCtool into. El4r modifies ~/.emacs, ~/.el4rrc.rb, ~/.el4r/init.rb with RCtool.

Here is the definition script, el4r-rctool. It is long, but script in itself is simple because most are here document string.

# (shell-command "rm ~/.el4rrc.rb")
# (progn (find-sh "rake rctool; el4r-rctool -p ; el4r-rctool -d; el4r-rctool -i") (find-filez "~/.el4rrc.rb ~/.emacs ~/.el4r/init.rb"))
# (find-sh "ruby ~/.el4rrc.rb")
require 'tmpdir'
require 'rbconfig'
include Config

home_dir_expr = %q!ENV['EL4R_HOME'] || File.expand_path("~/.el4r")!
home_dir = eval home_dir_expr

bindir = CONFIG["bindir"]
datadir = CONFIG["datadir"]
sitelibdir = CONFIG["sitelibdir"]
emacsrubydir = File.join(sitelibdir, "el4r/emacsruby")
el_program = File.expand_path('emacs/site-lisp/el4r.el', datadir)
el_dir = File.dirname el_program

rc = RCtool.new(:name=>"el4r")
rc.define_patch(".el4rrc.rb", <<END_OF_BLOCK, "#", <<END_OF_TEMPLATE, :prepend)
### Internal variables
@stdlib_dir = #{emacsrubydir.dump}
@autoload_dir = #{File.join(emacsrubydir, "autoload").dump}
@el_program_relative = "data/emacs/site-lisp/el4r.el"
@instance_program_relative = "bin/el4r-instance"
@el_program = #{el_program.dump}
@instance_program = #{File.expand_path('el4r-instance', bindir).dump}
@lisp_object_gc_trigger_count = 100
@lisp_object_gc_trigger_increment = 100
@ruby_gc_trigger_count = 100
@ruby_gc_trigger_increment = 100
@log_buffer = "*el4r:log*"
@output_buffer = "*el4r:output*"
@unittest_lisp_object_gc_trigger_count = 5000
@unittest_lisp_object_gc_trigger_increment = 5000
@unittest_ruby_gc_trigger_count = 5000
@unittest_ruby_gc_trigger_increment = 5000
@temp_file = "#{Dir.tmpdir}/el4r-\#{ENV['USER'] || ENV['USERNAME'] || 'me'}.tmp"

### El4r bootstrap code
def __conf__
  if ENV['EL4R_ROOT']
    $: << File.join(ENV['EL4R_ROOT'], "lib")
  end
  require 'el4r/el4r-sub'
  ConfigScript.new(__FILE__)
end

def __elisp_init__
  $> << "(setq \\n"
  instance_variables.map{|iv| [iv[1..-1], instance_variable_get(iv)]}.each {|k,v|  $> << "el4r-\#{k.gsub(/_/,'-')} \#{v.inspect}\\n" if Numeric === v or String === v}
  $> << ')' << "\n"
end

at_exit { __elisp_init__  if __FILE__==$0 }

### Customizable variables
### You can override these variables in User-setting area.
# directory containing EmacsRuby scripts
@home_dir = #{home_dir_expr}
# directory containing other package's EmacsRuby scripts
@site_dir = "\#{@home_dir}/site"
# startup EmacsRuby script
@init_script = "init.rb"
# EmacsRuby search path
@el4r_load_path = [ @home_dir, @site_dir, @stdlib_dir, "." ]
END_OF_BLOCK
%s

# Ruby interpreter name used by el4r
@ruby_program = "ruby"
# Emacs program name used by el4r / el4r-runtest.rb
@emacs_program = "emacs"
END_OF_TEMPLATE


rc.define_patch(".emacs", <<END_OF_BLOCK, ";;", "%s", :append)
(add-to-list 'load-path #{el_dir.dump})
(require 'el4r)
(el4r-boot)
END_OF_BLOCK

rc.define_patch("#{home_dir}/init.rb", <<END_OF_BLOCK, "#", "%s", :prepend)
# This is the el4r initialization file.
END_OF_BLOCK

At first rc is an RCtool object.

rc = RCtool.new(:name=>"el4r")

The next line defines an RCtool patch of .el4rrc.rb.

rc.define_patch(".el4rrc.rb", <<END_OF_BLOCK, "#", <<END_OF_TEMPLATE, :prepend)

Because :home_dir is not specified, .el4rrc.rb is a relative path from a home directory. Because el4rrc.rb is a Ruby script, comment character string is #.

A block ends at END_OF_BLOCK. This is a part updated for el4r-rctool run time. In the block, because it contains the line

root_dir = #{Dir.pwd.dump}

contents of a block vary with current directory.

A template begins from the next line of END_OF_BLOCK. It is over before END_OF_TEMPLATE. *1

When ~/.el4rrc.rb does not exist, the template is used. Because it is different by an individual, a name of a Ruby interpreter and a name of Emacs define it as a template. A user may modify these values freely.

@ruby_program = "ruby"
@emacs_program = "emacs"

When ~/.el4rrc.rb exists because :prepend is specified, a block comes to the top of a file.

There is a definition of a patch of ~/.emacs next.

rc.define_patch(".emacs", <<END_OF_BLOCK, ";;", "%s", :append)

Because :append is specified, a block is added to the end of ~/.emacs. Notice that the comment start character string is ";;", and the template is "%s".

There is a definition of a patch of an EmacsRuby script executed at the startup of el4r.

rc.define_patch("#{home_dir}/init.rb", <<END_OF_BLOCK, "#", "%s", :prepend)

A part of a file name becomes complicated because it is changed in environment variable EL4R_HOME. This example shows that the patch file name can be specified by an absolute path.

The actual installation of el4r shows how el4r-rctool modifies rcfiles.


Back to Top

Valid XHTML 1.0!
rubikitch(rubikitch@ruby-lang.org)

Mail Form
Name Mail
URL


*1In Ruby, You can define a here document in succession.