From fb9358206e29c8b018b3b8553e96bf35eb9a4a63 Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Tue, 19 Jun 2018 17:25:38 +0900 Subject: Fix wrong free function mrb_locale_free() should be used for the return value of mrb_locale_from_utf8(). --- mrbgems/mruby-io/src/file.c | 4 ++-- mrbgems/mruby-io/src/io.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 3dcfe3a0b..b3ad49297 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -310,7 +310,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } home = mrb_locale_from_utf8(home, -1); path = mrb_str_new_cstr(mrb, home); - mrb_utf8_free(home); + mrb_locale_free(home); return path; #else argc = mrb_get_argc(mrb); @@ -327,7 +327,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) } home = mrb_locale_from_utf8(home, -1); path = mrb_str_new_cstr(mrb, home); - mrb_utf8_free(home); + mrb_locale_free(home); return path; #endif } diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 38b0b06c2..67c57a08e 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -780,7 +780,7 @@ reopen: mrb_str_modify(mrb, mrb_str_ptr(emsg)); mrb_sys_fail(mrb, RSTRING_PTR(emsg)); } - mrb_utf8_free(fname); + mrb_locale_free(fname); if (fd <= 2) { mrb_fd_cloexec(mrb, fd); -- cgit v1.2.3 From 33c8c8f8a62c4fb00f30e4a4554ed4a912c69b7b Mon Sep 17 00:00:00 2001 From: Kouhei Sutou Date: Tue, 19 Jun 2018 17:27:34 +0900 Subject: Stop to use freed value --- mrbgems/mruby-io/src/file.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index 3dcfe3a0b..2daa3294a 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -114,11 +114,13 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { + const char *utf8_path; pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); - path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathv), -1); + utf8_path = mrb_string_value_cstr(mrb, &pathv); + path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { mrb_locale_free(path); - mrb_sys_fail(mrb, path); + mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); } @@ -415,10 +417,11 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "i*", &mode, &filenames, &argc); for (i = 0; i < argc; i++) { - char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, filenames[i]), -1); + const char *utf8_path = mrb_str_to_cstr(mrb, filenames[i]); + char *path = mrb_locale_from_utf8(utf8_path, -1); if (CHMOD(path, mode) == -1) { mrb_locale_free(path); - mrb_sys_fail(mrb, path); + mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); } -- cgit v1.2.3 From f29bc4607a0d89f717671092b9abcde16ef28dd0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 20 Jun 2018 15:21:16 +0900 Subject: Add test_dependency from mruby-io to mruby-time. --- mrbgems/mruby-io/mrbgem.rake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/mrbgem.rake b/mrbgems/mruby-io/mrbgem.rake index 50fa49678..d79964590 100644 --- a/mrbgems/mruby-io/mrbgem.rake +++ b/mrbgems/mruby-io/mrbgem.rake @@ -4,7 +4,7 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| spec.summary = 'IO and File class' spec.cc.include_paths << "#{build.root}/src" - + case RUBY_PLATFORM when /mingw|mswin/ spec.linker.libraries += ['Ws2_32'] @@ -14,4 +14,5 @@ MRuby::Gem::Specification.new('mruby-io') do |spec| if build.kind_of?(MRuby::CrossBuild) && %w(x86_64-w64-mingw32 i686-w64-mingw32).include?(build.host_target) spec.linker.libraries += ['ws2_32'] end + spec.add_test_dependency 'mruby-time', core: 'mruby-time' end -- cgit v1.2.3 From 8f808cc9b148710617e840f8ff589709b7fc1fff Mon Sep 17 00:00:00 2001 From: take-cheeze Date: Wed, 20 Jun 2018 21:42:48 +0900 Subject: Use temporary name for `File#mtime` test to avoid conflicts. --- mrbgems/mruby-io/test/file.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index dc6fe369a..ab4678fe9 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -75,12 +75,12 @@ assert('File#mtime') do begin now = Time.now.to_i mt = 0 - File.open('mtime-test', 'w') do |f| + File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| mt = f.mtime.to_i end assert_equal true, mt >= now ensure - File.delete('mtime-test') + File.delete("#{$mrbtest_io_wfname}.mtime") end end -- cgit v1.2.3 From 7917b7f8bf40f0a824130f2569744df3109081ec Mon Sep 17 00:00:00 2001 From: Yusuke Endoh Date: Mon, 2 Jul 2018 10:47:56 +0900 Subject: Support MRB_WITHOUT_FLOAT to mruby-io --- mrbgems/mruby-io/src/file.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index e5cf53488..ca21256cc 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -345,7 +345,11 @@ mrb_file_mtime(mrb_state *mrb, mrb_value self) fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); if (fstat(fd, &st) == -1) return mrb_false_value(); +#ifndef MRB_WITHOUT_FLOAT return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime)); +#else + return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime)); +#endif } mrb_value -- cgit v1.2.3 From c095736002e72d8f00c2c09b0295d2630e4375c7 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Aug 2018 23:11:34 +0900 Subject: Try to fix a fragile `File#mtime` test. --- mrbgems/mruby-io/src/file.c | 4 ---- mrbgems/mruby-io/test/file.rb | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index ca21256cc..e65741061 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -345,11 +345,7 @@ mrb_file_mtime(mrb_state *mrb, mrb_value self) fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self)); if (fstat(fd, &st) == -1) return mrb_false_value(); -#ifndef MRB_WITHOUT_FLOAT - return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime)); -#else return mrb_funcall(mrb, obj, "at", 1, mrb_fixnum_value(st.st_mtime)); -#endif } mrb_value diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ab4678fe9..ca285f5bd 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -73,12 +73,12 @@ assert('File#mtime') do skip "File#mtime require Time" end begin - now = Time.now.to_i - mt = 0 File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| - mt = f.mtime.to_i + assert_equal Time, f.mtime.class + File.open("#{$mrbtest_io_wfname}.mtime", 'r') do |f2| + assert_equal true, f.mtime == f2.mtime + end end - assert_equal true, mt >= now ensure File.delete("#{$mrbtest_io_wfname}.mtime") end -- cgit v1.2.3 From e471d37ca5f1422860a1eaa81d4c9f1b3c8b6aed Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 30 Aug 2018 16:07:59 +0900 Subject: Separate meta-programming features to `mruby-metaprog` gem. We assume meta-programming is less used in embedded environments. We have moved following methods: * Kernel module global_variables, local_variables, singleton_class, instance_variables, instance_variables_defined?, instance_variable_get, instance_variable_set, methods, private_methods, public_methods, protected_methods, singleton_methods, define_singleton_methods * Module class class_variables, class_variables_defined?, class_variable_get, class_variable_set, remove_class_variable, included_modules, instance_methods, remove_method, method_removed, constants * Module class methods constants, nesting Note: Following meta-programming methods are kept in the core: * Module class alias_method, undef_method, ancestors, const_defined?, const_get, const_set, remove_const, method_defined?, define_method * Toplevel object define_method `mruby-metaprog` gem is linked by default (specified in default.gembox). When it is removed, it will save 40KB (stripped:8KB) on x86-64 environment last time I measured. --- mrbgems/default.gembox | 3 + mrbgems/mruby-bin-strip/bintest/mruby-strip.rb | 6 +- mrbgems/mruby-class-ext/test/module.rb | 2 +- mrbgems/mruby-eval/test/eval.rb | 2 +- mrbgems/mruby-io/test/io.rb | 2 +- mrbgems/mruby-metaprog/mrbgem.rake | 5 + mrbgems/mruby-metaprog/src/metaprog.c | 701 +++++++++++++++++++++++++ mrbgems/mruby-metaprog/test/metaprog.rb | 303 +++++++++++ mrbgems/mruby-method/mrblib/kernel.rb | 5 +- mrbgems/mruby-method/test/method.rb | 12 +- mrbgems/mruby-toplevel-ext/test/toplevel.rb | 4 +- src/class.c | 446 +++------------- src/etc.c | 1 + src/kernel.c | 401 +------------- test/t/class.rb | 25 +- test/t/codegen.rb | 2 +- test/t/kernel.rb | 91 +--- test/t/module.rb | 258 ++------- 18 files changed, 1149 insertions(+), 1120 deletions(-) create mode 100644 mrbgems/mruby-metaprog/mrbgem.rake create mode 100644 mrbgems/mruby-metaprog/src/metaprog.c create mode 100644 mrbgems/mruby-metaprog/test/metaprog.rb (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index 7ddbb16d1..23e65fcee 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -1,4 +1,7 @@ MRuby::GemBox.new do |conf| + # Meta-programming features + conf.gem :core => "mruby-metaprog" + # Use standard IO/File class conf.gem :core => "mruby-io" diff --git a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb index bb664a2b1..2db3c10b1 100644 --- a/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb +++ b/mrbgems/mruby-bin-strip/bintest/mruby-strip.rb @@ -67,7 +67,7 @@ EOS `#{cmd('mruby-strip')} -l #{without_lv.path}` assert_true without_lv.size < with_lv.size - - assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp - assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp +# +# assert_equal '[:a, :b]', `#{cmd('mruby')} -b #{with_lv.path}`.chomp +# assert_equal '[]', `#{cmd('mruby')} -b #{without_lv.path}`.chomp end diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb index ed6713aac..71a8da451 100644 --- a/mrbgems/mruby-class-ext/test/module.rb +++ b/mrbgems/mruby-class-ext/test/module.rb @@ -26,7 +26,7 @@ end assert 'Module#singleton_class?' do mod = Module.new cls = Class.new - scl = cls.singleton_class + scl = (class < true or false + * + * Returns true if the given instance variable is + * defined in obj. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_defined?(:@a) #=> true + * fred.instance_variable_defined?("@b") #=> true + * fred.instance_variable_defined?("@c") #=> false + */ +static mrb_value +mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) +{ + mrb_sym sym; + + mrb_get_args(mrb, "n", &sym); + mrb_iv_name_sym_check(mrb, sym); + return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); +} + +/* 15.3.1.3.21 */ +/* + * call-seq: + * obj.instance_variable_get(symbol) -> obj + * + * Returns the value of the given instance variable, or nil if the + * instance variable is not set. The @ part of the + * variable name should be included for regular instance + * variables. Throws a NameError exception if the + * supplied symbol is not valid as an instance variable name. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_get(:@a) #=> "cat" + * fred.instance_variable_get("@b") #=> 99 + */ +static mrb_value +mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + + mrb_get_args(mrb, "n", &iv_name); + mrb_iv_name_sym_check(mrb, iv_name); + return mrb_iv_get(mrb, self, iv_name); +} + +/* 15.3.1.3.22 */ +/* + * call-seq: + * obj.instance_variable_set(symbol, obj) -> obj + * + * Sets the instance variable names by symbol to + * object, thereby frustrating the efforts of the class's + * author to attempt to provide proper encapsulation. The variable + * did not have to exist prior to this call. + * + * class Fred + * def initialize(p1, p2) + * @a, @b = p1, p2 + * end + * end + * fred = Fred.new('cat', 99) + * fred.instance_variable_set(:@a, 'dog') #=> "dog" + * fred.instance_variable_set(:@c, 'cat') #=> "cat" + * fred.inspect #=> "#" + */ +static mrb_value +mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) +{ + mrb_sym iv_name; + mrb_value val; + + mrb_get_args(mrb, "no", &iv_name, &val); + mrb_iv_name_sym_check(mrb, iv_name); + mrb_iv_set(mrb, self, iv_name, val); + return val; +} + +/* 15.3.1.2.7 */ +/* + * call-seq: + * local_variables -> array + * + * Returns the names of local variables in the current scope. + * + * [mruby limitation] + * If variable symbol information was stripped out from + * compiled binary files using `mruby-strip -l`, this + * method always returns an empty array. + */ +static mrb_value +mrb_local_variables(mrb_state *mrb, mrb_value self) +{ + struct RProc *proc; + mrb_irep *irep; + mrb_value vars; + size_t i; + + proc = mrb->c->ci[-1].proc; + + if (MRB_PROC_CFUNC_P(proc)) { + return mrb_ary_new(mrb); + } + vars = mrb_hash_new(mrb); + while (proc) { + if (MRB_PROC_CFUNC_P(proc)) break; + irep = proc->body.irep; + if (!irep->lv) break; + for (i = 0; i + 1 < irep->nlocals; ++i) { + if (irep->lv[i].name) { + mrb_sym sym = irep->lv[i].name; + const char *name = mrb_sym2name(mrb, sym); + switch (name[0]) { + case '*': case '&': + break; + default: + mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); + break; + } + } + } + if (!MRB_PROC_ENV_P(proc)) break; + proc = proc->upper; + //if (MRB_PROC_SCOPE_P(proc)) break; + if (!proc->c) break; + } + + return mrb_hash_keys(mrb, vars); +} + +KHASH_DECLARE(st, mrb_sym, char, FALSE) + +static void +method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) +{ + khint_t i; + + khash_t(mt) *h = klass->mt; + if (!h || kh_size(h) == 0) return; + for (i=0;iflags & MRB_FL_CLASS_IS_PREPENDED)) { + MRB_CLASS_ORIGIN(klass); + prepended = TRUE; + } + + oldklass = 0; + while (klass && (klass != oldklass)) { + method_entry_loop(mrb, klass, set); + if ((klass->tt == MRB_TT_ICLASS && !prepended) || + (klass->tt == MRB_TT_SCLASS)) { + } + else { + if (!recur) break; + } + oldklass = klass; + klass = klass->super; + } + + ary = mrb_ary_new_capa(mrb, kh_size(set)); + for (i=0;i array + * + * Returns a list of the names of methods publicly accessible in + * obj. This will include all the methods accessible in + * obj's ancestors. + * + * class Klass + * def kMethod() + * end + * end + * k = Klass.new + * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, + * # :class, :instance_variable_set, + * # :methods, :extend, :__send__, :instance_eval] + * k.methods.length #=> 42 + */ +static mrb_value +mrb_obj_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ +} + +/* 15.3.1.3.36 */ +/* + * call-seq: + * obj.private_methods(all=true) -> array + * + * Returns the list of private methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_private_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ +} + +/* 15.3.1.3.37 */ +/* + * call-seq: + * obj.protected_methods(all=true) -> array + * + * Returns the list of protected methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ +} + +/* 15.3.1.3.38 */ +/* + * call-seq: + * obj.public_methods(all=true) -> array + * + * Returns the list of public methods accessible to obj. If + * the all parameter is set to false, only those methods + * in the receiver will be listed. + */ +static mrb_value +mrb_obj_public_methods(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ +} + +static mrb_value +mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj) +{ + khint_t i; + mrb_value ary; + struct RClass* klass; + khash_t(st)* set = kh_init(st, mrb); + + klass = mrb_class(mrb, obj); + + if (klass && (klass->tt == MRB_TT_SCLASS)) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + if (recur) { + while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { + method_entry_loop(mrb, klass, set); + klass = klass->super; + } + } + + ary = mrb_ary_new(mrb); + for (i=0;i array + * + * Returns an array of the names of singleton methods for obj. + * If the optional all parameter is true, the list will include + * methods in modules included in obj. + * Only public and protected singleton methods are returned. + * + * module Other + * def three() end + * end + * + * class Single + * def Single.four() end + * end + * + * a = Single.new + * + * def a.one() + * end + * + * class << a + * include Other + * def two() + * end + * end + * + * Single.singleton_methods #=> [:four] + * a.singleton_methods(false) #=> [:two, :one] + * a.singleton_methods #=> [:two, :one, :three] + */ +static mrb_value +mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) +{ + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_obj_singleton_methods(mrb, recur, self); +} + +static mrb_value +mod_define_singleton_method(mrb_state *mrb, mrb_value self) +{ + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value blk = mrb_nil_value(); + + mrb_get_args(mrb, "n&", &mid, &blk); + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); + return mrb_symbol_value(mid); +} + +static void +check_cv_name_str(mrb_state *mrb, mrb_value str) +{ + const char *s = RSTRING_PTR(str); + mrb_int len = RSTRING_LEN(str); + + if (len < 3 || !(s[0] == '@' && s[1] == '@')) { + mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); + } +} + +static void +check_cv_name_sym(mrb_state *mrb, mrb_sym id) +{ + check_cv_name_str(mrb, mrb_sym2str(mrb, id)); +} + +/* 15.2.2.4.39 */ +/* + * call-seq: + * remove_class_variable(sym) -> obj + * + * Removes the definition of the sym, returning that + * constant's value. + * + * class Dummy + * @@var = 99 + * puts @@var + * p class_variables + * remove_class_variable(:@@var) + * p class_variables + * end + * + * produces: + * + * 99 + * [:@@var] + * [] + */ + +static mrb_value +mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) +{ + mrb_value val; + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + + val = mrb_iv_remove(mrb, mod, id); + if (!mrb_undef_p(val)) return val; + + if (mrb_cv_defined(mrb, mod, id)) { + mrb_name_error(mrb, id, "cannot remove %S for %S", + mrb_sym2str(mrb, id), mod); + } + + mrb_name_error(mrb, id, "class variable %S not defined for %S", + mrb_sym2str(mrb, id), mod); + + /* not reached */ + return mrb_nil_value(); +} + +/* 15.2.2.4.16 */ +/* + * call-seq: + * obj.class_variable_defined?(symbol) -> true or false + * + * Returns true if the given class variable is defined + * in obj. + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_defined?(:@@foo) #=> true + * Fred.class_variable_defined?(:@@bar) #=> false + */ + +static mrb_value +mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); +} + +/* 15.2.2.4.17 */ +/* + * call-seq: + * mod.class_variable_get(symbol) -> obj + * + * Returns the value of the given class variable (or throws a + * NameError exception). The @@ part of the + * variable name should be included for regular class variables + * + * class Fred + * @@foo = 99 + * end + * Fred.class_variable_get(:@@foo) #=> 99 + */ + +static mrb_value +mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) +{ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + check_cv_name_sym(mrb, id); + return mrb_cv_get(mrb, mod, id); +} + +/* 15.2.2.4.18 */ +/* + * call-seq: + * obj.class_variable_set(symbol, obj) -> obj + * + * Sets the class variable names by symbol to + * object. + * + * class Fred + * @@foo = 99 + * def foo + * @@foo + * end + * end + * Fred.class_variable_set(:@@foo, 101) #=> 101 + * Fred.new.foo #=> 101 + */ + +static mrb_value +mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) +{ + mrb_value value; + mrb_sym id; + + mrb_get_args(mrb, "no", &id, &value); + check_cv_name_sym(mrb, id); + mrb_cv_set(mrb, mod, id, value); + return value; +} + +static mrb_value +mrb_mod_included_modules(mrb_state *mrb, mrb_value self) +{ + mrb_value result; + struct RClass *c = mrb_class_ptr(self); + struct RClass *origin = c; + + MRB_CLASS_ORIGIN(origin); + result = mrb_ary_new(mrb); + while (c) { + if (c != origin && c->tt == MRB_TT_ICLASS) { + if (c->c->tt == MRB_TT_MODULE) { + mrb_ary_push(mrb, result, mrb_obj_value(c->c)); + } + } + c = c->super; + } + + return result; +} + +mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); + +/* 15.2.2.4.33 */ +/* + * call-seq: + * mod.instance_methods(include_super=true) -> array + * + * Returns an array containing the names of the public and protected instance + * methods in the receiver. For a module, these are the public and protected methods; + * for a class, they are the instance (not singleton) methods. With no + * argument, or with an argument that is false, the + * instance methods in mod are returned, otherwise the methods + * in mod and mod's superclasses are returned. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * def method3() end + * end + * + * A.instance_methods #=> [:method1] + * B.instance_methods(false) #=> [:method2] + * C.instance_methods(false) #=> [:method3] + * C.instance_methods(true).length #=> 43 + */ + +static mrb_value +mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) +{ + struct RClass *c = mrb_class_ptr(mod); + mrb_bool recur = TRUE; + mrb_get_args(mrb, "|b", &recur); + return mrb_class_instance_method_list(mrb, recur, c, 0); +} + +static void +remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) +{ + struct RClass *c = mrb_class_ptr(mod); + khash_t(mt) *h; + khiter_t k; + + MRB_CLASS_ORIGIN(c); + h = c->mt; + + if (h) { + k = kh_get(mt, mrb, h, mid); + if (k != kh_end(h)) { + kh_del(mt, mrb, h, k); + mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); + return; + } + } + + mrb_name_error(mrb, mid, "method '%S' not defined in %S", + mrb_sym2str(mrb, mid), mod); +} + +/* 15.2.2.4.41 */ +/* + * call-seq: + * remove_method(symbol) -> self + * + * Removes the method identified by _symbol_ from the current + * class. For an example, see Module.undef_method. + */ + +static mrb_value +mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) +{ + mrb_int argc; + mrb_value *argv; + + mrb_get_args(mrb, "*", &argv, &argc); + while (argc--) { + remove_method(mrb, mod, mrb_obj_to_sym(mrb, *argv)); + argv++; + } + return mod; +} + +static mrb_value +mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); + return mrb_nil_value(); /* not reached */ +} + +/* implementation of Module.nesting */ +mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); + +void +mrb_mruby_metaprog_gem_init(mrb_state* mrb) +{ + struct RClass *krn = mrb->kernel_module; + struct RClass *mod = mrb->module_class; + + mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ + mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + + mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ + mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ + mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ + mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ + mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ + mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ + mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ + mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ + mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); + + mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ + mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ + mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ + mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ + mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ + mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ + mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ + mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ + mrb_define_method(mrb, mod, "method_removed", mrb_f_nil, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ + mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ + mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ +} + +void +mrb_mruby_metaprog_gem_final(mrb_state* mrb) +{ +} diff --git a/mrbgems/mruby-metaprog/test/metaprog.rb b/mrbgems/mruby-metaprog/test/metaprog.rb new file mode 100644 index 000000000..587d00d6f --- /dev/null +++ b/mrbgems/mruby-metaprog/test/metaprog.rb @@ -0,0 +1,303 @@ + +assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do + o = Object.new + o.instance_variable_set(:@a, 1) + + assert_true o.instance_variable_defined?("@a") + assert_false o.instance_variable_defined?("@b") + assert_true o.instance_variable_defined?("@a"[0,2]) + assert_true o.instance_variable_defined?("@abc"[0,2]) +end + +assert('Kernel#instance_variables', '15.3.1.3.23') do + o = Object.new + o.instance_eval do + @a = 11 + @b = 12 + end + ivars = o.instance_variables + + assert_equal Array, ivars.class, + assert_equal(2, ivars.size) + assert_true ivars.include?(:@a) + assert_true ivars.include?(:@b) +end + +assert('Kernel#methods', '15.3.1.3.31') do + assert_equal Array, methods.class +end + +assert('Kernel#private_methods', '15.3.1.3.36') do + assert_equal Array, private_methods.class +end + +assert('Kernel#protected_methods', '15.3.1.3.37') do + assert_equal Array, protected_methods.class +end + +assert('Kernel#public_methods', '15.3.1.3.38') do + assert_equal Array, public_methods.class + class Foo + def foo + end + end + assert_equal [:foo], Foo.new.public_methods(false) +end + +assert('Kernel#singleton_methods', '15.3.1.3.45') do + assert_equal singleton_methods.class, Array +end + +assert('Kernel.local_variables', '15.3.1.2.7') do + a, b = 0, 1 + a += b + + vars = Kernel.local_variables.sort + assert_equal [:a, :b, :vars], vars + + assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| + c = 2 + # Kernel#local_variables: 15.3.1.3.28 + local_variables.sort + }.call(-1, -2) +end + +assert('Kernel#define_singleton_method') do + o = Object.new + ret = o.define_singleton_method(:test_method) do + :singleton_method_ok + end + assert_equal :test_method, ret + assert_equal :singleton_method_ok, o.test_method +end + +def labeled_module(name, &block) + Module.new do + (class <tt == MRB_TT_ICLASS) { - if (c->c->tt == MRB_TT_MODULE) { - mrb_ary_push(mrb, result, mrb_obj_value(c->c)); - } - } - c = c->super; - } - - return result; -} - static mrb_value mrb_mod_initialize(mrb_state *mrb, mrb_value mod) { @@ -1250,45 +1214,6 @@ mrb_mod_initialize(mrb_state *mrb, mrb_value mod) return mod; } -mrb_value mrb_class_instance_method_list(mrb_state*, mrb_bool, struct RClass*, int); - -/* 15.2.2.4.33 */ -/* - * call-seq: - * mod.instance_methods(include_super=true) -> array - * - * Returns an array containing the names of the public and protected instance - * methods in the receiver. For a module, these are the public and protected methods; - * for a class, they are the instance (not singleton) methods. With no - * argument, or with an argument that is false, the - * instance methods in mod are returned, otherwise the methods - * in mod and mod's superclasses are returned. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * def method3() end - * end - * - * A.instance_methods #=> [:method1] - * B.instance_methods(false) #=> [:method2] - * C.instance_methods(false) #=> [:method3] - * C.instance_methods(true).length #=> 43 - */ - -static mrb_value -mrb_mod_instance_methods(mrb_state *mrb, mrb_value mod) -{ - struct RClass *c = mrb_class_ptr(mod); - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_class_instance_method_list(mrb, recur, c, 0); -} - /* implementation of module_eval/class_eval */ mrb_value mrb_mod_module_eval(mrb_state*, mrb_value); @@ -1994,270 +1919,6 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } -static mrb_value -mod_define_method(mrb_state *mrb, mrb_value self) -{ - struct RClass *c = mrb_class_ptr(self); - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value proc = mrb_undef_value(); - mrb_value blk; - - mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); - switch (mrb_type(proc)) { - case MRB_TT_PROC: - blk = proc; - break; - case MRB_TT_UNDEF: - /* ignored */ - break; - default: - mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); - break; - } - if (mrb_nil_p(blk)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, c, mid, m); - return mrb_symbol_value(mid); -} - -static mrb_value -top_define_method(mrb_state *mrb, mrb_value self) -{ - return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); -} - -static void -check_cv_name_str(mrb_state *mrb, mrb_value str) -{ - const char *s = RSTRING_PTR(str); - mrb_int len = RSTRING_LEN(str); - - if (len < 3 || !(s[0] == '@' && s[1] == '@')) { - mrb_name_error(mrb, mrb_intern_str(mrb, str), "'%S' is not allowed as a class variable name", str); - } -} - -static void -check_cv_name_sym(mrb_state *mrb, mrb_sym id) -{ - check_cv_name_str(mrb, mrb_sym2str(mrb, id)); -} - -/* 15.2.2.4.16 */ -/* - * call-seq: - * obj.class_variable_defined?(symbol) -> true or false - * - * Returns true if the given class variable is defined - * in obj. - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_defined?(:@@foo) #=> true - * Fred.class_variable_defined?(:@@bar) #=> false - */ - -static mrb_value -mrb_mod_cvar_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_bool_value(mrb_cv_defined(mrb, mod, id)); -} - -/* 15.2.2.4.17 */ -/* - * call-seq: - * mod.class_variable_get(symbol) -> obj - * - * Returns the value of the given class variable (or throws a - * NameError exception). The @@ part of the - * variable name should be included for regular class variables - * - * class Fred - * @@foo = 99 - * end - * Fred.class_variable_get(:@@foo) #=> 99 - */ - -static mrb_value -mrb_mod_cvar_get(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - return mrb_cv_get(mrb, mod, id); -} - -/* 15.2.2.4.18 */ -/* - * call-seq: - * obj.class_variable_set(symbol, obj) -> obj - * - * Sets the class variable names by symbol to - * object. - * - * class Fred - * @@foo = 99 - * def foo - * @@foo - * end - * end - * Fred.class_variable_set(:@@foo, 101) #=> 101 - * Fred.new.foo #=> 101 - */ - -static mrb_value -mrb_mod_cvar_set(mrb_state *mrb, mrb_value mod) -{ - mrb_value value; - mrb_sym id; - - mrb_get_args(mrb, "no", &id, &value); - check_cv_name_sym(mrb, id); - mrb_cv_set(mrb, mod, id, value); - return value; -} - -/* 15.2.2.4.39 */ -/* - * call-seq: - * remove_class_variable(sym) -> obj - * - * Removes the definition of the sym, returning that - * constant's value. - * - * class Dummy - * @@var = 99 - * puts @@var - * p class_variables - * remove_class_variable(:@@var) - * p class_variables - * end - * - * produces: - * - * 99 - * [:@@var] - * [] - */ - -static mrb_value -mrb_mod_remove_cvar(mrb_state *mrb, mrb_value mod) -{ - mrb_value val; - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - check_cv_name_sym(mrb, id); - - val = mrb_iv_remove(mrb, mod, id); - if (!mrb_undef_p(val)) return val; - - if (mrb_cv_defined(mrb, mod, id)) { - mrb_name_error(mrb, id, "cannot remove %S for %S", - mrb_sym2str(mrb, id), mod); - } - - mrb_name_error(mrb, id, "class variable %S not defined for %S", - mrb_sym2str(mrb, id), mod); - - /* not reached */ - return mrb_nil_value(); -} - -/* 15.2.2.4.34 */ -/* - * call-seq: - * mod.method_defined?(symbol) -> true or false - * - * Returns +true+ if the named method is defined by - * _mod_ (or its included modules and, if _mod_ is a class, - * its ancestors). Public and protected methods are matched. - * - * module A - * def method1() end - * end - * class B - * def method2() end - * end - * class C < B - * include A - * def method3() end - * end - * - * A.method_defined? :method1 #=> true - * C.method_defined? "method1" #=> true - * C.method_defined? "method2" #=> true - * C.method_defined? "method3" #=> true - * C.method_defined? "method4" #=> false - */ - -static mrb_value -mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) -{ - mrb_sym id; - - mrb_get_args(mrb, "n", &id); - return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); -} - -static void -remove_method(mrb_state *mrb, mrb_value mod, mrb_sym mid) -{ - struct RClass *c = mrb_class_ptr(mod); - khash_t(mt) *h = find_origin(c)->mt; - khiter_t k; - - if (h) { - k = kh_get(mt, mrb, h, mid); - if (k != kh_end(h)) { - kh_del(mt, mrb, h, k); - mrb_funcall(mrb, mod, "method_removed", 1, mrb_symbol_value(mid)); - return; - } - } - - mrb_name_error(mrb, mid, "method '%S' not defined in %S", - mrb_sym2str(mrb, mid), mod); -} - -/* 15.2.2.4.41 */ -/* - * call-seq: - * remove_method(symbol) -> self - * - * Removes the method identified by _symbol_ from the current - * class. For an example, see Module.undef_method. - */ - -static mrb_value -mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) -{ - mrb_int argc; - mrb_value *argv; - - mrb_get_args(mrb, "*", &argv, &argc); - while (argc--) { - remove_method(mrb, mod, to_sym(mrb, *argv)); - argv++; - } - return mod; -} - - - static void check_const_name_str(mrb_state *mrb, mrb_value str) { @@ -2272,15 +1933,6 @@ check_const_name_sym(mrb_state *mrb, mrb_sym id) check_const_name_str(mrb, mrb_sym2str(mrb, id)); } -static mrb_value -const_defined(mrb_state *mrb, mrb_value mod, mrb_sym id, mrb_bool inherit) -{ - if (inherit) { - return mrb_bool_value(mrb_const_defined(mrb, mod, id)); - } - return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); -} - static mrb_value mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) { @@ -2289,7 +1941,10 @@ mrb_mod_const_defined(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "n|b", &id, &inherit); check_const_name_sym(mrb, id); - return const_defined(mrb, mod, id, inherit); + if (inherit) { + return mrb_bool_value(mrb_const_defined(mrb, mod, id)); + } + return mrb_bool_value(mrb_const_defined_at(mrb, mod, id)); } static mrb_value @@ -2379,11 +2034,79 @@ mrb_mod_const_missing(mrb_state *mrb, mrb_value mod) return mrb_nil_value(); } +/* 15.2.2.4.34 */ +/* + * call-seq: + * mod.method_defined?(symbol) -> true or false + * + * Returns +true+ if the named method is defined by + * _mod_ (or its included modules and, if _mod_ is a class, + * its ancestors). Public and protected methods are matched. + * + * module A + * def method1() end + * end + * class B + * def method2() end + * end + * class C < B + * include A + * def method3() end + * end + * + * A.method_defined? :method1 #=> true + * C.method_defined? "method1" #=> true + * C.method_defined? "method2" #=> true + * C.method_defined? "method3" #=> true + * C.method_defined? "method4" #=> false + */ + static mrb_value -mrb_mod_s_constants(mrb_state *mrb, mrb_value mod) +mrb_mod_method_defined(mrb_state *mrb, mrb_value mod) { - mrb_raise(mrb, E_NOTIMP_ERROR, "Module.constants not implemented"); - return mrb_nil_value(); /* not reached */ + mrb_sym id; + + mrb_get_args(mrb, "n", &id); + return mrb_bool_value(mrb_obj_respond_to(mrb, mrb_class_ptr(mod), id)); +} + +static mrb_value +mod_define_method(mrb_state *mrb, mrb_value self) +{ + struct RClass *c = mrb_class_ptr(self); + struct RProc *p; + mrb_method_t m; + mrb_sym mid; + mrb_value proc = mrb_undef_value(); + mrb_value blk; + + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } + if (mrb_nil_p(blk)) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); + } + p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + p->flags |= MRB_PROC_STRICT; + MRB_METHOD_FROM_PROC(m, p); + mrb_define_method_raw(mrb, c, mid, m); + return mrb_symbol_value(mid); +} + +static mrb_value +top_define_method(mrb_state *mrb, mrb_value self) +{ + return mod_define_method(mrb, mrb_obj_value(mrb->object_class)); } static mrb_value @@ -2439,8 +2162,6 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); /* implementation of instance_eval */ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); -/* implementation of Module.nesting */ -mrb_value mrb_mod_s_nesting(mrb_state*, mrb_value); static mrb_value inspect_main(mrb_state *mrb, mrb_value mod) @@ -2500,9 +2221,6 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, cls, "inherited", mrb_bob_init, MRB_ARGS_REQ(1)); MRB_SET_INSTANCE_TT(mod, MRB_TT_MODULE); - mrb_define_method(mrb, mod, "class_variable_defined?", mrb_mod_cvar_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.16 */ - mrb_define_method(mrb, mod, "class_variable_get", mrb_mod_cvar_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.17 */ - mrb_define_method(mrb, mod, "class_variable_set", mrb_mod_cvar_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.18 */ mrb_define_method(mrb, mod, "extend_object", mrb_mod_extend_object, MRB_ARGS_REQ(1)); /* 15.2.2.4.25 */ mrb_define_method(mrb, mod, "extended", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.26 */ mrb_define_method(mrb, mod, "prepended", mrb_bob_init, MRB_ARGS_REQ(1)); @@ -2511,18 +2229,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "append_features", mrb_mod_append_features, MRB_ARGS_REQ(1)); /* 15.2.2.4.10 */ mrb_define_method(mrb, mod, "class_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.15 */ mrb_define_method(mrb, mod, "included", mrb_bob_init, MRB_ARGS_REQ(1)); /* 15.2.2.4.29 */ - mrb_define_method(mrb, mod, "included_modules", mrb_mod_included_modules, MRB_ARGS_NONE()); /* 15.2.2.4.30 */ mrb_define_method(mrb, mod, "initialize", mrb_mod_initialize, MRB_ARGS_NONE()); /* 15.2.2.4.31 */ - mrb_define_method(mrb, mod, "instance_methods", mrb_mod_instance_methods, MRB_ARGS_ANY()); /* 15.2.2.4.33 */ - mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4.34 */ mrb_define_method(mrb, mod, "module_eval", mrb_mod_module_eval, MRB_ARGS_ANY()); /* 15.2.2.4.35 */ mrb_define_method(mrb, mod, "module_function", mrb_mod_module_function, MRB_ARGS_ANY()); mrb_define_method(mrb, mod, "private", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.36 */ mrb_define_method(mrb, mod, "protected", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.37 */ mrb_define_method(mrb, mod, "public", mrb_mod_dummy_visibility, MRB_ARGS_ANY()); /* 15.2.2.4.38 */ - mrb_define_method(mrb, mod, "remove_class_variable", mrb_mod_remove_cvar, MRB_ARGS_REQ(1)); /* 15.2.2.4.39 */ - mrb_define_method(mrb, mod, "remove_method", mrb_mod_remove_method, MRB_ARGS_ANY()); /* 15.2.2.4.41 */ - mrb_define_method(mrb, mod, "method_removed", mrb_bob_init, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mod, "attr_reader", mrb_mod_attr_reader, MRB_ARGS_ANY()); /* 15.2.2.4.13 */ mrb_define_method(mrb, mod, "attr_writer", mrb_mod_attr_writer, MRB_ARGS_ANY()); /* 15.2.2.4.14 */ mrb_define_method(mrb, mod, "to_s", mrb_mod_to_s, MRB_ARGS_NONE()); @@ -2533,14 +2245,12 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "const_defined?", mrb_mod_const_defined, MRB_ARGS_ARG(1,1)); /* 15.2.2.4.20 */ mrb_define_method(mrb, mod, "const_get", mrb_mod_const_get, MRB_ARGS_REQ(1)); /* 15.2.2.4.21 */ mrb_define_method(mrb, mod, "const_set", mrb_mod_const_set, MRB_ARGS_REQ(2)); /* 15.2.2.4.23 */ - mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "method_defined?", mrb_mod_method_defined, MRB_ARGS_REQ(1)); /* 15.2.2.4 +.34 */ mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); - mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ - mrb_define_class_method(mrb, mod, "nesting", mrb_mod_s_nesting, MRB_ARGS_REQ(0)); /* 15.2.2.3.2 */ mrb_undef_method(mrb, cls, "append_features"); mrb_undef_method(mrb, cls, "extend_object"); diff --git a/src/etc.c b/src/etc.c index 1b8d44a53..12d948a55 100644 --- a/src/etc.c +++ b/src/etc.c @@ -75,6 +75,7 @@ mrb_obj_to_sym(mrb_state *mrb, mrb_value name) if (mrb_nil_p(name)) { name = mrb_inspect(mrb, name); mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", name); + /* not reached */ } /* fall through */ case MRB_TT_STRING: diff --git a/src/kernel.c b/src/kernel.c index fed64e9b0..db576b20d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,20 +14,6 @@ #include #include -typedef enum { - NOEX_PUBLIC = 0x00, - NOEX_NOSUPER = 0x01, - NOEX_PRIVATE = 0x02, - NOEX_PROTECTED = 0x04, - NOEX_MASK = 0x06, - NOEX_BASIC = 0x08, - NOEX_UNDEF = NOEX_NOSUPER, - NOEX_MODFUNC = 0x12, - NOEX_SUPER = 0x20, - NOEX_VCALL = 0x40, - NOEX_RESPONDS = 0x80 -} mrb_method_flag_t; - MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { @@ -551,96 +537,6 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self) return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); } -/* 15.3.1.3.20 */ -/* - * call-seq: - * obj.instance_variable_defined?(symbol) -> true or false - * - * Returns true if the given instance variable is - * defined in obj. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_defined?(:@a) #=> true - * fred.instance_variable_defined?("@b") #=> true - * fred.instance_variable_defined?("@c") #=> false - */ -static mrb_value -mrb_obj_ivar_defined(mrb_state *mrb, mrb_value self) -{ - mrb_sym sym; - - mrb_get_args(mrb, "n", &sym); - mrb_iv_name_sym_check(mrb, sym); - return mrb_bool_value(mrb_iv_defined(mrb, self, sym)); -} - -/* 15.3.1.3.21 */ -/* - * call-seq: - * obj.instance_variable_get(symbol) -> obj - * - * Returns the value of the given instance variable, or nil if the - * instance variable is not set. The @ part of the - * variable name should be included for regular instance - * variables. Throws a NameError exception if the - * supplied symbol is not valid as an instance variable name. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_get(:@a) #=> "cat" - * fred.instance_variable_get("@b") #=> 99 - */ -static mrb_value -mrb_obj_ivar_get(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - - mrb_get_args(mrb, "n", &iv_name); - mrb_iv_name_sym_check(mrb, iv_name); - return mrb_iv_get(mrb, self, iv_name); -} - -/* 15.3.1.3.22 */ -/* - * call-seq: - * obj.instance_variable_set(symbol, obj) -> obj - * - * Sets the instance variable names by symbol to - * object, thereby frustrating the efforts of the class's - * author to attempt to provide proper encapsulation. The variable - * did not have to exist prior to this call. - * - * class Fred - * def initialize(p1, p2) - * @a, @b = p1, p2 - * end - * end - * fred = Fred.new('cat', 99) - * fred.instance_variable_set(:@a, 'dog') #=> "dog" - * fred.instance_variable_set(:@c, 'cat') #=> "cat" - * fred.inspect #=> "#" - */ -static mrb_value -mrb_obj_ivar_set(mrb_state *mrb, mrb_value self) -{ - mrb_sym iv_name; - mrb_value val; - - mrb_get_args(mrb, "no", &iv_name, &val); - mrb_iv_name_sym_check(mrb, iv_name); - mrb_iv_set(mrb, self, iv_name, val); - return val; -} - /* 15.3.1.3.24 */ /* 15.3.1.3.26 */ /* @@ -681,124 +577,6 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) KHASH_DECLARE(st, mrb_sym, char, FALSE) KHASH_DEFINE(st, mrb_sym, char, FALSE, kh_int_hash_func, kh_int_hash_equal) -static void -method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set) -{ - khint_t i; - - khash_t(mt) *h = klass->mt; - if (!h || kh_size(h) == 0) return; - for (i=0;iflags & MRB_FL_CLASS_IS_PREPENDED)) { - MRB_CLASS_ORIGIN(klass); - prepended = TRUE; - } - - oldklass = 0; - while (klass && (klass != oldklass)) { - method_entry_loop(mrb, klass, set); - if ((klass->tt == MRB_TT_ICLASS && !prepended) || - (klass->tt == MRB_TT_SCLASS)) { - } - else { - if (!recur) break; - } - oldklass = klass; - klass = klass->super; - } - - ary = mrb_ary_new_capa(mrb, kh_size(set)); - for (i=0;itt == MRB_TT_SCLASS)) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - if (recur) { - while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) { - method_entry_loop(mrb, klass, set); - klass = klass->super; - } - } - - ary = mrb_ary_new(mrb); - for (i=0;i array - * - * Returns a list of the names of methods publicly accessible in - * obj. This will include all the methods accessible in - * obj's ancestors. - * - * class Klass - * def kMethod() - * end - * end - * k = Klass.new - * k.methods[0..9] #=> [:kMethod, :respond_to?, :nil?, :is_a?, - * # :class, :instance_variable_set, - * # :methods, :extend, :__send__, :instance_eval] - * k.methods.length #=> 42 - */ -static mrb_value -mrb_obj_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, (mrb_method_flag_t)0); /* everything but private */ -} - /* 15.3.1.3.32 */ /* * call_seq: @@ -813,57 +591,6 @@ mrb_false(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.3.36 */ -/* - * call-seq: - * obj.private_methods(all=true) -> array - * - * Returns the list of private methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_private_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PRIVATE); /* private attribute not define */ -} - -/* 15.3.1.3.37 */ -/* - * call-seq: - * obj.protected_methods(all=true) -> array - * - * Returns the list of protected methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_protected_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PROTECTED); /* protected attribute not define */ -} - -/* 15.3.1.3.38 */ -/* - * call-seq: - * obj.public_methods(all=true) -> array - * - * Returns the list of public methods accessible to obj. If - * the all parameter is set to false, only those methods - * in the receiver will be listed. - */ -static mrb_value -mrb_obj_public_methods(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_methods(mrb, recur, self, NOEX_PUBLIC); /* public attribute not define */ -} - /* 15.3.1.2.12 */ /* 15.3.1.3.40 */ /* @@ -1084,67 +811,6 @@ obj_respond_to(mrb_state *mrb, mrb_value self) return mrb_bool_value(respond_to_p); } -/* 15.3.1.3.45 */ -/* - * call-seq: - * obj.singleton_methods(all=true) -> array - * - * Returns an array of the names of singleton methods for obj. - * If the optional all parameter is true, the list will include - * methods in modules included in obj. - * Only public and protected singleton methods are returned. - * - * module Other - * def three() end - * end - * - * class Single - * def Single.four() end - * end - * - * a = Single.new - * - * def a.one() - * end - * - * class << a - * include Other - * def two() - * end - * end - * - * Single.singleton_methods #=> [:four] - * a.singleton_methods(false) #=> [:two, :one] - * a.singleton_methods #=> [:two, :one, :three] - */ -static mrb_value -mrb_obj_singleton_methods_m(mrb_state *mrb, mrb_value self) -{ - mrb_bool recur = TRUE; - mrb_get_args(mrb, "|b", &recur); - return mrb_obj_singleton_methods(mrb, recur, self); -} - -static mrb_value -mod_define_singleton_method(mrb_state *mrb, mrb_value self) -{ - struct RProc *p; - mrb_method_t m; - mrb_sym mid; - mrb_value blk = mrb_nil_value(); - - mrb_get_args(mrb, "n&", &mid, &blk); - if (mrb_nil_p(blk)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); - } - p = (struct RProc*)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb->proc_class); - mrb_proc_copy(p, mrb_proc_ptr(blk)); - p->flags |= MRB_PROC_STRICT; - MRB_METHOD_FROM_PROC(m, p); - mrb_define_method_raw(mrb, mrb_class_ptr(mrb_singleton_class(mrb, self)), mid, m); - return mrb_symbol_value(mid); -} - static mrb_value mrb_obj_ceqq(mrb_state *mrb, mrb_value self) { @@ -1162,58 +828,6 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) return mrb_false_value(); } -/* 15.3.1.2.7 */ -/* - * call-seq: - * local_variables -> array - * - * Returns the names of local variables in the current scope. - * - * [mruby limitation] - * If variable symbol information was stripped out from - * compiled binary files using `mruby-strip -l`, this - * method always returns an empty array. - */ -static mrb_value -mrb_local_variables(mrb_state *mrb, mrb_value self) -{ - struct RProc *proc; - mrb_irep *irep; - mrb_value vars; - size_t i; - - proc = mrb->c->ci[-1].proc; - - if (MRB_PROC_CFUNC_P(proc)) { - return mrb_ary_new(mrb); - } - vars = mrb_hash_new(mrb); - while (proc) { - if (MRB_PROC_CFUNC_P(proc)) break; - irep = proc->body.irep; - if (!irep->lv) break; - for (i = 0; i + 1 < irep->nlocals; ++i) { - if (irep->lv[i].name) { - mrb_sym sym = irep->lv[i].name; - const char *name = mrb_sym2name(mrb, sym); - switch (name[0]) { - case '*': case '&': - break; - default: - mrb_hash_set(mrb, vars, mrb_symbol_value(sym), mrb_true_value()); - break; - } - } - } - if (!MRB_PROC_ENV_P(proc)) break; - proc = proc->upper; - //if (MRB_PROC_SCOPE_P(proc)) break; - if (!proc->c) break; - } - - return mrb_hash_keys(mrb, vars); -} - mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); void mrb_init_kernel(mrb_state *mrb) @@ -1222,13 +836,10 @@ mrb_init_kernel(mrb_state *mrb) mrb->kernel_module = krn = mrb_define_module(mrb, "Kernel"); /* 15.3.1 */ mrb_define_class_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.2 */ - mrb_define_class_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.2.4 */ mrb_define_class_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.2.5 */ - mrb_define_class_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.2.7 */ ; /* 15.3.1.2.11 */ mrb_define_class_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_OPT(2)); /* 15.3.1.2.12 */ - mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ @@ -1245,29 +856,19 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ - mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ - mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ - mrb_define_method(mrb, krn, "instance_variable_set", mrb_obj_ivar_set, MRB_ARGS_REQ(2)); /* 15.3.1.3.22 */ - mrb_define_method(mrb, krn, "instance_variables", mrb_obj_instance_variables, MRB_ARGS_NONE()); /* 15.3.1.3.23 */ + mrb_define_method(mrb, krn, "is_a?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.24 */ mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ - mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ #ifdef MRB_DEFAULT_METHOD_MISSING mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ #endif - mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ - mrb_define_method(mrb, krn, "private_methods", mrb_obj_private_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.36 */ - mrb_define_method(mrb, krn, "protected_methods", mrb_obj_protected_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.37 */ - mrb_define_method(mrb, krn, "public_methods", mrb_obj_public_methods, MRB_ARGS_OPT(1)); /* 15.3.1.3.38 */ mrb_define_method(mrb, krn, "raise", mrb_f_raise, MRB_ARGS_ANY()); /* 15.3.1.3.40 */ mrb_define_method(mrb, krn, "remove_instance_variable", mrb_obj_remove_instance_variable,MRB_ARGS_REQ(1)); /* 15.3.1.3.41 */ mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "send", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.44 */ - mrb_define_method(mrb, krn, "singleton_methods", mrb_obj_singleton_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.45 */ - mrb_define_method(mrb, krn, "define_singleton_method", mod_define_singleton_method, MRB_ARGS_ANY()); mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ diff --git a/test/t/class.rb b/test/t/class.rb index a5118fa93..85450f200 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -36,7 +36,7 @@ end assert('Class#new', '15.2.3.3.3') do assert_raise(TypeError, 'Singleton should raise TypeError') do - "a".singleton_class.new + (class <<"a"; self; end).new end class TestClass @@ -293,15 +293,7 @@ assert('singleton tests') do end end - assert_false baz.singleton_methods.include? :run_foo_mod - assert_false baz.singleton_methods.include? :run_baz - - assert_raise(NoMethodError, 'should raise NoMethodError') do - baz.run_foo_mod - end - assert_raise(NoMethodError, 'should raise NoMethodError') do - baz.run_baz - end + assert_equal :run_baz, baz assert_raise(NoMethodError, 'should raise NoMethodError') do bar.run_foo_mod @@ -318,8 +310,8 @@ assert('singleton tests') do self end - assert_true baz.singleton_methods.include? :run_baz - assert_true baz.singleton_methods.include? :run_foo_mod + assert_true baz.respond_to? :run_baz + assert_true baz.respond_to? :run_foo_mod assert_equal 100, baz.run_foo_mod assert_equal 300, baz.run_baz @@ -440,12 +432,3 @@ assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } end - -assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do - klass = Class.new - assert_raise(TypeError) { klass.remove_method nil } - assert_raise(TypeError) { klass.remove_method 123 } - assert_raise(TypeError) { klass.remove_method 1.23 } - assert_raise(NameError) { klass.remove_method "hello" } - assert_raise(TypeError) { klass.remove_method Class.new } -end diff --git a/test/t/codegen.rb b/test/t/codegen.rb index 4c9e2c594..154d44168 100644 --- a/test/t/codegen.rb +++ b/test/t/codegen.rb @@ -194,4 +194,4 @@ assert('register window of calls (#3783)') do alias send2 send end end -end \ No newline at end of file +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 561118302..9744bddba 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -103,7 +103,7 @@ assert('Kernel#__send__', '15.3.1.3.4') do # test with argument assert_true __send__(:respond_to?, :nil?) # test without argument and without block - assert_equal Array, __send__(:public_methods).class + assert_equal String, __send__(:to_s).class end assert('Kernel#block_given?', '15.3.1.3.6') do @@ -278,30 +278,6 @@ assert('Kernel#inspect', '15.3.1.3.17') do assert_equal "main", s end -assert('Kernel#instance_variable_defined?', '15.3.1.3.20') do - o = Object.new - o.instance_variable_set(:@a, 1) - - assert_true o.instance_variable_defined?("@a") - assert_false o.instance_variable_defined?("@b") - assert_true o.instance_variable_defined?("@a"[0,2]) - assert_true o.instance_variable_defined?("@abc"[0,2]) -end - -assert('Kernel#instance_variables', '15.3.1.3.23') do - o = Object.new - o.instance_eval do - @a = 11 - @b = 12 - end - ivars = o.instance_variables - - assert_equal Array, ivars.class, - assert_equal(2, ivars.size) - assert_true ivars.include?(:@a) - assert_true ivars.include?(:@b) -end - assert('Kernel#is_a?', '15.3.1.3.24') do assert_true is_a?(Kernel) assert_false is_a?(Array) @@ -381,10 +357,6 @@ assert('Kernel#method_missing', '15.3.1.3.30') do end end -assert('Kernel#methods', '15.3.1.3.31') do - assert_equal Array, methods.class -end - assert('Kernel#nil?', '15.3.1.3.32') do assert_false nil? end @@ -408,23 +380,6 @@ end # Kernel#print is defined in mruby-print mrbgem. '15.3.1.3.35' -assert('Kernel#private_methods', '15.3.1.3.36') do - assert_equal Array, private_methods.class -end - -assert('Kernel#protected_methods', '15.3.1.3.37') do - assert_equal Array, protected_methods.class -end - -assert('Kernel#public_methods', '15.3.1.3.38') do - assert_equal Array, public_methods.class - class Foo - def foo - end - end - assert_equal [:foo], Foo.new.public_methods(false) -end - # Kernel#puts is defined in mruby-print mrbgem. '15.3.1.3.39' assert('Kernel#raise', '15.3.1.3.40') do @@ -496,46 +451,13 @@ assert('Kernel#send', '15.3.1.3.44') do # test with argument assert_true send(:respond_to?, :nil?) # test without argument and without block - assert_equal send(:public_methods).class, Array -end - -assert('Kernel#singleton_methods', '15.3.1.3.45') do - assert_equal singleton_methods.class, Array + assert_equal send(:to_s).class, String end assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end -assert('Kernel#to_s on primitives') do - begin - Fixnum.alias_method :to_s_, :to_s - Fixnum.remove_method :to_s - - assert_nothing_raised do - # segfaults if mrb_cptr is used - 1.to_s - end - ensure - Fixnum.alias_method :to_s, :to_s_ - Fixnum.remove_method :to_s_ - end -end - -assert('Kernel.local_variables', '15.3.1.2.7') do - a, b = 0, 1 - a += b - - vars = Kernel.local_variables.sort - assert_equal [:a, :b, :vars], vars - - assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| - c = 2 - # Kernel#local_variables: 15.3.1.3.28 - local_variables.sort - }.call(-1, -2) -end - assert('Kernel#!=') do str1 = "hello" str2 = str1 @@ -585,15 +507,6 @@ assert('Kernel#global_variables') do end end -assert('Kernel#define_singleton_method') do - o = Object.new - ret = o.define_singleton_method(:test_method) do - :singleton_method_ok - end - assert_equal :test_method, ret - assert_equal :singleton_method_ok, o.test_method -end - assert('stack extend') do def recurse(count, stop) return count if count > stop diff --git a/test/t/module.rb b/test/t/module.rb index fb82fc934..fda375721 100644 --- a/test/t/module.rb +++ b/test/t/module.rb @@ -3,7 +3,7 @@ def labeled_module(name, &block) Module.new do - singleton_class.class_eval do + (class < Date: Sun, 16 Sep 2018 00:41:48 +0900 Subject: Add support for iOS platforms that does not support `fork`; fix #4113 --- include/mruby/common.h | 5 ++ mrbgems/mruby-io/src/io.c | 209 ++++++++++++++++++++++++---------------------- 2 files changed, 113 insertions(+), 101 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/include/mruby/common.h b/include/mruby/common.h index d6ec78b0d..4c7d9384a 100644 --- a/include/mruby/common.h +++ b/include/mruby/common.h @@ -7,6 +7,11 @@ #ifndef MRUBY_COMMON_H #define MRUBY_COMMON_H +#ifdef __APPLE__ + #ifndef __TARGETCONDITIONALS__ + #include "TargetConditionals.h" + #endif +#endif #ifdef __cplusplus #ifdef MRB_ENABLE_CXX_ABI diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 67c57a08e..be5c4ba68 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -305,7 +305,112 @@ option_to_fd(mrb_state *mrb, mrb_value obj, const char *key) return -1; /* never reached */ } -#ifndef _WIN32 +#ifdef _WIN32 +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_value cmd, io; + mrb_value mode = mrb_str_new_cstr(mrb, "r"); + mrb_value opt = mrb_hash_new(mrb); + + struct mrb_io *fptr; + const char *pname; + int pid = 0, flags; + STARTUPINFO si; + PROCESS_INFORMATION pi; + SECURITY_ATTRIBUTES saAttr; + + HANDLE ifd[2]; + HANDLE ofd[2]; + + int doexec; + int opt_in, opt_out, opt_err; + + ifd[0] = INVALID_HANDLE_VALUE; + ifd[1] = INVALID_HANDLE_VALUE; + ofd[0] = INVALID_HANDLE_VALUE; + ofd[1] = INVALID_HANDLE_VALUE; + + mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); + io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); + + pname = mrb_string_value_cstr(mrb, &cmd); + flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); + + doexec = (strcmp("-", pname) != 0); + opt_in = option_to_fd(mrb, opt, "in"); + opt_out = option_to_fd(mrb, opt, "out"); + opt_err = option_to_fd(mrb, opt, "err"); + + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + if (flags & FMODE_READABLE) { + if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0) + || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) { + mrb_sys_fail(mrb, "pipe"); + } + } + + if (flags & FMODE_WRITABLE) { + if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0) + || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) { + mrb_sys_fail(mrb, "pipe"); + } + } + + if (doexec) { + ZeroMemory(&pi, sizeof(pi)); + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + si.dwFlags |= STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + si.dwFlags |= STARTF_USESTDHANDLES; + if (flags & FMODE_READABLE) { + si.hStdOutput = ofd[1]; + si.hStdError = ofd[1]; + } + if (flags & FMODE_WRITABLE) { + si.hStdInput = ifd[0]; + } + if (!CreateProcess( + NULL, (char*)pname, NULL, NULL, + TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { + CloseHandle(ifd[0]); + CloseHandle(ifd[1]); + CloseHandle(ofd[0]); + CloseHandle(ofd[1]); + mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); + } + CloseHandle(pi.hThread); + CloseHandle(ifd[0]); + CloseHandle(ofd[1]); + pid = pi.dwProcessId; + } + + mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); + + fptr = mrb_io_alloc(mrb); + fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0); + fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0); + fptr->pid = pid; + fptr->readable = ((flags & FMODE_READABLE) != 0); + fptr->writable = ((flags & FMODE_WRITABLE) != 0); + fptr->sync = 0; + + DATA_TYPE(io) = &mrb_io_type; + DATA_PTR(io) = fptr; + return io; +} +#elif TARGET_OS_IPHONE +mrb_value +mrb_io_s_popen(mrb_state *mrb, mrb_value klass) +{ + mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform"); + return mrb_false_value();w +} +#else mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { @@ -440,104 +545,6 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) } return result; } -#else -mrb_value -mrb_io_s_popen(mrb_state *mrb, mrb_value klass) -{ - mrb_value cmd, io; - mrb_value mode = mrb_str_new_cstr(mrb, "r"); - mrb_value opt = mrb_hash_new(mrb); - - struct mrb_io *fptr; - const char *pname; - int pid = 0, flags; - STARTUPINFO si; - PROCESS_INFORMATION pi; - SECURITY_ATTRIBUTES saAttr; - - HANDLE ifd[2]; - HANDLE ofd[2]; - - int doexec; - int opt_in, opt_out, opt_err; - - ifd[0] = INVALID_HANDLE_VALUE; - ifd[1] = INVALID_HANDLE_VALUE; - ofd[0] = INVALID_HANDLE_VALUE; - ofd[1] = INVALID_HANDLE_VALUE; - - mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt); - io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type)); - - pname = mrb_string_value_cstr(mrb, &cmd); - flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode)); - - doexec = (strcmp("-", pname) != 0); - opt_in = option_to_fd(mrb, opt, "in"); - opt_out = option_to_fd(mrb, opt, "out"); - opt_err = option_to_fd(mrb, opt, "err"); - - saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); - saAttr.bInheritHandle = TRUE; - saAttr.lpSecurityDescriptor = NULL; - - if (flags & FMODE_READABLE) { - if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0) - || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) { - mrb_sys_fail(mrb, "pipe"); - } - } - - if (flags & FMODE_WRITABLE) { - if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0) - || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) { - mrb_sys_fail(mrb, "pipe"); - } - } - - if (doexec) { - ZeroMemory(&pi, sizeof(pi)); - ZeroMemory(&si, sizeof(si)); - si.cb = sizeof(si); - si.dwFlags |= STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - si.dwFlags |= STARTF_USESTDHANDLES; - if (flags & FMODE_READABLE) { - si.hStdOutput = ofd[1]; - si.hStdError = ofd[1]; - } - if (flags & FMODE_WRITABLE) { - si.hStdInput = ifd[0]; - } - if (!CreateProcess( - NULL, (char*)pname, NULL, NULL, - TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) { - CloseHandle(ifd[0]); - CloseHandle(ifd[1]); - CloseHandle(ofd[0]); - CloseHandle(ofd[1]); - mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd); - } - CloseHandle(pi.hThread); - CloseHandle(ifd[0]); - CloseHandle(ofd[1]); - pid = pi.dwProcessId; - } - - mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, "")); - - fptr = mrb_io_alloc(mrb); - fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0); - fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0); - fptr->pid = pid; - fptr->readable = ((flags & FMODE_READABLE) != 0); - fptr->writable = ((flags & FMODE_WRITABLE) != 0); - fptr->sync = 0; - - DATA_TYPE(io) = &mrb_io_type; - DATA_PTR(io) = fptr; - return io; -} #endif static int @@ -1004,7 +1011,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) return 0; } -#ifndef _WIN32 +#if !defined(_WIN32) && !TARGET_OS_IPHONE static mrb_value mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) { @@ -1306,7 +1313,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); -#ifndef _WIN32 +#if !defined(_WIN32) && !TARGET_OS_IPHONE mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE()); #endif -- cgit v1.2.3 From ed4dbce052bd58a7a6d493936711f447792dec20 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 16 Sep 2018 00:58:36 +0900 Subject: fixup! Add support for iOS platforms that does not support `fork`; fix #4113 --- mrbgems/mruby-io/src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index be5c4ba68..8982650dd 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -408,7 +408,7 @@ mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform"); - return mrb_false_value();w + return mrb_false_value(); } #else mrb_value -- cgit v1.2.3 From 82053dd9457c8bed0b493a0e13e9c005fa9ffbb9 Mon Sep 17 00:00:00 2001 From: Tom Black Date: Sat, 15 Sep 2018 13:55:11 -0700 Subject: Exclude pipe and exec on iOS/tvOS Use of `execl()` is prohibited on these platforms --- mrbgems/mruby-io/src/io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 8982650dd..1ac15aab3 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -209,7 +209,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) #endif } -#ifndef _WIN32 +#if !defined(_WIN32) && !TARGET_OS_IPHONE static int mrb_cloexec_pipe(mrb_state *mrb, int fildes[2]) { -- cgit v1.2.3 From ff08856fe314faa4d16b4502c0960a3475387846 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 21:51:53 +0900 Subject: Remove implicit conversion using `to_str` method; fix #3854 We have added internal convenience method `__to_str` which does string type check. The issue #3854 was fixed but fundamental flaw of lack of stack depth check along with fibers still remains. Use `MRB_GC_FIXED_ARENA` for workaround. --- include/mruby.h | 5 +--- include/mruby/string.h | 3 +-- mrbgems/mruby-io/src/file.c | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 8 ++----- mrbgems/mruby-string-ext/mrblib/string.rb | 6 ++--- mrbgems/mruby-string-ext/src/string.c | 6 ++--- mrbgems/mruby-string-ext/test/string.rb | 11 --------- mrblib/string.rb | 11 ++++----- src/class.c | 11 +++++++-- src/kernel.c | 39 +++++-------------------------- src/object.c | 27 +++++++++++++++++++++ src/string.c | 32 ++----------------------- test/t/string.rb | 13 ----------- 13 files changed, 60 insertions(+), 114 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/include/mruby.h b/include/mruby.h index 33597101a..12df9cd5a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -854,10 +854,6 @@ typedef const char *mrb_args_format; /** * Retrieve arguments from mrb_state. * - * When applicable, implicit conversions (such as `to_str`, `to_ary`, `to_hash`) are - * applied to received arguments. - * Used inside a function of mrb_func_t type. - * * @param mrb The current MRuby state. * @param format [mrb_args_format] is a list of format specifiers * @param ... The passing variadic arguments must be a pointer of retrieving type. @@ -1187,6 +1183,7 @@ MRB_API void mrb_gc_unregister(mrb_state *mrb, mrb_value obj); MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val); #define mrb_int(mrb, val) mrb_fixnum(mrb_to_int(mrb, val)) +MRB_API mrb_value mrb_to_str(mrb_state *mrb, mrb_value val); MRB_API void mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t); typedef enum call_type { diff --git a/include/mruby/string.h b/include/mruby/string.h index 481b2fb38..fa1955f48 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -311,8 +311,7 @@ MRB_API mrb_value mrb_str_substr(mrb_state *mrb, mrb_value str, mrb_int beg, mrb * @param [mrb_value] str Ruby string. * @return [mrb_value] A Ruby string. */ -MRB_API mrb_value mrb_string_type(mrb_state *mrb, mrb_value str); - +MRB_API mrb_value mrb_ensure_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_check_string_type(mrb_state *mrb, mrb_value str); MRB_API mrb_value mrb_str_new_capa(mrb_state *mrb, size_t capa); MRB_API mrb_value mrb_str_buf_new(mrb_state *mrb, size_t capa); diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index e65741061..c00663481 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -115,7 +115,7 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj) mrb_get_args(mrb, "*", &argv, &argc); for (i = 0; i < argc; i++) { const char *utf8_path; - pathv = mrb_convert_type(mrb, argv[i], MRB_TT_STRING, "String", "to_str"); + pathv = mrb_ensure_string_type(mrb, argv[i]); utf8_path = mrb_string_value_cstr(mrb, &pathv); path = mrb_locale_from_utf8(utf8_path, -1); if (UNLINK(path) < 0) { diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index a60e9a210..bc2656399 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -141,8 +141,7 @@ mrb_f_float(mrb_state *mrb, mrb_value self) * String(arg) -> string * * Returns arg as an String. - * - * First tries to call its to_str method, then its to_s method. + * converted using to_s method. * * String(self) #=> "main" * String(self.class) #=> "Object" @@ -154,10 +153,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self) mrb_value arg, tmp; mrb_get_args(mrb, "o", &arg); - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(tmp)) { - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); - } + tmp = mrb_convert_type(mrb, arg, MRB_TT_STRING, "String", "to_s"); return tmp; } diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 27ca30610..9212d83a5 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -12,8 +12,8 @@ class String # String.try_convert(/re/) #=> nil # def self.try_convert(obj) - if obj.respond_to?(:to_str) - obj.to_str + if self === obj + obj else nil end @@ -142,7 +142,7 @@ class String # "abcdef".casecmp("ABCDEF") #=> 0 # def casecmp(str) - self.downcase <=> str.to_str.downcase + self.downcase <=> str.__to_str.downcase rescue NoMethodError nil end diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index 6d661c352..ba7e3c610 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -163,7 +163,7 @@ mrb_str_concat_m(mrb_state *mrb, mrb_value self) if (mrb_fixnum_p(str)) str = mrb_fixnum_chr(mrb, str); else - str = mrb_string_type(mrb, str); + str = mrb_ensure_string_type(mrb, str); mrb_str_concat(mrb, self, str); return self; } @@ -191,7 +191,7 @@ mrb_str_start_with(mrb_state *mrb, mrb_value self) for (i = 0; i < argc; i++) { size_t len_l, len_r; int ai = mrb_gc_arena_save(mrb); - sub = mrb_string_type(mrb, argv[i]); + sub = mrb_ensure_string_type(mrb, argv[i]); mrb_gc_arena_restore(mrb, ai); len_l = RSTRING_LEN(self); len_r = RSTRING_LEN(sub); @@ -220,7 +220,7 @@ mrb_str_end_with(mrb_state *mrb, mrb_value self) for (i = 0; i < argc; i++) { size_t len_l, len_r; int ai = mrb_gc_arena_save(mrb); - sub = mrb_string_type(mrb, argv[i]); + sub = mrb_ensure_string_type(mrb, argv[i]); mrb_gc_arena_restore(mrb, ai); len_l = RSTRING_LEN(self); len_r = RSTRING_LEN(sub); diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 781506949..4ccdfd6c3 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -114,12 +114,6 @@ assert('String#concat') do assert_equal "Hello World!", "Hello " << "World" << 33 assert_equal "Hello World!", "Hello ".concat("World").concat(33) - o = Object.new - def o.to_str - "to_str" - end - assert_equal "hi to_str", "hi " << o - assert_raise(TypeError) { "".concat(Object.new) } end @@ -128,11 +122,6 @@ assert('String#casecmp') do assert_equal 0, "aBcDeF".casecmp("abcdef") assert_equal(-1, "abcdef".casecmp("abcdefg")) assert_equal 0, "abcdef".casecmp("ABCDEF") - o = Object.new - def o.to_str - "ABCDEF" - end - assert_equal 0, "abcdef".casecmp(o) end assert('String#count') do diff --git a/mrblib/string.rb b/mrblib/string.rb index 07b80b340..397603e9d 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -12,7 +12,7 @@ class String def each_line(rs = "\n", &block) return to_enum(:each_line, rs, &block) unless block return block.call(self) if rs.nil? - rs = rs.to_str + rs = rs.__to_str offset = 0 rs_len = rs.length this = dup @@ -67,7 +67,7 @@ class String block = nil end if !replace.nil? || !block - replace = replace.to_str + replace = replace.__to_str end offset = 0 result = [] @@ -129,12 +129,12 @@ class String end pattern, replace = *args - pattern = pattern.to_str + pattern = pattern.__to_str if args.length == 2 && block block = nil end unless block - replace = replace.to_str + replace = replace.__to_str end result = [] this = dup @@ -245,14 +245,13 @@ class String ## # ISO 15.2.10.5.3 def =~(re) - raise TypeError, "type mismatch: String given" if re.respond_to? :to_str re =~ self end ## # ISO 15.2.10.5.27 def match(re, &block) - if re.respond_to? :to_str + if String === re if Object.const_defined?(:Regexp) r = Regexp.new(re) r.match(self, &block) diff --git a/src/class.c b/src/class.c index 50ab0ea59..90c73104e 100644 --- a/src/class.c +++ b/src/class.c @@ -504,10 +504,17 @@ check_type(mrb_state *mrb, mrb_value val, enum mrb_vtype t, const char *c, const return tmp; } +#define CHECK_TYPE(mrb, val, t, c) do { \ + if (mrb_type(val) != (t)) {\ + mrb_raisef(mrb, E_TYPE_ERROR, "expected %S", mrb_str_new_lit(mrb, c));\ + }\ +} while (0) + static mrb_value to_str(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_STRING, "String", "to_str"); + CHECK_TYPE(mrb, val, MRB_TT_STRING, "String"); + return val; } static mrb_value @@ -1972,7 +1979,7 @@ mrb_mod_const_get(mrb_state *mrb, mrb_value mod) } /* const get with class path string */ - path = mrb_string_type(mrb, path); + path = mrb_ensure_string_type(mrb, path); ptr = RSTRING_PTR(path); len = RSTRING_LEN(path); off = 0; diff --git a/src/kernel.c b/src/kernel.c index 195594d6b..ce9cd1d44 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -746,6 +746,7 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) { return mrb_respond_to(mrb, obj, id); } + /* 15.3.1.3.43 */ /* * call-seq: @@ -765,45 +766,16 @@ basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) static mrb_value obj_respond_to(mrb_state *mrb, mrb_value self) { - mrb_value mid; mrb_sym id, rtm_id; - mrb_bool priv = FALSE, respond_to_p = TRUE; - - mrb_get_args(mrb, "o|b", &mid, &priv); - - if (mrb_symbol_p(mid)) { - id = mrb_symbol(mid); - } - else { - mrb_value tmp; - if (mrb_string_p(mid)) { - tmp = mrb_check_intern_str(mrb, mid); - } - else { - tmp = mrb_check_string_type(mrb, mid); - if (mrb_nil_p(tmp)) { - tmp = mrb_inspect(mrb, mid); - mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); - } - tmp = mrb_check_intern_str(mrb, tmp); - } - if (mrb_nil_p(tmp)) { - respond_to_p = FALSE; - } - else { - id = mrb_symbol(tmp); - } - } - - if (respond_to_p) { - respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); - } + mrb_bool priv = FALSE, respond_to_p; + mrb_get_args(mrb, "n|b", &id, &priv); + respond_to_p = basic_obj_respond_to(mrb, self, id, !priv); if (!respond_to_p) { rtm_id = mrb_intern_lit(mrb, "respond_to_missing?"); if (basic_obj_respond_to(mrb, self, rtm_id, !priv)) { mrb_value args[2], v; - args[0] = mid; + args[0] = mrb_symbol_value(id); args[1] = mrb_bool_value(priv); v = mrb_funcall_argv(mrb, self, rtm_id, 2, args); return mrb_bool_value(mrb_bool(v)); @@ -873,6 +845,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ + mrb_define_method(mrb, krn, "__to_str", mrb_to_str, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); diff --git a/src/object.c b/src/object.c index ba6fa3947..18ccacfb9 100644 --- a/src/object.c +++ b/src/object.c @@ -579,6 +579,33 @@ mrb_Float(mrb_state *mrb, mrb_value val) } #endif +MRB_API mrb_value +mrb_to_str(mrb_state *mrb, mrb_value val) +{ + if (!mrb_string_p(val)) { + mrb_value type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to String", type); + } + return val; +} + +MRB_API mrb_value +mrb_ensure_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to String", + inspect_type(mrb, str)); + } + return str; +} + +MRB_API mrb_value +mrb_check_string_type(mrb_state *mrb, mrb_value str) +{ + if (!mrb_string_p(str)) return mrb_nil_value(); + return str; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { diff --git a/src/string.c b/src/string.c index b7abfb762..b6d4ecef0 100644 --- a/src/string.c +++ b/src/string.c @@ -956,15 +956,7 @@ str_eql(mrb_state *mrb, const mrb_value str1, const mrb_value str2) MRB_API mrb_bool mrb_str_equal(mrb_state *mrb, mrb_value str1, mrb_value str2) { - if (mrb_immediate_p(str2)) return FALSE; - if (!mrb_string_p(str2)) { - if (mrb_nil_p(str2)) return FALSE; - if (!mrb_respond_to(mrb, str2, mrb_intern_lit(mrb, "to_str"))) { - return FALSE; - } - str2 = mrb_funcall(mrb, str2, "to_str", 0); - return mrb_equal(mrb, str2, str1); - } + if (!mrb_string_p(str2)) return FALSE; return str_eql(mrb, str1, str2); } @@ -992,14 +984,8 @@ mrb_str_equal_m(mrb_state *mrb, mrb_value str1) MRB_API mrb_value mrb_str_to_str(mrb_state *mrb, mrb_value str) { - mrb_value s; - if (!mrb_string_p(str)) { - s = mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); - if (mrb_nil_p(s)) { - s = mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); - } - return s; + return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_s"); } return str; } @@ -1714,18 +1700,6 @@ mrb_ptr_to_str(mrb_state *mrb, void *p) return mrb_obj_value(p_str); } -MRB_API mrb_value -mrb_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} - -MRB_API mrb_value -mrb_check_string_type(mrb_state *mrb, mrb_value str) -{ - return mrb_check_convert_type(mrb, str, MRB_TT_STRING, "String", "to_str"); -} - /* 15.2.10.5.30 */ /* * call-seq: @@ -2379,7 +2353,6 @@ mrb_str_to_f(mrb_state *mrb, mrb_value self) /* * call-seq: * str.to_s => str - * str.to_str => str * * Returns the receiver. */ @@ -2783,7 +2756,6 @@ mrb_init_string(mrb_state *mrb) #endif mrb_define_method(mrb, s, "to_i", mrb_str_to_i, MRB_ARGS_ANY()); /* 15.2.10.5.39 */ mrb_define_method(mrb, s, "to_s", mrb_str_to_s, MRB_ARGS_NONE()); /* 15.2.10.5.40 */ - mrb_define_method(mrb, s, "to_str", mrb_str_to_s, MRB_ARGS_NONE()); mrb_define_method(mrb, s, "to_sym", mrb_str_intern, MRB_ARGS_NONE()); /* 15.2.10.5.41 */ mrb_define_method(mrb, s, "upcase", mrb_str_upcase, MRB_ARGS_NONE()); /* 15.2.10.5.42 */ mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ diff --git a/test/t/string.rb b/test/t/string.rb index e91b915fe..3a1eced16 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -253,19 +253,6 @@ assert('String#chomp!', '15.2.10.5.10') do assert_equal 'abc', e end -assert('String#chomp! uses the correct length') do - class A - def to_str - $s.replace("AA") - "A" - end - end - - $s = "AAA" - $s.chomp!(A.new) - assert_equal $s, "A" -end - assert('String#chop', '15.2.10.5.11') do a = ''.chop b = 'abc'.chop -- cgit v1.2.3 From 027f4ded34d09221ea6146aa7ccb54d001418f8c Mon Sep 17 00:00:00 2001 From: dearblue Date: Sun, 23 Dec 2018 17:24:16 +0900 Subject: Suppress TARGET_OS_IPHONE warns --- mrbgems/mruby-io/src/io.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 1ac15aab3..e5b83e923 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -209,7 +209,7 @@ mrb_fd_cloexec(mrb_state *mrb, int fd) #endif } -#if !defined(_WIN32) && !TARGET_OS_IPHONE +#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) static int mrb_cloexec_pipe(mrb_state *mrb, int fildes[2]) { @@ -403,7 +403,7 @@ mrb_io_s_popen(mrb_state *mrb, mrb_value klass) DATA_PTR(io) = fptr; return io; } -#elif TARGET_OS_IPHONE +#elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE mrb_value mrb_io_s_popen(mrb_state *mrb, mrb_value klass) { @@ -1011,7 +1011,7 @@ mrb_io_read_data_pending(mrb_state *mrb, mrb_value io) return 0; } -#if !defined(_WIN32) && !TARGET_OS_IPHONE +#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) static mrb_value mrb_io_s_pipe(mrb_state *mrb, mrb_value klass) { @@ -1313,7 +1313,7 @@ mrb_init_io(mrb_state *mrb) mrb_define_class_method(mrb, io, "for_fd", mrb_io_s_for_fd, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "select", mrb_io_s_select, MRB_ARGS_ANY()); mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY()); -#if !defined(_WIN32) && !TARGET_OS_IPHONE +#if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE()); #endif -- cgit v1.2.3 From ff0ab552d0f44c62ea9852f12353b9a6de5ab7d9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 1 Jan 2019 19:25:12 +0900 Subject: io: Skip TTY test for environments that TTY device is unavailable. e.g. GitLab CI --- mrbgems/mruby-io/test/io.rb | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 48a74f31e..e4a449696 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -344,15 +344,21 @@ end assert('IO#isatty') do skip "isatty is not supported on this platform" if MRubyIOTestUtil.win? - f1 = File.open("/dev/tty") - f2 = File.open($mrbtest_io_rfname) - - assert_true f1.isatty - assert_false f2.isatty - - f1.close - f2.close - true + begin + f = File.open("/dev/tty") + rescue RuntimeError => e + skip e.message + else + assert_true f.isatty + ensure + f&.close + end + begin + f = File.open($mrbtest_io_rfname) + assert_false f.isatty + ensure + f&.close + end end assert('IO#pos=, IO#seek') do -- cgit v1.2.3 From d88d7aaf4b3c994d5f1e8903fb4b14752981f721 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 9 Jan 2019 13:04:23 +0900 Subject: Use `$mrbtest_io_wfname` for `chmod` test. --- mrbgems/mruby-io/test/file.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ca285f5bd..8d2be04c8 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -200,11 +200,11 @@ assert('File.symlink') do end assert('File.chmod') do - File.open('chmod-test', 'w') {} + File.open("#{$mrbtest_io_wfname}.chmod-test", 'w') {} begin - assert_equal 1, File.chmod(0400, 'chmod-test') + assert_equal 1, File.chmod(0400, "#{$mrbtest_io_wfname}.chmod-test") ensure - File.delete('chmod-test') + File.delete("#{$mrbtest_io_wfname}.chmod-test") end end -- cgit v1.2.3 From bdbbac999f00532559c1b3b9aa2b372cd26eddc0 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 25 Jan 2019 20:02:45 +0900 Subject: Remove definition of `assert_nothing_raised` in `IO` test --- mrbgems/mruby-io/test/io.rb | 20 -------------------- 1 file changed, 20 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index e4a449696..881e94185 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -1,26 +1,6 @@ ## # IO Test -unless Object.respond_to? :assert_nothing_raised - def assert_nothing_raised(*exp) - ret = true - if $mrbtest_assert - $mrbtest_assert_idx += 1 - msg = exp.last.class == String ? exp.pop : "" - begin - yield - rescue Exception => e - msg = "#{msg} exception raised." - diff = " Class: <#{e.class}>\n" + - " Message: #{e.message}" - $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff]) - ret = false - end - end - ret - end -end - assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not -- cgit v1.2.3 From e9a6ec05b69e2463711e584eb336c56dc06fbe71 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 25 Jan 2019 20:12:24 +0900 Subject: Use assertion methods in `File` test --- mrbgems/mruby-io/test/file.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 8d2be04c8..7b67ded26 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -1,16 +1,16 @@ ## -# IO Test +# File Test -assert('File', '15.2.21') do - File.class == Class +assert('File TEST SETUP') do + MRubyIOTestUtil.io_test_setup end -assert('File', '15.2.21.2') do - File.superclass == IO +assert('File', '15.2.21') do + assert_equal Class, File.class end -assert('File TEST SETUP') do - MRubyIOTestUtil.io_test_setup +assert('File', '15.2.21.2') do + assert_equal IO, File.superclass end assert('File#initialize', '15.2.21.4.1') do @@ -27,7 +27,7 @@ assert('File#path', '15.2.21.4.2') do assert_equal $mrbtest_io_rfname, io.path io.close assert_equal $mrbtest_io_rfname, io.path - io.closed? + assert_true io.closed? end assert('File.basename') do -- cgit v1.2.3 From b91a17b33b93966feeea75facad42cc4730e7485 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 25 Jan 2019 20:35:55 +0900 Subject: Remove unused file for `mruby-io` test --- mrbgems/mruby-io/test/gc_filedes.sh | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 mrbgems/mruby-io/test/gc_filedes.sh (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/gc_filedes.sh b/mrbgems/mruby-io/test/gc_filedes.sh deleted file mode 100644 index 6e5d1bbf1..000000000 --- a/mrbgems/mruby-io/test/gc_filedes.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -ulimit -n 20 -mruby -e '100.times { File.open "'$0'" }' -- cgit v1.2.3 From e85cb9799cd54d5fa79500f07e559a4169d4243f Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 27 Jan 2019 20:35:41 +0900 Subject: Remove no meaning statements in `mruby-io` tests --- mrbgems/mruby-io/test/file.rb | 1 - mrbgems/mruby-io/test/file_test.rb | 4 ---- mrbgems/mruby-io/test/io.rb | 23 ----------------------- 3 files changed, 28 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 7b67ded26..539e25047 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -177,7 +177,6 @@ assert('File.path') do assert_equal "a/../b/./c", File.path("a/../b/./c") assert_raise(TypeError) { File.path(nil) } assert_raise(TypeError) { File.path(123) } - end assert('File.symlink') do diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 2c831f0d5..7148e9dc2 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -70,8 +70,6 @@ assert("FileTest.size?") do assert_raise IOError do FileTest.size?(fp2) end - - fp1.closed? && fp2.closed? end assert("FileTest.socket?") do @@ -108,8 +106,6 @@ assert("FileTest.zero?") do assert_raise IOError do FileTest.zero?(fp2) end - - fp1.closed? && fp2.closed? end assert('FileTest TEST CLEANUP') do diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 881e94185..85852c179 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -30,8 +30,6 @@ assert('IO.open', '15.2.20.4.1') do IO.open(fd) do |io| assert_equal $mrbtest_io_msg, io.read end - - true end assert('IO#close', '15.2.20.5.1') do @@ -72,8 +70,6 @@ assert('IO#eof?', '15.2.20.5.6') do io.read assert_true io.eof? io.close - - true end assert('IO#flush', '15.2.20.5.7') do @@ -93,7 +89,6 @@ assert('IO#getc', '15.2.20.5.8') do } assert_equal nil, io.getc io.close - true end #assert('IO#gets', '15.2.20.5.9') do @@ -179,8 +174,6 @@ assert('IO#write', '15.2.20.5.20') do io.rewind assert_equal "ab123fg", io.read io.close - - true end assert('IO#<<') do @@ -188,7 +181,6 @@ assert('IO#<<') do io << "" << "" assert_equal 0, io.pos io.close - true end assert('IO#dup for readable') do @@ -208,7 +200,6 @@ assert('IO#dup for readable') do dup.close assert_false io.closed? io.close - true end assert('IO#dup for writable') do @@ -221,7 +212,6 @@ assert('IO#dup for writable') do assert_equal "mruby", dup.sysread(5) dup.close io.close - true end assert('IO.for_fd') do @@ -229,13 +219,11 @@ assert('IO.for_fd') do io = IO.for_fd(fd) assert_equal $mrbtest_io_msg, io.read io.close - true end assert('IO.new') do io = IO.new(0) io.close - true end assert('IO gc check') do @@ -280,7 +268,6 @@ assert('IO.sysopen, IO#sysread') do io = IO.new fd, "w" assert_raise(IOError) { io.sysread(1) } io.close - true end assert('IO.sysopen, IO#syswrite') do @@ -294,8 +281,6 @@ assert('IO.sysopen, IO#syswrite') do io = IO.new(IO.sysopen($mrbtest_io_rfname), "r") assert_raise(IOError) { io.syswrite("a") } io.close - - true end assert('IO#_read_buf') do @@ -319,7 +304,6 @@ assert('IO#_read_buf') do assert_equal true, io.eof assert_equal true, io.eof? io.close - io.closed? end assert('IO#isatty') do @@ -352,7 +336,6 @@ assert('IO#pos=, IO#seek') do assert_equal 0, io.seek(0) assert_equal 0, io.pos io.close - io.closed? end assert('IO#rewind') do @@ -363,7 +346,6 @@ assert('IO#rewind') do assert_equal 0, io.rewind assert_equal 0, io.pos io.close - io.closed? end assert('IO#gets') do @@ -412,7 +394,6 @@ assert('IO#gets') do assert_equal nil, io.gets, "gets third line; returns nil" io.close - io.closed? end assert('IO#gets - paragraph mode') do @@ -423,7 +404,6 @@ assert('IO#gets - paragraph mode') do io.write "2" * 10 + "\n" assert_equal 34 + $cr * 4, io.pos io.close - assert_equal true, io.closed? fd = IO.sysopen $mrbtest_io_wfname io = IO.new fd @@ -434,7 +414,6 @@ assert('IO#gets - paragraph mode') do text2 = io.gets("") assert_equal para2, text2 io.close - io.closed? end assert('IO.popen') do @@ -528,7 +507,6 @@ assert('IO#fileno') do assert_equal io.fileno, fd assert_equal io.to_i, fd io.close - io.closed? end assert('IO#close_on_exec') do @@ -550,7 +528,6 @@ assert('IO#close_on_exec') do assert_equal(false, io.close_on_exec?) io.close - io.closed? begin r, w = IO.pipe -- cgit v1.2.3 From 12ba571a1385dd83bdccb63aab3b0ce34720c694 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 28 Jan 2019 12:17:41 +0900 Subject: Use assertion methods in `FileTest` tests --- mrbgems/mruby-io/test/file_test.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 7148e9dc2..04e10e0c8 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -67,9 +67,11 @@ assert("FileTest.size?") do assert_raise IOError do FileTest.size?(fp1) end + assert_true fp1.closed? assert_raise IOError do FileTest.size?(fp2) end + assert_true fp2.closed? end assert("FileTest.socket?") do @@ -103,9 +105,11 @@ assert("FileTest.zero?") do assert_raise IOError do FileTest.zero?(fp1) end + assert_true fp1.closed? assert_raise IOError do FileTest.zero?(fp2) end + assert_true fp2.closed? end assert('FileTest TEST CLEANUP') do -- cgit v1.2.3 From c6cd69970bcb43adbba40111757d57ea85a4899b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 26 Feb 2019 21:12:41 +0900 Subject: Remove unneeded `const_defined?(:Time)` in `mruby-io` test `mruby-time` is included in test dependencies. --- mrbgems/mruby-io/test/file.rb | 3 --- 1 file changed, 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 539e25047..ba4100492 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -69,9 +69,6 @@ assert('File#flock') do end assert('File#mtime') do - unless Object.const_defined?(:Time) - skip "File#mtime require Time" - end begin File.open("#{$mrbtest_io_wfname}.mtime", 'w') do |f| assert_equal Time, f.mtime.class -- cgit v1.2.3 From 164985881b6d7d96218ec5cd986ca1bb4c919698 Mon Sep 17 00:00:00 2001 From: Shouji Kuboyama Date: Mon, 15 Apr 2019 17:16:08 +0900 Subject: Fix test, popen and cmd in mruby-io --- mrbgems/mruby-io/test/io.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 85852c179..44eaca6be 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -3,7 +3,7 @@ assert('IO TEST SETUP') do MRubyIOTestUtil.io_test_setup - $cr = MRubyIOTestUtil.win? ? 1 : 0 # "\n" include CR or not + $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] end assert('IO', '15.2.20') do @@ -419,7 +419,7 @@ end assert('IO.popen') do begin $? = nil - io = IO.popen("echo mruby-io") + io = IO.popen("#{$cmd}echo mruby-io") assert_true io.close_on_exec? assert_equal Fixnum, io.pid.class @@ -598,7 +598,7 @@ end assert('`cmd`') do begin - assert_equal `echo foo`, "foo\n" + assert_equal `#{$cmd}echo foo`, "foo#{$crlf}" rescue NotImplementedError => e skip e.message end -- cgit v1.2.3 From 270131253f62d806ea480ef4793e0b39cd068ee4 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sat, 27 Apr 2019 12:50:02 +0900 Subject: Remove duplicated `String#each_char` --- mrbgems/mruby-io/test/io.rb | 4 ++-- mrbgems/mruby-method/test/method.rb | 2 +- mrbgems/mruby-string-ext/mrblib/string.rb | 10 +++++++--- mrbgems/mruby-string-ext/test/string.rb | 12 ++++++------ mrblib/string.rb | 12 ------------ 5 files changed, 16 insertions(+), 24 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 44eaca6be..2b3f9cf13 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -84,7 +84,7 @@ end assert('IO#getc', '15.2.20.5.8') do io = IO.new(IO.sysopen($mrbtest_io_rfname)) - $mrbtest_io_msg.each_char { |ch| + $mrbtest_io_msg.split("").each { |ch| assert_equal ch, io.getc } assert_equal nil, io.getc @@ -127,7 +127,7 @@ end assert('IO#readchar', '15.2.20.5.15') do # almost same as IO#getc IO.open(IO.sysopen($mrbtest_io_rfname)) do |io| - $mrbtest_io_msg.each_char { |ch| + $mrbtest_io_msg.split("").each { |ch| assert_equal ch, io.readchar } assert_raise(EOFError) do diff --git a/mrbgems/mruby-method/test/method.rb b/mrbgems/mruby-method/test/method.rb index dfddde9cc..0b67d3e61 100644 --- a/mrbgems/mruby-method/test/method.rb +++ b/mrbgems/mruby-method/test/method.rb @@ -21,7 +21,7 @@ class Interpreter } def interpret(string) @ret = "" - string.each_char {|b| Dispatcher[b].bind(self).call } + string.split("").each {|b| Dispatcher[b].bind(self).call } end end diff --git a/mrbgems/mruby-string-ext/mrblib/string.rb b/mrbgems/mruby-string-ext/mrblib/string.rb index 311803ea2..fdaf2f960 100644 --- a/mrbgems/mruby-string-ext/mrblib/string.rb +++ b/mrbgems/mruby-string-ext/mrblib/string.rb @@ -310,11 +310,15 @@ class String end end + ## + # Call the given block for each character of + # +self+. def each_char(&block) return to_enum :each_char unless block - - split('').each do |i| - block.call(i) + pos = 0 + while pos < self.size + block.call(self[pos]) + pos += 1 end self end diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index 44ca1fde2..02777e594 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -657,19 +657,19 @@ assert('String#chars(UTF-8)') do end if UTF8STRING assert('String#each_char') do - s = "" + chars = [] "hello!".each_char do |x| - s += x + chars << x end - assert_equal "hello!", s + assert_equal ["h", "e", "l", "l", "o", "!"], chars end assert('String#each_char(UTF-8)') do - s = "" + chars = [] "こんにちは世界!".each_char do |x| - s += x + chars << x end - assert_equal "こんにちは世界!", s + assert_equal ["こ", "ん", "に", "ち", "は", "世", "界", "!"], chars end if UTF8STRING assert('String#codepoints') do diff --git a/mrblib/string.rb b/mrblib/string.rb index c92a9e7be..506f23c83 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -164,18 +164,6 @@ class String self.replace(str) end - ## - # Call the given block for each character of - # +self+. - def each_char(&block) - pos = 0 - while pos < self.size - block.call(self[pos]) - pos += 1 - end - self - end - ## # Call the given block for each byte of +self+. def each_byte(&block) -- cgit v1.2.3 From 8cc2ad3348d00825d5daa6aed63a952ac6cec845 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 29 Apr 2019 11:09:35 +0900 Subject: Fix missing assertions in `mruby-io` test --- mrbgems/mruby-io/test/file.rb | 12 +++----- mrbgems/mruby-io/test/file_test.rb | 8 ++---- mrbgems/mruby-io/test/io.rb | 57 ++++++++++++++++++++------------------ 3 files changed, 36 insertions(+), 41 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index ba4100492..88ced31a6 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -1,15 +1,13 @@ ## # File Test -assert('File TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end +MRubyIOTestUtil.io_test_setup -assert('File', '15.2.21') do +assert('File.class', '15.2.21') do assert_equal Class, File.class end -assert('File', '15.2.21.2') do +assert('File.superclass', '15.2.21.2') do assert_equal IO, File.superclass end @@ -204,6 +202,4 @@ assert('File.chmod') do end end -assert('File TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 04e10e0c8..72e921ce9 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -1,9 +1,7 @@ ## # FileTest -assert('FileTest TEST SETUP') do - MRubyIOTestUtil.io_test_setup -end +MRubyIOTestUtil.io_test_setup assert("FileTest.directory?") do dir = MRubyIOTestUtil.mkdtemp("mruby-io-test.XXXXXX") @@ -112,6 +110,4 @@ assert("FileTest.zero?") do assert_true fp2.closed? end -assert('FileTest TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 2b3f9cf13..5004d0042 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -1,35 +1,44 @@ ## # IO Test -assert('IO TEST SETUP') do - MRubyIOTestUtil.io_test_setup - $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] +MRubyIOTestUtil.io_test_setup +$cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] + +assert_io_open = ->(meth) do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end + + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end + end + io2.close unless meth == :open end -assert('IO', '15.2.20') do +assert('IO.class', '15.2.20') do assert_equal(Class, IO.class) end -assert('IO', '15.2.20.2') do +assert('IO.superclass', '15.2.20.2') do assert_equal(Object, IO.superclass) end -assert('IO', '15.2.20.3') do +assert('IO.ancestors', '15.2.20.3') do assert_include(IO.ancestors, Enumerable) end assert('IO.open', '15.2.20.4.1') do - fd = IO.sysopen $mrbtest_io_rfname - assert_equal Fixnum, fd.class - io = IO.open fd - assert_equal IO, io.class - assert_equal $mrbtest_io_msg, io.read - io.close - - fd = IO.sysopen $mrbtest_io_rfname - IO.open(fd) do |io| - assert_equal $mrbtest_io_msg, io.read - end + assert_io_open.(:open) end assert('IO#close', '15.2.20.5.1') do @@ -215,19 +224,15 @@ assert('IO#dup for writable') do end assert('IO.for_fd') do - fd = IO.sysopen($mrbtest_io_rfname) - io = IO.for_fd(fd) - assert_equal $mrbtest_io_msg, io.read - io.close + assert_io_open.(:for_fd) end assert('IO.new') do - io = IO.new(0) - io.close + assert_io_open.(:new) end assert('IO gc check') do - 100.times { IO.new(0) } + assert_nothing_raised { 100.times { IO.new(0) } } end assert('IO.sysopen("./nonexistent")') do @@ -604,6 +609,4 @@ assert('`cmd`') do end end -assert('IO TEST CLEANUP') do - assert_nil MRubyIOTestUtil.io_test_cleanup -end +MRubyIOTestUtil.io_test_cleanup -- cgit v1.2.3 From e2604c1550562b6fa507570e817cadf9981e1c82 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Mon, 6 May 2019 23:16:03 +0900 Subject: Avoid using `mrb_str_to_cstr` if possible Because it always allocate new string. Replace with the followings: - Use `RSRING_PTR` if string is guaranteed to be null-terminated. - Use `mrb_string_value_cstr` or `mrb_get_args("z")` if return value isn't modified. --- mrbgems/mruby-io/src/file.c | 21 ++++++++++----------- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/test/mruby_io_test.c | 6 ++---- mrbgems/mruby-socket/src/socket.c | 4 ++-- 4 files changed, 15 insertions(+), 18 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index c00663481..b17b95e24 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -146,7 +146,7 @@ mrb_file_s_rename(mrb_state *mrb, mrb_value obj) #endif mrb_locale_free(src); mrb_locale_free(dst); - mrb_sys_fail(mrb, mrb_str_to_cstr(mrb, mrb_format(mrb, "(%S, %S)", from, to))); + mrb_sys_fail(mrb, RSTRING_PTR(mrb_format(mrb, "(%S, %S)", from, to))); } mrb_locale_free(src); mrb_locale_free(dst); @@ -159,12 +159,12 @@ mrb_file_dirname(mrb_state *mrb, mrb_value klass) #if defined(_WIN32) || defined(_WIN64) char dname[_MAX_DIR], vname[_MAX_DRIVE]; char buffer[_MAX_DRIVE + _MAX_DIR]; + const char *utf8_path; char *path; size_t ridx; - mrb_value s; - mrb_get_args(mrb, "S", &s); - path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, s), -1); - _splitpath((const char*)path, vname, dname, NULL, NULL); + mrb_get_args(mrb, "z", &utf8_path); + path = mrb_locale_from_utf8(utf8_path, -1); + _splitpath(path, vname, dname, NULL, NULL); snprintf(buffer, _MAX_DRIVE + _MAX_DIR, "%s%s", vname, dname); mrb_locale_free(path); ridx = strlen(buffer); @@ -248,7 +248,7 @@ mrb_file_realpath(mrb_state *mrb, mrb_value klass) s = mrb_str_append(mrb, s, pathname); pathname = s; } - cpath = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, pathname), -1); + cpath = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &pathname), -1); result = mrb_str_buf_new(mrb, PATH_MAX); if (realpath(cpath, RSTRING_PTR(result)) == NULL) { mrb_locale_free(cpath); @@ -300,7 +300,7 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass) mrb_raise(mrb, E_ARGUMENT_ERROR, "non-absolute home"); } } else { - const char *cuser = mrb_str_to_cstr(mrb, username); + const char *cuser = mrb_string_value_cstr(mrb, &username); struct passwd *pwd = getpwnam(cuser); if (pwd == NULL) { return mrb_nil_value(); @@ -393,9 +393,8 @@ mrb_file_s_symlink(mrb_state *mrb, mrb_value klass) int ai = mrb_gc_arena_save(mrb); mrb_get_args(mrb, "SS", &from, &to); - src = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, from), -1); - dst = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, to), -1); - + src = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &from), -1); + dst = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &to), -1); if (symlink(src, dst) == -1) { mrb_locale_free(src); mrb_locale_free(dst); @@ -417,7 +416,7 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_get_args(mrb, "i*", &mode, &filenames, &argc); for (i = 0; i < argc; i++) { - const char *utf8_path = mrb_str_to_cstr(mrb, filenames[i]); + const char *utf8_path = mrb_string_value_cstr(mrb, &filenames[i]); char *path = mrb_locale_from_utf8(utf8_path, -1); if (CHMOD(path, mode) == -1) { mrb_locale_free(path); diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index e429b06b3..7d36f79b3 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -63,7 +63,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); if (mrb_test(tmp)) { - char *path = mrb_locale_from_utf8(mrb_str_to_cstr(mrb, obj), -1); + char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); int ret; if (do_lstat) { ret = LSTAT(path, st); diff --git a/mrbgems/mruby-io/test/mruby_io_test.c b/mrbgems/mruby-io/test/mruby_io_test.c index 71239a827..3312d6c7e 100644 --- a/mrbgems/mruby-io/test/mruby_io_test.c +++ b/mrbgems/mruby-io/test/mruby_io_test.c @@ -215,11 +215,9 @@ mrb_io_test_mkdtemp(mrb_state *mrb, mrb_value klass) static mrb_value mrb_io_test_rmdir(mrb_state *mrb, mrb_value klass) { - mrb_value str; - char *cp; + const char *cp; - mrb_get_args(mrb, "S", &str); - cp = mrb_str_to_cstr(mrb, str); + mrb_get_args(mrb, "z", &cp); if (rmdir(cp) == -1) { mrb_sys_fail(mrb, "rmdir"); } diff --git a/mrbgems/mruby-socket/src/socket.c b/mrbgems/mruby-socket/src/socket.c index 2a8ae1b2c..8515a6057 100644 --- a/mrbgems/mruby-socket/src/socket.c +++ b/mrbgems/mruby-socket/src/socket.c @@ -131,7 +131,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) mrb_get_args(mrb, "oo|oooi", &nodename, &service, &family, &socktype, &protocol, &flags); if (mrb_string_p(nodename)) { - hostname = mrb_str_to_cstr(mrb, nodename); + hostname = mrb_string_value_cstr(mrb, &nodename); } else if (mrb_nil_p(nodename)) { hostname = NULL; } else { @@ -139,7 +139,7 @@ mrb_addrinfo_getaddrinfo(mrb_state *mrb, mrb_value klass) } if (mrb_string_p(service)) { - servname = mrb_str_to_cstr(mrb, service); + servname = mrb_string_value_cstr(mrb, &service); } else if (mrb_fixnum_p(service)) { servname = RSTRING_PTR(mrb_fixnum_to_str(mrb, service, 10)); } else if (mrb_nil_p(service)) { -- cgit v1.2.3 From 35943e7beb0e4fd22f2096b56817e0cf22b8cf42 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Tue, 7 May 2019 23:01:13 +0900 Subject: Refactor `mrb_str_to_cstr` and `mrb_string_value_cstr` - Extract null byte check to function. - Avoid string allocation if null byte is included. - Use `str_new` instead of `mrb_str_dup` + `mrb_str_modify` --- mrbgems/mruby-io/test/file.rb | 3 +++ src/string.c | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 29 insertions(+), 16 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb index 88ced31a6..1535ebb44 100644 --- a/mrbgems/mruby-io/test/file.rb +++ b/mrbgems/mruby-io/test/file.rb @@ -33,6 +33,7 @@ assert('File.basename') do assert_equal 'a', File.basename('/a/') assert_equal 'b', File.basename('/a/b') assert_equal 'b', File.basename('../a/b') + assert_raise(ArgumentError) { File.basename("/a/b\0") } end assert('File.dirname') do @@ -106,6 +107,8 @@ assert('File.realpath') do MRubyIOTestUtil.rmdir dir end end + + assert_raise(ArgumentError) { File.realpath("TO\0DO") } end assert("File.readlink") do diff --git a/src/string.c b/src/string.c index f043bfd5a..7fc405a2b 100644 --- a/src/string.c +++ b/src/string.c @@ -194,6 +194,15 @@ str_decref(mrb_state *mrb, mrb_shared_string *shared) } } +static void +check_null_byte(mrb_state *mrb, mrb_value str) +{ + mrb_to_str(mrb, str); + if (memchr(RSTRING_PTR(str), '\0', RSTRING_LEN(str))) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); + } +} + void mrb_gc_free_str(mrb_state *mrb, struct RString *str) { @@ -723,14 +732,8 @@ mrb_str_to_cstr(mrb_state *mrb, mrb_value str0) { struct RString *s; - if (!mrb_string_p(str0)) { - mrb_raise(mrb, E_TYPE_ERROR, "expected String"); - } - + check_null_byte(mrb, str0); s = str_new(mrb, RSTRING_PTR(str0), RSTRING_LEN(str0)); - if ((strlen(RSTR_PTR(s)) ^ RSTR_LEN(s)) != 0) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "string contains null byte"); - } return RSTR_PTR(s); } @@ -2144,20 +2147,27 @@ mrb_cstr_to_inum(mrb_state *mrb, const char *str, mrb_int base, mrb_bool badchec MRB_API const char* mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) { - mrb_value str = mrb_to_str(mrb, *ptr); - struct RString *ps = mrb_str_ptr(str); - mrb_int len = mrb_str_strlen(mrb, ps); - char *p = RSTR_PTR(ps); + struct RString *ps; + const char *p; + mrb_int len; - if (!p || p[len] != '\0') { + check_null_byte(mrb, *ptr); + ps = mrb_str_ptr(*ptr); + p = RSTR_PTR(ps); + len = RSTR_LEN(ps); + if (p[len] == '\0') { + return p; + } + else { if (MRB_FROZEN_P(ps)) { - *ptr = str = mrb_str_dup(mrb, str); - ps = mrb_str_ptr(str); + ps = str_new(mrb, p, len); + *ptr = mrb_obj_value(ps); + } + else { + mrb_str_modify(mrb, ps); } - mrb_str_modify(mrb, ps); return RSTR_PTR(ps); } - return p; } MRB_API mrb_value -- cgit v1.2.3 From 0d94a2e3a917b39ffcf4ed930edeacf9fabcff5b Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 9 May 2019 23:26:40 +0900 Subject: Raise `TypeError` if the argument type is unsupported in `mrb_stat0` --- mrbgems/mruby-io/src/file_test.c | 15 ++------------- mrbgems/mruby-io/test/file_test.rb | 5 ++--- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 7d36f79b3..ec731b094 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -42,14 +42,7 @@ extern struct mrb_data_type mrb_io_type; static int mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { - mrb_value tmp; - mrb_value io_klass, str_klass; - - io_klass = mrb_obj_value(mrb_class_get(mrb, "IO")); - str_klass = mrb_obj_value(mrb_class_get(mrb, "String")); - - tmp = mrb_funcall(mrb, obj, "is_a?", 1, io_klass); - if (mrb_test(tmp)) { + if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) { struct mrb_io *fptr; fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); @@ -60,9 +53,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) mrb_raise(mrb, E_IO_ERROR, "closed stream"); return -1; } - - tmp = mrb_funcall(mrb, obj, "is_a?", 1, str_klass); - if (mrb_test(tmp)) { + else { char *path = mrb_locale_from_utf8(mrb_string_value_cstr(mrb, &obj), -1); int ret; if (do_lstat) { @@ -73,8 +64,6 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) mrb_locale_free(path); return ret; } - - return -1; } static int diff --git a/mrbgems/mruby-io/test/file_test.rb b/mrbgems/mruby-io/test/file_test.rb index 72e921ce9..2134c6a75 100644 --- a/mrbgems/mruby-io/test/file_test.rb +++ b/mrbgems/mruby-io/test/file_test.rb @@ -20,9 +20,8 @@ assert("FileTest.exist?") do assert_equal true, FileTest.exist?(io), "io obj - exist" io.close assert_equal true, io.closed? - assert_raise IOError do - FileTest.exist?(io) - end + assert_raise(IOError) { FileTest.exist?(io) } + assert_raise(TypeError) { File.exist?($mrbtest_io_rfname.to_sym) } end assert("FileTest.file?") do -- cgit v1.2.3 From f2719e903aef90bc1e8c45f866abb3471c2d6e52 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 10 May 2019 20:52:15 +0900 Subject: Move `mrb_gc_arena_restore` to inside the loop in `mrb_file_s_chmod` --- mrbgems/mruby-io/src/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c index b17b95e24..243f634b4 100644 --- a/mrbgems/mruby-io/src/file.c +++ b/mrbgems/mruby-io/src/file.c @@ -423,9 +423,9 @@ mrb_file_s_chmod(mrb_state *mrb, mrb_value klass) { mrb_sys_fail(mrb, utf8_path); } mrb_locale_free(path); + mrb_gc_arena_restore(mrb, ai); } - mrb_gc_arena_restore(mrb, ai); return mrb_fixnum_value(argc); } -- cgit v1.2.3 From 5f664fb6f890e9c3a6c8e56cf1d173fa46dd39e9 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 15 May 2019 16:27:08 +0900 Subject: Fix typo in `mrbgems/mruby-io/src/file_test.c` [ci skip] --- mrbgems/mruby-io/src/file_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index ec731b094..5d5ecb93f 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -1,5 +1,5 @@ /* -** file.c - File class +** file_test.c - FileTest class */ #include "mruby.h" -- cgit v1.2.3 From f8f75fc9c66d834fa81632b113dad5713e2b42b4 Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 7 Jun 2019 22:54:03 +0900 Subject: Replace obsolete macros --- mrbgems/mruby-io/src/file_test.c | 2 +- mrbgems/mruby-io/src/io.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/src/file_test.c b/mrbgems/mruby-io/src/file_test.c index 5d5ecb93f..85a221ff9 100644 --- a/mrbgems/mruby-io/src/file_test.c +++ b/mrbgems/mruby-io/src/file_test.c @@ -44,7 +44,7 @@ mrb_stat0(mrb_state *mrb, mrb_value obj, struct stat *st, int do_lstat) { if (mrb_obj_is_kind_of(mrb, obj, mrb_class_get(mrb, "IO"))) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, obj, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, obj, &mrb_io_type); if (fptr && fptr->fd >= 0) { return fstat(fptr->fd, st); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index e5b83e923..99441f16b 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -79,7 +79,7 @@ io_get_open_fptr(mrb_state *mrb, mrb_value self) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, self, &mrb_io_type); if (fptr == NULL) { mrb_raise(mrb, E_IO_ERROR, "uninitialized stream."); } @@ -955,7 +955,7 @@ mrb_value mrb_io_closed(mrb_state *mrb, mrb_value io) { struct mrb_io *fptr; - fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type); + fptr = (struct mrb_io *)mrb_data_get_ptr(mrb, io, &mrb_io_type); if (fptr == NULL || fptr->fd >= 0) { return mrb_false_value(); } -- cgit v1.2.3 From 1b9f949f3662ffaf39145638e15d628e0e94661e Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:17:25 +0900 Subject: Use a normal method instead of a lambda Ref commit 35319bed01d58c785f73ce03e67d4e58be30f4b5 --- mrbgems/mruby-io/test/io.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 5004d0042..ef0b49643 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -4,7 +4,7 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] -assert_io_open = ->(meth) do +def assert_io_open(meth) fd = IO.sysopen($mrbtest_io_rfname) assert_equal Fixnum, fd.class io1 = IO.__send__(meth, fd) @@ -38,7 +38,7 @@ assert('IO.ancestors', '15.2.20.3') do end assert('IO.open', '15.2.20.4.1') do - assert_io_open.(:open) + assert_io_open(:open) end assert('IO#close', '15.2.20.5.1') do @@ -224,11 +224,11 @@ assert('IO#dup for writable') do end assert('IO.for_fd') do - assert_io_open.(:for_fd) + assert_io_open(:for_fd) end assert('IO.new') do - assert_io_open.(:new) + assert_io_open(:new) end assert('IO gc check') do -- cgit v1.2.3 From a215292b6ad4315a5a0edef49a1df65e3f27b46a Mon Sep 17 00:00:00 2001 From: dearblue Date: Fri, 28 Jun 2019 23:13:29 +0900 Subject: Use nested `assert` --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 8 +++++--- mrbgems/mruby-complex/test/complex.rb | 6 ++++-- mrbgems/mruby-io/test/io.rb | 32 +++++++++++++++++--------------- mrbgems/mruby-pack/test/pack.rb | 6 ++++-- mrbgems/mruby-rational/test/rational.rb | 20 ++++++++++++-------- 5 files changed, 42 insertions(+), 30 deletions(-) (limited to 'mrbgems/mruby-io') diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 09350ff49..5dbbc5592 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -3,9 +3,11 @@ require 'open3' def assert_mruby(exp_out, exp_err, exp_success, args) out, err, stat = Open3.capture3(cmd("mruby"), *args) - assert_operator(exp_out, :===, out, "standard output") - assert_operator(exp_err, :===, err, "standard error") - assert_equal(exp_success, stat.success?, "exit success?") + assert do + assert_operator(exp_out, :===, out, "standard output") + assert_operator(exp_err, :===, err, "standard error") + assert_equal(exp_success, stat.success?, "exit success?") + end end assert('regression for #1564') do diff --git a/mrbgems/mruby-complex/test/complex.rb b/mrbgems/mruby-complex/test/complex.rb index 6996eb214..ab882664e 100644 --- a/mrbgems/mruby-complex/test/complex.rb +++ b/mrbgems/mruby-complex/test/complex.rb @@ -1,6 +1,8 @@ def assert_complex(real, exp) - assert_float real.real, exp.real - assert_float real.imaginary, exp.imaginary + assert do + assert_float real.real, exp.real + assert_float real.imaginary, exp.imaginary + end end assert 'Complex' do diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index ef0b49643..1491a4cfe 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -5,24 +5,26 @@ MRubyIOTestUtil.io_test_setup $cr, $crlf, $cmd = MRubyIOTestUtil.win? ? [1, "\r\n", "cmd /c "] : [0, "\n", ""] def assert_io_open(meth) - fd = IO.sysopen($mrbtest_io_rfname) - assert_equal Fixnum, fd.class - io1 = IO.__send__(meth, fd) - begin - assert_equal IO, io1.class - assert_equal $mrbtest_io_msg, io1.read - ensure - io1.close - end + assert do + fd = IO.sysopen($mrbtest_io_rfname) + assert_equal Fixnum, fd.class + io1 = IO.__send__(meth, fd) + begin + assert_equal IO, io1.class + assert_equal $mrbtest_io_msg, io1.read + ensure + io1.close + end - io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| - if meth == :open - assert_equal $mrbtest_io_msg, io.read - else - flunk "IO.#{meth} does not take block" + io2 = IO.__send__(meth, IO.sysopen($mrbtest_io_rfname))do |io| + if meth == :open + assert_equal $mrbtest_io_msg, io.read + else + flunk "IO.#{meth} does not take block" + end end + io2.close unless meth == :open end - io2.close unless meth == :open end assert('IO.class', '15.2.20') do diff --git a/mrbgems/mruby-pack/test/pack.rb b/mrbgems/mruby-pack/test/pack.rb index 110aee5db..eb24e8d1f 100644 --- a/mrbgems/mruby-pack/test/pack.rb +++ b/mrbgems/mruby-pack/test/pack.rb @@ -2,8 +2,10 @@ PACK_IS_LITTLE_ENDIAN = "\x01\00".unpack('S')[0] == 0x01 def assert_pack tmpl, packed, unpacked t = tmpl.inspect - assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" - assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + assert do + assert_equal packed, unpacked.pack(tmpl), "#{unpacked.inspect}.pack(#{t})" + assert_equal unpacked, packed.unpack(tmpl), "#{packed.inspect}.unpack(#{t})" + end end # pack & unpack 'm' (base64) diff --git a/mrbgems/mruby-rational/test/rational.rb b/mrbgems/mruby-rational/test/rational.rb index 5e9d9ea48..11737034b 100644 --- a/mrbgems/mruby-rational/test/rational.rb +++ b/mrbgems/mruby-rational/test/rational.rb @@ -23,17 +23,21 @@ class ComplexLikeNumeric < UserDefinedNumeric end def assert_rational(exp, real) - assert_float exp.numerator, real.numerator - assert_float exp.denominator, real.denominator + assert do + assert_float exp.numerator, real.numerator + assert_float exp.denominator, real.denominator + end end def assert_equal_rational(exp, o1, o2) - if exp - assert_operator(o1, :==, o2) - assert_not_operator(o1, :!=, o2) - else - assert_not_operator(o1, :==, o2) - assert_operator(o1, :!=, o2) + assert do + if exp + assert_operator(o1, :==, o2) + assert_not_operator(o1, :!=, o2) + else + assert_not_operator(o1, :==, o2) + assert_operator(o1, :!=, o2) + end end end -- cgit v1.2.3