[439] | 1 | class Base
|
---|
| 2 | def foo() :base end
|
---|
| 3 | end
|
---|
| 4 |
|
---|
| 5 | class Derived < Base
|
---|
| 6 | def foo() :derived end
|
---|
| 7 | end
|
---|
| 8 |
|
---|
| 9 | class Interpreter
|
---|
| 10 | attr_accessor :ret
|
---|
| 11 |
|
---|
| 12 | def do_a() @ret += "there, "; end
|
---|
| 13 | def do_d() @ret += "Hello "; end
|
---|
| 14 | def do_e() @ret += "!\n"; end
|
---|
| 15 | def do_v() @ret += "Dave"; end
|
---|
| 16 | Dispatcher = {
|
---|
| 17 | "a" => instance_method(:do_a),
|
---|
| 18 | "d" => instance_method(:do_d),
|
---|
| 19 | "e" => instance_method(:do_e),
|
---|
| 20 | "v" => instance_method(:do_v)
|
---|
| 21 | }
|
---|
| 22 | def interpret(string)
|
---|
| 23 | @ret = ""
|
---|
| 24 | string.split("").each {|b| Dispatcher[b].bind(self).call }
|
---|
| 25 | end
|
---|
| 26 | end
|
---|
| 27 |
|
---|
| 28 | assert 'demo' do
|
---|
| 29 | interpreter = Interpreter.new
|
---|
| 30 | interpreter.interpret('dave')
|
---|
| 31 | assert_equal "Hello there, Dave!\n", interpreter.ret
|
---|
| 32 | end
|
---|
| 33 |
|
---|
| 34 | assert 'Method#arity' do
|
---|
| 35 | Class.new {
|
---|
| 36 | attr_accessor :done
|
---|
| 37 | def initialize; @done = false; end
|
---|
| 38 | def m0() end
|
---|
| 39 | def m1(a) end
|
---|
| 40 | def m2(a, b) end
|
---|
| 41 | def mo1(a = nil, &b) end
|
---|
| 42 | def mo2(a, b = nil) end
|
---|
| 43 | def mo3(*a) end
|
---|
| 44 | def mo4(a, *b, &c) end
|
---|
| 45 | def mo5(a, *b, c) end
|
---|
| 46 | def mo6(a, *b, c, &d) end
|
---|
| 47 | def mo7(a, b = nil, *c, d, &e) end
|
---|
| 48 | def ma1((a), &b) nil && a end
|
---|
| 49 |
|
---|
| 50 | def run
|
---|
| 51 | assert_equal(0, method(:m0).arity)
|
---|
| 52 | assert_equal(1, method(:m1).arity)
|
---|
| 53 | assert_equal(2, method(:m2).arity)
|
---|
| 54 | assert_equal(-1, method(:mo1).arity)
|
---|
| 55 | assert_equal(-2, method(:mo2).arity)
|
---|
| 56 | assert_equal(-1, method(:mo3).arity)
|
---|
| 57 | assert_equal(-2, method(:mo4).arity)
|
---|
| 58 | assert_equal(-3, method(:mo5).arity)
|
---|
| 59 | assert_equal(-3, method(:mo6).arity)
|
---|
| 60 | assert_equal(-3, method(:mo7).arity)
|
---|
| 61 | assert_equal(1, method(:ma1).arity)
|
---|
| 62 |
|
---|
| 63 | assert_equal(-1, method(:__send__).arity)
|
---|
| 64 | assert_equal(-1, method(:nothing).arity)
|
---|
| 65 | end
|
---|
| 66 |
|
---|
| 67 | def respond_to_missing?(m, b)
|
---|
| 68 | m == :nothing
|
---|
| 69 | end
|
---|
| 70 | }.new.run
|
---|
| 71 | end
|
---|
| 72 |
|
---|
| 73 | assert 'Method and UnboundMethod should not be have a `new` method' do
|
---|
| 74 | assert_raise(NoMethodError){ Method.new }
|
---|
| 75 | assert_raise(NoMethodError){ UnboundMethod.new }
|
---|
| 76 | end
|
---|
| 77 |
|
---|
| 78 | assert 'instance' do
|
---|
| 79 | assert_kind_of Method, 1.method(:+)
|
---|
| 80 | assert_kind_of UnboundMethod, Fixnum.instance_method(:+)
|
---|
| 81 | end
|
---|
| 82 |
|
---|
| 83 | assert 'Method#call' do
|
---|
| 84 | assert_equal 3, 1.method(:+).call(2)
|
---|
| 85 | assert_equal "ab", "a".method(:+)["b"]
|
---|
| 86 | klass = Class.new {
|
---|
| 87 | def foo; 42; end
|
---|
| 88 | }
|
---|
| 89 | klass2 = Class.new(klass) {
|
---|
| 90 | def foo; super; end
|
---|
| 91 | }
|
---|
| 92 | assert_equal 42, klass2.new.method(:foo).call
|
---|
| 93 |
|
---|
| 94 | i = Class.new {
|
---|
| 95 | def bar
|
---|
| 96 | yield 3
|
---|
| 97 | end
|
---|
| 98 | }.new
|
---|
| 99 | assert_raise(LocalJumpError) { i.method(:bar).call }
|
---|
| 100 | assert_equal 3, i.method(:bar).call { |i| i }
|
---|
| 101 | end
|
---|
| 102 |
|
---|
| 103 | assert 'Method#call for regression' do
|
---|
| 104 | obj = BasicObject.new
|
---|
| 105 | assert_equal String, Kernel.instance_method(:inspect).bind(obj).call().class, "https://github.com/ksss/mruby-method/issues/4"
|
---|
| 106 | end
|
---|
| 107 |
|
---|
| 108 | assert 'Method#call with undefined method' do
|
---|
| 109 | c = Class.new {
|
---|
| 110 | attr_accessor :m, :argv
|
---|
| 111 | def respond_to_missing?(m, b)
|
---|
| 112 | m == :foo
|
---|
| 113 | end
|
---|
| 114 |
|
---|
| 115 | def method_missing(m, *argv)
|
---|
| 116 | @m = m
|
---|
| 117 | @argv = argv
|
---|
| 118 | super
|
---|
| 119 | end
|
---|
| 120 | }
|
---|
| 121 | cc = c.new
|
---|
| 122 | assert_raise(NameError) { cc.method(:nothing) }
|
---|
| 123 | assert_kind_of Method, cc.method(:foo)
|
---|
| 124 | assert_raise(NoMethodError) { cc.method(:foo).call(:arg1, :arg2) }
|
---|
| 125 | assert_equal :foo, cc.m
|
---|
| 126 | assert_equal [:arg1, :arg2], cc.argv
|
---|
| 127 |
|
---|
| 128 | cc = c.new
|
---|
| 129 | m = cc.method(:foo)
|
---|
| 130 | c.class_eval do
|
---|
| 131 | def foo
|
---|
| 132 | :ng
|
---|
| 133 | end
|
---|
| 134 | end
|
---|
| 135 | assert_raise(NoMethodError) { m.call(:arg1, :arg2) }
|
---|
| 136 | end
|
---|
| 137 |
|
---|
| 138 | assert 'Method#source_location' do
|
---|
| 139 | skip if proc{}.source_location.nil?
|
---|
| 140 |
|
---|
| 141 | filename = __FILE__
|
---|
| 142 | klass = Class.new
|
---|
| 143 |
|
---|
| 144 | lineno = __LINE__ + 1
|
---|
| 145 | klass.define_method(:find_me_if_you_can) {}
|
---|
| 146 | assert_equal [filename, lineno], klass.new.method(:find_me_if_you_can).source_location
|
---|
| 147 |
|
---|
| 148 | lineno = __LINE__ + 1
|
---|
| 149 | class <<klass; define_method(:s_find_me_if_you_can) {}; end
|
---|
| 150 | assert_equal [filename, lineno], klass.method(:s_find_me_if_you_can).source_location
|
---|
| 151 |
|
---|
| 152 | klass = Class.new { def respond_to_missing?(m, b); m == :nothing; end }
|
---|
| 153 | assert_nil klass.new.method(:nothing).source_location
|
---|
| 154 | end
|
---|
| 155 |
|
---|
| 156 | assert 'UnboundMethod#source_location' do
|
---|
| 157 | skip if proc{}.source_location.nil?
|
---|
| 158 |
|
---|
| 159 | filename = __FILE__
|
---|
| 160 | klass = Class.new {
|
---|
| 161 | def respond_to_missing?(m, b)
|
---|
| 162 | m == :nothing
|
---|
| 163 | end
|
---|
| 164 | }
|
---|
| 165 |
|
---|
| 166 | lineno = __LINE__ + 1
|
---|
| 167 | klass.define_method(:find_me_if_you_can) {}
|
---|
| 168 | assert_equal [filename, lineno], klass.instance_method(:find_me_if_you_can).source_location
|
---|
| 169 | assert_nil klass.new.method(:nothing).unbind.source_location
|
---|
| 170 | end
|
---|
| 171 |
|
---|
| 172 | assert 'Method#parameters' do
|
---|
| 173 | klass = Class.new {
|
---|
| 174 | def foo(a, b=nil, *c) end
|
---|
| 175 | def respond_to_missing?(m, b)
|
---|
| 176 | m == :missing
|
---|
| 177 | end
|
---|
| 178 | }
|
---|
| 179 | assert_equal [[:req, :a], [:opt, :b], [:rest, :c]], klass.new.method(:foo).parameters
|
---|
| 180 | assert_equal [[:rest]], klass.new.method(:missing).parameters
|
---|
| 181 | end
|
---|
| 182 |
|
---|
| 183 | assert 'UnboundMethod#parameters' do
|
---|
| 184 | klass = Class.new {
|
---|
| 185 | def foo(a, b=nil, *c) end
|
---|
| 186 | def respond_to_missing?(m, b)
|
---|
| 187 | m == :nothing
|
---|
| 188 | end
|
---|
| 189 | }
|
---|
| 190 | assert_equal [[:req, :a], [:opt, :b], [:rest, :c]], klass.instance_method(:foo).parameters
|
---|
| 191 | assert_equal [[:rest]], klass.new.method(:nothing).unbind.parameters
|
---|
| 192 | end
|
---|
| 193 |
|
---|
| 194 | assert 'Method#to_proc' do
|
---|
| 195 | m = 3.method(:+)
|
---|
| 196 | assert_kind_of Proc, m.to_proc
|
---|
| 197 | assert_equal 7, m.call(4)
|
---|
| 198 |
|
---|
| 199 | o = Object.new
|
---|
| 200 | def o.foo(a, b=nil, *c)
|
---|
| 201 | [a, b, c]
|
---|
| 202 | end
|
---|
| 203 | assert_equal [:bar, nil, []], o.method(:foo).to_proc.call(:bar)
|
---|
| 204 | # We can fix this issue but leave until the problem
|
---|
| 205 | # assert_equal o.method(:foo).arity, o.method(:foo).to_proc.arity
|
---|
| 206 |
|
---|
| 207 | def o.bar
|
---|
| 208 | yield 39
|
---|
| 209 | end
|
---|
| 210 | assert_equal 42, o.bar(&3.method(:+))
|
---|
| 211 | end
|
---|
| 212 |
|
---|
| 213 | assert 'to_s' do
|
---|
| 214 | o = Object.new
|
---|
| 215 | def o.foo; end
|
---|
| 216 | m = o.method(:foo)
|
---|
| 217 | assert_equal("#<UnboundMethod: #{ class << o; self; end.inspect }#foo>", m.unbind.inspect)
|
---|
| 218 |
|
---|
| 219 | c = Class.new
|
---|
| 220 | c.class_eval { def foo; end; }
|
---|
| 221 | m = c.new.method(:foo)
|
---|
| 222 | assert_equal("#<Method: #{ c.inspect }#foo>", m.inspect)
|
---|
| 223 | m = c.instance_method(:foo)
|
---|
| 224 | assert_equal("#<UnboundMethod: #{ c.inspect }#foo>", m.inspect)
|
---|
| 225 | end
|
---|
| 226 |
|
---|
| 227 | assert 'owner' do
|
---|
| 228 | c = Class.new do
|
---|
| 229 | def foo; end
|
---|
| 230 | def self.bar; end
|
---|
| 231 | end
|
---|
| 232 | m = Module.new do
|
---|
| 233 | def baz; end
|
---|
| 234 | end
|
---|
| 235 | c.include(m)
|
---|
| 236 | c2 = Class.new(c)
|
---|
| 237 |
|
---|
| 238 | assert_equal(c, c.instance_method(:foo).owner)
|
---|
| 239 | assert_equal(c, c2.instance_method(:foo).owner)
|
---|
| 240 |
|
---|
| 241 | assert_equal(c, c.new.method(:foo).owner)
|
---|
| 242 | assert_equal(c, c2.new.method(:foo).owner)
|
---|
| 243 | assert_equal((class <<c; self; end), c2.method(:bar).owner)
|
---|
| 244 | end
|
---|
| 245 |
|
---|
| 246 | assert 'owner missing' do
|
---|
| 247 | c = Class.new do
|
---|
| 248 | def respond_to_missing?(name, bool)
|
---|
| 249 | name == :foo
|
---|
| 250 | end
|
---|
| 251 | end
|
---|
| 252 | c2 = Class.new(c)
|
---|
| 253 | assert_equal(c, c.new.method(:foo).owner)
|
---|
| 254 | assert_equal(c2, c2.new.method(:foo).owner)
|
---|
| 255 | end
|
---|
| 256 |
|
---|
| 257 | assert 'receiver name owner' do
|
---|
| 258 | o = Object.new
|
---|
| 259 | def o.foo; end
|
---|
| 260 | m = o.method(:foo)
|
---|
| 261 | assert_equal(o, m.receiver)
|
---|
| 262 | assert_equal(:foo, m.name)
|
---|
| 263 | assert_equal(class << o; self; end, m.owner)
|
---|
| 264 | assert_equal(:foo, m.unbind.name)
|
---|
| 265 | assert_equal(class << o; self; end, m.unbind.owner)
|
---|
| 266 | end
|
---|
| 267 |
|
---|
| 268 | assert 'Method#unbind' do
|
---|
| 269 | assert_equal(:derived, Derived.new.foo)
|
---|
| 270 | um = Derived.new.method(:foo).unbind
|
---|
| 271 | assert_kind_of(UnboundMethod, um)
|
---|
| 272 | Derived.class_eval do
|
---|
| 273 | def foo() :changed end
|
---|
| 274 | end
|
---|
| 275 | assert_equal(:changed, Derived.new.foo)
|
---|
| 276 | assert_equal(:changed, Derived.new.foo{})
|
---|
| 277 | assert_equal(:derived, um.bind(Derived.new).call)
|
---|
| 278 | assert_raise(TypeError) do
|
---|
| 279 | um.bind(Base.new)
|
---|
| 280 | end
|
---|
| 281 |
|
---|
| 282 | # TODO:
|
---|
| 283 | # Block passed method not handled correctly with workaround.
|
---|
| 284 | # See comment near `mrb_funcall_with_block` for detail.
|
---|
| 285 | # assert_equal(:derived, um.bind(Derived.new).call{})
|
---|
| 286 | end
|
---|
| 287 |
|
---|
| 288 | assert 'Kernel#method' do
|
---|
| 289 | c1 = Class.new {
|
---|
| 290 | def foo; :foo; end
|
---|
| 291 | }
|
---|
| 292 | o = c1.new
|
---|
| 293 | assert_kind_of Method, o.method(:foo)
|
---|
| 294 | assert_kind_of Method, o.method('foo')
|
---|
| 295 | assert_raise(TypeError) { o.method(nil) }
|
---|
| 296 | assert_raise(NameError) { o.method('bar') }
|
---|
| 297 | assert_raise(NameError) { o.method(:bar) }
|
---|
| 298 | end
|
---|
| 299 |
|
---|
| 300 | assert "Module#instance_method" do
|
---|
| 301 | assert_kind_of UnboundMethod, Object.instance_method(:object_id)
|
---|
| 302 | assert_raise(NameError) { Object.instance_method(:nothing) }
|
---|
| 303 | c = Class.new {
|
---|
| 304 | def respond_to_missing?(m, b)
|
---|
| 305 | false
|
---|
| 306 | end
|
---|
| 307 | }
|
---|
| 308 | assert_raise(NameError) { c.instance_method(:nothing) }
|
---|
| 309 | end
|
---|
| 310 |
|
---|
| 311 | assert 'Kernel#singleton_method' do
|
---|
| 312 | c1 = Class.new {
|
---|
| 313 | def foo; :foo; end
|
---|
| 314 | }
|
---|
| 315 | o = c1.new
|
---|
| 316 | def o.bar; :bar; end
|
---|
| 317 | assert_kind_of Method, o.method(:foo)
|
---|
| 318 | assert_raise(NameError) { o.singleton_method(:foo) }
|
---|
| 319 | assert_kind_of Method, o.singleton_method(:bar)
|
---|
| 320 | assert_raise(TypeError) { o.singleton_method(nil) }
|
---|
| 321 | m = assert_nothing_raised(NameError) { break o.singleton_method(:bar) }
|
---|
| 322 | assert_equal(:bar, m.call)
|
---|
| 323 | end
|
---|
| 324 |
|
---|
| 325 | assert 'Method#super_method' do
|
---|
| 326 | o = Derived.new
|
---|
| 327 | m = o.method(:foo).super_method
|
---|
| 328 | assert_equal(Base, m.owner)
|
---|
| 329 | assert_true(o.equal? m.receiver)
|
---|
| 330 | assert_equal(:foo, m.name)
|
---|
| 331 | assert_nil(m.super_method)
|
---|
| 332 |
|
---|
| 333 | c = Class.new {
|
---|
| 334 | def foo; end
|
---|
| 335 | }
|
---|
| 336 | o = c.new
|
---|
| 337 | o.extend Module.new {
|
---|
| 338 | def foo; end
|
---|
| 339 | }
|
---|
| 340 | assert_equal c, o.method(:foo).super_method.owner
|
---|
| 341 | assert_equal :foo, o.method(:foo).super_method.name
|
---|
| 342 | assert_equal o, o.method(:foo).super_method.receiver
|
---|
| 343 | end
|
---|
| 344 |
|
---|
| 345 | assert 'Method#==' do
|
---|
| 346 | o = Object.new
|
---|
| 347 | class << o
|
---|
| 348 | def foo; end
|
---|
| 349 | end
|
---|
| 350 | assert_not_equal(o.method(:foo), nil)
|
---|
| 351 | m = o.method(:foo)
|
---|
| 352 | def m.foo; end
|
---|
| 353 | # TODO: assert_not_equal(o.method(:foo), m)
|
---|
| 354 | assert_equal(o.method(:foo), o.method(:foo))
|
---|
| 355 | # TODO: assert_false(o.method(:foo).eql? m)
|
---|
| 356 | assert_true(o.method(:foo).eql? o.method(:foo))
|
---|
| 357 |
|
---|
| 358 | assert_false(0.method(:+) == 1.method(:+))
|
---|
| 359 | assert_false(0.method(:+) == 0.method(:-))
|
---|
| 360 | a = 0.method(:+)
|
---|
| 361 | assert_true(a.method(:==) == a.method(:eql?))
|
---|
| 362 | end
|
---|
| 363 |
|
---|
| 364 | assert "Method#initialize_copy" do
|
---|
| 365 | c = Class.new {
|
---|
| 366 | def foo
|
---|
| 367 | end
|
---|
| 368 | }.new
|
---|
| 369 | m1 = c.method(:foo)
|
---|
| 370 | m2 = m1.clone
|
---|
| 371 | assert_equal(m1, m2)
|
---|
| 372 | end
|
---|
| 373 |
|
---|
| 374 | assert "Method#<< and Method#>>" do
|
---|
| 375 | obj = Object.new
|
---|
| 376 | class << obj
|
---|
| 377 | def mul2(n); n * 2; end
|
---|
| 378 | def add3(n); n + 3; end
|
---|
| 379 | end
|
---|
| 380 |
|
---|
| 381 | f = obj.method(:mul2)
|
---|
| 382 | g = obj.method(:add3)
|
---|
| 383 |
|
---|
| 384 | m1 = f << g
|
---|
| 385 | assert_kind_of Proc, m1
|
---|
| 386 | assert_equal 16, m1.call(5)
|
---|
| 387 |
|
---|
| 388 | m2 = f >> g
|
---|
| 389 | assert_kind_of Proc, m2
|
---|
| 390 | assert_equal 13, m2.call(5)
|
---|
| 391 | end
|
---|
| 392 |
|
---|
| 393 | assert 'UnboundMethod#arity' do
|
---|
| 394 | c = Class.new {
|
---|
| 395 | def foo(a, b)
|
---|
| 396 | end
|
---|
| 397 |
|
---|
| 398 | def respond_to_missing?(m, b)
|
---|
| 399 | m == :nothing
|
---|
| 400 | end
|
---|
| 401 | }
|
---|
| 402 | assert_equal 2, c.instance_method(:foo).arity
|
---|
| 403 | assert_equal(-1, c.new.method(:nothing).unbind.arity)
|
---|
| 404 | end
|
---|
| 405 |
|
---|
| 406 | assert 'UnboundMethod#==' do
|
---|
| 407 | assert_false(Fixnum.instance_method(:+) == Fixnum.instance_method(:-))
|
---|
| 408 | assert_true(Fixnum.instance_method(:+) == Fixnum.instance_method(:+))
|
---|
| 409 | assert_false(Fixnum.instance_method(:+) == Float.instance_method(:+))
|
---|
| 410 | assert_true(UnboundMethod.instance_method(:==) == UnboundMethod.instance_method(:eql?))
|
---|
| 411 | end
|
---|
| 412 |
|
---|
| 413 | assert 'UnboundMethod#super_method' do
|
---|
| 414 | m = Derived.instance_method(:foo)
|
---|
| 415 | m = m.super_method
|
---|
| 416 | assert_equal(Base.instance_method(:foo), m)
|
---|
| 417 | assert_nil(m.super_method)
|
---|
| 418 |
|
---|
| 419 | m = Object.instance_method(:object_id)
|
---|
| 420 | assert_nil(m.super_method)
|
---|
| 421 | end
|
---|
| 422 |
|
---|
| 423 | assert 'UnboundMethod#bind' do
|
---|
| 424 | m = Module.new{ def meth() :meth end }.instance_method(:meth)
|
---|
| 425 | assert_raise(ArgumentError) { m.bind }
|
---|
| 426 | assert_kind_of Method, m.bind(1)
|
---|
| 427 | assert_kind_of Method, m.bind(:sym)
|
---|
| 428 | assert_kind_of Method, m.bind(Object.new)
|
---|
| 429 | assert_equal(:meth, m.bind(1).call)
|
---|
| 430 | assert_equal(:meth, m.bind(:sym).call)
|
---|
| 431 | assert_equal(:meth, m.bind(Object.new).call)
|
---|
| 432 | sc = nil
|
---|
| 433 | Class.new {
|
---|
| 434 | sc = class << self
|
---|
| 435 | def foo
|
---|
| 436 | end
|
---|
| 437 | self
|
---|
| 438 | end
|
---|
| 439 | }
|
---|
| 440 | assert_raise(TypeError) { sc.instance_method(:foo).bind([]) }
|
---|
| 441 | assert_raise(TypeError) { Array.instance_method(:each).bind(1) }
|
---|
| 442 | assert_kind_of Method, Object.instance_method(:object_id).bind(Object.new)
|
---|
| 443 | end
|
---|
| 444 |
|
---|
| 445 | assert 'UnboundMethod#bind_call' do
|
---|
| 446 | m = Array.instance_method(:size)
|
---|
| 447 | assert_equal(:size, m.name)
|
---|
| 448 | assert_equal(0, m.bind_call([]))
|
---|
| 449 | assert_equal(1, m.bind_call([1]))
|
---|
| 450 | assert_equal(2, m.bind_call([1,2]))
|
---|
| 451 | end
|
---|