Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mruby
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
mruby
Commits
1cbbb7e1
Commit
1cbbb7e1
authored
Sep 05, 2015
by
Yukihiro "Matz" Matsumoto
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'polyfox-module-prepend'
parents
2f1a031f
2550edd5
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
493 additions
and
51 deletions
+493
-51
include/mruby.h
include/mruby.h
+1
-0
include/mruby/class.h
include/mruby/class.h
+14
-2
include/mruby/object.h
include/mruby/object.h
+2
-0
src/class.c
src/class.c
+142
-43
src/gc.c
src/gc.c
+10
-2
src/kernel.c
src/kernel.c
+23
-4
src/object.c
src/object.c
+1
-0
test/t/module.rb
test/t/module.rb
+300
-0
No files found.
include/mruby.h
View file @
1cbbb7e1
...
...
@@ -206,6 +206,7 @@ MRB_API struct RClass *mrb_define_class(mrb_state *, const char*, struct RClass*
MRB_API
struct
RClass
*
mrb_define_module
(
mrb_state
*
,
const
char
*
);
MRB_API
mrb_value
mrb_singleton_class
(
mrb_state
*
,
mrb_value
);
MRB_API
void
mrb_include_module
(
mrb_state
*
,
struct
RClass
*
,
struct
RClass
*
);
MRB_API
void
mrb_prepend_module
(
mrb_state
*
,
struct
RClass
*
,
struct
RClass
*
);
MRB_API
void
mrb_define_method
(
mrb_state
*
,
struct
RClass
*
,
const
char
*
,
mrb_func_t
,
mrb_aspec
);
MRB_API
void
mrb_define_class_method
(
mrb_state
*
,
struct
RClass
*
,
const
char
*
,
mrb_func_t
,
mrb_aspec
);
...
...
include/mruby/class.h
View file @
1cbbb7e1
...
...
@@ -48,8 +48,20 @@ mrb_class(mrb_state *mrb, mrb_value v)
}
}
#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~0xff) | (char)tt)
#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & 0xff)
// TODO: figure out where to put user flags
#define MRB_FLAG_IS_PREPENDED (1 << 19)
#define MRB_FLAG_IS_ORIGIN (1 << 20)
#define MRB_CLASS_ORIGIN(c) do {\
if (c->flags & MRB_FLAG_IS_PREPENDED) {\
c = c->super;\
while (!(c->flags & MRB_FLAG_IS_ORIGIN)) {\
c = c->super;\
}\
}\
} while (0)
#define MRB_INSTANCE_TT_MASK (0xFF)
#define MRB_SET_INSTANCE_TT(c, tt) c->flags = ((c->flags & ~MRB_INSTANCE_TT_MASK) | (char)tt)
#define MRB_INSTANCE_TT(c) (enum mrb_vtype)(c->flags & MRB_INSTANCE_TT_MASK)
MRB_API
struct
RClass
*
mrb_define_class_id
(
mrb_state
*
,
mrb_sym
,
struct
RClass
*
);
MRB_API
struct
RClass
*
mrb_define_module_id
(
mrb_state
*
,
mrb_sym
);
...
...
include/mruby/object.h
View file @
1cbbb7e1
...
...
@@ -14,6 +14,8 @@
struct RClass *c;\
struct RBasic *gcnext
#define MRB_FLAG_TEST(obj, flag) ((obj)->flags & flag)
/* white: 011, black: 100, gray: 000 */
#define MRB_GC_GRAY 0
#define MRB_GC_WHITE_A 1
...
...
src/class.c
View file @
1cbbb7e1
...
...
@@ -76,7 +76,7 @@ prepare_singleton_class(mrb_state *mrb, struct RBasic *o)
if
(
o
->
c
->
tt
==
MRB_TT_SCLASS
)
return
;
sc
=
(
struct
RClass
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_SCLASS
,
mrb
->
class_class
);
sc
->
mt
=
0
;
sc
->
mt
=
kh_init
(
mt
,
mrb
)
;
sc
->
iv
=
0
;
if
(
o
->
tt
==
MRB_TT_CLASS
)
{
c
=
(
struct
RClass
*
)
o
;
...
...
@@ -187,6 +187,13 @@ mrb_define_module_under(mrb_state *mrb, struct RClass *outer, const char *name)
return
c
;
}
static
struct
RClass
*
find_origin
(
struct
RClass
*
c
)
{
MRB_CLASS_ORIGIN
(
c
);
return
c
;
}
static
struct
RClass
*
define_class
(
mrb_state
*
mrb
,
mrb_sym
name
,
struct
RClass
*
super
,
struct
RClass
*
outer
)
{
...
...
@@ -194,6 +201,7 @@ define_class(mrb_state *mrb, mrb_sym name, struct RClass *super, struct RClass *
if
(
mrb_const_defined_at
(
mrb
,
mrb_obj_value
(
outer
),
name
))
{
c
=
class_from_sym
(
mrb
,
outer
,
name
);
MRB_CLASS_ORIGIN
(
c
);
if
(
super
&&
mrb_class_real
(
c
->
super
)
!=
super
)
{
mrb_raisef
(
mrb
,
E_TYPE_ERROR
,
"superclass mismatch for Class %S (%S not %S)"
,
mrb_sym2str
(
mrb
,
name
),
...
...
@@ -323,8 +331,10 @@ mrb_define_class_under(mrb_state *mrb, struct RClass *outer, const char *name, s
MRB_API
void
mrb_define_method_raw
(
mrb_state
*
mrb
,
struct
RClass
*
c
,
mrb_sym
mid
,
struct
RProc
*
p
)
{
khash_t
(
mt
)
*
h
=
c
->
mt
;
khash_t
(
mt
)
*
h
;
khiter_t
k
;
MRB_CLASS_ORIGIN
(
c
);
h
=
c
->
mt
;
if
(
!
h
)
h
=
c
->
mt
=
kh_init
(
mt
,
mrb
);
k
=
kh_put
(
mt
,
mrb
,
h
,
mid
);
...
...
@@ -817,47 +827,130 @@ boot_defclass(mrb_state *mrb, struct RClass *super)
return
c
;
}
MRB_API
void
mrb_include_module
(
mrb_state
*
mrb
,
struct
RClass
*
c
,
struct
RClass
*
m
)
static
void
boot_initmod
(
mrb_state
*
mrb
,
struct
RClass
*
mod
)
{
mod
->
mt
=
kh_init
(
mt
,
mrb
);
}
static
struct
RClass
*
include_class_new
(
mrb_state
*
mrb
,
struct
RClass
*
m
,
struct
RClass
*
super
)
{
struct
RClass
*
ic
=
(
struct
RClass
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_ICLASS
,
mrb
->
class_class
);
if
(
m
->
tt
==
MRB_TT_ICLASS
)
{
m
=
m
->
c
;
}
MRB_CLASS_ORIGIN
(
m
);
ic
->
iv
=
m
->
iv
;
ic
->
mt
=
m
->
mt
;
ic
->
super
=
super
;
if
(
m
->
tt
==
MRB_TT_ICLASS
)
{
ic
->
c
=
m
->
c
;
}
else
{
ic
->
c
=
m
;
}
return
ic
;
}
static
int
include_module_at
(
mrb_state
*
mrb
,
struct
RClass
*
c
,
struct
RClass
*
ins_pos
,
struct
RClass
*
m
,
int
search_super
)
{
struct
RClass
*
ins_pos
;
struct
RClass
*
p
,
*
ic
;
void
*
klass_mt
=
find_origin
(
c
)
->
mt
;
ins_pos
=
c
;
while
(
m
)
{
struct
RClass
*
p
=
c
,
*
ic
;
int
superclass_seen
=
0
;
if
(
c
->
mt
&&
c
->
mt
==
m
->
mt
)
{
mrb_raise
(
mrb
,
E_ARGUMENT_ERROR
,
"cyclic include detected"
);
}
while
(
p
)
{
if
(
c
!=
p
&&
p
->
tt
==
MRB_TT_CLASS
)
{
superclass_seen
=
1
;
}
else
if
(
p
->
mt
==
m
->
mt
)
{
if
(
p
->
tt
==
MRB_TT_ICLASS
&&
!
superclass_seen
)
{
ins_pos
=
p
;
}
if
(
m
->
flags
&
MRB_FLAG_IS_PREPENDED
)
goto
skip
;
if
(
klass_mt
&&
klass_mt
==
m
->
mt
)
return
-
1
;
p
=
c
->
super
;
while
(
p
)
{
if
(
p
->
tt
==
MRB_TT_ICLASS
)
{
if
(
p
->
mt
==
m
->
mt
)
{
if
(
!
superclass_seen
)
{
ins_pos
=
p
;
// move insert point
}
p
=
p
->
super
;
goto
skip
;
}
ic
=
(
struct
RClass
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_ICLASS
,
mrb
->
class_class
);
if
(
m
->
tt
==
MRB_TT_ICLASS
)
{
ic
->
c
=
m
->
c
;
}
else
if
(
p
->
tt
==
MRB_TT_CLASS
)
{
if
(
!
search_super
)
break
;
superclass_seen
=
1
;
}
else
{
ic
->
c
=
m
;
p
=
p
->
super
;
}
ic
->
mt
=
m
->
mt
;
ic
->
iv
=
m
->
iv
;
ic
->
super
=
ins_pos
->
super
;
ic
=
include_class_new
(
mrb
,
m
,
ins_pos
->
super
);
ins_pos
->
super
=
ic
;
mrb_field_write_barrier
(
mrb
,
(
struct
RBasic
*
)
ins_pos
,
(
struct
RBasic
*
)
i
c
);
mrb_field_write_barrier
(
mrb
,
(
struct
RBasic
*
)
ins_pos
,
(
struct
RBasic
*
)
i
ns_pos
->
super
);
ins_pos
=
ic
;
skip:
m
=
m
->
super
;
}
return
0
;
}
MRB_API
void
mrb_include_module
(
mrb_state
*
mrb
,
struct
RClass
*
c
,
struct
RClass
*
m
)
{
int
changed
=
include_module_at
(
mrb
,
c
,
find_origin
(
c
),
m
,
1
);
if
(
changed
<
0
)
{
mrb_raise
(
mrb
,
E_ARGUMENT_ERROR
,
"cyclic include detected"
);
}
}
MRB_API
void
mrb_prepend_module
(
mrb_state
*
mrb
,
struct
RClass
*
c
,
struct
RClass
*
m
)
{
struct
RClass
*
origin
;
int
changed
=
0
;
if
(
!
(
c
->
flags
&
MRB_FLAG_IS_PREPENDED
))
{
origin
=
(
struct
RClass
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_ICLASS
,
c
);
origin
->
flags
|=
MRB_FLAG_IS_ORIGIN
;
origin
->
super
=
c
->
super
;
c
->
super
=
origin
;
origin
->
mt
=
c
->
mt
;
c
->
mt
=
kh_init
(
mt
,
mrb
);
mrb_field_write_barrier
(
mrb
,
(
struct
RBasic
*
)
c
,
(
struct
RBasic
*
)
origin
);
c
->
flags
|=
MRB_FLAG_IS_PREPENDED
;
}
changed
=
include_module_at
(
mrb
,
c
,
c
,
m
,
0
);
if
(
changed
<
0
)
{
mrb_raise
(
mrb
,
E_ARGUMENT_ERROR
,
"cyclic prepend detected"
);
}
}
static
mrb_value
mrb_mod_prepend_features
(
mrb_state
*
mrb
,
mrb_value
mod
)
{
mrb_value
klass
;
mrb_check_type
(
mrb
,
mod
,
MRB_TT_MODULE
);
mrb_get_args
(
mrb
,
"C"
,
&
klass
);
mrb_prepend_module
(
mrb
,
mrb_class_ptr
(
klass
),
mrb_class_ptr
(
mod
));
return
mod
;
}
static
mrb_value
mrb_mod_prepend
(
mrb_state
*
mrb
,
mrb_value
klass
)
{
mrb_value
*
argv
;
mrb_int
argc
,
i
;
mrb_get_args
(
mrb
,
"*"
,
&
argv
,
&
argc
);
for
(
i
=
0
;
i
<
argc
;
i
++
)
{
mrb_check_type
(
mrb
,
argv
[
i
],
MRB_TT_MODULE
);
}
while
(
argc
--
)
{
mrb_funcall
(
mrb
,
argv
[
argc
],
"prepend_features"
,
1
,
klass
);
mrb_funcall
(
mrb
,
argv
[
argc
],
"prepended"
,
1
,
klass
);
}
return
klass
;
}
static
mrb_value
...
...
@@ -931,15 +1024,12 @@ mrb_mod_ancestors(mrb_state *mrb, mrb_value self)
{
mrb_value
result
;
struct
RClass
*
c
=
mrb_class_ptr
(
self
);
result
=
mrb_ary_new
(
mrb
);
mrb_ary_push
(
mrb
,
result
,
mrb_obj_value
(
c
));
c
=
c
->
super
;
while
(
c
)
{
if
(
c
->
tt
==
MRB_TT_ICLASS
)
{
mrb_ary_push
(
mrb
,
result
,
mrb_obj_value
(
c
->
c
));
}
else
if
(
c
->
tt
!=
MRB_TT_SCLASS
)
{
else
if
(
!
(
c
->
flags
&
MRB_FLAG_IS_PREPENDED
)
)
{
mrb_ary_push
(
mrb
,
result
,
mrb_obj_value
(
c
));
}
c
=
c
->
super
;
...
...
@@ -964,12 +1054,16 @@ 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
->
tt
==
MRB_TT_ICLASS
)
{
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
;
}
...
...
@@ -980,10 +1074,11 @@ static mrb_value
mrb_mod_initialize
(
mrb_state
*
mrb
,
mrb_value
mod
)
{
mrb_value
b
;
mrb_get_args
(
mrb
,
"&"
,
&
b
);
struct
RClass
*
m
=
mrb_class_ptr
(
mod
);
boot_initmod
(
mrb
,
m
);
// bootstrap a newly initialized module
mrb_get_args
(
mrb
,
"|&"
,
&
b
);
if
(
!
mrb_nil_p
(
b
))
{
mrb_yield_with_class
(
mrb
,
b
,
1
,
&
mod
,
mod
,
m
rb_class_ptr
(
mod
)
);
mrb_yield_with_class
(
mrb
,
b
,
1
,
&
mod
,
mod
,
m
);
}
return
mod
;
}
...
...
@@ -1300,9 +1395,9 @@ mrb_class_superclass(mrb_state *mrb, mrb_value klass)
struct
RClass
*
c
;
c
=
mrb_class_ptr
(
klass
);
c
=
c
->
super
;
c
=
find_origin
(
c
)
->
super
;
while
(
c
&&
c
->
tt
==
MRB_TT_ICLASS
)
{
c
=
c
->
super
;
c
=
find_origin
(
c
)
->
super
;
}
if
(
!
c
)
return
mrb_nil_value
();
return
mrb_obj_value
(
c
);
...
...
@@ -1540,8 +1635,7 @@ MRB_API struct RClass*
mrb_module_new
(
mrb_state
*
mrb
)
{
struct
RClass
*
m
=
(
struct
RClass
*
)
mrb_obj_alloc
(
mrb
,
MRB_TT_MODULE
,
mrb
->
module_class
);
m
->
mt
=
kh_init
(
mt
,
mrb
);
boot_initmod
(
mrb
,
m
);
return
m
;
}
...
...
@@ -1900,13 +1994,14 @@ static void
remove_method
(
mrb_state
*
mrb
,
mrb_value
mod
,
mrb_sym
mid
)
{
struct
RClass
*
c
=
mrb_class_ptr
(
mod
);
khash_t
(
mt
)
*
h
=
c
->
mt
;
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
;
}
}
...
...
@@ -2140,6 +2235,9 @@ mrb_init_class(mrb_state *mrb)
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
,
"prepend"
,
mrb_mod_prepend
,
MRB_ARGS_ANY
());
mrb_define_method
(
mrb
,
mod
,
"prepended"
,
mrb_bob_init
,
MRB_ARGS_REQ
(
1
));
mrb_define_method
(
mrb
,
mod
,
"prepend_features"
,
mrb_mod_prepend_features
,
MRB_ARGS_REQ
(
1
));
mrb_define_method
(
mrb
,
mod
,
"include"
,
mrb_mod_include
,
MRB_ARGS_ANY
());
/* 15.2.2.4.27 */
mrb_define_method
(
mrb
,
mod
,
"include?"
,
mrb_mod_include_p
,
MRB_ARGS_REQ
(
1
));
/* 15.2.2.4.28 */
mrb_define_method
(
mrb
,
mod
,
"append_features"
,
mrb_mod_append_features
,
MRB_ARGS_REQ
(
1
));
/* 15.2.2.4.10 */
...
...
@@ -2156,6 +2254,7 @@ mrb_init_class(mrb_state *mrb)
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
());
...
...
src/gc.c
View file @
1cbbb7e1
...
...
@@ -498,7 +498,12 @@ gc_mark_children(mrb_state *mrb, struct RBasic *obj)
mrb_gc_mark
(
mrb
,
(
struct
RBasic
*
)
obj
->
c
);
switch
(
obj
->
tt
)
{
case
MRB_TT_ICLASS
:
{
struct
RClass
*
c
=
(
struct
RClass
*
)
obj
;
if
(
MRB_FLAG_TEST
(
c
,
MRB_FLAG_IS_ORIGIN
))
mrb_gc_mark_mt
(
mrb
,
c
);
mrb_gc_mark
(
mrb
,
(
struct
RBasic
*
)((
struct
RClass
*
)
obj
)
->
super
);
}
break
;
case
MRB_TT_CLASS
:
...
...
@@ -624,7 +629,10 @@ obj_free(mrb_state *mrb, struct RBasic *obj)
mrb_gc_free_mt
(
mrb
,
(
struct
RClass
*
)
obj
);
mrb_gc_free_iv
(
mrb
,
(
struct
RObject
*
)
obj
);
break
;
case
MRB_TT_ICLASS
:
if
(
MRB_FLAG_TEST
(
obj
,
MRB_FLAG_IS_ORIGIN
))
mrb_gc_free_mt
(
mrb
,
(
struct
RClass
*
)
obj
);
break
;
case
MRB_TT_ENV
:
{
struct
REnv
*
e
=
(
struct
REnv
*
)
obj
;
...
...
src/kernel.c
View file @
1cbbb7e1
...
...
@@ -240,14 +240,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj)
/* copy singleton(unnamed) class */
struct
RClass
*
clone
=
(
struct
RClass
*
)
mrb_obj_alloc
(
mrb
,
klass
->
tt
,
mrb
->
class_class
);
if
((
mrb_type
(
obj
)
==
MRB_TT_CLASS
)
||
(
mrb_type
(
obj
)
==
MRB_TT_SCLASS
))
{
/* BUILTIN_TYPE(obj) == T_CLASS */
if
((
mrb_type
(
obj
)
==
MRB_TT_CLASS
)
||
(
mrb_type
(
obj
)
==
MRB_TT_SCLASS
))
{
clone
->
c
=
clone
;
}
else
{
clone
->
c
=
mrb_singleton_class_clone
(
mrb
,
mrb_obj_value
(
klass
));
}
clone
->
super
=
klass
->
super
;
if
(
klass
->
iv
)
{
mrb_iv_copy
(
mrb
,
mrb_obj_value
(
clone
),
mrb_obj_value
(
klass
));
...
...
@@ -269,6 +267,21 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src)
{
struct
RClass
*
dc
=
mrb_class_ptr
(
dst
);
struct
RClass
*
sc
=
mrb_class_ptr
(
src
);
/* if the origin is not the same as the class, then the origin and
the current class need to be copied */
if
(
sc
->
flags
&
MRB_FLAG_IS_PREPENDED
)
{
struct
RClass
*
c0
=
sc
->
super
;
struct
RClass
*
c1
=
dc
;
/* copy prepended iclasses */
while
(
!
(
c0
->
flags
&
MRB_FLAG_IS_ORIGIN
))
{
c1
->
super
=
mrb_class_ptr
(
mrb_obj_dup
(
mrb
,
mrb_obj_value
(
c0
)));
c1
=
c1
->
super
;
c0
=
c0
->
super
;
}
c1
->
super
=
mrb_class_ptr
(
mrb_obj_dup
(
mrb
,
mrb_obj_value
(
c0
)));
c1
->
super
->
flags
|=
MRB_FLAG_IS_ORIGIN
;
}
dc
->
mt
=
kh_copy
(
mt
,
mrb
,
sc
->
mt
);
dc
->
super
=
sc
->
super
;
}
...
...
@@ -641,13 +654,19 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* kl
{
khint_t
i
;
mrb_value
ary
;
mrb_bool
prepended
;
struct
RClass
*
oldklass
;
khash_t
(
st
)
*
set
=
kh_init
(
st
,
mrb
);
if
(
!
recur
&&
(
klass
->
flags
&
MRB_FLAG_IS_PREPENDED
))
{
MRB_CLASS_ORIGIN
(
klass
);
prepended
=
1
;
}
oldklass
=
0
;
while
(
klass
&&
(
klass
!=
oldklass
))
{
method_entry_loop
(
mrb
,
klass
,
set
);
if
((
klass
->
tt
==
MRB_TT_ICLASS
)
||
if
((
klass
->
tt
==
MRB_TT_ICLASS
&&
!
prepended
)
||
(
klass
->
tt
==
MRB_TT_SCLASS
))
{
}
else
{
...
...
src/object.c
View file @
1cbbb7e1
...
...
@@ -487,6 +487,7 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c)
mrb_raise
(
mrb
,
E_TYPE_ERROR
,
"class or module required"
);
}
MRB_CLASS_ORIGIN
(
c
);
while
(
cl
)
{
if
(
cl
==
c
||
cl
->
mt
==
c
->
mt
)
return
TRUE
;
...
...
test/t/module.rb
View file @
1cbbb7e1
##
# Module ISO Test
def
labeled_module
(
name
,
&
block
)
Module
.
new
do
singleton_class
.
class_eval
do
define_method
(
:to_s
)
{
name
}
alias_method
:inspect
,
:to_s
end
class_eval
(
&
block
)
if
block
end
end
def
labeled_class
(
name
,
supklass
=
Object
,
&
block
)
Class
.
new
(
supklass
)
do
singleton_class
.
class_eval
do
define_method
(
:to_s
)
{
name
}
alias_method
:inspect
,
:to_s
end
class_eval
(
&
block
)
if
block
end
end
assert
(
'Module'
,
'15.2.2'
)
do
assert_equal
Class
,
Module
.
class
end
...
...
@@ -474,6 +494,286 @@ end
# Not ISO specified
# @!group prepend
assert
(
'Module#prepend'
)
do
module
M0
def
m1
;
[
:M0
]
end
end
module
M1
def
m1
;
[
:M1
,
super
,
:M1
]
end
end
module
M2
def
m1
;
[
:M2
,
super
,
:M2
]
end
end
M3
=
Module
.
new
do
def
m1
;
[
:M3
,
super
,
:M3
]
end
end
module
M4
def
m1
;
[
:M4
,
super
,
:M4
]
end
end
class
P0
include
M0
prepend
M1
def
m1
;
[
:C0
,
super
,
:C0
]
end
end
class
P1
<
P0
prepend
M2
,
M3
include
M4
def
m1
;
[
:C1
,
super
,
:C1
]
end
end
obj
=
P1
.
new
expected
=
[
:M2
,[
:M3
,[
:C1
,[
:M4
,[
:M1
,[
:C0
,[
:M0
],
:C0
],
:M1
],
:M4
],
:C1
],
:M3
],
:M2
]
assert_equal
(
expected
,
obj
.
m1
)
end
# mruby shouldn't be affected by this since there is
# no visibility control (yet)
assert
(
'Module#prepend public'
)
do
assert_nothing_raised
(
'ruby/ruby #8846'
)
do
Class
.
new
.
prepend
(
Module
.
new
)
end
end
assert
(
'Module#prepend inheritance'
)
do
bug6654
=
'[ruby-core:45914]'
a
=
labeled_module
(
'a'
)
b
=
labeled_module
(
'b'
)
{
include
a
}
c
=
labeled_module
(
'c'
)
{
prepend
b
}
#assert bug6654 do
# the Module#< operator should be used here instead, but we don't have it
assert_include
(
c
.
ancestors
,
a
)
assert_include
(
c
.
ancestors
,
b
)
#end
bug8357
=
'[ruby-core:54736] [Bug #8357]'
b
=
labeled_module
(
'b'
)
{
prepend
a
}
c
=
labeled_class
(
'c'
)
{
include
b
}
#assert bug8357 do
# the Module#< operator should be used here instead, but we don't have it
assert_include
(
c
.
ancestors
,
a
)
assert_include
(
c
.
ancestors
,
b
)
#end
bug8357
=
'[ruby-core:54742] [Bug #8357]'
assert_kind_of
(
b
,
c
.
new
,
bug8357
)
end
assert
(
'Moduler#prepend + #instance_methods'
)
do
bug6655
=
'[ruby-core:45915]'
assert_equal
(
Object
.
instance_methods
,
Class
.
new
{
prepend
Module
.
new
}.
instance_methods
,
bug6655
)
end
assert
'Module#prepend + #singleton_methods'
do
o
=
Object
.
new
o
.
singleton_class
.
class_eval
{
prepend
Module
.
new
}
assert_equal
([],
o
.
singleton_methods
)
end
assert
'Module#prepend + #remove_method'
do
c
=
Class
.
new
do
prepend
Module
.
new
{
def
foo
;
end
}
end
assert_raise
(
NameError
)
do
c
.
class_eval
do
remove_method
(
:foo
)
end
end
c
.
class_eval
do
def
foo
;
end
end
removed
=
nil
c
.
singleton_class
.
class_eval
do
define_method
(
:method_removed
)
{
|
id
|
removed
=
id
}
end
assert_nothing_raised
(
NoMethodError
,
NameError
,
'[Bug #7843]'
)
do
c
.
class_eval
do
remove_method
(
:foo
)
end
end
assert_equal
(
:foo
,
removed
)
end
assert
'Module#prepend + Class#ancestors'
do
bug6658
=
'[ruby-core:45919]'
m
=
labeled_module
(
"m"
)
c
=
labeled_class
(
"c"
)
{
prepend
m
}
assert_equal
([
m
,
c
],
c
.
ancestors
[
0
,
2
],
bug6658
)
bug6662
=
'[ruby-dev:45868]'
c2
=
labeled_class
(
"c2"
,
c
)
anc
=
c2
.
ancestors
assert_equal
([
c2
,
m
,
c
,
Object
],
anc
[
0
..
anc
.
index
(
Object
)],
bug6662
)
end
assert
'Module#prepend + Module#ancestors'
do
bug6659
=
'[ruby-dev:45861]'
m0
=
labeled_module
(
"m0"
)
{
def
x
;
[
:m0
,
*
super
]
end
}
m1
=
labeled_module
(
"m1"
)
{
def
x
;
[
:m1
,
*
super
]
end
;
prepend
m0
}
m2
=
labeled_module
(
"m2"
)
{
def
x
;
[
:m2
,
*
super
]
end
;
prepend
m1
}
c0
=
labeled_class
(
"c0"
)
{
def
x
;
[
:c0
]
end
}
c1
=
labeled_class
(
"c1"
)
{
def
x
;
[
:c1
]
end
;
prepend
m2
}
c2
=
labeled_class
(
"c2"
,
c0
)
{
def
x
;
[
:c2
,
*
super
]
end
;
include
m2
}
#
assert_equal
([
m0
,
m1
],
m1
.
ancestors
,
bug6659
)
#
bug6662
=
'[ruby-dev:45868]'
assert_equal
([
m0
,
m1
,
m2
],
m2
.
ancestors
,
bug6662
)
assert_equal
([
m0
,
m1
,
m2
,
c1
],
c1
.
ancestors
[
0
,
4
],
bug6662
)
assert_equal
([
:m0
,
:m1
,
:m2
,
:c1
],
c1
.
new
.
x
)
assert_equal
([
c2
,
m0
,
m1
,
m2
,
c0
],
c2
.
ancestors
[
0
,
5
],
bug6662
)
assert_equal
([
:c2
,
:m0
,
:m1
,
:m2
,
:c0
],
c2
.
new
.
x
)
#
m3
=
labeled_module
(
"m3"
)
{
include
m1
;
prepend
m1
}
assert_equal
([
m3
,
m0
,
m1
],
m3
.
ancestors
)
m3
=
labeled_module
(
"m3"
)
{
prepend
m1
;
include
m1
}
assert_equal
([
m0
,
m1
,
m3
],
m3
.
ancestors
)
m3
=
labeled_module
(
"m3"
)
{
prepend
m1
;
prepend
m1
}
assert_equal
([
m0
,
m1
,
m3
],
m3
.
ancestors
)
m3
=
labeled_module
(
"m3"
)
{
include
m1
;
include
m1
}
assert_equal
([
m3
,
m0
,
m1
],
m3
.
ancestors
)
end
assert
'Module#prepend #instance_methods(false)'
do
bug6660
=
'[ruby-dev:45863]'
assert_equal
([
:m1
],
Class
.
new
{
prepend
Module
.
new
;
def
m1
;
end
}.
instance_methods
(
false
),
bug6660
)
assert_equal
([
:m1
],
Class
.
new
(
Class
.
new
{
def
m2
;
end
}){
prepend
Module
.
new
;
def
m1
;
end
}.
instance_methods
(
false
),
bug6660
)
end
assert
'cyclic Module#prepend'
do
bug7841
=
'[ruby-core:52205] [Bug #7841]'
m1
=
Module
.
new
m2
=
Module
.
new
m1
.
instance_eval
{
prepend
(
m2
)
}
assert_raise
(
ArgumentError
,
bug7841
)
do
m2
.
instance_eval
{
prepend
(
m1
)
}
end
end
# these assertions will not run without a #assert_seperately method
#assert 'test_prepend_optmethod' do
# bug7983 = '[ruby-dev:47124] [Bug #7983]'
# assert_separately [], %{
# module M
# def /(other)
# to_f / other
# end
# end
# Fixnum.send(:prepend, M)
# assert_equal(0.5, 1 / 2, "#{bug7983}")
# }
# assert_equal(0, 1 / 2)
#end
# mruby has no visibility control
assert
'Module#prepend visibility'
do
bug8005
=
'[ruby-core:53106] [Bug #8005]'
c
=
Class
.
new
do
prepend
Module
.
new
{}
def
foo
()
end
protected
:foo
end
a
=
c
.
new
assert_true
a
.
respond_to?
(
:foo
),
bug8005
assert_nothing_raised
(
NoMethodError
,
bug8005
)
{
a
.
send
:foo
}
end
# mruby has no visibility control
assert
'Module#prepend inherited visibility'
do
bug8238
=
'[ruby-core:54105] [Bug #8238]'
module
Test4PrependVisibilityInherited
class
A
def
foo
()
A
;
end
private
:foo
end
class
B
<
A
public
:foo
prepend
Module
.
new
end
end
assert_equal
(
Test4PrependVisibilityInherited
::
A
,
Test4PrependVisibilityInherited
::
B
.
new
.
foo
,
"
#{
bug8238
}
"
)
end
assert
'Module#prepend + #included_modules'
do
bug8025
=
'[ruby-core:53158] [Bug #8025]'
mixin
=
labeled_module
(
"mixin"
)
c
=
labeled_module
(
"c"
)
{
prepend
mixin
}
im
=
c
.
included_modules
assert_not_include
(
im
,
c
,
bug8025
)
assert_include
(
im
,
mixin
,
bug8025
)
c1
=
labeled_class
(
"c1"
)
{
prepend
mixin
}
c2
=
labeled_class
(
"c2"
,
c1
)
im
=
c2
.
included_modules
assert_not_include
(
im
,
c1
,
bug8025
)
assert_not_include
(
im
,
c2
,
bug8025
)
assert_include
(
im
,
mixin
,
bug8025
)
end
assert
'Module#prepend super in alias'
do
skip
"super does not currently work in aliased methods"
bug7842
=
'[Bug #7842]'
p
=
labeled_module
(
"P"
)
do
def
m
;
"P"
+
super
;
end
end
a
=
labeled_class
(
"A"
)
do
def
m
;
"A"
;
end
end
b
=
labeled_class
(
"B"
,
a
)
do
def
m
;
"B"
+
super
;
end
alias
m2
m
prepend
p
alias
m3
m
end
assert_nothing_raised
do
assert_equal
(
"BA"
,
b
.
new
.
m2
,
bug7842
)
end
assert_nothing_raised
do
assert_equal
(
"PBA"
,
b
.
new
.
m3
,
bug7842
)
end
end
assert
'Module#prepend each class'
do
m
=
labeled_module
(
"M"
)
c1
=
labeled_class
(
"C1"
)
{
prepend
m
}
c2
=
labeled_class
(
"C2"
,
c1
)
{
prepend
m
}
assert_equal
([
m
,
c2
,
m
,
c1
],
c2
.
ancestors
[
0
,
4
],
"should be able to prepend each class"
)
end
assert
'Module#prepend no duplication'
do
m
=
labeled_module
(
"M"
)
c
=
labeled_class
(
"C"
)
{
prepend
m
;
prepend
m
}
assert_equal
([
m
,
c
],
c
.
ancestors
[
0
,
2
],
"should never duplicate"
)
end
assert
'Module#prepend in superclass'
do
m
=
labeled_module
(
"M"
)
c1
=
labeled_class
(
"C1"
)
c2
=
labeled_class
(
"C2"
,
c1
)
{
prepend
m
}
c1
.
class_eval
{
prepend
m
}
assert_equal
([
m
,
c2
,
m
,
c1
],
c2
.
ancestors
[
0
,
4
],
"should accesisble prepended module in superclass"
)
end
# requires #assert_seperately
#assert 'Module#prepend call super' do
# assert_separately([], <<-'end;') #do
# bug10847 = '[ruby-core:68093] [Bug #10847]'
# module M; end
# Float.prepend M
# assert_nothing_raised(SystemStackError, bug10847) do
# 0.3.numerator
# end
# end;
#end
# @!endgroup prepend
assert
(
'Module#to_s'
)
do
module
Test4to_sModules
end
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment