[前][次][番号順一覧][スレッド一覧]

ruby-changes:6797

From: kouji <ko1@a...>
Date: Sat, 2 Aug 2008 00:10:56 +0900 (JST)
Subject: [ruby-changes:6797] Ruby:r18313 (trunk): * ext/readline/extconf.rb: checked to have clear_history in

kouji	2008-08-02 00:04:37 +0900 (Sat, 02 Aug 2008)

  New Revision: 18313

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=18313

  Log:
    * ext/readline/extconf.rb: checked to have clear_history in
      readline library.
    * ext/readline/readline.c (hist_get, hist_each, Init_readline): 
      The offset specified for the argument of history_get() might be
      different in GNU Readline and libedit. If use libedit, it was
      corrected that the computational method of the offset specified
      for the argument of history_get() when the Readline module was
      initialized was decided.
      (hist_get, hist_set): If use libedit, accesses first an input
      content in history when specifies the negative offset for the
      argument of history_get() or replace_history_entry(). Then
      checks the offset is negative in ruby.
      (rb_remove_history): When compiling, it corrects it to warning
      when libedit is used.
      (hist_clear, Init_readline): added Readline::HISTORY.clear
      method. [ruby-dev:35551]
    * test/readline/test_readline_history.rb: added unit test for
      Readline::HISTORY.

  Added files:
    trunk/test/readline/test_readline_history.rb
  Modified files:
    trunk/ChangeLog
    trunk/ext/readline/extconf.rb
    trunk/ext/readline/readline.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 18312)
+++ ChangeLog	(revision 18313)
@@ -1,3 +1,24 @@
+Fri Aug  1 23:49:44 2008  TAKAO Kouji  <kouji@t...>
+
+	* ext/readline/extconf.rb: checked to have clear_history in
+	  readline library.
+	* ext/readline/readline.c (hist_get, hist_each, Init_readline): 
+	  The offset specified for the argument of history_get() might be
+	  different in GNU Readline and libedit. If use libedit, it was
+	  corrected that the computational method of the offset specified
+	  for the argument of history_get() when the Readline module was
+	  initialized was decided.
+	  (hist_get, hist_set): If use libedit, accesses first an input
+	  content in history when specifies the negative offset for the
+	  argument of history_get() or replace_history_entry(). Then
+	  checks the offset is negative in ruby.
+	  (rb_remove_history): When compiling, it corrects it to warning
+	  when libedit is used.
+	  (hist_clear, Init_readline): added Readline::HISTORY.clear
+	  method. [ruby-dev:35551]
+	* test/readline/test_readline_history.rb: added unit test for
+	  Readline::HISTORY.
+	
 Fri Aug  1 23:26:45 2008  NARUSE, Yui  <naruse@r...>
 
 	* transcode.c (transcode_loop): undefined character is replaced with
Index: ext/readline/readline.c
===================================================================
--- ext/readline/readline.c	(revision 18312)
+++ ext/readline/readline.c	(revision 18313)
@@ -29,6 +29,8 @@
 
 static VALUE mReadline;
 
+#define EDIT_LINE_LIBRARY_VERSION "EditLine wrapper"
+
 #define COMPLETION_PROC "completion_proc"
 #define COMPLETION_CASE_FOLD "completion_case_fold"
 static ID completion_proc, completion_case_fold;
@@ -43,6 +45,8 @@
 # define rl_completion_matches completion_matches
 #endif
 
+static int (*history_get_offset_func)(int);
+
 static char **readline_attempted_completion_function(const char *text,
                                                      int start, int end);
 
@@ -505,10 +509,22 @@
     return rb_str_new2("HISTORY");
 }
 
+static int
+history_get_offset_history_base(int offset)
+{
+    return history_base + offset;
+}
+
+static int
+history_get_offset_0(int offset)
+{
+    return offset;
+}
+
 static VALUE
 hist_get(VALUE self, VALUE index)
 {
-    HIST_ENTRY *entry;
+    HIST_ENTRY *entry = NULL;
     int i;
 
     rb_secure(4);
@@ -516,7 +532,9 @@
     if (i < 0) {
         i += history_length;
     }
-    entry = history_get(history_base + i);
+    if (i >= 0) {
+	entry = history_get(history_get_offset_func(i));
+    }
     if (entry == NULL) {
 	rb_raise(rb_eIndexError, "invalid index");
     }
@@ -527,7 +545,7 @@
 hist_set(VALUE self, VALUE index, VALUE str)
 {
 #ifdef HAVE_REPLACE_HISTORY_ENTRY
-    HIST_ENTRY *entry;
+    HIST_ENTRY *entry = NULL;
     int i;
 
     rb_secure(4);
@@ -536,7 +554,9 @@
     if (i < 0) {
         i += history_length;
     }
-    entry = replace_history_entry(i, RSTRING_PTR(str), NULL);
+    if (i >= 0) {
+	entry = replace_history_entry(i, RSTRING_PTR(str), NULL);
+    }
     if (entry == NULL) {
 	rb_raise(rb_eIndexError, "invalid index");
     }
@@ -581,7 +601,7 @@
     entry = remove_history(index);
     if (entry) {
         val = rb_tainted_str_new2(entry->line);
-        free(entry->line);
+        free((void *) entry->line);
         free(entry);
         return val;
     }
@@ -624,7 +644,7 @@
 
     rb_secure(4);
     for (i = 0; i < history_length; i++) {
-        entry = history_get(history_base + i);
+        entry = history_get(history_get_offset_func(i));
         if (entry == NULL)
             break;
 	rb_yield(rb_tainted_str_new2(entry->line));
@@ -662,6 +682,19 @@
 }
 
 static VALUE
+hist_clear(VALUE self)
+{
+#ifdef HAVE_CLEAR_HISTORY
+    rb_secure(4);
+    clear_history();
+    return self;
+#else
+    rb_notimplement();
+    return Qnil; /* not reached */
+#endif
+}
+
+static VALUE
 filename_completion_proc_call(VALUE self, VALUE str)
 {
     VALUE result;
@@ -782,6 +815,7 @@
     rb_define_singleton_method(history,"size", hist_length, 0);
     rb_define_singleton_method(history,"empty?", hist_empty_p, 0);
     rb_define_singleton_method(history,"delete_at", hist_delete_at, 1);
+    rb_define_singleton_method(history,"clear", hist_clear, 0);
     rb_define_const(mReadline, "HISTORY", history);
 
     fcomp = rb_obj_alloc(rb_cObject);
@@ -793,8 +827,19 @@
     rb_define_singleton_method(ucomp, "call",
 			       username_completion_proc_call, 1);
     rb_define_const(mReadline, "USERNAME_COMPLETION_PROC", ucomp);
+    history_get_offset_func = history_get_offset_history_base;
 #if defined HAVE_RL_LIBRARY_VERSION
     rb_define_const(mReadline, "VERSION", rb_str_new2(rl_library_version));
+#if defined HAVE_CLEAR_HISTORY
+    if (strncmp(rl_library_version, EDIT_LINE_LIBRARY_VERSION, 
+		strlen(EDIT_LINE_LIBRARY_VERSION)) == 0) {
+	add_history("1");
+	if (history_get(history_get_offset_func(0)) == NULL) {
+	    history_get_offset_func = history_get_offset_0;
+	}
+	clear_history();
+    }
+#endif
 #else
     rb_define_const(mReadline, "VERSION", rb_str_new2("2.0 or prior version"));
 #endif
Index: ext/readline/extconf.rb
===================================================================
--- ext/readline/extconf.rb	(revision 18312)
+++ ext/readline/extconf.rb	(revision 18313)
@@ -66,4 +66,5 @@
 have_readline_func("rl_emacs_editing_mode")
 have_readline_func("replace_history_entry")
 have_readline_func("remove_history")
+have_readline_func("clear_history")
 create_makefile("readline")
Index: test/readline/test_readline_history.rb
===================================================================
--- test/readline/test_readline_history.rb	(revision 0)
+++ test/readline/test_readline_history.rb	(revision 18313)
@@ -0,0 +1,313 @@
+begin
+  require "readline"
+=begin
+  class << Readline::HISTORY
+    def []=(index, str)
+      raise NotImplementedError
+    end
+
+    def pop
+      raise NotImplementedError
+    end
+
+    def shift
+      raise NotImplementedError
+    end
+
+    def delete_at(index)
+      raise NotImplementedError
+    end
+  end
+=end
+
+=begin
+  class << Readline::HISTORY
+    def clear
+      raise NotImplementedError
+    end
+  end
+=end
+rescue LoadError
+else
+  require "test/unit"
+end
+
+class Readline::TestHistory < Test::Unit::TestCase
+  include Readline
+
+  def setup
+    HISTORY.clear
+  end
+
+  def test_safe_level_4
+    method_args =
+      [
+       ["[]", [0]],
+       ["[]=", [0, "s"]],
+       ["\<\<", ["s"]],
+       ["push", ["s"]],
+       ["pop", []],
+       ["shift", []],
+       ["length", []],
+       ["delete_at", [0]],
+       ["clear", []],
+      ]
+    method_args.each do |method_name, args|
+      assert_raises(SecurityError, NotImplementedError,
+                    "method=<#{method_name}>") do
+        Thread.start {
+          $SAFE = 4
+          HISTORY.send(method_name.to_sym, *args)
+          assert(true)
+        }.join
+      end
+    end
+
+    assert_raises(SecurityError, NotImplementedError,
+                  "method=<each>") do
+      Thread.start {
+        $SAFE = 4
+        HISTORY.each { |s|
+          assert(true)
+        }
+      }.join
+    end
+  end
+  
+  def test_to_s
+    assert_equal("HISTORY", HISTORY.to_s)
+  end
+
+  def test_get
+    lines = push_history(5)
+    lines.each_with_index do |s, i|
+      assert_equal(s, HISTORY[i])
+    end
+  end
+
+  def test_get__negative
+    lines = push_history(5)
+    (1..5).each do |i|
+      assert_equal(lines[-i], HISTORY[-i])
+    end
+  end
+
+  def test_get__out_of_range
+    lines = push_history(5)
+    invalid_indexes = [5, 6, 100, -6, -7, -100]
+    invalid_indexes.each do |i|
+      assert_raise(IndexError, "i=<#{i}>") do
+        HISTORY[i]
+      end
+    end
+    
+    invalid_indexes = [100_000_000_000_000_000_000,
+                       -100_000_000_000_000_000_000]
+    invalid_indexes.each do |i|
+      assert_raise(RangeError, "i=<#{i}>") do
+        HISTORY[i]
+      end
+    end
+  end
+
+  def test_set
+    begin
+      lines = push_history(5)
+      5.times do |i|
+        expected = "set: #{i}"
+        HISTORY[i] = expected
+        assert_equal(expected, HISTORY[i])
+      end
+    rescue NotImplementedError
+    end
+  end
+
+  def test_set__out_of_range
+    assert_raises(IndexError, NotImplementedError, "index=<0>") do
+      HISTORY[0] = "set: 0"
+    end
+    
+    lines = push_history(5)
+    invalid_indexes = [5, 6, 100, -6, -7, -100]
+    invalid_indexes.each do |i|
+      assert_raises(IndexError, NotImplementedError, "index=<#{i}>") do
+        HISTORY[i] = "set: #{i}"
+      end
+    end
+    
+    invalid_indexes = [100_000_000_000_000_000_000,
+                       -100_000_000_000_000_000_000]
+    invalid_indexes.each do |i|
+      assert_raise(RangeError, NotImplementedError, "index=<#{i}>") do
+        HISTORY[i] = "set: #{i}"
+      end
+    end
+  end
+
+  def test_push
+    5.times do |i|
+      assert_equal(HISTORY, HISTORY.push(i.to_s))
+      assert_equal(i.to_s, HISTORY[i])
+    end
+    assert_equal(5, HISTORY.length)
+  end
+
+  def test_push__operator
+    5.times do |i|
+      assert_equal(HISTORY, HISTORY << i.to_s)
+      assert_equal(i.to_s, HISTORY[i])
+    end
+    assert_equal(5, HISTORY.length)
+  end
+
+  def test_push__plural
+    assert_equal(HISTORY, HISTORY.push("0", "1", "2", "3", "4"))
+    (0..4).each do |i|
+      assert_equal(i.to_s, HISTORY[i])
+    end
+    assert_equal(5, HISTORY.length)
+
+    assert_equal(HISTORY, HISTORY.push("5", "6", "7", "8", "9"))
+    (5..9).each do |i|
+      assert_equal(i.to_s, HISTORY[i])
+    end
+    assert_equal(10, HISTORY.length)
+  end
+
+  def test_pop
+    begin
+      assert_equal(nil, HISTORY.pop)
+      
+      lines = push_history(5)
+      (1..5).each do |i|
+        assert_equal(lines[-i], HISTORY.pop)
+        assert_equal(lines.length - i, HISTORY.length)
+      end
+      
+      assert_equal(nil, HISTORY.pop)
+    rescue NotImplementedError
+    end
+  end
+
+  def test_shift
+    begin
+      assert_equal(nil, HISTORY.shift)
+      
+      lines = push_history(5)
+      (0..4).each do |i|
+        assert_equal(lines[i], HISTORY.shift)
+        assert_equal(lines.length - (i + 1), HISTORY.length)
+      end
+    
+      assert_equal(nil, HISTORY.shift)
+    rescue NotImplementedError
+    end
+  end
+
+  def test_each
+    HISTORY.each do |s|
+      assert(false) # not reachable
+    end
+    lines = push_history(5)
+    i = 0
+    HISTORY.each do |s|
+      assert_equal(HISTORY[i], s)
+      assert_equal(lines[i], s)
+      i += 1
+    end
+  end
+
+  def test_each__enumerator
+    e = HISTORY.each
+    assert_instance_of(Enumerable::Enumerator, e)
+  end
+
+  def test_length
+    assert_equal(0, HISTORY.length)
+    push_history(1)
+    assert_equal(1, HISTORY.length)
+    push_history(4)
+    assert_equal(5, HISTORY.length)
+    HISTORY.clear
+    assert_equal(0, HISTORY.length)
+  end
+
+  def test_empty_p
+    2.times do
+      assert(HISTORY.empty?)
+      HISTORY.push("s")
+      assert_equal(false, HISTORY.empty?)
+      HISTORY.clear
+      assert(HISTORY.empty?)
+    end
+  end
+
+  def test_delete_at
+    begin
+      lines = push_history(5)
+      (0..4).each do |i|
+        assert_equal(lines[i], HISTORY.delete_at(0))
+      end
+      assert(HISTORY.empty?)
+
+      lines = push_history(5)
+      (1..5).each do |i|
+        assert_equal(lines[lines.length - i], HISTORY.delete_at(-1))
+      end
+      assert(HISTORY.empty?)
+
+      lines = push_history(5)
+      assert_equal(lines[0], HISTORY.delete_at(0))
+      assert_equal(lines[4], HISTORY.delete_at(3))
+      assert_equal(lines[1], HISTORY.delete_at(0))
+      assert_equal(lines[3], HISTORY.delete_at(1))
+      assert_equal(lines[2], HISTORY.delete_at(0))
+      assert(HISTORY.empty?)
+    rescue NotImplementedError
+    end
+  end
+
+  def test_delete_at__out_of_range
+    assert_raises(IndexError, NotImplementedError, "index=<0>") do
+      HISTORY.delete_at(0)
+    end
+      
+    lines = push_history(5)
+    invalid_indexes = [5, 6, 100, -6, -7, -100]
+    invalid_indexes.each do |i|
+      assert_raises(IndexError, NotImplementedError, "index=<#{i}>") do
+        HISTORY.delete_at(i)
+      end
+    end
+    
+    invalid_indexes = [100_000_000_000_000_000_000,
+                       -100_000_000_000_000_000_000]
+    invalid_indexes.each do |i|
+      assert_raises(RangeError, NotImplementedError, "index=<#{i}>") do
+        HISTORY.delete_at(i)
+      end
+    end
+  end
+
+  private
+
+  def push_history(num)
+    lines = []
+    num.times do |i|
+      s = "a"
+      i.times do
+        s = s.succ
+      end
+      lines.push("#{i + 1}:#{s}")
+    end
+    HISTORY.push(*lines)
+    return lines
+  end
+end if defined?(::Readline) && defined?(::Readline::HISTORY) &&
+  (
+   begin
+     Readline::HISTORY.clear
+   rescue NotImplementedError
+     false
+   end
+   )

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]