summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--MITL2
-rw-r--r--README.md2
-rw-r--r--doc/guides/debugger.md2
-rw-r--r--doc/limitations.md14
-rw-r--r--include/mrbconf.h8
-rw-r--r--include/mruby.h2
-rw-r--r--include/mruby/proc.h4
-rw-r--r--include/mruby/version.h8
-rw-r--r--lib/mruby/build.rb22
-rw-r--r--mrbgems/default.gembox6
-rw-r--r--mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c2
-rw-r--r--mrbgems/mruby-class-ext/src/class.c38
-rw-r--r--mrbgems/mruby-class-ext/test/module.rb21
-rw-r--r--mrbgems/mruby-compiler/core/codegen.c8
-rw-r--r--mrbgems/mruby-compiler/core/parse.y67
-rw-r--r--mrbgems/mruby-enum-ext/mrblib/enum.rb96
-rw-r--r--mrbgems/mruby-enum-ext/test/enum.rb14
-rw-r--r--mrbgems/mruby-hash-ext/mrblib/hash.rb2
-rw-r--r--mrbgems/mruby-hash-ext/src/hash-ext.c40
-rw-r--r--mrbgems/mruby-hash-ext/test/hash.rb36
-rw-r--r--mrbgems/mruby-io/src/file.c15
-rw-r--r--mrbgems/mruby-io/src/io.c24
-rw-r--r--mrbgems/mruby-io/test/file.rb18
-rw-r--r--mrbgems/mruby-io/test/io.rb4
-rw-r--r--mrbgems/mruby-numeric-ext/src/numeric_ext.c76
-rw-r--r--mrbgems/mruby-pack/src/pack.c9
-rw-r--r--mrbgems/mruby-socket/mrbgem.rake4
-rw-r--r--mrbgems/mruby-socket/test/socket.rb2
-rw-r--r--mrbgems/mruby-socket/test/sockettest.c59
-rw-r--r--mrbgems/mruby-socket/test/unix.rb2
-rw-r--r--mrbgems/mruby-time/src/time.c25
-rw-r--r--mrbgems/mruby-time/test/time.rb4
-rw-r--r--src/class.c2
-rw-r--r--src/error.c3
-rw-r--r--src/gc.c2
-rw-r--r--src/kernel.c21
-rw-r--r--src/variable.c48
-rw-r--r--src/vm.c15
-rw-r--r--test/t/kernel.rb38
39 files changed, 586 insertions, 179 deletions
diff --git a/MITL b/MITL
index d02b8fe1c..8d8c78fab 100644
--- a/MITL
+++ b/MITL
@@ -1,4 +1,4 @@
-Copyright (c) 2017 mruby developers
+Copyright (c) 2018 mruby developers
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
diff --git a/README.md b/README.md
index 9d0c611b2..196cc2ef7 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ of the Ministry of Economy, Trade and Industry of Japan.
## How to get mruby
-The stable version 1.3.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.3.0.zip](https://github.com/mruby/mruby/archive/1.3.0.zip)
+The stable version 1.4.0 of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/archive/1.4.0.zip](https://github.com/mruby/mruby/archive/1.4.0.zip)
The latest development version of mruby can be downloaded via the following URL: [https://github.com/mruby/mruby/zipball/master](https://github.com/mruby/mruby/zipball/master)
diff --git a/doc/guides/debugger.md b/doc/guides/debugger.md
index 72f2c2b32..a41b6ce45 100644
--- a/doc/guides/debugger.md
+++ b/doc/guides/debugger.md
@@ -38,7 +38,7 @@ To confirm mrdb was installed properly, run mrdb with the `--version` option:
```bash
$ mrdb --version
-mruby 1.3.0 (2017-7-4)
+mruby 1.4.0 (2018-1-16)
```
## 2.2 Basic Operation
diff --git a/doc/limitations.md b/doc/limitations.md
index 134ff6e26..855ae16ee 100644
--- a/doc/limitations.md
+++ b/doc/limitations.md
@@ -38,7 +38,7 @@ puts [1,2,3]
3
```
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
```
[1, 2, 3]
@@ -61,7 +61,7 @@ end
```ZeroDivisionError``` is raised.
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
No exception is raised.
@@ -89,7 +89,7 @@ p Liste.new "foobar"
``` [] ```
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
```ArgumentError``` is raised.
@@ -119,7 +119,7 @@ false
true
```
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
```
true
@@ -142,7 +142,7 @@ defined?(Foo)
nil
```
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
```NameError``` is raised.
@@ -159,7 +159,7 @@ alias $a $__a__
``` nil ```
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
Syntax error
@@ -181,7 +181,7 @@ end
```ArgumentError``` is raised.
The re-defined ```+``` operator does not accept any arguments.
-#### mruby [1.3.0 (2017-7-4)]
+#### mruby [1.4.0 (2018-1-16)]
``` 'ab' ```
Behavior of the operator wasn't changed.
diff --git a/include/mrbconf.h b/include/mrbconf.h
index 96ab6b77f..cc28acfaa 100644
--- a/include/mrbconf.h
+++ b/include/mrbconf.h
@@ -36,12 +36,10 @@
/* size of the method cache (need to be the power of 2) */
//#define MRB_METHOD_CACHE_SIZE (1<<7)
-/* add -DMRB_METHOD_TABLE_INLINE unless platform uses MSB of pointers */
+/* add -DMRB_METHOD_TABLE_INLINE to reduce the size of method table */
+/* MRB_METHOD_TABLE_INLINE requires LSB of function pointers to be zero */
+/* you might need to specify --falign-functions=n (where n>1) */
//#define MRB_METHOD_TABLE_INLINE
-/* turn MRB_METHOD_TABLE_INLINE on for linux by default */
-#if !defined(MRB_METHOD_TABLE_INLINE) && defined(__linux__)
-# define MRB_METHOD_TABLE_INLINE
-#endif
/* add -DMRB_INT16 to use 16bit integer for mrb_int; conflict with MRB_INT64 */
//#define MRB_INT16
diff --git a/include/mruby.h b/include/mruby.h
index d93874dfa..f4d8e229a 100644
--- a/include/mruby.h
+++ b/include/mruby.h
@@ -1,7 +1,7 @@
/*
** mruby - An embeddable Ruby implementation
**
-** Copyright (c) mruby developers 2010-2017
+** Copyright (c) mruby developers 2010-2018
**
** Permission is hereby granted, free of charge, to any person obtaining
** a copy of this software and associated documentation files (the
diff --git a/include/mruby/proc.h b/include/mruby/proc.h
index 3f246314b..aa281b6dd 100644
--- a/include/mruby/proc.h
+++ b/include/mruby/proc.h
@@ -98,8 +98,8 @@ MRB_API mrb_value mrb_proc_cfunc_env_get(mrb_state*, mrb_int);
#ifdef MRB_METHOD_TABLE_INLINE
-#define MRB_METHOD_FUNC_FL ((uintptr_t)1U<<(sizeof(uintptr_t)*8-1))
-#define MRB_METHOD_FUNC_P(m) ((uintptr_t)(m)&MRB_METHOD_FUNC_FL)
+#define MRB_METHOD_FUNC_FL ((uintptr_t)1)
+#define MRB_METHOD_FUNC_P(m) (((uintptr_t)(m))&MRB_METHOD_FUNC_FL)
#define MRB_METHOD_FUNC(m) ((mrb_func_t)((uintptr_t)(m)&(~MRB_METHOD_FUNC_FL)))
#define MRB_METHOD_FROM_FUNC(m,fn) m=(mrb_method_t)((struct RProc*)((uintptr_t)(fn)|MRB_METHOD_FUNC_FL))
#define MRB_METHOD_FROM_PROC(m,pr) m=(mrb_method_t)(struct RProc*)(pr)
diff --git a/include/mruby/version.h b/include/mruby/version.h
index 8414bf204..3ba2db031 100644
--- a/include/mruby/version.h
+++ b/include/mruby/version.h
@@ -42,7 +42,7 @@ MRB_BEGIN_DECL
/*
* Minor release version number.
*/
-#define MRUBY_RELEASE_MINOR 3
+#define MRUBY_RELEASE_MINOR 4
/*
* Tiny release version number.
@@ -62,17 +62,17 @@ MRB_BEGIN_DECL
/*
* Release year.
*/
-#define MRUBY_RELEASE_YEAR 2017
+#define MRUBY_RELEASE_YEAR 2018
/*
* Release month.
*/
-#define MRUBY_RELEASE_MONTH 7
+#define MRUBY_RELEASE_MONTH 1
/*
* Release day.
*/
-#define MRUBY_RELEASE_DAY 4
+#define MRUBY_RELEASE_DAY 16
/*
* Release date as a string.
diff --git a/lib/mruby/build.rb b/lib/mruby/build.rb
index 7d6aa49e1..c06a62282 100644
--- a/lib/mruby/build.rb
+++ b/lib/mruby/build.rb
@@ -334,6 +334,7 @@ EOS
attr_accessor :host_target, :build_target
def initialize(name, build_dir=nil, &block)
+ @endian = nil
@test_runner = Command::CrossTestRunner.new(self)
super
end
@@ -351,5 +352,26 @@ EOS
@test_runner.run(mrbtest)
end
end
+
+ def big_endian
+ if @endian
+ puts "Endian has already specified as #{@endian}."
+ return
+ end
+ @endian = :big
+ @mrbc.compile_options += ' -E'
+ compilers.each do |c|
+ c.defines += %w(MRB_ENDIAN_BIG)
+ end
+ end
+
+ def little_endian
+ if @endian
+ puts "Endian has already specified as #{@endian}."
+ return
+ end
+ @endian = :little
+ @mrbc.compile_options += ' -e'
+ end
end # CrossBuild
end # MRuby
diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox
index 65584681d..7ddbb16d1 100644
--- a/mrbgems/default.gembox
+++ b/mrbgems/default.gembox
@@ -1,4 +1,10 @@
MRuby::GemBox.new do |conf|
+ # Use standard IO/File class
+ conf.gem :core => "mruby-io"
+
+ # Use standard Array#pack, String#unpack methods
+ conf.gem :core => "mruby-pack"
+
# Use standard Kernel#sprintf method
conf.gem :core => "mruby-sprintf"
diff --git a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
index 62f7670e0..21fe64127 100644
--- a/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
+++ b/mrbgems/mruby-bin-debugger/tools/mrdb/apilist.c
@@ -84,7 +84,7 @@ dirname(mrb_state *mrb, const char *path)
static source_file*
source_file_new(mrb_state *mrb, mrb_debug_context *dbg, char *filename)
{
- source_file *file = NULL;
+ source_file *file;
file = (source_file*)mrb_malloc(mrb, sizeof(source_file));
diff --git a/mrbgems/mruby-class-ext/src/class.c b/mrbgems/mruby-class-ext/src/class.c
index 5506c4829..705db9949 100644
--- a/mrbgems/mruby-class-ext/src/class.c
+++ b/mrbgems/mruby-class-ext/src/class.c
@@ -15,6 +15,42 @@ mrb_mod_singleton_class_p(mrb_state *mrb, mrb_value self)
return mrb_bool_value(mrb_type(self) == MRB_TT_SCLASS);
}
+/*
+ * call-seq:
+ * module_exec(arg...) {|var...| block } -> obj
+ * class_exec(arg...) {|var...| block } -> obj
+ *
+ * Evaluates the given block in the context of the
+ * class/module. The method defined in the block will belong
+ * to the receiver. Any arguments passed to the method will be
+ * passed to the block. This can be used if the block needs to
+ * access instance variables.
+ *
+ * class Thing
+ * end
+ * Thing.class_exec{
+ * def hello() "Hello there!" end
+ * }
+ * puts Thing.new.hello()
+ */
+
+static mrb_value
+mrb_mod_module_exec(mrb_state *mrb, mrb_value self)
+{
+ const mrb_value *argv;
+ mrb_int argc;
+ mrb_value blk;
+
+ mrb_get_args(mrb, "*&", &argv, &argc, &blk);
+
+ if (mrb_nil_p(blk)) {
+ mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given");
+ }
+
+ mrb->c->ci->target_class = mrb_class_ptr(self);
+ return mrb_yield_cont(mrb, blk, self, argc, argv);
+}
+
void
mrb_mruby_class_ext_gem_init(mrb_state *mrb)
{
@@ -22,6 +58,8 @@ mrb_mruby_class_ext_gem_init(mrb_state *mrb)
mrb_define_method(mrb, mod, "name", mrb_mod_name, MRB_ARGS_NONE());
mrb_define_method(mrb, mod, "singleton_class?", mrb_mod_singleton_class_p, MRB_ARGS_NONE());
+ mrb_define_method(mrb, mod, "module_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
+ mrb_define_method(mrb, mod, "class_exec", mrb_mod_module_exec, MRB_ARGS_ANY()|MRB_ARGS_BLOCK());
}
void
diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb
index 65abde108..ed6713aac 100644
--- a/mrbgems/mruby-class-ext/test/module.rb
+++ b/mrbgems/mruby-class-ext/test/module.rb
@@ -32,3 +32,24 @@ assert 'Module#singleton_class?' do
assert_false cls.singleton_class?
assert_true scl.singleton_class?
end
+
+assert 'Module#module_eval' do
+ mod = Module.new
+ mod.class_exec(1,2,3) do |a,b,c|
+ assert_equal([1,2,3], [a,b,c])
+ def hi
+ "hi"
+ end
+ end
+ cls = Class.new
+ cls.class_exec(42) do |x|
+ assert_equal(42, x)
+ include mod
+ def hello
+ "hello"
+ end
+ end
+ obj = cls.new
+ assert_equal("hi", obj.hi)
+ assert_equal("hello", obj.hello)
+end
diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c
index c4227ca8e..eb82110b8 100644
--- a/mrbgems/mruby-compiler/core/codegen.c
+++ b/mrbgems/mruby-compiler/core/codegen.c
@@ -149,8 +149,14 @@ new_label(codegen_scope *s)
static inline int
genop(codegen_scope *s, mrb_code i)
{
- if (s->pc == s->icapa) {
+ if (s->pc >= s->icapa) {
s->icapa *= 2;
+ if (s->pc >= MAXARG_sBx) {
+ codegen_error(s, "too big code block");
+ }
+ if (s->icapa > MAXARG_sBx) {
+ s->icapa = MAXARG_sBx;
+ }
s->iseq = (mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->icapa);
if (s->lines) {
s->lines = (uint16_t*)codegen_realloc(s, s->lines, sizeof(short)*s->icapa);
diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y
index 01269d8da..7f848b4df 100644
--- a/mrbgems/mruby-compiler/core/parse.y
+++ b/mrbgems/mruby-compiler/core/parse.y
@@ -781,7 +781,7 @@ new_dxstr(parser_state *p, node *a)
static node*
new_dsym(parser_state *p, node *a)
{
- return cons((node*)NODE_DSYM, new_dstr(p, a));
+ return cons((node*)NODE_DSYM, a);
}
/* (:regx . (s . (opt . enc))) */
@@ -1106,9 +1106,9 @@ heredoc_end(parser_state *p)
keyword__FILE__
keyword__ENCODING__
-%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL
+%token <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL_TAG
%token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP
-%token <nd> tSTRING tSTRING_PART tSTRING_MID tLABEL_END
+%token <nd> tSTRING tSTRING_PART tSTRING_MID
%token <nd> tNTH_REF tBACK_REF
%token <num> tREGEXP_END
@@ -1180,7 +1180,7 @@ heredoc_end(parser_state *p)
%right keyword_not
%right '=' tOP_ASGN
%left modifier_rescue
-%right '?' ':'
+%right '?' ':' tLABEL_TAG
%nonassoc tDOT2 tDOT3
%left tOROP
%left tANDOP
@@ -1926,6 +1926,10 @@ arg : lhs '=' arg_rhs
{
$$ = new_if(p, cond($1), $3, $6);
}
+ | arg '?' arg opt_nl tLABEL_TAG arg
+ {
+ $$ = new_if(p, cond($1), $3, $6);
+ }
| primary
{
$$ = $1;
@@ -2568,7 +2572,7 @@ lambda_body : tLAMBEG compstmt '}'
{
$$ = $2;
}
- | keyword_do_LAMBDA compstmt keyword_end
+ | keyword_do_LAMBDA bodystmt keyword_end
{
$$ = $2;
}
@@ -2861,7 +2865,7 @@ symbol : basic_symbol
| tSYMBEG tSTRING_BEG string_rep tSTRING
{
p->lstate = EXPR_ENDARG;
- $$ = new_dsym(p, push($3, $4));
+ $$ = new_dsym(p, new_dstr(p, push($3, $4)));
}
;
@@ -3266,25 +3270,20 @@ assoc : arg tASSOC arg
void_expr_error(p, $3);
$$ = cons($1, $3);
}
- | tLABEL arg
- {
- void_expr_error(p, $2);
- $$ = cons(new_sym(p, $1), $2);
- }
- | tLABEL_END arg
- {
- void_expr_error(p, $2);
- $$ = cons(new_sym(p, new_strsym(p, $1)), $2);
- }
- | tSTRING_BEG tLABEL_END arg
+ | tIDENTIFIER tLABEL_TAG arg
{
void_expr_error(p, $3);
- $$ = cons(new_sym(p, new_strsym(p, $2)), $3);
+ $$ = cons(new_sym(p, $1), $3);
}
- | tSTRING_BEG string_rep tLABEL_END arg
+ | string tLABEL_TAG arg
{
- void_expr_error(p, $4);
- $$ = cons(new_dsym(p, push($2, $3)), $4);
+ void_expr_error(p, $3);
+ if ($1->car == (node*)NODE_DSTR) {
+ $$ = cons(new_dsym(p, $1), $3);
+ }
+ else {
+ $$ = cons(new_sym(p, new_strsym(p, $1)), $3);
+ }
}
;
@@ -3973,7 +3972,6 @@ parse_string(parser_state *p)
int beg = intn(p->lex_strterm->cdr->cdr->car);
int end = intn(p->lex_strterm->cdr->cdr->cdr);
parser_heredoc_info *hinf = (type & STR_FUNC_HEREDOC) ? parsing_heredoc_inf(p) : NULL;
- int cmd_state = p->cmd_start;
if (beg == 0) beg = -3; /* should never happen */
if (end == 0) end = -3;
@@ -4188,13 +4186,6 @@ parse_string(parser_state *p)
return tREGEXP;
}
pylval.nd = new_str(p, tok(p), toklen(p));
- if (IS_LABEL_POSSIBLE()) {
- if (IS_LABEL_SUFFIX(0)) {
- p->lstate = EXPR_BEG;
- nextc(p);
- return tLABEL_END;
- }
- }
return tSTRING;
}
@@ -5012,14 +5003,19 @@ parser_yylex(parser_state *p)
p->lstate = EXPR_DOT;
return tCOLON2;
}
- if (IS_END() || ISSPACE(c)) {
+ if (!space_seen && IS_END()) {
pushback(p, c);
p->lstate = EXPR_BEG;
- return ':';
+ return tLABEL_TAG;
+ }
+ if (!ISSPACE(c) || IS_BEG()) {
+ pushback(p, c);
+ p->lstate = EXPR_FNAME;
+ return tSYMBEG;
}
pushback(p, c);
- p->lstate = EXPR_FNAME;
- return tSYMBEG;
+ p->lstate = EXPR_BEG;
+ return ':';
case '/':
if (IS_BEG()) {
@@ -5443,11 +5439,10 @@ parser_yylex(parser_state *p)
if (IS_LABEL_POSSIBLE()) {
if (IS_LABEL_SUFFIX(0)) {
- p->lstate = EXPR_BEG;
- nextc(p);
+ p->lstate = EXPR_END;
tokfix(p);
pylval.id = intern_cstr(tok(p));
- return tLABEL;
+ return tIDENTIFIER;
}
}
if (p->lstate != EXPR_DOT) {
diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb
index 327b573d4..e489698ec 100644
--- a/mrbgems/mruby-enum-ext/mrblib/enum.rb
+++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb
@@ -451,20 +451,30 @@ module Enumerable
##
# call-seq:
# enum.none? [{ |obj| block }] -> true or false
+ # enum.none?(pattern) -> true or false
#
# Passes each element of the collection to the given block. The method
# returns <code>true</code> if the block never returns <code>true</code>
# for all elements. If the block is not given, <code>none?</code> will return
# <code>true</code> only if none of the collection members is true.
#
+ # If a pattern is supplied instead, the method returns whether
+ # <code>pattern === element</code> for none of the collection members.
+ #
# %w(ant bear cat).none? { |word| word.length == 5 } #=> true
# %w(ant bear cat).none? { |word| word.length >= 4 } #=> false
+ # %w{ant bear cat}.none?(/d/) #=> true
+ # [1, 3.14, 42].none?(Float) #=> false
# [].none? #=> true
# [nil, false].none? #=> true
# [nil, true].none? #=> false
- def none?(&block)
- if block
+ def none?(pat=NONE, &block)
+ if pat != NONE
+ self.each do |*val|
+ return false if pat === val.__svalue
+ end
+ elsif block
self.each do |*val|
return false if block.call(*val)
end
@@ -479,6 +489,7 @@ module Enumerable
##
# call-seq:
# enum.one? [{ |obj| block }] -> true or false
+ # enum.one?(pattern) -> true or false
#
# Passes each element of the collection to the given block. The method
# returns <code>true</code> if the block returns <code>true</code>
@@ -486,16 +497,26 @@ module Enumerable
# <code>true</code> only if exactly one of the collection members is
# true.
#
+ # If a pattern is supplied instead, the method returns whether
+ # <code>pattern === element</code> for exactly one collection member.
+ #
# %w(ant bear cat).one? { |word| word.length == 4 } #=> true
# %w(ant bear cat).one? { |word| word.length > 4 } #=> false
# %w(ant bear cat).one? { |word| word.length < 4 } #=> false
+ # %w{ant bear cat}.one?(/t/) #=> false
# [nil, true, 99].one? #=> false
# [nil, true, false].one? #=> true
- #
+ # [ nil, true, 99 ].one?(Integer) #=> true
+ # [].one? #=> false
- def one?(&block)
+ def one?(pat=NONE, &block)
count = 0
- if block
+ if pat!=NONE
+ self.each do |*val|
+ count += 1 if pat === val.__svalue
+ return false if count > 1
+ end
+ elsif block
self.each do |*val|
count += 1 if block.call(*val)
return false if count > 1
@@ -510,6 +531,71 @@ module Enumerable
count == 1 ? true : false
end
+ # ISO 15.3.2.2.1
+ # call-seq:
+ # enum.all? [{ |obj| block } ] -> true or false
+ # enum.all?(pattern) -> true or false
+ #
+ # Passes each element of the collection to the given block. The method
+ # returns <code>true</code> if the block never returns
+ # <code>false</code> or <code>nil</code>. If the block is not given,
+ # Ruby adds an implicit block of <code>{ |obj| obj }</code> which will
+ # cause #all? to return +true+ when none of the collection members are
+ # +false+ or +nil+.
+ #
+ # If a pattern is supplied instead, the method returns whether
+ # <code>pattern === element</code> for every collection member.
+ #
+ # %w[ant bear cat].all? { |word| word.length >= 3 } #=> true
+ # %w[ant bear cat].all? { |word| word.length >= 4 } #=> false
+ # %w[ant bear cat].all?(/t/) #=> false
+ # [1, 2i, 3.14].all?(Numeric) #=> true
+ # [nil, true, 99].all? #=> false
+ #
+ def all?(pat=NONE, &block)
+ if pat != NONE
+ self.each{|*val| return false unless pat === val.__svalue}
+ elsif block
+ self.each{|*val| return false unless block.call(*val)}
+ else
+ self.each{|*val| return false unless val.__svalue}
+ end
+ true
+ end
+
+ # ISO 15.3.2.2.2
+ # call-seq:
+ # enum.any? [{ |obj| block }] -> true or false
+ # enum.any?(pattern) -> true or false
+ #
+ # Passes each element of the collection to the given block. The method
+ # returns <code>true</code> if the block ever returns a value other
+ # than <code>false</code> or <code>nil</code>. If the block is not
+ # given, Ruby adds an implicit block of <code>{ |obj| obj }</code> that
+ # will cause #any? to return +true+ if at least one of the collection
+ # members is not +false+ or +nil+.
+ #
+ # If a pattern is supplied instead, the method returns whether
+ # <code>pattern === element</code> for any collection member.
+ #
+ # %w[ant bear cat].any? { |word| word.length >= 3 } #=> true
+ # %w[ant bear cat].any? { |word| word.length >= 4 } #=> true
+ # %w[ant bear cat].any?(/d/) #=> false
+ # [nil, true, 99].any?(Integer) #=> true
+ # [nil, true, 99].any? #=> true
+ # [].any? #=> false
+ #
+ def any?(pat=NONE, &block)
+ if pat != NONE
+ self.each{|*val| return true if pat === val.__svalue}
+ elsif block
+ self.each{|*val| return true if block.call(*val)}
+ else
+ self.each{|*val| return true if val.__svalue}
+ end
+ false
+ end
+
##
# call-seq:
# enum.each_with_object(obj) { |(*args), memo_obj| ... } -> obj
diff --git a/mrbgems/mruby-enum-ext/test/enum.rb b/mrbgems/mruby-enum-ext/test/enum.rb
index e772f85bf..7b9989861 100644
--- a/mrbgems/mruby-enum-ext/test/enum.rb
+++ b/mrbgems/mruby-enum-ext/test/enum.rb
@@ -100,6 +100,7 @@ end
assert("Enumerable#none?") do
assert_true %w(ant bear cat).none? { |word| word.length == 5 }
assert_false %w(ant bear cat).none? { |word| word.length >= 4 }
+ assert_false [1, 3.14, 42].none?(Float)
assert_true [].none?
assert_true [nil, false].none?
assert_false [nil, true].none?
@@ -109,8 +110,21 @@ assert("Enumerable#one?") do
assert_true %w(ant bear cat).one? { |word| word.length == 4 }
assert_false %w(ant bear cat).one? { |word| word.length > 4 }
assert_false %w(ant bear cat).one? { |word| word.length < 4 }
+ assert_true [1, 3.14, 42].one?(Float)
assert_false [nil, true, 99].one?
assert_true [nil, true, false].one?
+ assert_true [ nil, true, 99 ].one?(Integer)
+ assert_false [].one?
+end
+
+assert("Enumerable#all? (enhancement)") do
+ assert_false [1, 2, 3.14].all?(Integer)
+ assert_true [1, 2, 3.14].all?(Numeric)
+end
+
+assert("Enumerable#any? (enhancement)") do
+ assert_false [1, 2, 3].all?(Float)
+ assert_true [nil, true, 99].any?(Integer)
end
assert("Enumerable#each_with_object") do
diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb
index d1a709325..549bca0a8 100644
--- a/mrbgems/mruby-hash-ext/mrblib/hash.rb
+++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb
@@ -165,7 +165,7 @@ class Hash
elsif none != NONE
none
else
- raise KeyError, "Key not found: #{key}"
+ raise KeyError, "Key not found: #{key.inspect}"
end
else
self[key]
diff --git a/mrbgems/mruby-hash-ext/src/hash-ext.c b/mrbgems/mruby-hash-ext/src/hash-ext.c
index 952f2eb64..6619f5268 100644
--- a/mrbgems/mruby-hash-ext/src/hash-ext.c
+++ b/mrbgems/mruby-hash-ext/src/hash-ext.c
@@ -72,6 +72,45 @@ hash_compact_bang(mrb_state *mrb, mrb_value hash)
return hash;
}
+/*
+ * call-seq:
+ * hsh.slice(*keys) -> a_hash
+ *
+ * Returns a hash containing only the given keys and their values.
+ *
+ * h = { a: 100, b: 200, c: 300 }
+ * h.slice(:a) #=> {:a=>100}
+ * h.slice(:b, :c, :d) #=> {:b=>200, :c=>300}
+ */
+static mrb_value
+hash_slice(mrb_state *mrb, mrb_value hash)
+{
+ khash_t(ht) *h = RHASH_TBL(hash);
+ mrb_value *argv, result;
+ mrb_int argc, i;
+ khiter_t k;
+ int ai;
+
+ mrb_get_args(mrb, "*", &argv, &argc);
+ if (argc == 0 || h == NULL) {
+ return mrb_hash_new_capa(mrb, argc);
+ }
+ result = mrb_hash_new_capa(mrb, argc);
+ ai = mrb_gc_arena_save(mrb);
+ for (i = 0; i < argc; i++) {
+ mrb_value key = argv[i];
+
+ k = kh_get(ht, mrb, h, key);
+ if (k != kh_end(h)) {
+ mrb_value val = kh_value(h, k).v;
+
+ mrb_hash_set(mrb, result, key, val);
+ }
+ mrb_gc_arena_restore(mrb, ai);
+ }
+ return result;
+}
+
void
mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
{
@@ -80,6 +119,7 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
h = mrb->hash_class;
mrb_define_method(mrb, h, "values_at", hash_values_at, MRB_ARGS_ANY());
mrb_define_method(mrb, h, "compact!", hash_compact_bang, MRB_ARGS_NONE());
+ mrb_define_method(mrb, h, "slice", hash_slice, MRB_ARGS_ANY());
}
void
diff --git a/mrbgems/mruby-hash-ext/test/hash.rb b/mrbgems/mruby-hash-ext/test/hash.rb
index ca4e346fb..269da800d 100644
--- a/mrbgems/mruby-hash-ext/test/hash.rb
+++ b/mrbgems/mruby-hash-ext/test/hash.rb
@@ -271,24 +271,30 @@ end
assert("Hash#transform_keys") do
h = {"1" => 100, "2" => 200}
- assert_equal(h.transform_keys{|k| k+"!"},
- {"1!" => 100, "2!" => 200})
- assert_equal(h.transform_keys{|k|k.to_i},
- {1 => 100, 2 => 200})
- assert_equal(h.transform_keys.with_index{|k, i| "#{k}.#{i}"},
- {"1.0" => 100, "2.1" => 200})
- assert_equal(h.transform_keys!{|k|k.to_i}, h)
+ assert_equal({"1!" => 100, "2!" => 200},
+ h.transform_keys{|k| k+"!"})
+ assert_equal({1 => 100, 2 => 200},
+ h.transform_keys{|k|k.to_i})
+ assert_equal({"1.0" => 100, "2.1" => 200},
+ h.transform_keys.with_index{|k, i| "#{k}.#{i}"})
+ assert_equal(h, h.transform_keys!{|k|k.to_i})
assert_equal(h, {1 => 100, 2 => 200})
end
assert("Hash#transform_values") do
h = {a: 1, b: 2, c: 3}
- assert_equal(h.transform_values{|v| v * v + 1},
- {a: 2, b: 5, c: 10})
- assert_equal(h.transform_values{|v|v.to_s},
- {a: "1", b: "2", c: "3"})
- assert_equal(h.transform_values.with_index{|v, i| "#{v}.#{i}"},
- {a: "1.0", b: "2.1", c: "3.2"})
- assert_equal(h.transform_values!{|v|v.to_s}, h)
- assert_equal(h, {a: "1", b: "2", c: "3"})
+ assert_equal({a: 2, b: 5, c: 10},
+ h.transform_values{|v| v * v + 1})
+ assert_equal({a: "1", b: "2", c: "3"},
+ h.transform_values{|v|v.to_s})
+ assert_equal({a: "1.0", b: "2.1", c: "3.2"},
+ h.transform_values.with_index{|v, i| "#{v}.#{i}"})
+ assert_equal(h, h.transform_values!{|v|v.to_s})
+ assert_equal({a: "1", b: "2", c: "3"}, h)
+end
+
+assert("Hash#slice") do
+ h = { a: 100, b: 200, c: 300 }
+ assert_equal({:a=>100}, h.slice(:a))
+ assert_equal({:b=>200, :c=>300}, h.slice(:b, :c, :d))
end
diff --git a/mrbgems/mruby-io/src/file.c b/mrbgems/mruby-io/src/file.c
index 1018e90e6..3dcfe3a0b 100644
--- a/mrbgems/mruby-io/src/file.c
+++ b/mrbgems/mruby-io/src/file.c
@@ -332,6 +332,20 @@ mrb_file__gethome(mrb_state *mrb, mrb_value klass)
#endif
}
+static mrb_value
+mrb_file_mtime(mrb_state *mrb, mrb_value self)
+{
+ mrb_value obj;
+ struct stat st;
+ int fd;
+
+ obj = mrb_obj_value(mrb_class_get(mrb, "Time"));
+ fd = (int)mrb_fixnum(mrb_io_fileno(mrb, self));
+ if (fstat(fd, &st) == -1)
+ return mrb_false_value();
+ return mrb_funcall(mrb, obj, "at", 1, mrb_float_value(mrb, st.st_mtime));
+}
+
mrb_value
mrb_file_flock(mrb_state *mrb, mrb_value self)
{
@@ -471,6 +485,7 @@ mrb_init_file(mrb_state *mrb)
mrb_define_class_method(mrb, file, "_gethome", mrb_file__gethome, MRB_ARGS_OPT(1));
mrb_define_method(mrb, file, "flock", mrb_file_flock, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, file, "mtime", mrb_file_mtime, MRB_ARGS_NONE());
cnst = mrb_define_module_under(mrb, file, "Constants");
mrb_define_const(mrb, cnst, "LOCK_SH", mrb_fixnum_value(LOCK_SH));
diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c
index 21a733b00..58bcdd1ee 100644
--- a/mrbgems/mruby-io/src/io.c
+++ b/mrbgems/mruby-io/src/io.c
@@ -180,7 +180,7 @@ mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
return modenum;
}
-void
+static void
mrb_fd_cloexec(mrb_state *mrb, int fd)
{
#if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
@@ -188,7 +188,8 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
flags = fcntl(fd, F_GETFD);
if (flags == -1) {
- mrb_sys_fail(mrb, "fcntl");
+ mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_GETFD) failed: %S",
+ mrb_fixnum_value(fd), mrb_fixnum_value(errno));
}
if (fd <= 2) {
flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
@@ -198,7 +199,8 @@ mrb_fd_cloexec(mrb_state *mrb, int fd)
}
if (flags != flags2) {
if (fcntl(fd, F_SETFD, flags2) == -1) {
- mrb_sys_fail(mrb, "fcntl");
+ mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_SETFD, %S) failed: %S",
+ mrb_fixnum_value(fd), mrb_fixnum_value(flags2), mrb_fixnum_value(errno));
}
}
#endif
@@ -577,11 +579,17 @@ mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
if (failed) {
mrb_sys_fail(mrb, 0);
}
- fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
- if (failed) {
- close(fptr_copy->fd);
- mrb_sys_fail(mrb, 0);
+ mrb_fd_cloexec(mrb, fptr_copy->fd);
+
+ if (fptr_orig->fd2 != -1) {
+ fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
+ if (failed) {
+ close(fptr_copy->fd);
+ mrb_sys_fail(mrb, 0);
+ }
+ mrb_fd_cloexec(mrb, fptr_copy->fd2);
}
+
fptr_copy->pid = fptr_orig->pid;
fptr_copy->readable = fptr_orig->readable;
fptr_copy->writable = fptr_orig->writable;
@@ -676,7 +684,7 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
io_set_process_status(mrb, pid, status);
}
#else
- HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
+ HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
DWORD status;
if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
if (!quiet)
diff --git a/mrbgems/mruby-io/test/file.rb b/mrbgems/mruby-io/test/file.rb
index e5c127746..dc6fe369a 100644
--- a/mrbgems/mruby-io/test/file.rb
+++ b/mrbgems/mruby-io/test/file.rb
@@ -54,7 +54,7 @@ assert('File.extname') do
assert_equal '', File.extname('.foo')
end
-assert('IO#flock') do
+assert('File#flock') do
f = File.open $mrbtest_io_rfname
begin
assert_equal(f.flock(File::LOCK_SH), 0)
@@ -68,6 +68,22 @@ assert('IO#flock') do
end
end
+assert('File#mtime') do
+ unless Object.const_defined?(:Time)
+ skip "File#mtime require Time"
+ end
+ begin
+ now = Time.now.to_i
+ mt = 0
+ File.open('mtime-test', 'w') do |f|
+ mt = f.mtime.to_i
+ end
+ assert_equal true, mt >= now
+ ensure
+ File.delete('mtime-test')
+ end
+end
+
assert('File.join') do
assert_equal "", File.join()
assert_equal "a", File.join("a")
diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb
index 96c3495d0..e06b14996 100644
--- a/mrbgems/mruby-io/test/io.rb
+++ b/mrbgems/mruby-io/test/io.rb
@@ -216,6 +216,10 @@ assert('IO#dup for readable') do
dup = io.dup
assert_true io != dup
assert_true io.fileno != dup.fileno
+ begin
+ assert_true dup.close_on_exec?
+ rescue NotImplementedError
+ end
assert_equal 'm', dup.sysread(1)
assert_equal 'r', io.sysread(1)
assert_equal 'u', dup.sysread(1)
diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c
index f71236a32..1d6a07769 100644
--- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c
+++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c
@@ -1,13 +1,34 @@
#include <limits.h>
#include <mruby.h>
+static inline mrb_int
+to_int(mrb_value x)
+{
+ double f;
+
+ if (mrb_fixnum_p(x)) return mrb_fixnum(x);
+ f = mrb_float(x);
+ return (mrb_int)f;
+}
+
+/*
+ * Document-method: Integer#chr
+ * call-seq:
+ * int.chr -> string
+ *
+ * Returns a string containing the character represented by the +int+'s value
+ * according to +encoding+.
+ *
+ * 65.chr #=> "A"
+ * 230.chr #=> "\xE6"
+ */
static mrb_value
mrb_int_chr(mrb_state *mrb, mrb_value x)
{
mrb_int chr;
char c;
- chr = mrb_fixnum(x);
+ chr = to_int(x);
if (chr >= (1 << CHAR_BIT)) {
mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x);
}
@@ -16,12 +37,63 @@ mrb_int_chr(mrb_state *mrb, mrb_value x)
return mrb_str_new(mrb, &c, 1);
}
+/*
+ * call-seq:
+ * int.allbits?(mask) -> true or false
+ *
+ * Returns +true+ if all bits of <code>+int+ & +mask+</code> are 1.
+ */
+static mrb_value
+mrb_int_allbits(mrb_state *mrb, mrb_value self)
+{
+ mrb_int n, m;
+
+ n = to_int(self);
+ mrb_get_args(mrb, "i", &m);
+ return mrb_bool_value((n & m) == m);
+}
+
+/*
+ * call-seq:
+ * int.anybits?(mask) -> true or false
+ *
+ * Returns +true+ if any bits of <code>+int+ & +mask+</code> are 1.
+ */
+static mrb_value
+mrb_int_anybits(mrb_state *mrb, mrb_value self)
+{
+ mrb_int n, m;
+
+ n = to_int(self);
+ mrb_get_args(mrb, "i", &m);
+ return mrb_bool_value((n & m) != 0);
+}
+
+/*
+ * call-seq:
+ * int.nobits?(mask) -> true or false
+ *
+ * Returns +true+ if no bits of <code>+int+ & +mask+</code> are 1.
+ */
+static mrb_value
+mrb_int_nobits(mrb_state *mrb, mrb_value self)
+{
+ mrb_int n, m;
+
+ n = to_int(self);
+ mrb_get_args(mrb, "i", &m);
+ return mrb_bool_value((n & m) == 0);
+}
+
void
mrb_mruby_numeric_ext_gem_init(mrb_state* mrb)
{
- struct RClass *i = mrb_class_get(mrb, "Integer");
+ struct RClass *i = mrb_module_get(mrb, "Integral");
mrb_define_method(mrb, i, "chr", mrb_int_chr, MRB_ARGS_NONE());
+ mrb_define_method(mrb, i, "allbits?", mrb_int_allbits, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, i, "anybits?", mrb_int_anybits, MRB_ARGS_REQ(1));
+ mrb_define_method(mrb, i, "nobits?", mrb_int_nobits, MRB_ARGS_REQ(1));
}
void
diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c
index ceb862d3f..3a7489f56 100644
--- a/mrbgems/mruby-pack/src/pack.c
+++ b/mrbgems/mruby-pack/src/pack.c
@@ -833,9 +833,10 @@ pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
{
long i;
+ if (count < 0) return 0;
dst = str_len_ensure(mrb, dst, didx + count);
- for (i = 0; i < count; i++) {
- RSTRING_PTR(dst)[didx] = '\0';
+ for (i = didx; i < count; i++) {
+ RSTRING_PTR(dst)[i] = '\0';
}
return count;
}
@@ -843,6 +844,7 @@ pack_x(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, long count, u
static int
unpack_x(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count, unsigned int flags)
{
+ if (count < 0) return slen;
if (slen < count) {
mrb_raise(mrb, E_ARGUMENT_ERROR, "x outside of string");
}
@@ -1050,6 +1052,9 @@ alias:
count = ch - '0';
while (tmpl->idx < tlen && isdigit(tptr[tmpl->idx])) {
count = count * 10 + (tptr[tmpl->idx++] - '0');
+ if (count < 0) {
+ mrb_raisef(mrb, E_RUNTIME_ERROR, "too big template length");
+ }
}
continue; /* special case */
} else if (ch == '*') {
diff --git a/mrbgems/mruby-socket/mrbgem.rake b/mrbgems/mruby-socket/mrbgem.rake
index dcb1f77a2..8096815eb 100644
--- a/mrbgems/mruby-socket/mrbgem.rake
+++ b/mrbgems/mruby-socket/mrbgem.rake
@@ -11,7 +11,7 @@ MRuby::Gem::Specification.new('mruby-socket') do |spec|
spec.linker.libraries << "ws2_32"
end
- spec.add_dependency('mruby-io')
- spec.add_dependency('mruby-pack')
+ spec.add_dependency('mruby-io', :core => 'mruby-io')
+ spec.add_dependency('mruby-pack', :core => 'mruby-pack')
# spec.add_dependency('mruby-mtest')
end
diff --git a/mrbgems/mruby-socket/test/socket.rb b/mrbgems/mruby-socket/test/socket.rb
index 41f5d1cbe..aa893588f 100644
--- a/mrbgems/mruby-socket/test/socket.rb
+++ b/mrbgems/mruby-socket/test/socket.rb
@@ -15,7 +15,7 @@ assert('Socket::getaddrinfo') do
assert_equal "127.0.0.1", a[3]
assert_equal Socket::AF_INET, a[4]
assert_equal Socket::SOCK_DGRAM, a[5]
- assert_equal Socket::IPPROTO_UDP, a[6]
+ assert_equal Socket::IPPROTO_UDP, a[6] unless SocketTest.cygwin?
end
assert('Socket#recvfrom') do
diff --git a/mrbgems/mruby-socket/test/sockettest.c b/mrbgems/mruby-socket/test/sockettest.c
index 835606141..086bc4892 100644
--- a/mrbgems/mruby-socket/test/sockettest.c
+++ b/mrbgems/mruby-socket/test/sockettest.c
@@ -2,18 +2,54 @@
#include <stdlib.h>
#include "mruby.h"
+#include "mruby/error.h"
+
+#if defined(_WIN32) || defined(_WIN64)
+
+#include <io.h>
+
+#ifdef _MSC_VER
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#define close _close
+#define unlink _unlink
+
+static int
+mkstemp(char *p)
+{
+ int fd;
+ char* fname = _mktemp(p);
+ if (fname == NULL)
+ return -1;
+ fd = open(fname, O_RDWR | O_CREAT | O_EXCL, _S_IREAD | _S_IWRITE);
+ if (fd >= 0)
+ return fd;
+ return -1;
+}
+#endif
+
+#else
+
+#include <unistd.h>
-#ifdef _WIN32
- #define tempnam _tempnam
#endif
mrb_value
mrb_sockettest_tmppath(mrb_state *mrb, mrb_value klass)
{
- char *tmp = tempnam(NULL, "mruby-socket");
- mrb_value str = mrb_str_new_cstr(mrb, tmp);
- free(tmp);
- return str;
+ char name[] = "mruby-socket.XXXXXXXX";
+ int fd = mkstemp(name);
+ if (fd == -1) {
+ mrb_sys_fail(mrb, 0);
+ }
+ if (close(fd) == -1) {
+ mrb_sys_fail(mrb, 0);
+ }
+ if (unlink(name) == -1) {
+ mrb_sys_fail(mrb, 0);
+ }
+ return mrb_str_new_cstr(mrb, name);
}
mrb_value
@@ -26,10 +62,21 @@ mrb_sockettest_win_p(mrb_state *mrb, mrb_value klass)
#endif
}
+mrb_value
+mrb_sockettest_cygwin_p(mrb_state *mrb, mrb_value klass)
+{
+#if defined(__CYGWIN__) || defined(__CYGWIN32__)
+ return mrb_true_value();
+#else
+ return mrb_false_value();
+#endif
+}
+
void
mrb_mruby_socket_gem_test(mrb_state* mrb)
{
struct RClass *c = mrb_define_module(mrb, "SocketTest");
mrb_define_class_method(mrb, c, "tmppath", mrb_sockettest_tmppath, MRB_ARGS_NONE());
mrb_define_class_method(mrb, c, "win?", mrb_sockettest_win_p, MRB_ARGS_NONE());
+ mrb_define_class_method(mrb, c, "cygwin?", mrb_sockettest_cygwin_p, MRB_ARGS_NONE());
}
diff --git a/mrbgems/mruby-socket/test/unix.rb b/mrbgems/mruby-socket/test/unix.rb
index 2a29ddae7..4a88fba21 100644
--- a/mrbgems/mruby-socket/test/unix.rb
+++ b/mrbgems/mruby-socket/test/unix.rb
@@ -1,4 +1,4 @@
-unless SocketTest.win?
+unless SocketTest.win? || SocketTest.cygwin?
def unixserver_test_block
path = SocketTest.tmppath
diff --git a/mrbgems/mruby-time/src/time.c b/mrbgems/mruby-time/src/time.c
index e6c6b9904..cfd51ac63 100644
--- a/mrbgems/mruby-time/src/time.c
+++ b/mrbgems/mruby-time/src/time.c
@@ -67,6 +67,11 @@ double round(double x) {
/* define following macro to use probably faster timegm() on the platform */
/* #define USE_SYSTEM_TIMEGM */
+/* time_t */
+/* If your platform supports time_t as uint (e.g. uint32_t, uint64_t), */
+/* uncomment following macro. */
+/* #define MRB_TIME_T_UINT */
+
/** end of Time class configuration */
#ifndef NO_GETTIMEOFDAY
@@ -138,8 +143,14 @@ timegm(struct tm *tm)
int i;
unsigned int *nday = (unsigned int*) ndays[is_leapyear(tm->tm_year+1900)];
- for (i = 70; i < tm->tm_year; ++i)
- r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
+ static const int epoch_year = 70;
+ if(tm->tm_year >= epoch_year) {
+ for (i = epoch_year; i < tm->tm_year; ++i)
+ r += is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
+ } else {
+ for (i = tm->tm_year; i < epoch_year; ++i)
+ r -= is_leapyear(i+1900) ? 366*24*60*60 : 365*24*60*60;
+ }
for (i = 0; i < tm->tm_mon; ++i)
r += nday[i] * 24 * 60 * 60;
r += (tm->tm_mday - 1) * 24 * 60 * 60;
@@ -234,13 +245,21 @@ time_alloc(mrb_state *mrb, double sec, double usec, enum mrb_timezone timezone)
mrb_check_num_exact(mrb, (mrb_float)sec);
mrb_check_num_exact(mrb, (mrb_float)usec);
-
+#ifndef MRB_TIME_T_UINT
if (sizeof(time_t) == 4 && (sec > (double)INT32_MAX || (double)INT32_MIN > sec)) {
goto out_of_range;
}
if (sizeof(time_t) == 8 && (sec > (double)INT64_MAX || (double)INT64_MIN > sec)) {
goto out_of_range;
}
+#else
+ if (sizeof(time_t) == 4 && (sec > (double)UINT32_MAX || (double)0 > sec)) {
+ goto out_of_range;
+ }
+ if (sizeof(time_t) == 8 && (sec > (double)UINT64_MAX || (double)0 > sec)) {
+ goto out_of_range;
+ }
+#endif
tsec = (time_t)sec;
if ((sec > 0 && tsec < 0) || (sec < 0 && (double)tsec > sec)) {
out_of_range:
diff --git a/mrbgems/mruby-time/test/time.rb b/mrbgems/mruby-time/test/time.rb
index 52b931177..54c446ca3 100644
--- a/mrbgems/mruby-time/test/time.rb
+++ b/mrbgems/mruby-time/test/time.rb
@@ -226,3 +226,7 @@ assert('2000 times 500us make a second') do
end
t.usec == 0
end
+
+assert('Time.gm with Dec 31 23:59:59 1969 raise ArgumentError') do
+ assert_raise(ArgumentError) {Time.gm(1969, 12, 31, 23, 59, 59)}
+end
diff --git a/src/class.c b/src/class.c
index 132cf0176..3f24528ca 100644
--- a/src/class.c
+++ b/src/class.c
@@ -1744,7 +1744,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c)
return mrb_class_find_path(mrb, c);
}
else if (mrb_symbol_p(path)) {
- /* topleve class/module */
+ /* toplevel class/module */
const char *str;
mrb_int len;
diff --git a/src/error.c b/src/error.c
index 1b24f3065..5445b51bf 100644
--- a/src/error.c
+++ b/src/error.c
@@ -229,7 +229,8 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc)
}
else {
mrb->exc = mrb_obj_ptr(exc);
- if ((struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
+ if (mrb->gc.arena_idx > 0 &&
+ (struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
mrb->gc.arena_idx--;
}
if (!mrb->gc.out_of_memory) {
diff --git a/src/gc.c b/src/gc.c
index 62161b7f0..3604066dd 100644
--- a/src/gc.c
+++ b/src/gc.c
@@ -658,7 +658,7 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
struct REnv *e = (struct REnv*)obj;
mrb_int i, len;
- if (MRB_ENV_STACK_SHARED_P(e) && e->cxt->fib) {
+ if (MRB_ENV_STACK_SHARED_P(e) && e->cxt && e->cxt->fib) {
mrb_gc_mark(mrb, (struct RBasic*)e->cxt->fib);
}
len = MRB_ENV_STACK_LEN(e);
diff --git a/src/kernel.c b/src/kernel.c
index 1ac49ed04..e9dc93bbd 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -956,26 +956,7 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self)
void
mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args)
{
- mrb_sym inspect;
- mrb_value repr;
-
- inspect = mrb_intern_lit(mrb, "inspect");
- if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) {
- /* method missing in inspect; avoid recursion */
- repr = mrb_any_to_s(mrb, self);
- }
- else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 16) {
- repr = mrb_funcall_argv(mrb, self, inspect, 0, 0);
- if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) {
- repr = mrb_any_to_s(mrb, self);
- }
- }
- else {
- repr = mrb_any_to_s(mrb, self);
- }
-
- mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S",
- mrb_sym2str(mrb, name), repr);
+ mrb_no_method_error(mrb, name, args, "undefined method '%S'", mrb_sym2str(mrb, name));
}
/* 15.3.1.3.30 */
diff --git a/src/variable.c b/src/variable.c
index 968fc2fc1..de36efac6 100644
--- a/src/variable.c
+++ b/src/variable.c
@@ -955,27 +955,61 @@ find_class_sym(mrb_state *mrb, struct RClass *outer, struct RClass *c)
return arg.sym;
}
+static struct RClass*
+outer_class(mrb_state *mrb, struct RClass *c)
+{
+ mrb_value ov;
+
+ ov = mrb_obj_iv_get(mrb, (struct RObject*)c, mrb_intern_lit(mrb, "__outer__"));
+ if (mrb_nil_p(ov)) return NULL;
+ switch (mrb_type(ov)) {
+ case MRB_TT_CLASS:
+ case MRB_TT_MODULE:
+ return mrb_class_ptr(ov);
+ default:
+ break;
+ }
+ return NULL;
+}
+
+static mrb_bool
+detect_outer_loop(mrb_state *mrb, struct RClass *c)
+{
+ struct RClass *t = c; /* tortoise */
+ struct RClass *h = c; /* hare */
+
+ for (;;) {
+ if (h == NULL) return FALSE;
+ h = outer_class(mrb, h);
+ if (h == NULL) return FALSE;
+ h = outer_class(mrb, h);
+ t = outer_class(mrb, t);
+ if (t == h) return TRUE;
+ }
+}
+
mrb_value
mrb_class_find_path(mrb_state *mrb, struct RClass *c)
{
- mrb_value outer, path;
+ struct RClass *outer;
+ mrb_value path;
mrb_sym name;
const char *str;
mrb_int len;
- mrb_sym osym = mrb_intern_lit(mrb, "__outer__");
- outer = mrb_obj_iv_get(mrb, (struct RObject*)c, osym);
- if (mrb_nil_p(outer)) return outer;
- name = find_class_sym(mrb, mrb_class_ptr(outer), c);
+ if (detect_outer_loop(mrb, c)) return mrb_nil_value();
+ outer = outer_class(mrb, c);
+ if (outer == NULL) return mrb_nil_value();
+ name = find_class_sym(mrb, outer, c);
if (name == 0) return mrb_nil_value();
- str = mrb_class_name(mrb, mrb_class_ptr(outer));
+ str = mrb_class_name(mrb, outer);
path = mrb_str_new_capa(mrb, 40);
mrb_str_cat_cstr(mrb, path, str);
mrb_str_cat_cstr(mrb, path, "::");
str = mrb_sym2name_len(mrb, name, &len);
mrb_str_cat(mrb, path, str, len);
- iv_del(mrb, c->iv, osym, NULL);
+ iv_del(mrb, c->iv, mrb_intern_lit(mrb, "__outer__"), NULL);
iv_put(mrb, c->iv, mrb_intern_lit(mrb, "__classname__"), path);
mrb_field_write_barrier_value(mrb, (struct RBasic*)c, path);
return path;
diff --git a/src/vm.c b/src/vm.c
index bf33cce51..330bcd024 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -455,7 +455,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc
}
else if (argc >= CALL_MAXARGS) {
mrb_value args = mrb_ary_new_from_values(mrb, argc, argv);
- stack_extend(mrb, ci->nregs);
+ stack_extend(mrb, ci->nregs+2);
mrb->c->stack[1] = args;
ci->argc = -1;
argc = 1;
@@ -511,7 +511,6 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p)
mrb->c->stack[0] = self;
ci->proc = p;
- ci->target_class = MRB_PROC_TARGET_CLASS(p);
if (MRB_PROC_CFUNC_P(p)) {
return MRB_PROC_CFUNC(p)(mrb, self);
}
@@ -1352,6 +1351,7 @@ RETRY_TRY_BLOCK:
for (n=0; n<a; n++) {
proc = mrb->c->ensure[epos+n];
mrb->c->ensure[epos+n] = NULL;
+ if (proc == NULL) continue;
irep = proc->body.irep;
ci = cipush(mrb);
ci->mid = ci[-1].mid;
@@ -1420,7 +1420,7 @@ RETRY_TRY_BLOCK:
if (MRB_METHOD_UNDEF_P(m)) {
mrb_sym missing = mrb_intern_lit(mrb, "method_missing");
m = mrb_method_search_vm(mrb, &c, missing);
- if (MRB_METHOD_UNDEF_P(m)) {
+ if (MRB_METHOD_UNDEF_P(m) || (missing == mrb->c->ci->mid && mrb_obj_eq(mrb, regs[0], recv))) {
mrb_value args = (argc < 0) ? regs[a+1] : mrb_ary_new_from_values(mrb, n, regs+a+1);
ERR_PC_SET(mrb, pc);
mrb_method_missing(mrb, mid, recv, args);
@@ -1607,6 +1607,12 @@ RETRY_TRY_BLOCK:
}
}
recv = regs[0];
+ if (!mrb_obj_is_kind_of(mrb, recv, target_class)) {
+ mrb_value exc = mrb_exc_new_str_lit(mrb, E_TYPE_ERROR,
+ "self has wrong type to call super in this context");
+ mrb_exc_set(mrb, exc);
+ goto L_RAISE;
+ }
blk = regs[bidx];
if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) {
blk = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc");
@@ -2929,9 +2935,6 @@ RETRY_TRY_BLOCK:
CASE(OP_STOP) {
/* stop VM */
L_STOP:
- while (mrb->c->ci > mrb->c->cibase) {
- cipop(mrb);
- }
while (mrb->c->eidx > 0) {
ecall(mrb);
}
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index 4bd102392..eaae78e47 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -366,48 +366,14 @@ assert('Kernel#method_missing', '15.3.1.3.30') do
begin
no_super_test.no_super_method_named_this
rescue NoMethodError => e
- assert_equal "undefined method 'no_super_method_named_this' for #{no_super_test}", e.message
+ assert_equal "undefined method 'no_super_method_named_this'", e.message
end
a = String.new
begin
a.no_method_named_this
rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this' for \"\"", e.message
- end
-
- class ShortInspectClass
- def inspect
- 'An inspect string'
- end
- end
- b = ShortInspectClass.new
- begin
- b.no_method_named_this
- rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this' for An inspect string", e.message
- end
-
- class LongInspectClass
- def inspect
- "A" * 70
- end
- end
- c = LongInspectClass.new
- begin
- c.no_method_named_this
- rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this' for #{c}", e.message
- end
-
- class NoInspectClass
- undef inspect
- end
- d = NoInspectClass.new
- begin
- d.no_method_named_this
- rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this' for #{d}", e.message
+ assert_equal "undefined method 'no_method_named_this'", e.message
end
end