Method: Struct.new

Defined in:
struct.c

.new(*member_names, keyword_init: nil) {|Struct_subclass| ... } ⇒ Struct_subclass .new(class_name, *member_names, keyword_init: nil) {|Struct_subclass| ... } ⇒ Struct_subclass .new(*member_names) ⇒ Struct_subclass_instance .new(**member_names) ⇒ Struct_subclass_instance

Struct.new returns a new subclass of Struct. The new subclass:

  • May be anonymous, or may have the name given by class_name.

  • May have members as given by member_names.

  • May have initialization via ordinary arguments, or via keyword arguments

The new subclass has its own method ::new; thus:

Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo
f = Foo.new(0, 1)                   # => #<struct Struct::Foo foo=0, bar=1>

Class Name

With string argument class_name, returns a new subclass of Struct named Struct::class_name:

Foo = Struct.new('Foo', :foo, :bar) # => Struct::Foo
Foo.name                            # => "Struct::Foo"
Foo.superclass                      # => Struct

Without string argument class_name, returns a new anonymous subclass of Struct:

Struct.new(:foo, :bar).name # => nil

Block

With a block given, the created subclass is yielded to the block:

Customer = Struct.new('Customer', :name, :address) do |new_class|
  p "The new subclass is #{new_class}"
  def greeting
    "Hello #{name} at #{address}"
  end
end           # => Struct::Customer
dave = Customer.new('Dave', '123 Main')
dave # =>     #<struct Struct::Customer name="Dave", address="123 Main">
dave.greeting # => "Hello Dave at 123 Main"

Output, from Struct.new:

"The new subclass is Struct::Customer"

Member Names

Symbol arguments member_names determines the members of the new subclass:

Struct.new(:foo, :bar).members        # => [:foo, :bar]
Struct.new('Foo', :foo, :bar).members # => [:foo, :bar]

The new subclass has instance methods corresponding to member_names:

Foo = Struct.new('Foo', :foo, :bar)
Foo.instance_methods(false) # => [:foo, :bar, :foo=, :bar=]
f = Foo.new                 # => #<struct Struct::Foo foo=nil, bar=nil>
f.foo                       # => nil
f.foo = 0                   # => 0
f.bar                       # => nil
f.bar = 1                   # => 1
f                           # => #<struct Struct::Foo foo=0, bar=1>

Singleton Methods

A subclass returned by Struct.new has these singleton methods:

  • Method ::new creates an instance of the subclass:

    Foo.new          # => #<struct Struct::Foo foo=nil, bar=nil>
    Foo.new(0)       # => #<struct Struct::Foo foo=0, bar=nil>
    Foo.new(0, 1)    # => #<struct Struct::Foo foo=0, bar=1>
    Foo.new(0, 1, 2) # Raises ArgumentError: struct size differs
    
    # Initialization with keyword arguments:
    Foo.new(foo: 0)         # => #<struct Struct::Foo foo=0, bar=nil>
    Foo.new(foo: 0, bar: 1) # => #<struct Struct::Foo foo=0, bar=1>
    Foo.new(foo: 0, bar: 1, baz: 2)
    # Raises ArgumentError: unknown keywords: baz
    
  • Method :inspect returns a string representation of the subclass:

    Foo.inspect
    # => "Struct::Foo"
    
  • Method ::members returns an array of the member names:

    Foo.members # => [:foo, :bar]
    

Keyword Argument

By default, the arguments for initializing an instance of the new subclass can be both positional and keyword arguments.

Optional keyword argument keyword_init: allows to force only one type of arguments to be accepted:

KeywordsOnly = Struct.new(:foo, :bar, keyword_init: true)
KeywordsOnly.new(bar: 1, foo: 0)
# => #<struct KeywordsOnly foo=0, bar=1>
KeywordsOnly.new(0, 1)
# Raises ArgumentError: wrong number of arguments

PositionalOnly = Struct.new(:foo, :bar, keyword_init: false)
PositionalOnly.new(0, 1)
# => #<struct PositionalOnly foo=0, bar=1>
PositionalOnly.new(bar: 1, foo: 0)
# => #<struct PositionalOnly foo={:foo=>1, :bar=>2}, bar=nil>
# Note that no error is raised, but arguments treated as one hash value

# Same as not providing keyword_init:
Any = Struct.new(:foo, :bar, keyword_init: nil)
Any.new(foo: 1, bar: 2)
# => #<struct Any foo=1, bar=2>
Any.new(1, 2)
# => #<struct Any foo=1, bar=2>

Overloads:

  • .new(*member_names, keyword_init: nil) {|Struct_subclass| ... } ⇒ Struct_subclass

    Yields:

    • (Struct_subclass)

    Returns:

    • (Struct_subclass)
  • .new(class_name, *member_names, keyword_init: nil) {|Struct_subclass| ... } ⇒ Struct_subclass

    Yields:

    • (Struct_subclass)

    Returns:

    • (Struct_subclass)
  • .new(*member_names) ⇒ Struct_subclass_instance

    Returns:

    • (Struct_subclass_instance)
  • .new(**member_names) ⇒ Struct_subclass_instance

    Returns:

    • (Struct_subclass_instance)


641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
# File 'struct.c', line 641

static VALUE
rb_struct_s_def(int argc, VALUE *argv, VALUE klass)
{
    VALUE name = Qnil, rest, keyword_init = Qnil;
    long i;
    VALUE st;
    VALUE opt;

    argc = rb_scan_args(argc, argv, "0*:", NULL, &opt);
    if (argc >= 1 && !SYMBOL_P(argv[0])) {
        name = argv[0];
        --argc;
        ++argv;
    }

    if (!NIL_P(opt)) {
        static ID keyword_ids[1];

        if (!keyword_ids[0]) {
            keyword_ids[0] = rb_intern("keyword_init");
        }
        rb_get_kwargs(opt, keyword_ids, 0, 1, &keyword_init);
        if (UNDEF_P(keyword_init)) {
            keyword_init = Qnil;
        }
        else if (RTEST(keyword_init)) {
            keyword_init = Qtrue;
        }
    }

    rest = rb_ident_hash_new();
    RBASIC_CLEAR_CLASS(rest);
    for (i=0; i<argc; i++) {
        VALUE mem = rb_to_symbol(argv[i]);
        if (rb_is_attrset_sym(mem)) {
            rb_raise(rb_eArgError, "invalid struct member: %"PRIsVALUE, mem);
        }
        if (RTEST(rb_hash_has_key(rest, mem))) {
            rb_raise(rb_eArgError, "duplicate member: %"PRIsVALUE, mem);
        }
        rb_hash_aset(rest, mem, Qtrue);
    }
    rest = rb_hash_keys(rest);
    RBASIC_CLEAR_CLASS(rest);
    OBJ_FREEZE(rest);
    if (NIL_P(name)) {
        st = anonymous_struct(klass);
    }
    else {
        st = new_struct(name, klass);
    }
    setup_struct(st, rest);
    rb_ivar_set(st, id_keyword_init, keyword_init);
    if (rb_block_given_p()) {
        rb_mod_module_eval(0, 0, st);
    }

    return st;
}