Feature #11158 » symbol_enumerator.patch
| ChangeLog | ||
|---|---|---|
|
Thu May 21 10:44:07 2015 Lourens Naudé <lourens@bearmetal.eu>
|
||
|
* symbol.c (rb_sym_each): Implement `rb_sym_each` to expose the Symbol table
|
||
|
as an Enumerator. This is a more versatile method to walking the Symbol table
|
||
|
with the slower `rb_sym_all_symbols` API. Also possible to count total Symbols
|
||
|
with `Symbol.each.size`
|
||
|
* include/ruby/intern.h (rb_sym_each): Expose `rb_sym_each` API. Move
|
||
|
`rb_sym_all_symbols` to a symbol.c specific section (does not live in parse.y
|
||
|
anymore)
|
||
|
* string.c (Init_string): Implement Symbol.each, extend Symbol with Enumerable
|
||
|
* test/ruby/test_symbol.rb: Test for Symbol API addition.
|
||
|
* test/ruby/test_parse.rb: Moved `test_all_symbols` to test/ruby/test_symbol.rb
|
||
|
Thu May 21 04:11:03 2015 Koichi Sasada <ko1@atdot.net>
|
||
|
* iseq.c (exception_type2symbol): show correct bug message.
|
||
| include/ruby/intern.h | ||
|---|---|---|
|
void rb_backref_set(VALUE);
|
||
|
VALUE rb_lastline_get(void);
|
||
|
void rb_lastline_set(VALUE);
|
||
|
VALUE rb_sym_all_symbols(void);
|
||
|
/* process.c */
|
||
|
void rb_last_status_set(int status, rb_pid_t pid);
|
||
|
VALUE rb_last_status_get(void);
|
||
| ... | ... | |
|
size_t rb_str_capacity(VALUE);
|
||
|
VALUE rb_str_ellipsize(VALUE, long);
|
||
|
VALUE rb_str_scrub(VALUE, VALUE);
|
||
|
/* symbol.c */
|
||
|
VALUE rb_sym_all_symbols(void);
|
||
|
VALUE rb_sym_each(void);
|
||
|
#if defined(__GNUC__) && !defined(__PCC__)
|
||
|
#define rb_str_new(str, len) __extension__ ( \
|
||
| string.c | ||
|---|---|---|
|
rb_cSymbol = rb_define_class("Symbol", rb_cObject);
|
||
|
rb_include_module(rb_cSymbol, rb_mComparable);
|
||
|
rb_include_module(rb_singleton_class(rb_cSymbol), rb_mEnumerable);
|
||
|
rb_undef_alloc_func(rb_cSymbol);
|
||
|
rb_undef_method(CLASS_OF(rb_cSymbol), "new");
|
||
|
rb_define_singleton_method(rb_cSymbol, "all_symbols", rb_sym_all_symbols, 0); /* in symbol.c */
|
||
|
rb_define_singleton_method(rb_cSymbol, "each", rb_sym_each, 0); /* in symbol.c */
|
||
|
rb_define_method(rb_cSymbol, "==", sym_equal, 1);
|
||
|
rb_define_method(rb_cSymbol, "===", sym_equal, 1);
|
||
| symbol.c | ||
|---|---|---|
|
return ary;
|
||
|
}
|
||
|
static int
|
||
|
symbols_each_i(st_data_t key, st_data_t value, st_data_t arg)
|
||
|
{
|
||
|
VALUE sym = (VALUE)value;
|
||
|
if (STATIC_SYM_P(sym)) {
|
||
|
rb_yield(sym);
|
||
|
return ST_CONTINUE;
|
||
|
}
|
||
|
else if (!DYNAMIC_SYM_P(sym)) {
|
||
|
rb_bug("invalid symbol: %s", RSTRING_PTR((VALUE)key));
|
||
|
}
|
||
|
else if (!SYMBOL_PINNED_P(sym) && rb_objspace_garbage_object_p(sym)) {
|
||
|
RSYMBOL(sym)->fstr = 0;
|
||
|
return ST_DELETE;
|
||
|
}
|
||
|
else {
|
||
|
rb_yield(sym);
|
||
|
return ST_CONTINUE;
|
||
|
}
|
||
|
}
|
||
|
static VALUE
|
||
|
symbol_enum_size(VALUE hash, VALUE args, VALUE eobj)
|
||
|
{
|
||
|
#if SIZEOF_LONG == SIZEOF_VOIDP
|
||
|
return ULONG2NUM(global_symbols.str_sym->num_entries);
|
||
|
#elif SIZEOF_LONG_LONG == SIZEOF_VOIDP
|
||
|
return ULL2NUM(global_symbols.str_sym->num_entries);
|
||
|
#endif
|
||
|
}
|
||
|
/*
|
||
|
* call-seq:
|
||
|
* Symobl.each {| sym | block } -> Symbol
|
||
|
* Symbol.each -> an_enumerator
|
||
|
*
|
||
|
* Calls <i>block</i> once for each symbol in <i>the symbol table</i>, passing the
|
||
|
* symbol as a parameter.
|
||
|
*
|
||
|
* If no block is given, an enumerator is returned instead.
|
||
|
*
|
||
|
* bacon = :bacon
|
||
|
* lettuce = :lettuce
|
||
|
* Symbol.each {|sym| puts sym }
|
||
|
*
|
||
|
* <em>produces:</em>
|
||
|
*
|
||
|
* ... many other symbols ...
|
||
|
* bacon
|
||
|
* lettuce
|
||
|
*
|
||
|
* It's also a cheaper alternative to <i>Symbol.all_symbols.size</i> to get the
|
||
|
* size of Ruby's symbol table.
|
||
|
*
|
||
|
* Symbol.count
|
||
|
*
|
||
|
* <em>produces:</em>
|
||
|
*
|
||
|
* 903
|
||
|
*/
|
||
|
VALUE
|
||
|
rb_sym_each(void)
|
||
|
{
|
||
|
RETURN_SIZED_ENUMERATOR(Qnil, 0, 0, symbol_enum_size);
|
||
|
st_foreach(global_symbols.str_sym, symbols_each_i, 0);
|
||
|
return rb_cSymbol;
|
||
|
}
|
||
|
int
|
||
|
rb_is_const_id(ID id)
|
||
|
{
|
||
| test/ruby/test_parse.rb | ||
|---|---|---|
|
assert_equal(':"foo=="', "foo==".intern.inspect)
|
||
|
end
|
||
|
def test_all_symbols
|
||
|
x = Symbol.all_symbols
|
||
|
assert_kind_of(Array, x)
|
||
|
assert_empty(x.reject {|s| s.is_a?(Symbol) })
|
||
|
end
|
||
|
def test_is_class_id
|
||
|
c = Class.new
|
||
|
assert_raise(NameError) do
|
||
| test/ruby/test_symbol.rb | ||
|---|---|---|
|
assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(n))}
|
||
|
end
|
||
|
def test_all_symbols
|
||
|
x = Symbol.all_symbols
|
||
|
assert_kind_of(Array, x)
|
||
|
assert_empty(x.reject {|s| s.is_a?(Symbol) })
|
||
|
end
|
||
|
def test_each
|
||
|
x = Symbol.each.size
|
||
|
assert_kind_of(Fixnum, x)
|
||
|
assert_equal x, Symbol.all_symbols.size
|
||
|
assert_equal x, Symbol.count
|
||
|
assert_equal Symbol.to_a, Symbol.all_symbols
|
||
|
answer_to_life = :bacon_lettuce_tomato
|
||
|
assert_equal [:bacon_lettuce_tomato], Symbol.grep(/bacon_lettuce_tomato/)
|
||
|
end
|
||
|
def test_inspect_invalid
|
||
|
# 2) Symbol#inspect sometimes returns invalid symbol representations:
|
||
|
assert_eval_inspected(:"!")
|
||
- « Previous
- 1
- 2
- Next »