[PATCH/RFC 0/7] Support for Ruby

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

It was discussed before that there was a need to replace Git scripts from perl
and sh that utilize the 'git' binary to do everything they need, which requires
many forks, and that creates problems on platforms like Windows.

This is a first step meant to show how a solution using Ruby would look like.

Other alternatives just don't cut it. Shell scripts are too simple, and
invariably require forks. Perl could use Git's internal C code, but it's syntax
is too cumbersome and it's loosing more and more popularity. Python and Ruby
are the only modern languages that could fit all the needs, but Python's syntax
is not ideal, specially considering the background of the Git community, and
also, Ruby's C extensibility is simply superb.

This patch series introduces Ruby bindings for Git's C internal library, and
add example commands to show how it could be used, and how it resembles the
original C code, shell code, and perl code. Basically, Ruby fits like a glove.

== Syntax ==

First of all, the syntax of Ruby is very similar to other languages used by Git:

C:

  if (a && b || (c & FLAG) != 0)
    return 0
  else
    break
  end

  printf("format: %s: %i\n", "this string", 0)

  count += 1

Shell:

  out = `git rev-parse #{committish}`

  str = <<EOF
  multi
  line
  string
  EOF

Perl

  var ||= 'default'

The following Perl code:

  sub abbr {
    my $ref = shift;
    if ($ref =~ m{^refs/heads/(.*)$}) {
      return $1;
    }
    return $ref;
  }

Looks like this in Ruby:

  def abbr(ref)
    if (ref =~ %r{^refs/heads/(.*)$}m)
      return $1
    end
    return ref
  end

== C bindings ==

It's extremely easy to write wrappers for Git's C functions:

  static VALUE git_rb_get_git_dir(VALUE self)
  {
    return rb_str_new2(get_git_dir());
  }

  rb_define_global_function("get_git_dir", git_rb_get_git_dir, 0);

Then in Ruby:

  dir = get_git_dir()

== Much more ==

Ruby's power allows for plenty of extensibility.

For example:

  p `echo yes`
  => "yes\n"

Usually we want to chomp the last new line. Fortunately everything is open in
Ruby, so it's possible to override the `() method:

  def `(cmd)
    IO.popen(cmd) { |pipe| pipe.read.chomp }
  end

Now:

  p `echo yes`
  => "yes"

Also, in shell, if we want to make sure a sequence of commands is executed, we
would do something like:

  git command 1 &&
  git command 2 &&
  git command 3 ||
  error

This gets specially troublesome the bigger the sequence. In Ruby:

  def run(*args)
    system(*args)
    raise RuntimeError unless $?.success?
  end

  begin
    run('git command 1')
    run('git command 2')
    run('git command 3')
  rescue RuntimeError
    error
  end

Finally, Ruby has the concept of blocks:

  def run_with_lock()
    puts "lock"
    yield
    puts "unlock"
  end

  branch = 'master'

  run_with_lock() do
    puts "do stuff with #{branch}"
  end

Notice how the block inside run_with_lock() is able to access the 'branch'
variable, because it's in it's context, but the block is not actually called
until run_with_lock() calls 'yield'.

Python has a similar concept, but not nearly as powerful.

== Upgrade path ==

Ruby 2.0 didn't suffer the problems Python 3 is suffering because they have a
sane upgrade path.

Ruby 1.9 changed the syntax, so people using 1.8 had to do minor changes to
upgrade to 1.9, but they didn't miss many major features. After people updated
to 1.9, 2.0 came along with major features, but it was compatible with 1.9, so
nobody had to do any further changes.

Either way, it's still possible to run code that works in 1.8, 1.9, and 2.0.

== Community ==

The Ruby community is already heavily engaged in Git, as statistics in GitHub
show, plenty of Ruby projects use Git, outnumbering by far the Python ones.

There might be some correlation based on the fact that Mercurial is written in
Python.

http://adambard.com/blog/top-github-languages-for-2013-so-far/

== Conclusion ==

Ruby is an extremly powerful modern language, it features object oriented
paradigm, as well as functional, and procedural. It borrows from languages such
as C, Perl, and many others.

It's possible that by opening the possibilities to write Ruby scripts, many
Ruby developers would join the effort to improve Git.

Felipe Contreras (7):
  Add support for ruby commands
  ruby: add setup script
  ruby: add simple wrappers
  ruby: rewrite 'request-pull'
  ruby: rewrite perl script
  ruby: remove one fork
  ruby: rewrite 'reset'

 Makefile            |  16 +-
 cache.h             |   2 +
 git-rb-setup.rb     | 125 +++++++++++++
 git-refs.rb         |   7 +
 git-request-pull.rb | 159 ++++++++++++++++
 git-request-pull.sh | 162 -----------------
 git-reset.rb        | 223 +++++++++++++++++++++++
 git.c               |   4 +-
 ruby.c              | 511 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 1044 insertions(+), 165 deletions(-)
 create mode 100644 git-rb-setup.rb
 create mode 100644 git-refs.rb
 create mode 100644 git-request-pull.rb
 delete mode 100755 git-request-pull.sh
 create mode 100644 git-reset.rb
 create mode 100644 ruby.c

-- 
1.8.4-fc

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]