class Struct
Struct serialization/deserialization
A Struct
is a convenient way to bundle a number of attributes
together, using accessor methods, without having to write an explicit
class.
The Struct
class is a generator of specific classes, each one
of which is defined to hold a set of variables and their accessors. In
these examples, we'll call the generated class
“CustomerClass,'' and we'll show an example instance
of that class as “CustomerInst.''
In the descriptions that follow, the parameter symbol refers to a
symbol, which is either a quoted string or a Symbol
(such as
:name
).
Public Class Methods
Creates a new class, named by aString, containing accessor methods
for the given symbols. If the name aString is omitted, an
anonymous structure class will be created. Otherwise, the name of this
struct will appear as a constant in class Struct
, so it must
be unique for all Struct
s in the system and should start with
a capital letter. Assigning a structure class to a constant effectively
gives the class the name of the constant.
If a block is given, it will be evaluated in the context of StructClass, passing StructClass as a parameter.
Customer = Struct.new(:name, :address) do def greeting "Hello #{name}!" end end Customer.new("Dave", "123 Main").greeting # => "Hello Dave!"
Struct::new
returns a new Class
object, which can
then be used to create specific instances of the new structure. The number
of actual parameters must be less than or equal to the number of attributes
defined for this class; unset parameters default to nil
.
Passing too many parameters will raise an ArgumentError
.
The remaining methods listed in this section (class and instance) are defined for this generated class.
# Create a structure with a name in Struct Struct.new("Customer", :name, :address) #=> Struct::Customer Struct::Customer.new("Dave", "123 Main") #=> #<struct Struct::Customer name="Dave", address="123 Main"> # Create a structure named by its constant Customer = Struct.new(:name, :address) #=> Customer Customer.new("Dave", "123 Main") #=> #<struct Customer name="Dave", address="123 Main">
static VALUE rb_struct_s_def(int argc, VALUE *argv, VALUE klass) { VALUE name, rest; long i; VALUE st; ID id; rb_check_arity(argc, 1, UNLIMITED_ARGUMENTS); name = argv[0]; if (SYMBOL_P(name)) { name = Qnil; } else { --argc; ++argv; } rest = rb_ary_tmp_new(argc); for (i=0; i<argc; i++) { id = rb_to_id(argv[i]); RARRAY_PTR(rest)[i] = ID2SYM(id); rb_ary_set_len(rest, i+1); } if (NIL_P(name)) { st = anonymous_struct(klass); } else { st = new_struct(name, klass); } setup_struct(st, rest); if (rb_block_given_p()) { rb_mod_module_eval(0, 0, st); } return st; }
Public Instance Methods
Equality—Returns true
if other_struct is equal to
this one: they must be of the same class as generated by
Struct::new
, and the values of all instance variables must be
equal (according to Object#==
).
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joejr = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) jane = Customer.new("Jane Doe", "456 Elm, Anytown NC", 12345) joe == joejr #=> true joe == jane #=> false
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); }
Attribute Reference—Returns the value of the instance variable named by
symbol, or indexed (0..length-1) by fixnum. Will raise
NameError
if the named variable does not exist, or
IndexError
if the index is out of range.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe["name"] #=> "Joe Smith" joe[:name] #=> "Joe Smith" joe[0] #=> "Joe Smith"
VALUE rb_struct_aref(VALUE s, VALUE idx) { long i; if (RB_TYPE_P(idx, T_SYMBOL)) { return rb_struct_aref_id(s, SYM2ID(idx)); } else if (RB_TYPE_P(idx, T_STRING)) { ID id = rb_check_id(&idx); if (!id) { rb_name_error_str(idx, "no member '%"PRIsVALUE"' in struct", QUOTE(idx)); } return rb_struct_aref_id(s, id); } i = NUM2LONG(idx); if (i < 0) i = RSTRUCT_LEN(s) + i; if (i < 0) rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)", i, RSTRUCT_LEN(s)); if (RSTRUCT_LEN(s) <= i) rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)", i, RSTRUCT_LEN(s)); return RSTRUCT_PTR(s)[i]; }
Attribute Assignment—Assigns to the instance variable named by
symbol or fixnum the value obj and returns it.
Will raise a NameError
if the named variable does not exist,
or an IndexError
if the index is out of range.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe["name"] = "Luke" joe[:zip] = "90210" joe.name #=> "Luke" joe.zip #=> "90210"
VALUE rb_struct_aset(VALUE s, VALUE idx, VALUE val) { long i; if (RB_TYPE_P(idx, T_SYMBOL)) { return rb_struct_aset_id(s, SYM2ID(idx), val); } if (RB_TYPE_P(idx, T_STRING)) { ID id = rb_check_id(&idx); if (!id) { rb_name_error_str(idx, "no member '%"PRIsVALUE"' in struct", QUOTE(idx)); } return rb_struct_aset_id(s, id, val); } i = NUM2LONG(idx); if (i < 0) i = RSTRUCT_LEN(s) + i; if (i < 0) { rb_raise(rb_eIndexError, "offset %ld too small for struct(size:%ld)", i, RSTRUCT_LEN(s)); } if (RSTRUCT_LEN(s) <= i) { rb_raise(rb_eIndexError, "offset %ld too large for struct(size:%ld)", i, RSTRUCT_LEN(s)); } rb_struct_modify(s); return RSTRUCT_PTR(s)[i] = val; }
Returns a hash, that will be turned into a JSON object and represent this object.
# File ext/json/lib/json/add/struct.rb, line 16 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
Calls block once for each instance variable, passing the value as a parameter.
If no block is given, an enumerator is returned instead.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.each {|x| puts(x) }
produces:
Joe Smith 123 Maple, Anytown NC 12345
static VALUE rb_struct_each(VALUE s) { long i; RETURN_SIZED_ENUMERATOR(s, 0, 0, rb_struct_size); for (i=0; i<RSTRUCT_LEN(s); i++) { rb_yield(RSTRUCT_PTR(s)[i]); } return s; }
Calls block once for each instance variable, passing the name (as a symbol) and the value as parameters.
If no block is given, an enumerator is returned instead.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.each_pair {|name, value| puts("#{name} => #{value}") }
produces:
name => Joe Smith address => 123 Maple, Anytown NC zip => 12345
static VALUE rb_struct_each_pair(VALUE s) { VALUE members; long i; RETURN_SIZED_ENUMERATOR(s, 0, 0, rb_struct_size); members = rb_struct_members(s); for (i=0; i<RSTRUCT_LEN(s); i++) { VALUE key = rb_ary_entry(members, i); VALUE value = RSTRUCT_PTR(s)[i]; rb_yield(rb_assoc_new(key, value)); } return s; }
Two structures are equal if they are the same object, or if all their
fields are equal (using eql?
).
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); }
Return a hash value based on this struct's contents.
static VALUE rb_struct_hash(VALUE s) { return rb_exec_recursive_outer(recursive_hash, s, 0); }
Describe the contents of this struct in a string.
static VALUE rb_struct_inspect(VALUE s) { return rb_exec_recursive(inspect_struct, s, 0); }
Returns the number of instance variables.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.length #=> 3
static VALUE rb_struct_size(VALUE s) { return LONG2FIX(RSTRUCT_LEN(s)); }
Returns an array of symbols representing the names of the instance variables.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.members #=> [:name, :address, :zip]
static VALUE rb_struct_members_m(VALUE obj) { return rb_struct_s_members_m(rb_obj_class(obj)); }
# File lib/pp.rb, line 362 def pretty_print(q) q.group(1, sprintf("#<struct %s", PP.mcall(self, Kernel, :class).name), '>') { q.seplist(PP.mcall(self, Struct, :members), lambda { q.text "," }) {|member| q.breakable q.text member.to_s q.text '=' q.group(1) { q.breakable '' q.pp self[member] } } } end
# File lib/pp.rb, line 376 def pretty_print_cycle(q) q.text sprintf("#<struct %s:...>", PP.mcall(self, Kernel, :class).name) end
Invokes the block passing in successive elements from struct,
returning an array containing those elements for which the block returns a
true value (equivalent to Enumerable#select
).
Lots = Struct.new(:a, :b, :c, :d, :e, :f) l = Lots.new(11, 22, 33, 44, 55, 66) l.select {|v| (v % 2).zero? } #=> [22, 44, 66]
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, rb_struct_size); result = rb_ary_new(); for (i = 0; i < RSTRUCT_LEN(s); i++) { if (RTEST(rb_yield(RSTRUCT_PTR(s)[i]))) { rb_ary_push(result, RSTRUCT_PTR(s)[i]); } } return result; }
Returns the number of instance variables.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.length #=> 3
static VALUE rb_struct_size(VALUE s) { return LONG2FIX(RSTRUCT_LEN(s)); }
Returns the values for this instance as an array.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.to_a[1] #=> "123 Maple, Anytown NC"
static VALUE rb_struct_to_a(VALUE s) { return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_PTR(s)); }
Returns the values for this instance as a hash with keys corresponding to the instance variable name.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.to_h[:address] #=> "123 Maple, Anytown NC"
static VALUE rb_struct_to_h(VALUE s) { VALUE h = rb_hash_new(); VALUE members = rb_struct_members(s); long i; for (i=0; i<RSTRUCT_LEN(s); i++) { rb_hash_aset(h, rb_ary_entry(members, i), RSTRUCT_PTR(s)[i]); } return h; }
Returns the values for this instance as an array.
Customer = Struct.new(:name, :address, :zip) joe = Customer.new("Joe Smith", "123 Maple, Anytown NC", 12345) joe.to_a[1] #=> "123 Maple, Anytown NC"
static VALUE rb_struct_to_a(VALUE s) { return rb_ary_new4(RSTRUCT_LEN(s), RSTRUCT_PTR(s)); }
Returns an array containing the elements in self
corresponding
to the given selector(s). The selectors may be either integer indices or
ranges. See also </code>.select<code>.
a = %w{ a b c d e f } a.values_at(1, 3, 5) a.values_at(1, 3, 5, 7) a.values_at(-1, -3, -5, -7) a.values_at(1..3, 2...5)
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); }