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 Customer.class Customer.superclass
Corresponding to each member are two methods, a writer and a reader, that store and fetch values:
methods = Customer.instance_methods false methods
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
The member values may be managed thus:
joe.name joe.name = 'Joseph Smith' joe.name
And thus; note that member name may be expressed as either a string or a symbol:
joe[:name] joe[:name] = 'Joseph Smith, Jr.' joe['name']
See Struct::new
.
First, whatâs elsewhere. Class Struct:
Inherits from class Object.
Includes module Enumerable, which provides dozens of additional methods.
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 aStruct
Subclass¶ ↑
::new
: Returns a new subclass of Struct.
==
: 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.
[]
: 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.
[]=
: Assigns a given value to a given member name.
each
: Calls a given block with each member name.
each_pair
: Calls a given block with each member name/value pair.
inspect
(aliased as to_s
): Returns a string representation of self
.
to_h
: Returns a hash of the member name/value pairs in self
.
def self.json_create(object) new(*object['v']) end
See as_json
.
static VALUE rb_struct_s_keyword_init_p(VALUE obj) { }
Returns true
if the class was initialized with keyword_init: true
. Otherwise returns nil
or false
.
Examples:
Foo = Struct.new(:a) Foo.keyword_init? Bar = Struct.new(:a, keyword_init: true) Bar.keyword_init? Baz = Struct.new(:a, keyword_init: false) Baz.keyword_init?Source
static VALUE rb_struct_s_members_m(VALUE klass) { VALUE members = rb_struct_s_members(klass); return rb_ary_dup(members); }
Returns the member names of the Struct
descendant as an array:
Customer = Struct.new(:name, :address, :zip) Customer.membersSource
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; }
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) f = Foo.new(0, 1)
Class Name
With string argument class_name
, returns a new subclass of Struct
named Struct::class_name
:
Foo = Struct.new('Foo', :foo, :bar) Foo.name Foo.superclass
Without string argument class_name
, returns a new anonymous subclass of Struct
:
Struct.new(:foo, :bar).name
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 dave = Customer.new('Dave', '123 Main') dave dave.greeting
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 Struct.new('Foo', :foo, :bar).members
The new subclass has instance methods corresponding to member_names
:
Foo = Struct.new('Foo', :foo, :bar) Foo.instance_methods(false) f = Foo.new f.foo f.foo = 0 f.bar f.bar = 1 f
Singleton Methods
A subclass returned by Struct.new
has these singleton methods:
Method ::new
creates an instance of the subclass:
Foo.new Foo.new(0) Foo.new(0, 1) Foo.new(0, 1, 2) Foo.new(foo: 0) Foo.new(foo: 0, bar: 1) Foo.new(foo: 0, bar: 1, baz: 2)
Method :inspect
returns a string representation of the subclass:
Foo.inspect
Method ::members
returns an array of the member names:
Foo.members
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) KeywordsOnly.new(0, 1) PositionalOnly = Struct.new(:foo, :bar, keyword_init: false) PositionalOnly.new(0, 1) PositionalOnly.new(bar: 1, foo: 0) Any = Struct.new(:foo, :bar, keyword_init: nil) Any.new(foo: 1, bar: 2) Any.new(1, 2)Public Instance Methods Source
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); }
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 joe_jr[:name] = 'Joe Smith, Jr.' joe_jr == joeSource
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); }
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]
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 Indexes at Array
:
joe[2] joe[-2]
Raises IndexError
if n
is out of range.
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; }
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 joe
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 Indexes at Array
:
joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe[2] = 54321 joe[-3] = 'Joseph Smith' joe
Raises IndexError
if n
is out of range.
def as_json(*) klass = self.class.name klass.to_s.empty? and raise JSON::JSONError, "Only named structs are supported!" { JSON.create_id => klass, 'v' => values, } end
Methods Struct#as_json
and Struct.json_create
may be used to serialize and deserialize a Struct object; see Marshal
.
Method Struct#as_json
serializes self
, returning a 2-element hash representing self
:
require 'json/add/struct' Customer = Struct.new('Customer', :name, :address, :zip) x = Struct::Customer.new.as_json
Method JSON.create
deserializes such a hash, returning a Struct object:
Struct::Customer.json_create(x)Source
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; }
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
Returns all names and values if array_of_names
is nil
:
h = joe.deconstruct_keys(nil) hSource
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); }
Finds and returns an object among nested objects. The nested objects may be instances of various classes. See Dig Methods.
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) f.dig(:a, :a) f.dig(:a, :a, :b) f.dig(:a, :a, :b, 0) f.dig(:b, 0)
Given integer argument n
, returns the object that is specified by n
and identifiers
:
f.dig(0) f.dig(0, 0) f.dig(0, 0, :b) f.dig(0, 0, :b, 0) f.dig(:b, 0)Source
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; }
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
.
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; }
Calls the given block with each member name/value pair; returns self
:
Customer = Struct.new(:name, :address, :zip) 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
.
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); }
Returns true
if and only if the following are true; otherwise returns false
:
other.class == self.class
.
For each member name name
, other.name.eql?(self.name)
.
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) joe_jr[:name] = 'Joe Smith, Jr.' joe_jr.eql?(joe)
Related: Object#==
.
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); }
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 joe_jr[:name] = 'Joe Smith, Jr.' joe.hash == joe_jr.hash
Related: Object#hash
.
static VALUE rb_struct_inspect(VALUE s) { return rb_exec_recursive(inspect_struct, s, rb_str_new2("#<struct ")); }
Returns a string representation of self
:
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.inspectSource
static VALUE rb_struct_members_m(VALUE obj) { return rb_struct_s_members_m(rb_obj_class(obj)); }
Returns the member names from self
as an array:
Customer = Struct.new(:name, :address, :zip) Customer.new.members
Related: to_a
.
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; }
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 a = joe.select {|value| value.is_a?(Integer) } a
With no block given, returns an Enumerator
.
VALUE rb_struct_size(VALUE s) { return LONG2FIX(RSTRUCT_LEN(s)); }
Returns the number of members.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.sizeSource
static VALUE rb_struct_to_a(VALUE s) { return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_CONST_PTR(s)); }
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
Related: members
.
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; }
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
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
Raises ArgumentError
if the block returns an inappropriate value.
def to_json(*args) as_json.to_json(*args) end
Returns a JSON
string representing self
:
require 'json/add/struct' Customer = Struct.new('Customer', :name, :address, :zip) puts Struct::Customer.new.to_json
Output:
{"json_class":"Struct","t":{'name':'Rowdy',"age":null}}Source
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); }
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.values_at(2, 0) joe.values_at(2, 1, 0) joe.values_at(0, -3)
Raises IndexError
if any of integers
is out of range; see Array Indexes at Array
.
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.values_at(-3..-1) joe.values_at(1..4)
Raises RangeError
if any element of the range is negative and out of range; see Array Indexes at Array
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4