Class: Module

Inherits:
Object show all
Defined in:
lib/internal/module/as_code.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.load(String) ⇒ Module

Load a module from a string.

Returns:



737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
# File 'ext/internal/module/module.c', line 737

static VALUE module_load(VALUE klass, VALUE str)
{
  VALUE arr, class_name, metaclass_str, metaclass, superclass_name,
        included_modules, class_variables_str, class_variables,
        instance_methods_str, instance_methods, flags, module;

  if(   rb_safe_level() >= 4
     || (rb_safe_level() >= 1 && OBJ_TAINTED(str)))
  {
    /* no playing with knives in the sandbox */
    rb_raise(rb_eSecurityError, "Insecure: can't load module");
  }

  arr = marshal_load(str);
  class_name = rb_ary_pop(arr);
  metaclass_str = rb_ary_pop(arr);
  superclass_name = rb_ary_pop(arr);
  included_modules = rb_ary_pop(arr);
  class_variables_str = rb_ary_pop(arr);
  instance_methods_str = rb_ary_pop(arr);
  flags = rb_ary_pop(arr);

  if(RTEST(superclass_name))
  {
    VALUE superclass;
    rb_check_type(superclass_name, T_STRING);
    superclass = rb_funcall(
        lookup_module_proc,
        rb_intern("call"),
        1,
        superclass_name);
#if RUBY_VERSION_CODE >= 180
    /* Can't make subclass of Class on 1.8.x */
    module = rb_class_boot(superclass);
    rb_define_alloc_func(module, module_instance_allocate);
#else
    module = rb_class_new(superclass);
#endif
  }
  else
  {
    module = rb_module_new();
  }

  if(!NIL_P(class_name))
  {
    VALUE outer_module = rb_funcall(outer_module_proc, rb_intern("call"), 1, class_name);
    VALUE module_name = rb_funcall(module_name_proc, rb_intern("call"), 1, class_name);
    rb_const_set(outer_module, SYM2ID(module_name), module);
  }

  RBASIC(module)->flags = NUM2INT(flags);
  include_modules(module, included_modules);
  class_variables = marshal_load(class_variables_str);
  add_class_variables(module, class_variables);
  instance_methods = marshal_load(instance_methods_str);
  add_methods(module, instance_methods);

  metaclass = marshal_load(metaclass_str);
  if(RTEST(metaclass))
  {
    rb_singleton_class_attached(metaclass, module);
    RBASIC(module)->klass = metaclass;
  }

  return module;
}

Instance Method Details

#dump(limit) ⇒ String

Dump a module to a string. The module will be dumped along with its instance methods, class variables, names of included modules, name of superclass, its entire metaclass, and the name of the class.

Note that on ruby 1.8 and newer the module is temporarily modified while dumping in order to allow singleton classes to be dumped. To prevent access to the modifed module, Thread.critical is temporarily set, then restored to its original value once dumping is complete. Note also that because YARV does not support Thread.critical, the user must synchronize access to the class with a Mutex in order to prevent accessing the modified class.

Returns:

  • (String)


608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# File 'ext/internal/module/module.c', line 608

static VALUE module_dump(VALUE self, VALUE limit)
{
  VALUE flags, instance_methods, class_variables;
  VALUE included_modules, superclass, metaclass, arr, str, class_name;

  limit = INT2NUM(NUM2INT(limit) - 1);

  if(rb_safe_level() >= 4)
  {
    /* no access to potentially sensitive data from the sandbox */
    rb_raise(rb_eSecurityError, "Insecure: can't dump module");
  }

  flags = INT2NUM(RBASIC(self)->flags);
  instance_methods = instance_method_hash(self);
  class_variables = class_variable_hash(self);
  included_modules = included_modules_list(self);
  superclass = superclass_name(self);
  arr = rb_ary_new();

  if(FL_TEST(self, FL_SINGLETON))
  {
    metaclass = Qnil;
    class_name = Qnil;
  }
  else
  {
    metaclass = rb_singleton_class(self);
    class_name = rb_class_path(self);
  }

  rb_ary_push(arr, flags);
  rb_ary_push(arr, marshal_dump(instance_methods, limit));
  rb_ary_push(arr, marshal_dump(class_variables, limit));
  rb_ary_push(arr, included_modules);
  rb_ary_push(arr, superclass);
  rb_ary_push(arr, marshal_dump(metaclass, limit));
  rb_ary_push(arr, class_name);

  str = marshal_dump(arr, limit);

#if RUBY_VERSION_CODE > 180
  {
    VALUE class_restorer = create_class_restorer(self);
    rb_iv_set(str, "__class_restorer__", class_restorer);
    set_class_restore_state(self);
  }
#endif

  return str;
}

#add_method(id, node) ⇒ Object

Adds the method as an instance method to the given class.

To add a singleton method to a class, add the method to its singleton class.



406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
# File 'ext/internal/module/module.c', line 406

static VALUE module_add_method(VALUE klass, VALUE id, VALUE node, VALUE noex)
{
  NODE * n = 0;

  if(rb_safe_level() >= 2)
  {
    /* adding a method with the wrong node type can cause a crash */
    rb_raise(rb_eSecurityError, "Insecure: can't add method");
  }

#if RUBY_VERSION_CODE >= 192
  if(rb_obj_is_kind_of(node, rb_cISeq))
  {
    rb_iseq_t *iseqdat = iseq_check(node);
    set_cref_stack(iseqdat, klass, noex);
    iseqdat->klass = klass;
    iseqdat->defined_method_id = SYM2ID(id);

#ifdef HAVE_RB_ADD_METHOD
    rb_add_method(klass, SYM2ID(id), VM_METHOD_TYPE_ISEQ, iseqdat, NUM2INT(noex));
#else
    rb_funcall(rb_mRubyVMFrozenCore, rb_intern("core#define_method"), 3, klass, id, node); /* TODO: noex */
#endif

    return Qnil;
  }

#elif RUBY_VERSION_CODE >= 190
  if(rb_obj_is_kind_of(node, rb_cISeq))
  {
    rb_iseq_t *iseqdat = iseq_check(node);
    /* TODO: any restrictions on what kinds of iseqs we can add here? */
    set_cref_stack(iseqdat, klass, noex);
    iseqdat->klass = klass;
    iseqdat->defined_method_id = SYM2ID(id);
    n = NEW_METHOD(iseqdat->self, klass, NUM2INT(noex));
    goto add_node;
  }
#endif

  if(!rb_obj_is_kind_of(node, rb_cNode))
  {
    rb_raise(
        rb_eTypeError,
        "Expected Node for 2nd parameter, got %s",
        rb_class2name(CLASS_OF(n)));
  }

  Data_Get_Struct(node, NODE, n);

#if RUBY_VERSION_CODE >= 192
  rb_raise(rb_eRuntimeError, "Unable to add node on this version of ruby");
#elif RUBY_VERSION_CODE >= 190
  if(nd_type(n) != NODE_METHOD)
  {
    rb_raise(
        rb_eTypeError,
        "Expected METHOD node, got %s",
        rb_class2name(CLASS_OF(n)));
  }

  {
    rb_iseq_t *iseqdat = iseq_check((VALUE)n->nd_body);
    set_cref_stack(iseqdat, klass, noex);
    iseqdat->klass = klass;
    iseqdat->defined_method_id = SYM2ID(id);
    n = NEW_METHOD(iseqdat->self, klass, NUM2INT(noex));
  }

add_node:

#endif

#if RUBY_VERSION_CODE >= 192
  rb_raise(rb_eRuntimeError, "Unable to add node on this version of ruby");
#else
  /* TODO: if noex is NOEX_MODFUNC, add this method as a module function
   * (that is, both as an instance and singleton method)
   */
  rb_add_method(klass, SYM2ID(id), n, NUM2INT(noex));
  return Qnil;
#endif
}

#as_code(indent = 0) ⇒ Object

TODO: it would be nice if we could go back and find the AST for the class instead of recreating the code from the class’s current state.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/internal/module/as_code.rb', line 8

def as_code(indent=0)
  imethods = self.instance_methods - self.superclass.instance_methods
  cmethods = self.instance_methods - self.superclass.instance_methods
  constants = self.constants - self.superclass.constants
  name = self.name.gsub(/.*::/, '')

  # TODO: included modules?
  if self.class == Class then
    s = "#{'  '*indent}class #{name} < #{self.superclass}\n"
  else
    s = "#{'  '*indent}module #{name}\n"
  end

  constants.each do |constant|
    s += "#{'  '*indent} #{constant}=#{self.const_get(constant).as_code}\n"
  end

  # TODO: protected/private
  imethods.each do |method|
    s += self.instance_method(method).as_code(indent+1)
    s += "\n"
  end

  cmethods.each do |method|
    s += self.instance_method(method).as_code(indent+1, "self.#{method}")
    s += "\n"
  end

  # TODO: singleton class constants
  # TODO: class variables
  # TODO: singleton instance variables

  s += "#{'  '*indent}end"

  return s
end

#real_superclassClass

Return the immediate superclass of a class or module. This may be a base class, a singleton class, or a module singleton.

Returns:

  • (Class)


585
586
587
588
589
590
# File 'ext/internal/module/module.c', line 585

VALUE module_real_superclass(VALUE self)
{
  VALUE super = RCLASS_SUPER(self);
  rb_include_module(rb_class_of(super), rb_mKernel);
  return super;
}