Project

General

Profile

Feature #11158 » symbol_enumerator.patch

Symbol.each - methodmissing (Lourens Naudé), 05/21/2015 02:14 AM

View differences:

ChangeLog
1
Thu May 21 10:44:07 2015  Lourens Naudé  <lourens@bearmetal.eu>
2

  
3
	* symbol.c (rb_sym_each): Implement `rb_sym_each` to expose the Symbol table
4
	  as an Enumerator. This is a more versatile method to walking the Symbol table
5
	  with the slower `rb_sym_all_symbols` API. Also possible to count total Symbols
6
	  with `Symbol.each.size`
7

  
8
	* include/ruby/intern.h (rb_sym_each): Expose `rb_sym_each` API. Move
9
	  `rb_sym_all_symbols` to a symbol.c specific section (does not live in parse.y
10
	  anymore)
11

  
12
	* string.c (Init_string): Implement Symbol.each, extend Symbol with Enumerable
13

  
14
	* test/ruby/test_symbol.rb: Test for Symbol API addition.
15

  
16
	* test/ruby/test_parse.rb: Moved `test_all_symbols` to test/ruby/test_symbol.rb
17

  
1 18
Thu May 21 04:11:03 2015  Koichi Sasada  <ko1@atdot.net>
2 19

  
3 20
	* iseq.c (exception_type2symbol): show correct bug message.
include/ruby/intern.h
636 636
void rb_backref_set(VALUE);
637 637
VALUE rb_lastline_get(void);
638 638
void rb_lastline_set(VALUE);
639
VALUE rb_sym_all_symbols(void);
640 639
/* process.c */
641 640
void rb_last_status_set(int status, rb_pid_t pid);
642 641
VALUE rb_last_status_get(void);
......
790 789
size_t rb_str_capacity(VALUE);
791 790
VALUE rb_str_ellipsize(VALUE, long);
792 791
VALUE rb_str_scrub(VALUE, VALUE);
792
/* symbol.c */
793
VALUE rb_sym_all_symbols(void);
794
VALUE rb_sym_each(void);
793 795

  
794 796
#if defined(__GNUC__) && !defined(__PCC__)
795 797
#define rb_str_new(str, len) __extension__ (	\
string.c
9234 9234

  
9235 9235
    rb_cSymbol = rb_define_class("Symbol", rb_cObject);
9236 9236
    rb_include_module(rb_cSymbol, rb_mComparable);
9237
    rb_include_module(rb_singleton_class(rb_cSymbol), rb_mEnumerable);
9237 9238
    rb_undef_alloc_func(rb_cSymbol);
9238 9239
    rb_undef_method(CLASS_OF(rb_cSymbol), "new");
9239 9240
    rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in symbol.c */
9241
    rb_define_singleton_method(rb_cSymbol, "each", rb_sym_each, 0); /* in symbol.c */
9240 9242

  
9241 9243
    rb_define_method(rb_cSymbol, "==", sym_equal, 1);
9242 9244
    rb_define_method(rb_cSymbol, "===", sym_equal, 1);
symbol.c
847 847
    return ary;
848 848
}
849 849

  
850
static int
851
symbols_each_i(st_data_t key, st_data_t value, st_data_t arg)
852
{
853
    VALUE sym = (VALUE)value;
854

  
855
    if (STATIC_SYM_P(sym)) {
856
	rb_yield(sym);
857
	return ST_CONTINUE;
858
    }
859
    else if (!DYNAMIC_SYM_P(sym)) {
860
	rb_bug("invalid symbol: %s", RSTRING_PTR((VALUE)key));
861
    }
862
    else if (!SYMBOL_PINNED_P(sym) && rb_objspace_garbage_object_p(sym)) {
863
	RSYMBOL(sym)->fstr = 0;
864
	return ST_DELETE;
865
    }
866
    else {
867
	rb_yield(sym);
868
	return ST_CONTINUE;
869
    }
870

  
871
}
872

  
873
static VALUE
874
symbol_enum_size(VALUE hash, VALUE args, VALUE eobj)
875
{
876
#if SIZEOF_LONG == SIZEOF_VOIDP
877
    return ULONG2NUM(global_symbols.str_sym->num_entries);
878
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
879
    return ULL2NUM(global_symbols.str_sym->num_entries);
880
#endif
881
}
882

  
883
/*
884
 *  call-seq:
885
 *     Symobl.each {| sym | block } -> Symbol
886
 *     Symbol.each                  -> an_enumerator
887
 *
888
 *  Calls <i>block</i> once for each symbol in <i>the symbol table</i>, passing the
889
 *  symbol as a parameter.
890
 *
891
 *  If no block is given, an enumerator is returned instead.
892
 *
893
 *     bacon = :bacon
894
 *     lettuce = :lettuce
895
 *     Symbol.each {|sym| puts sym }
896
 *
897
 *  <em>produces:</em>
898
 *
899
 *     ... many other symbols ...
900
 *     bacon
901
 *     lettuce
902
 *
903
 *   It's also a cheaper alternative to <i>Symbol.all_symbols.size</i> to get the
904
 *   size of Ruby's symbol table.
905
 *
906
 *     Symbol.count
907
 *
908
 *  <em>produces:</em>
909
 *
910
 *     903
911
 */
912

  
913
VALUE
914
rb_sym_each(void)
915
{
916
    RETURN_SIZED_ENUMERATOR(Qnil, 0, 0, symbol_enum_size);
917
    st_foreach(global_symbols.str_sym, symbols_each_i, 0);
918
    return rb_cSymbol;
919
}
920

  
850 921
int
851 922
rb_is_const_id(ID id)
852 923
{
test/ruby/test_parse.rb
846 846
    assert_equal(':"foo=="', "foo==".intern.inspect)
847 847
  end
848 848

  
849
  def test_all_symbols
850
    x = Symbol.all_symbols
851
    assert_kind_of(Array, x)
852
    assert_empty(x.reject {|s| s.is_a?(Symbol) })
853
  end
854

  
855 849
  def test_is_class_id
856 850
    c = Class.new
857 851
    assert_raise(NameError) do
test/ruby/test_symbol.rb
12 12
    assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(n))}
13 13
  end
14 14

  
15
  def test_all_symbols
16
    x = Symbol.all_symbols
17
    assert_kind_of(Array, x)
18
    assert_empty(x.reject {|s| s.is_a?(Symbol) })
19
  end
20

  
21
  def test_each
22
    x = Symbol.each.size
23
    assert_kind_of(Fixnum, x)
24
    assert_equal x, Symbol.all_symbols.size
25
    assert_equal x, Symbol.count
26
    assert_equal Symbol.to_a, Symbol.all_symbols
27
    answer_to_life = :bacon_lettuce_tomato
28
    assert_equal [:bacon_lettuce_tomato], Symbol.grep(/bacon_lettuce_tomato/)
29
  end
30

  
15 31
  def test_inspect_invalid
16 32
    # 2) Symbol#inspect sometimes returns invalid symbol representations:
17 33
    assert_eval_inspected(:"!")