Class: Struct

Inherits:
Object show all
Includes:
Enumerable
Defined in:
struct.c,
struct.c

Overview

Class Struct provides a convenient way to create a simple class that can store and fetch values.

This example creates a subclass of Struct, Struct::Customer; the first argument, a string, is the name of the subclass; the other arguments, symbols, determine the members of the new subclass.

Customer = Struct.new('Customer', :name, :address, :zip)
Customer.name       # => "Struct::Customer"
Customer.class      # => Class
Customer.superclass # => Struct

Corresponding to each member are two methods, a writer and a reader, that store and fetch values:

methods = Customer.instance_methods false
methods # => [:zip, :address=, :zip=, :address, :name, :name=]

An instance of the subclass may be created, and its members assigned values, via method ::new:

joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe # => #<struct Struct::Customer name="Joe Smith", address="123 Maple, Anytown NC", zip=12345>

The member values may be managed thus:

joe.name    # => "Joe Smith"
joe.name = 'Joseph Smith'
joe.name    # => "Joseph Smith"

And thus; note that member name may be expressed as either a string or a symbol:

joe[:name]  # => "Joseph Smith"
joe[:name] = 'Joseph Smith, Jr.'
joe['name'] # => "Joseph Smith, Jr."

See Struct::new.

What’s Here

First, what’s elsewhere. Class Struct:

See also Data, which is a somewhat similar, but stricter concept for defining immutable value objects.

Here, class Struct provides methods that are useful for:

Methods for Creating a Struct Subclass

  • ::new: Returns a new subclass of Struct.

Methods for Querying

  • #hash: Returns the integer hash code.

  • #size (aliased as #length): Returns the number of members.

Methods for Comparing

  • #==: Returns whether a given object is equal to self, using == to compare member values.

  • #eql?: Returns whether a given object is equal to self, using eql? to compare member values.

Methods for Fetching

  • #[]: Returns the value associated with a given member name.

  • #to_a (aliased as #values, #deconstruct): Returns the member values in self as an array.

  • #deconstruct_keys: Returns a hash of the name/value pairs for given member names.

  • #dig: Returns the object in nested objects that is specified by a given member name and additional arguments.

  • #members: Returns an array of the member names.

  • #select (aliased as #filter): Returns an array of member values from self, as selected by the given block.

  • #values_at: Returns an array containing values for given member names.

Methods for Assigning

  • #[]=: Assigns a given value to a given member name.

Methods for Iterating

  • #each: Calls a given block with each member name.

  • #each_pair: Calls a given block with each member name/value pair.

Methods for Converting

  • #inspect (aliased as #to_s): Returns a string representation of self.

  • #to_h: Returns a hash of the member name/value pairs in self.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Enumerable

#all?, #any?, #chain, #chunk, #chunk_while, #collect, #collect_concat, #compact, #count, #cycle, #detect, #drop, #drop_while, #each_cons, #each_entry, #each_slice, #each_with_index, #each_with_object, #entries, #filter_map, #find, #find_all, #find_index, #first, #flat_map, #grep, #grep_v, #group_by, #include?, #inject, #lazy, #map, #max, #max_by, #member?, #min, #min_by, #minmax, #minmax_by, #none?, #one?, #partition, #reduce, #reject, #reverse_each, #slice_after, #slice_before, #slice_when, #sort, #sort_by, #sum, #take, #take_while, #tally, #uniq, #zip

Constructor Details

#initialize(*args) ⇒ Object



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
# File 'struct.c', line 740

static VALUE
rb_struct_initialize_m(int argc, const VALUE *argv, VALUE self)
{
    VALUE klass = rb_obj_class(self);
    rb_struct_modify(self);
    long n = num_members(klass);
    if (argc == 0) {
        rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), n);
        return Qnil;
    }

    bool keyword_init = false;
    switch (rb_struct_s_keyword_init(klass)) {
      default:
        if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
            rb_error_arity(argc, 0, 0);
        }
        keyword_init = true;
        break;
      case Qfalse:
        break;
      case Qnil:
        if (argc > 1 || !RB_TYPE_P(argv[0], T_HASH)) {
            break;
        }
        keyword_init = rb_keyword_given_p();
        break;
    }
    if (keyword_init) {
        struct struct_hash_set_arg arg;
        rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self), n);
        arg.self = self;
        arg.unknown_keywords = Qnil;
        rb_hash_foreach(argv[0], struct_hash_set_i, (VALUE)&arg);
        if (arg.unknown_keywords != Qnil) {
            rb_raise(rb_eArgError, "unknown keywords: %s",
                     RSTRING_PTR(rb_ary_join(arg.unknown_keywords, rb_str_new2(", "))));
        }
    }
    else {
        if (n < argc) {
            rb_raise(rb_eArgError, "struct size differs");
        }
        for (long i=0; i<argc; i++) {
            RSTRUCT_SET(self, i, argv[i]);
        }
        if (n > argc) {
            rb_mem_clear((VALUE *)RSTRUCT_CONST_PTR(self)+argc, n-argc);
        }
    }
    return Qnil;
}

Class Method Details

.StructClass::keyword_init?true

Returns true if the class was initialized with keyword_init: true. Otherwise returns nil or false.

Examples:

Foo = Struct.new(:a)
Foo.keyword_init? # => nil
Bar = Struct.new(:a, keyword_init: true)
Bar.keyword_init? # => true
Baz = Struct.new(:a, keyword_init: false)
Baz.keyword_init? # => false

Returns:

  • (true)


343
344
345
346
# File 'struct.c', line 343

static VALUE
rb_struct_s_keyword_init_p(VALUE obj)
{
}

.StructClass::membersObject

Returns the member names of the Struct descendant as an array:

Customer = Struct.new(:name, :address, :zip)
Customer.members # => [:name, :address, :zip]


205
206
207
208
209
210
211
# File 'struct.c', line 205

static VALUE
rb_struct_s_members_m(VALUE klass)
{
    VALUE members = rb_struct_s_members(klass);

    return rb_ary_dup(members);
}

.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;
}

Instance Method Details

#==(other) ⇒ Boolean

Returns true if and only if the following are true; otherwise returns false:

  • other.class == self.class.

  • For each member name name, other.name == self.name.

Examples:

Customer = Struct.new(:name, :address, :zip)
joe    = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe_jr == joe # => true
joe_jr[:name] = 'Joe Smith, Jr.'
# => "Joe Smith, Jr."
joe_jr == joe # => false

Returns:

  • (Boolean)


1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
# File 'struct.c', line 1398

static VALUE
rb_struct_equal(VALUE s, VALUE s2)
{
    if (s == s2) return Qtrue;
    if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
    if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
    if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
        rb_bug("inconsistent struct"); /* should never happen */
    }

    return rb_exec_recursive_paired(recursive_equal, s, s2, s2);
}

#[](name) ⇒ Object #[](n) ⇒ Object

Returns a value from self.

With symbol or string argument name given, returns the value for the named member:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe[:zip] # => 12345

Raises NameError if name is not the name of a member.

With integer argument n given, returns self.values[n] if n is in range; see Array@Array+Indexes:

joe[2]  # => 12345
joe[-2] # => "123 Maple, Anytown NC"

Raises IndexError if n is out of range.

Overloads:



1216
1217
1218
1219
1220
1221
1222
# File 'struct.c', line 1216

VALUE
rb_struct_aref(VALUE s, VALUE idx)
{
    int i = rb_struct_pos(s, &idx);
    if (i < 0) invalid_struct_pos(s, idx);
    return RSTRUCT_GET(s, i);
}

#[]=(name) ⇒ Object #[]=(n) ⇒ Object

Assigns a value to a member.

With symbol or string argument name given, assigns the given value to the named member; returns value:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe[:zip] = 54321 # => 54321
joe # => #<struct Customer name="Joe Smith", address="123 Maple, Anytown NC", zip=54321>

Raises NameError if name is not the name of a member.

With integer argument n given, assigns the given value to the n-th member if n is in range; see Array@Array+Indexes:

joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe[2] = 54321           # => 54321
joe[-3] = 'Joseph Smith' # => "Joseph Smith"
joe # => #<struct Customer name="Joseph Smith", address="123 Maple, Anytown NC", zip=54321>

Raises IndexError if n is out of range.



1254
1255
1256
1257
1258
1259
1260
1261
1262
# File 'struct.c', line 1254

VALUE
rb_struct_aset(VALUE s, VALUE idx, VALUE val)
{
    int i = rb_struct_pos(s, &idx);
    if (i < 0) invalid_struct_pos(s, idx);
    rb_struct_modify(s);
    RSTRUCT_SET(s, i, val);
    return val;
}

#to_aArray

Returns the values in self as an array:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]

Related: #members.

Returns:



1026
1027
1028
1029
1030
# File 'struct.c', line 1026

static VALUE
rb_struct_to_a(VALUE s)
{
    return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
}

#deconstruct_keys(array_of_names) ⇒ Hash

Returns a hash of the name/value pairs for the given member names.

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
h = joe.deconstruct_keys([:zip, :address])
h # => {:zip=>12345, :address=>"123 Maple, Anytown NC"}

Returns all names and values if array_of_names is nil:

h = joe.deconstruct_keys(nil)
h # => {:name=>"Joseph Smith, Jr.", :address=>"123 Maple, Anytown NC", :zip=>12345}

Returns:



1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
# File 'struct.c', line 1090

static VALUE
rb_struct_deconstruct_keys(VALUE s, VALUE keys)
{
    VALUE h;
    long i;

    if (NIL_P(keys)) {
        return rb_struct_to_h(s);
    }
    if (UNLIKELY(!RB_TYPE_P(keys, T_ARRAY))) {
        rb_raise(rb_eTypeError,
                 "wrong argument type %"PRIsVALUE" (expected Array or nil)",
                 rb_obj_class(keys));

    }
    if (RSTRUCT_LEN(s) < RARRAY_LEN(keys)) {
        return rb_hash_new_with_size(0);
    }
    h = rb_hash_new_with_size(RARRAY_LEN(keys));
    for (i=0; i<RARRAY_LEN(keys); i++) {
        VALUE key = RARRAY_AREF(keys, i);
        int i = rb_struct_pos(s, &key);
        if (i < 0) {
            return h;
        }
        rb_hash_aset(h, key, RSTRUCT_GET(s, i));
    }
    return h;
}

#dig(name, *identifiers) ⇒ Object #dig(n, *identifiers) ⇒ Object

Finds and returns an object among nested objects.

The nested objects may be instances of various classes.
See {Dig Methods}[rdoc-ref:dig_methods.rdoc].

Given symbol or string argument +name+,
returns the object that is specified by +name+ and +identifiers+:

 Foo = Struct.new(:a)
 f = Foo.new(Foo.new({b: [1, 2, 3]}))
 f.dig(:a) # => #<struct Foo a={:b=>[1, 2, 3]}>
 f.dig(:a, :a) # => {:b=>[1, 2, 3]}
 f.dig(:a, :a, :b) # => [1, 2, 3]
 f.dig(:a, :a, :b, 0) # => 1
 f.dig(:b, 0) # => nil

Given integer argument +n+,
returns the object that is specified by +n+ and +identifiers+:

 f.dig(0) # => #<struct Foo a={:b=>[1, 2, 3]}>
 f.dig(0, 0) # => {:b=>[1, 2, 3]}
 f.dig(0, 0, :b) # => [1, 2, 3]
 f.dig(0, 0, :b, 0) # => 1
 f.dig(:b, 0) # => nil

Overloads:



1542
1543
1544
1545
1546
1547
1548
1549
1550
# File 'struct.c', line 1542

static VALUE
rb_struct_dig(int argc, VALUE *argv, VALUE self)
{
    rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS);
    self = rb_struct_lookup(self, *argv);
    if (!--argc) return self;
    ++argv;
    return rb_obj_dig(argc, argv, self, Qnil);
}

#each {|value| ... } ⇒ self #eachObject

Calls the given block with the value of each member; returns self:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.each {|value| p value }

Output:

"Joe Smith"
"123 Maple, Anytown NC"
12345

Returns an Enumerator if no block is given.

Related: #each_pair.

Overloads:

  • #each {|value| ... } ⇒ self

    Yields:

    • (value)

    Returns:

    • (self)


890
891
892
893
894
895
896
897
898
899
900
# File 'struct.c', line 890

static VALUE
rb_struct_each(VALUE s)
{
    long i;

    RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
    for (i=0; i<RSTRUCT_LEN(s); i++) {
        rb_yield(RSTRUCT_GET(s, i));
    }
    return s;
}

#each_pair {|(name, value)| ... } ⇒ self #each_pairObject

Calls the given block with each member name/value pair; returns self:

Customer = Struct.new(:name, :address, :zip) # => Customer
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.each_pair {|(name, value)| p "#{name} => #{value}" }

Output:

"name => Joe Smith"
"address => 123 Maple, Anytown NC"
"zip => 12345"

Returns an Enumerator if no block is given.

Related: #each.

Overloads:

  • #each_pair {|(name, value)| ... } ⇒ self

    Yields:

    • ((name, value))

    Returns:

    • (self)


925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
# File 'struct.c', line 925

static VALUE
rb_struct_each_pair(VALUE s)
{
    VALUE members;
    long i;

    RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
    members = rb_struct_members(s);
    if (rb_block_pair_yield_optimizable()) {
        for (i=0; i<RSTRUCT_LEN(s); i++) {
            VALUE key = rb_ary_entry(members, i);
            VALUE value = RSTRUCT_GET(s, i);
            rb_yield_values(2, key, value);
        }
    }
    else {
        for (i=0; i<RSTRUCT_LEN(s); i++) {
            VALUE key = rb_ary_entry(members, i);
            VALUE value = RSTRUCT_GET(s, i);
            rb_yield(rb_assoc_new(key, value));
        }
    }
    return s;
}

#eql?(other) ⇒ Boolean

Returns true if and only if the following are true; otherwise returns false:

- <tt>other.class == self.class</tt>.
- For each member name +name+, <tt>other.name.eql?(self.name)</tt>.

   Customer = Struct.new(:name, :address, :zip)
   joe    = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
   joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
   joe_jr.eql?(joe) # => true
   joe_jr[:name] = 'Joe Smith, Jr.'
   joe_jr.eql?(joe) # => false

Related: Object#==.

Returns:

  • (Boolean)


1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
# File 'struct.c', line 1479

static VALUE
rb_struct_eql(VALUE s, VALUE s2)
{
    if (s == s2) return Qtrue;
    if (!RB_TYPE_P(s2, T_STRUCT)) return Qfalse;
    if (rb_obj_class(s) != rb_obj_class(s2)) return Qfalse;
    if (RSTRUCT_LEN(s) != RSTRUCT_LEN(s2)) {
        rb_bug("inconsistent struct"); /* should never happen */
    }

    return rb_exec_recursive_paired(recursive_eql, s, s2, s2);
}

#select {|value| ... } ⇒ Array #selectObject

With a block given, returns an array of values from self for which the block returns a truthy value:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
a = joe.select {|value| value.is_a?(String) }
a # => ["Joe Smith", "123 Maple, Anytown NC"]
a = joe.select {|value| value.is_a?(Integer) }
a # => [12345]

With no block given, returns an Enumerator.

Overloads:

  • #select {|value| ... } ⇒ Array

    Yields:

    • (value)

    Returns:



1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
# File 'struct.c', line 1346

static VALUE
rb_struct_select(int argc, VALUE *argv, VALUE s)
{
    VALUE result;
    long i;

    rb_check_arity(argc, 0, 0);
    RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
    result = rb_ary_new();
    for (i = 0; i < RSTRUCT_LEN(s); i++) {
        if (RTEST(rb_yield(RSTRUCT_GET(s, i)))) {
            rb_ary_push(result, RSTRUCT_GET(s, i));
        }
    }

    return result;
}

#hashInteger

Returns the integer hash value for self.

Two structs of the same class and with the same content will have the same hash code (and will compare using Struct#eql?):

Customer = Struct.new(:name, :address, :zip)
joe    = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe_jr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.hash == joe_jr.hash # => true
joe_jr[:name] = 'Joe Smith, Jr.'
joe.hash == joe_jr.hash # => false

Related: Object#hash.

Returns:



1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
# File 'struct.c', line 1430

static VALUE
rb_struct_hash(VALUE s)
{
    long i, len;
    st_index_t h;
    VALUE n;

    h = rb_hash_start(rb_hash(rb_obj_class(s)));
    len = RSTRUCT_LEN(s);
    for (i = 0; i < len; i++) {
        n = rb_hash(RSTRUCT_GET(s, i));
        h = rb_hash_uint(h, NUM2LONG(n));
    }
    h = rb_hash_end(h);
    return ST2FIX(h);
}

#initialize_copy(s) ⇒ Object

:nodoc:



1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
# File 'struct.c', line 1121

VALUE
rb_struct_init_copy(VALUE copy, VALUE s)
{
    long i, len;

    if (!OBJ_INIT_COPY(copy, s)) return copy;
    if (RSTRUCT_LEN(copy) != RSTRUCT_LEN(s)) {
        rb_raise(rb_eTypeError, "struct size mismatch");
    }

    for (i=0, len=RSTRUCT_LEN(copy); i<len; i++) {
        RSTRUCT_SET(copy, i, RSTRUCT_GET(s, i));
    }

    return copy;
}

#inspectString Also known as: to_s

Returns a string representation of self:

Customer = Struct.new(:name, :address, :zip) # => Customer
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.inspect # => "#<struct Customer name=\"Joe Smith\", address=\"123 Maple, Anytown NC\", zip=12345>"

Returns:



1007
1008
1009
1010
1011
# File 'struct.c', line 1007

static VALUE
rb_struct_inspect(VALUE s)
{
    return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<struct "));
}

#sizeInteger

Returns the number of members.

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.size #=> 3

Returns:



1504
1505
1506
1507
1508
# File 'struct.c', line 1504

VALUE
rb_struct_size(VALUE s)
{
    return LONG2FIX(RSTRUCT_LEN(s));
}

#membersObject

Returns the member names from self as an array:

Customer = Struct.new(:name, :address, :zip)
Customer.new.members # => [:name, :address, :zip]

Related: #to_a.



225
226
227
228
229
# File 'struct.c', line 225

static VALUE
rb_struct_members_m(VALUE obj)
{
    return rb_struct_s_members_m(rb_obj_class(obj));
}

#select {|value| ... } ⇒ Array #selectObject

With a block given, returns an array of values from self for which the block returns a truthy value:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
a = joe.select {|value| value.is_a?(String) }
a # => ["Joe Smith", "123 Maple, Anytown NC"]
a = joe.select {|value| value.is_a?(Integer) }
a # => [12345]

With no block given, returns an Enumerator.

Overloads:

  • #select {|value| ... } ⇒ Array

    Yields:

    • (value)

    Returns:



1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
# File 'struct.c', line 1346

static VALUE
rb_struct_select(int argc, VALUE *argv, VALUE s)
{
    VALUE result;
    long i;

    rb_check_arity(argc, 0, 0);
    RETURN_SIZED_ENUMERATOR(s, 0, 0, struct_enum_size);
    result = rb_ary_new();
    for (i = 0; i < RSTRUCT_LEN(s); i++) {
        if (RTEST(rb_yield(RSTRUCT_GET(s, i)))) {
            rb_ary_push(result, RSTRUCT_GET(s, i));
        }
    }

    return result;
}

#sizeInteger

Returns the number of members.

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.size #=> 3

Returns:



1504
1505
1506
1507
1508
# File 'struct.c', line 1504

VALUE
rb_struct_size(VALUE s)
{
    return LONG2FIX(RSTRUCT_LEN(s));
}

#to_aArray

Returns the values in self as an array:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]

Related: #members.

Returns:



1026
1027
1028
1029
1030
# File 'struct.c', line 1026

static VALUE
rb_struct_to_a(VALUE s)
{
    return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
}

#to_hHash #to_h {|name, value| ... } ⇒ Hash

Returns a hash containing the name and value for each member:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
h = joe.to_h
h # => {:name=>"Joe Smith", :address=>"123 Maple, Anytown NC", :zip=>12345}

If a block is given, it is called with each name/value pair; the block should return a 2-element array whose elements will become a key/value pair in the returned hash:

h = joe.to_h{|name, value| [name.upcase, value.to_s.upcase]}
h # => {:NAME=>"JOE SMITH", :ADDRESS=>"123 MAPLE, ANYTOWN NC", :ZIP=>"12345"}

Raises ArgumentError if the block returns an inappropriate value.

Overloads:

  • #to_hHash

    Returns:

  • #to_h {|name, value| ... } ⇒ Hash

    Yields:

    • (name, value)

    Returns:



1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
# File 'struct.c', line 1055

static VALUE
rb_struct_to_h(VALUE s)
{
    VALUE h = rb_hash_new_with_size(RSTRUCT_LEN(s));
    VALUE members = rb_struct_members(s);
    long i;
    int block_given = rb_block_given_p();

    for (i=0; i<RSTRUCT_LEN(s); i++) {
        VALUE k = rb_ary_entry(members, i), v = RSTRUCT_GET(s, i);
        if (block_given)
            rb_hash_set_pair(h, rb_yield_values(2, k, v));
        else
            rb_hash_aset(h, k, v);
    }
    return h;
}

#to_aArray

Returns the values in self as an array:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.to_a # => ["Joe Smith", "123 Maple, Anytown NC", 12345]

Related: #members.

Returns:



1026
1027
1028
1029
1030
# File 'struct.c', line 1026

static VALUE
rb_struct_to_a(VALUE s)
{
    return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s));
}

#values_at(*integers) ⇒ Array #values_at(integer_range) ⇒ Array

Returns an array of values from self.

With integer arguments integers given, returns an array containing each value given by one of integers:

Customer = Struct.new(:name, :address, :zip)
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345)
joe.values_at(0, 2)    # => ["Joe Smith", 12345]
joe.values_at(2, 0)    # => [12345, "Joe Smith"]
joe.values_at(2, 1, 0) # => [12345, "123 Maple, Anytown NC", "Joe Smith"]
joe.values_at(0, -3)   # => ["Joe Smith", "Joe Smith"]

Raises IndexError if any of integers is out of range; see Array@Array+Indexes.

With integer range argument integer_range given, returns an array containing each value given by the elements of the range; fills with nil values for range elements larger than the structure:

joe.values_at(0..2)
# => ["Joe Smith", "123 Maple, Anytown NC", 12345]
joe.values_at(-3..-1)
# => ["Joe Smith", "123 Maple, Anytown NC", 12345]
joe.values_at(1..4) # => ["123 Maple, Anytown NC", 12345, nil, nil]

Raises RangeError if any element of the range is negative and out of range; see Array@Array+Indexes.

Overloads:

  • #values_at(*integers) ⇒ Array

    Returns:

  • #values_at(integer_range) ⇒ Array

    Returns:



1322
1323
1324
1325
1326
# File 'struct.c', line 1322

static VALUE
rb_struct_values_at(int argc, VALUE *argv, VALUE s)
{
    return rb_get_values_at(s, RSTRUCT_LEN(s), argc, argv, struct_entry);
}