class DataStruct
Constants
- VERSION
Public Class Methods
A more ideomatic way of calling +new(*array)+
# File lib/datastruct.rb, line 45 def self.from_array(array) self.new(*array) end
A more ideomatic way of calling +new(**hash)+
# File lib/datastruct.rb, line 52 def self.from_hash(hash) hash = symbol_keys(hash) self.new(**hash) end
Makes sure +@data+ is set before initialize
is called
The +@data+ instance variable is set to a hash with each key in PROPERTIES
set to nil
before the constructor is called. This avoids a host of annoying issues when users override the constructor.
# File lib/datastruct.rb, line 23 def self.new(*args, &block) instance = allocate() data_container = {} if instance.class.const_defined? :PROPERTIES properties = instance.class::PROPERTIES else properties = [] end properties.each { |key| data_container[key] = nil } instance.instance_variable_set(:@data, data_container) instance.send(:initialize, *args, &block) return instance end
# File lib/datastruct.rb, line 58 def initialize(*args, **kwargs) self.update(*args) self.update(**kwargs) end
Private Class Methods
# File lib/datastruct.rb, line 283 def self.symbol_keys(hash) Hash[hash.each_pair.map { |x| [x[0].to_sym, x[1]] }] end
Public Instance Methods
Delegates to +Hash#==+
# File lib/datastruct.rb, line 66 def ==(other) if not other.instance_of? self.class false else @data == other.instance_variable_get(:@data) end end
Does the same as #get
, but returns nil instead of raising KeyError
@param [String, Symbol] key @return [Object]
# File lib/datastruct.rb, line 113 def [](key) get(key) rescue KeyError nil end
Returns a shallow copy
# File lib/datastruct.rb, line 87 def dup self.class.from_hash(@data.dup) end
Delegates to +Hash#each+
@see ruby-doc.org/core-2.0.0/Hash.html#method-i-each Hash#each @overload each
# File lib/datastruct.rb, line 80 def each(*args, &block) @data.each(*args, &block) end
Returns a property using its getter method
@param [String, Symbol] property @raise [KeyError] on invalid property name
# File lib/datastruct.rb, line 97 def get(property) property = property.to_sym if not valid_property? property fail KeyError, "Property not defined: #{property}" end self.send(property) end
Produces a text representation of the object
# File lib/datastruct.rb, line 122 def inspect text = "#<#{self.class.to_s}" text << self.class::PROPERTIES.reduce("") { |a, key| a << " #{key}=#{self.get(key).inspect}" } text << ">" return text end
Delegates to +Hash#merge+
@return [Hash]
# File lib/datastruct.rb, line 277 def merge(other) @data.merge(other) end
# File lib/datastruct.rb, line 134 def respond_to?(method_name) if valid_property?(method_name) or valid_property?(getter(method_name)) true else super end end
Sets the value of a property using its setter method
@param [String, Symbol] property @param [Object] value @raise [KeyError] on invalid property name
# File lib/datastruct.rb, line 149 def set(property, value) property = property.to_sym if not valid_property? property fail KeyError, "Property not defined: #{property}" end self.send(setter(property), value) end
Returns the properties of the object as an array
@return [Array]
# File lib/datastruct.rb, line 166 def to_array self.class::PROPERTIES.map { |name| @data[name] } end
Returns the properties of the object as a hash
@param [Boolean] string_keys Return keys as strings instead of symbols @param [Boolean] deep Go deep and serialize all DataStruct
instances found
@return [Hash]
# File lib/datastruct.rb, line 180 def to_hash(string_keys: false, deep: false) # Builds a hash using property getters. This allows getters to override the # output of this function. data = Hash[self.class::PROPERTIES.map { |key| [key, self.get(key)] }] hashify = lambda { |obj| if obj.is_a? DataStruct and deep return obj.to_hash(string_keys: string_keys, deep: deep) elsif obj.is_a? Hash out = {} obj.each_pair { |key, value| # Only stringify the keys of the *top level* of the structure. We have # no business messing with the keys of nested hashes. key = key.to_s if string_keys and obj.equal? data out[key] = hashify[value] } return out elsif obj.is_a? Array return obj.map { |x| hashify[x] } else return obj end } return data if not string_keys and not deep return hashify[data] end
Dumps the properties of this object to JSON using Ruby's JSON module
@note JSON must be loaded for this function to work @see www.ruby-doc.org/stdlib-2.0/libdoc/json/rdoc/JSON.html JSON @return [String]
# File lib/datastruct.rb, line 223 def to_json(*args) self.to_hash.to_json(*args) end
Dumps the properties of this object to YAML using Ruby's YAML module
@note YAML must be loaded for this function to work @see ruby-doc.org/stdlib-2.0.0/libdoc/yaml/rdoc/YAML.html YAML @return [String]
# File lib/datastruct.rb, line 234 def to_yaml(*args) self.to_hash.to_yaml(*args) end
Updates the values of this object's properties
Both positional arguments and keyword arguments are used to update the property values of the object. Positional arguments should be passed in the same order as the defined properties.
@note Keyword arguments override posisional arguments @raise [ArgumentError] on invalid property names @return nil
# File lib/datastruct.rb, line 249 def update(*args, **kwargs) if args.length > self.class::PROPERTIES.length x = args.length y = self.class::PROPERTIES.length msg = "Too many arguments (you passed #{x} arguments for #{y} properties)" fail ArgumentError, msg end hash = Hash[self.class::PROPERTIES[0...args.length].zip(args)] hash.update(kwargs) hash.each_pair { |key, value| begin self.set(key, value) rescue KeyError => e fail ArgumentError, "Invalid property: #{key}" end } nil end
Private Instance Methods
@example
getter(:foo=) # => :foo getter(:foo) # => :foo
# File lib/datastruct.rb, line 339 def getter(sym) if is_setter?(sym) sym.to_s[0..-2].to_sym else sym end end
@example
is_setter?(:foo) # => false is_setter?(:foo=) # => true
# File lib/datastruct.rb, line 322 def is_setter?(sym) sym.to_s.end_with?("=") end
This makes the struct accept the defined properties as instance methods
# File lib/datastruct.rb, line 290 def method_missing(name, *args, &block) property = name set = false if is_setter?(property) property = getter(name) set = true end if valid_property? property if set @data[property] = args.first else @data[property] end else super end end
@example
setter(:foo) # => :foo=
# File lib/datastruct.rb, line 330 def setter(sym) (sym.to_s + "=").to_sym end
Returns true if prop
is a valid property
# File lib/datastruct.rb, line 313 def valid_property?(prop) self.class::PROPERTIES.include? prop end