Class: StructX

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/structx.rb,
lib/structx/version.rb

Overview

StructX is an extension of Ruby standard Struct. The diffences are that 1) the constructor handles hash table as key-value pairs, 2) you can specify members as statements, and 3) you can set default values of member. StructX’s API is compatible with Struct.

Examples:

Constructor with hash table

StructX.new(:x, :y, :z).new(x: 1, y: 2, z: 3) #=> #<struct x=1, y=10, z=100>

Member sentences

class A < StructX
  member :x
  member :y
  member :z
end
A.new(1, 2, 3) #=> #<struct A x=1, y=2, z=3>

Default values

class B < StructX
  member :x
  member :y, default: 10
  member :z, default: 100
end
B.new(1) # => #<struct B x=1, y=10, z=100>

Constant Summary collapse

VERSION =

version of StructX

"0.1.3"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*values) ⇒ StructX

See Struct.new.



121
122
123
124
125
126
127
128
# File 'lib/structx.rb', line 121

def initialize(*values)
  if values.first.kind_of?(Hash) and values.size == 1
    @value = __build__(values.first)
  else
    raise ArgumentError.new("struct size differs #{values}  #{members} ") if values.size > members.size
    @value = __build__(members.zip(values))
  end
end

Class Method Details

.[]Object

Same as Struct[].



33
# File 'lib/structx.rb', line 33

alias :[] :new

.default_valuesHash{Symbol=>Object}

Return default values.

Returns:

  • (Hash{Symbol=>Object})

    default values



90
91
92
93
94
# File 'lib/structx.rb', line 90

def default_values
  @__member__.inject({}) do |tbl, (key, val)|
    tbl.tap {|x| x[key] = val[:default] if val.has_key?(:default)}
  end
end

.immutable(b = true) ⇒ Object



96
97
98
# File 'lib/structx.rb', line 96

def immutable(b=true)
  @immutable = b
end

.immutable?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/structx.rb', line 100

def immutable?
  @immutable
end

.member(name, data = {}) ⇒ Object

Add member into structure.

Parameters:

  • name (Symbol)

    member name

  • data (Hash) (defaults to: {})

    member options



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/structx.rb', line 72

def member(name, data={})
  (@__member__ ||= {})[name] = Hash.new.merge(data) # clone the data

  # define member's value reader
  define_method(name) do
    @value[name]
  end

  # define member's value writer
  define_method("%s=" % name) do |val|
    @value[name] = val
  end
end

.membersObject

Same as Struct#members.



62
63
64
# File 'lib/structx.rb', line 62

def members
  (@__member__ ||= {}).keys
end

.new(*args) ⇒ Object

Create a instance or sublcass. If this class has members, create an instance. The case handles hash table as key-value pairs. If this class has no members, create a subclass.

Parameters:

  • args (Array or Hash)

    Same as Struct if args is Array. Consider args as key-value pairs if it is Hash.



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/structx.rb', line 41

def new(*args)
  # create an instance
  return orig_new(*args) if @__member__ and @__member__.keys.size > 0

  # create subclass
  Class.new(StructX).tap do |subclass|
    # class name
    if args.first.kind_of?(String)
      const_set(args.first, subclass)
      args = args.drop(1)
    end

    # set members
    args.each {|m| subclass.member(*m)}

    # this is according to MRI, why yield?
    yield if block_given?
  end
end

.orig_newObject



29
# File 'lib/structx.rb', line 29

alias :orig_new :new

Instance Method Details

#[](idx) ⇒ Object Also known as: get

Same as Struct#[].



131
132
133
134
135
136
137
138
# File 'lib/structx.rb', line 131

def [](idx)
  case idx
  when Integer
    size > idx && -size <= idx ? values[idx] : (raise IndexError.new(idx))
  when Symbol, String
    members.include?(idx.to_sym) ? @value[idx.to_sym] : (raise NameError.new(idx.to_s))
  end
end

#[]=(idx, val) ⇒ Object

Same as Struct#[]=.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/structx.rb', line 144

def []=(idx, val)
  case idx
  when Integer
    if size > idx && -size <= idx
      if not(immutable?)
        @value[members[idx]] = val
      else
        self.class.new(@value.merge(members[idx] => val))
      end
    else
      raise IndexError.new(idx)
    end
  when Symbol, String
    if members.include?(idx.to_sym)
      if not(immutable?)
        @value[idx.to_sym] = val
      else
        self.class.new(@value.merge(idx.to_sym => val))
      end
    else
      raise NameError.new(idx.to_s)
    end
  end
end

#eql?(other) ⇒ Boolean Also known as: ==

Same as Struct#eql?.

Returns:

  • (Boolean)


191
192
193
# File 'lib/structx.rb', line 191

def eql?(other)
  self.class == other.class and @value == other.to_h
end

#inspectObject

Same as Struct#inspect.



180
181
182
183
184
185
186
187
188
# File 'lib/structx.rb', line 180

def inspect
  name = self.class.inspect[0] == "#" ? "" : " " + self.class.inspect
  values = (@value || []).map do |key, val|
    k = (key.to_s[0] == "@" ? ":" : "") + key.to_s
    v = (self == val ? "#<struct %s:...>" % val : val.inspect)
    "%s=%s" % [k, v]
  end
  "#<struct%s %s>" % [name, values.join(", ")]
end

#set(pairs = {}) ⇒ Object

Same as #[]=, but you can set values by hash.



170
171
172
173
174
175
176
177
# File 'lib/structx.rb', line 170

def set(pairs={})
  if not(immutable?)
    pairs.each {|idx, val| self[idx] = val}
    return self
  else
    pairs.inject(self) {|obj, (idx, val)| obj.send("[]=", idx, val)}
  end
end

#to_hObject

Same as Struct#to_h. This method is available in Ruby 1.9 too.



197
198
199
# File 'lib/structx.rb', line 197

def to_h
  @value
end