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.
parent 75a01af7
MRuby::GemBox.new do |conf|
# Meta-programming features
conf.gem :core => "mruby-metaprog"
# Use standard IO/File class
conf.gem :core => "mruby-io"
......
......@@ -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
......@@ -26,7 +26,7 @@ end
assert 'Module#singleton_class?' do
mod = Module.new
cls = Class.new
scl = cls.singleton_class
scl = (class <<cls; self; end)
assert_false mod.singleton_class?
assert_false cls.singleton_class?
......
......@@ -58,7 +58,7 @@ end
assert('String instance_eval') do
obj = Object.new
obj.instance_variable_set :@test, 'test'
obj.instance_eval{ @test = 'test' }
assert_raise(ArgumentError) { obj.instance_eval(0) { } }
assert_raise(ArgumentError) { obj.instance_eval('0', 'test', 0, 'test') }
assert_equal(['test.rb', 10]) { obj.instance_eval('[__FILE__, __LINE__]', 'test.rb', 10)}
......
......@@ -35,7 +35,7 @@ assert('IO', '15.2.20.2') do
end
assert('IO', '15.2.20.3') do
assert_include(IO.included_modules, Enumerable)
assert_include(IO.ancestors, Enumerable)
end
assert('IO.open', '15.2.20.4.1') do
......
MRuby::Gem::Specification.new('mruby-metaprog') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.summary = 'Meta-programming features for mruby'
end
This diff is collapsed.
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 <<self; self end).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
(class <<self; self end).class_eval do
define_method(:to_s) { name }
alias_method :inspect, :to_s
end
class_eval(&block) if block
end
end
assert('Module#class_variable_defined?', '15.2.2.4.16') do
class Test4ClassVariableDefined
@@cv = 99
end
assert_true Test4ClassVariableDefined.class_variable_defined?(:@@cv)
assert_false Test4ClassVariableDefined.class_variable_defined?(:@@noexisting)
end
assert('Module#class_variable_get', '15.2.2.4.17') do
class Test4ClassVariableGet
@@cv = 99
end
assert_equal 99, Test4ClassVariableGet.class_variable_get(:@@cv)
end
assert('Module#class_variable_set', '15.2.2.4.18') do
class Test4ClassVariableSet
@@foo = 100
def foo
@@foo
end
end
assert_true Test4ClassVariableSet.class_variable_set(:@@cv, 99)
assert_true Test4ClassVariableSet.class_variable_set(:@@foo, 101)
assert_true Test4ClassVariableSet.class_variables.include? :@@cv
assert_equal 99, Test4ClassVariableSet.class_variable_get(:@@cv)
assert_equal 101, Test4ClassVariableSet.new.foo
end
assert('Module#class_variables', '15.2.2.4.19') do
class Test4ClassVariables1
@@var1 = 1
end
class Test4ClassVariables2 < Test4ClassVariables1
@@var2 = 2
end
assert_equal [:@@var1], Test4ClassVariables1.class_variables
assert_equal [:@@var2, :@@var1], Test4ClassVariables2.class_variables
end
assert('Module#constants', '15.2.2.4.24') do
$n = []
module TestA
C = 1
end
class TestB
include TestA
C2 = 1
$n = constants.sort
end
assert_equal [ :C ], TestA.constants
assert_equal [ :C, :C2 ], $n
end
assert('Module#included_modules', '15.2.2.4.30') do
module Test4includedModules
end
module Test4includedModules2
include Test4includedModules
end
r = Test4includedModules2.included_modules
assert_equal Array, r.class
assert_true r.include?(Test4includedModules)
end
assert('Module#instance_methods', '15.2.2.4.33') do
module Test4InstanceMethodsA
def method1() end
end
class Test4InstanceMethodsB
def method2() end
end
class Test4InstanceMethodsC < Test4InstanceMethodsB
def method3() end
end
r = Test4InstanceMethodsC.instance_methods(true)
assert_equal [:method1], Test4InstanceMethodsA.instance_methods
assert_equal [:method2], Test4InstanceMethodsB.instance_methods(false)
assert_equal [:method3], Test4InstanceMethodsC.instance_methods(false)
assert_equal Array, r.class
assert_true r.include?(:method3)
assert_true r.include?(:method2)
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('Module#remove_class_variable', '15.2.2.4.39') do
class Test4RemoveClassVariable
@@cv = 99
end
assert_equal 99, Test4RemoveClassVariable.remove_class_variable(:@@cv)
assert_false Test4RemoveClassVariable.class_variables.include? :@@cv
end
assert('Module#remove_method', '15.2.2.4.41') do
module Test4RemoveMethod
class Parent
def hello
end
end
class Child < Parent
def hello
end
end
end
assert_true Test4RemoveMethod::Child.class_eval{ remove_method :hello }
assert_true Test4RemoveMethod::Child.instance_methods.include? :hello
assert_false Test4RemoveMethod::Child.instance_methods(false).include? :hello
end
assert('Module.nesting', '15.2.2.2.2') do
module Test4ModuleNesting
module Test4ModuleNesting2
assert_equal [Test4ModuleNesting2, Test4ModuleNesting],
Module.nesting
end
end
module Test4ModuleNesting::Test4ModuleNesting2
assert_equal [Test4ModuleNesting::Test4ModuleNesting2], Module.nesting
end
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('[Bug #7843]') do
c.class_eval do
remove_method(:foo)
end
end
assert_equal(:foo, removed)
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("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
assert('alias_method and remove_method') 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
module Kernel
def singleton_method(name)
m = method(name)
if m.owner != singleton_class
raise NameError, "undefined method `#{name}' for class `#{singleton_class}'"
sc = (class <<self; self; end)
if m.owner != sc
raise NameError, "undefined method `#{name}' for class `#{sc}'"
end
m
end
......
......@@ -149,7 +149,7 @@ assert 'Method#source_location' do
assert_equal [filename, lineno], klass.new.method(:find_me_if_you_can).source_location
lineno = __LINE__ + 1
klass.define_singleton_method(:s_find_me_if_you_can) {}
class <<klass; define_method(:s_find_me_if_you_can) {}; end
assert_equal [filename, lineno], klass.method(:s_find_me_if_you_can).source_location
klass = Class.new { def respond_to_missing?(m, b); m == :nothing; end }
......@@ -243,7 +243,7 @@ assert 'owner' do
assert_equal(c, c.new.method(:foo).owner)
assert_equal(c, c2.new.method(:foo).owner)
assert_equal(c.singleton_class, c2.method(:bar).owner)
assert_equal((class <<c; self; end), c2.method(:bar).owner)
end
assert 'owner missing' do
......@@ -413,12 +413,14 @@ assert 'UnboundMethod#bind' do
assert_equal(:meth, m.bind(1).call)
assert_equal(:meth, m.bind(:sym).call)
assert_equal(:meth, m.bind(Object.new).call)
sc = Class.new {
class << self
sc = nil
Class.new {
sc = class << self
def foo
end
self
end
}.singleton_class
}
assert_raise(TypeError) { sc.instance_method(:foo).bind([]) }
assert_raise(TypeError) { Array.instance_method(:each).bind(1) }
assert_kind_of Method, Object.instance_method(:object_id).bind(Object.new)
......
......@@ -16,8 +16,8 @@ assert('Toplevel#include') do
self.include ToplevelTestModule2, ToplevelTestModule1
assert_true self.class.included_modules.include?( ToplevelTestModule1 )
assert_true self.class.included_modules.include?( ToplevelTestModule2 )
assert_true self.class.ancestors.include?( ToplevelTestModule1 )
assert_true self.class.ancestors.include?( ToplevelTestModule2 )
assert_equal :foo, method_foo
assert_equal :bar2, CONST_BAR
end
......
This diff is collapsed.
......@@ -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:
......
This diff is collapsed.
......@@ -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
......@@ -194,4 +194,4 @@ assert('register window of calls (#3783)') do
alias send2 send
end
end
end
\ No newline at end of file
end
......@@ -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
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment