1class Base 2 def foo() :base end 3end 4 5class Derived < Base 6 def foo() :derived end 7end 8 9class 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.each_char {|b| Dispatcher[b].bind(self).call } 25 end 26end 27 28assert 'demo' do 29 interpreter = Interpreter.new 30 interpreter.interpret('dave') 31 assert_equal "Hello there, Dave!\n", interpreter.ret 32end 33 34assert '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 71end 72 73assert 'Method and UnboundMethod should not be have a `new` method' do 74 assert_raise(NoMethodError){ Method.new } 75 assert_raise(NoMethodError){ UnboundMethod.new } 76end 77 78assert 'instance' do 79 assert_kind_of Method, 1.method(:+) 80 assert_kind_of UnboundMethod, Fixnum.instance_method(:+) 81end 82 83assert '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 } 101end 102 103assert '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" 106end 107 108assert '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) } 136end 137 138assert '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 154end 155 156assert '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 170end 171 172assert '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 181end 182 183assert '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 192end 193 194assert '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(:+)) 211end 212 213assert '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) 225end 226 227assert '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) 244end 245 246assert '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) 255end 256 257assert '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) 266end 267 268assert '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{}) 286end 287 288assert '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) } 298end 299 300assert "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) } 309end 310 311assert '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) 323end 324 325assert '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 343end 344 345assert '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?)) 362end 363 364assert "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) 372end 373 374assert "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) 391end 392 393assert '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) 404end 405 406assert '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?)) 411end 412 413assert '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) 421end 422 423assert '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) 443end 444