diff options
| author | Yukihiro "Matz" Matsumoto <[email protected]> | 2017-07-29 07:05:37 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2017-07-29 07:05:37 +0900 |
| commit | b290e98f3b4e8623fd8932c9996d0481f56f766b (patch) | |
| tree | 4b875e10e0037d14846999130e4f587bb23d4163 | |
| parent | cf23a85333c9c0ee83b0dca4c40d0d33beaf7f66 (diff) | |
| parent | f937af5745cbc6edead0ad3911bf16e08f66a96f (diff) | |
| download | mruby-b290e98f3b4e8623fd8932c9996d0481f56f766b.tar.gz mruby-b290e98f3b4e8623fd8932c9996d0481f56f766b.zip | |
Merge pull request #3757 from christopheraue/module_const_get_class_path
Extended Module#const_get to support class paths
| -rw-r--r-- | include/mruby/string.h | 7 | ||||
| -rw-r--r-- | src/class.c | 36 | ||||
| -rw-r--r-- | src/string.c | 33 | ||||
| -rw-r--r-- | test/t/module.rb | 8 |
4 files changed, 68 insertions, 16 deletions
diff --git a/include/mruby/string.h b/include/mruby/string.h index b18093218..c3fbb063d 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -84,6 +84,13 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); void mrb_gc_free_str(mrb_state*, struct RString*); MRB_API void mrb_str_modify(mrb_state*, struct RString*); + +/* + * Finds the index of a substring in a string + */ +MRB_API mrb_int mrb_str_index(mrb_state*, mrb_value, const char*, mrb_int, mrb_int); +#define mrb_str_index_lit(mrb, str, lit, off) mrb_str_index(mrb, str, lit, mrb_strlen_lit(lit), off); + /* * Appends self to other. Returns self as a concatnated string. * diff --git a/src/class.c b/src/class.c index 56f64fd4e..57f64dcc5 100644 --- a/src/class.c +++ b/src/class.c @@ -2161,13 +2161,43 @@ mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) } static mrb_value +mrb_const_get_sym(mrb_state *mrb, mrb_value mod, mrb_sym id) +{ + check_const_name_sym(mrb, id); + return mrb_const_get(mrb, mod, id); +} + +static mrb_value mrb_mod_const_get(mrb_state *mrb, mrb_value mod) { + mrb_value path; mrb_sym id; + char *ptr; + mrb_int off, end, len; - mrb_get_args(mrb, "n", &id); - check_const_name_sym(mrb, id); - return mrb_const_get(mrb, mod, id); + mrb_get_args(mrb, "o", &path); + + if (mrb_symbol_p(path)) { + /* const get with symbol */ + id = mrb_symbol(path); + return mrb_const_get_sym(mrb, mod, id); + } + + /* const get with class path string */ + path = mrb_string_type(mrb, path); + ptr = RSTRING_PTR(path); + len = RSTRING_LEN(path); + off = 0; + + while (off < len) { + end = mrb_str_index_lit(mrb, path, "::", off); + end = (end == -1) ? len : end; + id = mrb_intern(mrb, ptr+off, end-off); + mod = mrb_const_get_sym(mrb, mod, id); + off = (end == len) ? end : end+2; + } + + return mod; } static mrb_value diff --git a/src/string.c b/src/string.c index 2cc54a8cf..6fdb7fe72 100644 --- a/src/string.c +++ b/src/string.c @@ -478,15 +478,14 @@ str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) return str_subseq(mrb, str, beg, len); } -static mrb_int -str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) +MRB_API mrb_int +mrb_str_index(mrb_state *mrb, mrb_value str, const char *sptr, mrb_int slen, mrb_int offset) { mrb_int pos; - char *s, *sptr; - mrb_int len, slen; + char *s; + mrb_int len; len = RSTRING_LEN(str); - slen = RSTRING_LEN(sub); if (offset < 0) { offset += len; if (offset < 0) return -1; @@ -498,14 +497,24 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) } if (slen == 0) return offset; /* need proceed one character at a time */ - sptr = RSTRING_PTR(sub); - slen = RSTRING_LEN(sub); len = RSTRING_LEN(str) - offset; pos = mrb_memsearch(sptr, slen, s, len); if (pos < 0) return pos; return pos + offset; } +static mrb_int +str_index_str(mrb_state *mrb, mrb_value str, mrb_value str2, mrb_int offset) +{ + const char *ptr; + mrb_int len; + + ptr = RSTRING_PTR(str2); + len = RSTRING_LEN(str2); + + return mrb_str_index(mrb, str, ptr, len, offset); +} + static void check_frozen(mrb_state *mrb, struct RString *s) { @@ -1096,7 +1105,7 @@ num_index: return str; case MRB_TT_STRING: - if (str_index(mrb, str, indx, 0) != -1) + if (str_index_str(mrb, str, indx, 0) != -1) return mrb_str_dup(mrb, indx); return mrb_nil_value(); @@ -1563,7 +1572,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self) mrb_value str2; mrb_get_args(mrb, "S", &str2); - if (str_index(mrb, self, str2, 0) < 0) + if (str_index_str(mrb, self, str2, 0) < 0) return mrb_bool_value(FALSE); return mrb_bool_value(TRUE); } @@ -1590,7 +1599,7 @@ mrb_str_include(mrb_state *mrb, mrb_value self) * "hello".index(/[aeiou]/, -3) #=> 4 */ static mrb_value -mrb_str_index(mrb_state *mrb, mrb_value str) +mrb_str_index_m(mrb_state *mrb, mrb_value str) { mrb_value *argv; mrb_int argc; @@ -1631,7 +1640,7 @@ mrb_str_index(mrb_state *mrb, mrb_value str) } /* fall through */ case MRB_TT_STRING: - pos = str_index(mrb, str, sub, pos); + pos = str_index_str(mrb, str, sub, pos); break; } @@ -2752,7 +2761,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "hash", mrb_str_hash_m, MRB_ARGS_NONE()); /* 15.2.10.5.20 */ mrb_define_method(mrb, s, "include?", mrb_str_include, MRB_ARGS_REQ(1)); /* 15.2.10.5.21 */ - mrb_define_method(mrb, s, "index", mrb_str_index, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ + mrb_define_method(mrb, s, "index", mrb_str_index_m, MRB_ARGS_ANY()); /* 15.2.10.5.22 */ mrb_define_method(mrb, s, "initialize", mrb_str_init, MRB_ARGS_REQ(1)); /* 15.2.10.5.23 */ mrb_define_method(mrb, s, "initialize_copy", mrb_str_replace, MRB_ARGS_REQ(1)); /* 15.2.10.5.24 */ mrb_define_method(mrb, s, "intern", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.25 */ diff --git a/test/t/module.rb b/test/t/module.rb index 7b539e683..e32cac5f1 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -268,6 +268,12 @@ assert('Module#const_get', '15.2.2.4.21') do end assert_equal 42, Test4ConstGet.const_get(:Const4Test4ConstGet) + assert_equal 42, Test4ConstGet.const_get("Const4Test4ConstGet") + assert_equal 42, Object.const_get("Test4ConstGet::Const4Test4ConstGet") + + assert_raise(TypeError){ Test4ConstGet.const_get(123) } + assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) } + assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") } end assert('Module#const_missing', '15.2.2.4.22') do @@ -280,7 +286,7 @@ assert('Module#const_missing', '15.2.2.4.22') do assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist) end -assert('Module#const_get', '15.2.2.4.23') do +assert('Module#const_set', '15.2.2.4.23') do module Test4ConstSet Const4Test4ConstSet = 42 end |
