lib/facet/superstruct.rb in facets-0.7.2 vs lib/facet/superstruct.rb in facets-0.9.0
- old
+ new
@@ -1,241 +2 @@
-#:title: SuperStruct
-#--
-# SuperStruct
-# v 1.0
-#
-# Copyright (c) 2005 Hal Fulton
-#
-# Ruby License
-#
-# This module is free software. You may use, modify, and/or redistribute this
-# software under the same terms as Ruby.
-#
-# This program is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-# FOR A PARTICULAR PURPOSE.
-#
-#
-# $Id: superstruct.rb,v 1.0 2005/04/28 03:10:10 transami Exp $
-#
-# ==========================================================================
-# Revision History ::
-# YYYY.MM.DD Ver. Dev. Description
-# --------------------------------------------------------------------------
-# 2005.04.28 1.0 Trans * Minor modifications to documentation.
-# ==========================================================================
-#++
-
-# = Description
-#
-# This is an easy way to create Struct-like classes; it converts easily
-# between hashes and arrays, and it allows OpenStruct-like dynamic naming
-# of members.
-#
-# Unlike Struct, it creates a "real" class, and it has real instance variables
-# with predictable names.
-#
-# A basic limitation is that the hash keys must be legal method names (unless
-# used with send()).
-#
-# Basically, ss["alpha"], ss[:alpha], ss[0], and ss.alpha all mean the same.
-#
-# == Usage
-#
-# To do.
-#
-# == Author(s)
-#
-# * Hal Fulton
-#
-
-class SuperStruct
-
- def SuperStruct.new(*args)
- @table = []
- @setsyms = [] # Setter symbols
- klass = Class.new
- if (args.size == 1) && (args[0].is_a? Array)
- args = args[0]
- end
- strs = args.map {|x| x.to_s }
- args.each_with_index do |k,i|
- case
- when (! [String,Symbol].include? k.class)
- raise ArgumentError, "Need a String or Symbol"
- when (strs[i] !~ /[_a-zA-Z][_a-zA-Z0-9]*/)
- raise ArgumentError, "Illegal character"
- end
- k = k.intern if k.is_a? String
- @table << k
- @setsyms << (k.to_s + "=").intern
- klass.instance_eval { attr_accessor k }
- end
-
- setsyms = @setsyms
- table = @table
- vals = @vals
- klass.class_eval do
- attr_reader :singleton
- define_method(:initialize) do |*vals|
- n = vals.size
- m = table.size
- case
- when n < m
- # raise ArgumentError, "Too few arguments (#{n} for #{m})"
- # Never mind... extra variables will just be nil
- when n > m
- raise ArgumentError, "Too many arguments (#{n} for #{m})"
- end
- setsyms.each_with_index do |var,i|
- self.send(var,vals[i])
- end
- end
- define_method(:pretty_print) do |q| # pp.rb support
- q.object_group(self) do
- q.seplist(self.members, proc { q.text "," }) do |member|
-# self.members.each do |member|
-# q.text "," # unless q.first?
- q.breakable
- q.text member.to_s
- q.text '='
- q.group(1) do
- q.breakable ''
- q.pp self[member]
- end
- end
- end
- end
- define_method(:inspect) do
- str = "#<#{self.class}:"
- table.each {|item| str << " #{item}=#{self.send(item)}" }
- str + ">"
- end
- define_method(:[]) do |*index|
- case index.map {|x| x.class }
- when [Fixnum]
- self.send(table[*index])
- when [Fixnum,Fixnum], [Range]
- table[*index].map {|x| self.send(x)}
- when [String]
- self.send(index[0].intern)
- when [Symbol]
- self.send(index[0])
- else
- raise ArgumentError,"Illegal index"
- end
- end
- define_method(:[]=) do |*index|
- value = index[-1]
- index = index[0..-2]
- case index.map {|x| x.class }
- when [Fixnum]
- self.send(table[*index])
- when [Fixnum,Fixnum], [Range]
- setsyms[*index].map {|x| self.send(x,value) }
- when [String]
- self.send(index[0].intern,value)
- when [Symbol]
- self.send(index[0],value)
- else
- raise ArgumentError,"Illegal index"
- end
- end
- define_method(:to_a) { table.map {|x| eval("@"+x.to_s) } }
- define_method(:to_ary) { to_a }
- define_method(:members) { table.map {|x| x.to_s } }
- define_method(:to_struct) do
- mems = table
- Struct.new("TEMP",*mems)
- # Struct::TEMP.new(*vals) # Why doesn't this work??
- data = mems.map {|x| self.send(x) }
- Struct::TEMP.new(*data)
- end
- define_method(:to_hash) do
- hash = {}
- table.each do |mem|
- mem = mem.to_s
- hash.update(mem => self.send(mem))
- end
- hash
- end
- define_method(:set) {|h| h.each_pair {|k,v| send(k.to_s+"=",v) } }
-
- # Class methods...
-
- @singleton = class << self
- self
- end
-
- @singleton.instance_eval do
- define_method(:members) do
- table.map {|x| x.to_s }
- end
- me = self
- define_method(:attr_tester) do |*syms|
- syms.each {|sym| alias_method(sym.to_s+"?",sym) }
- end
- end
-
- end
- klass
- end
-
-
- def SuperStruct.open(*args)
- klass = SuperStruct.new(*args)
- table = @table
- setsyms = @setsyms
- table = @table
- klass.class_eval do
- define_method(:method_missing) do |meth, *args|
- mname = meth.id2name
- if mname =~ /=$/
- getter = mname.chop
- setter = mname
- elsif mname =~ /\?$/
- raise NoMethodError # ?-methods are not created automatically
- else
- getter = mname
- setter = mname + "="
- end
- gsym = getter.intern
- ssym = setter.intern
- ivar = "@" + getter
- setsyms << setter
- table << getter
- len = args.length
- if mname == getter
- klass.class_eval do # getter
- define_method(getter) do
- instance_variable_get(ivar)
- end
- end
- else
- klass.class_eval do # setter
- define_method(setter) do |*args|
- if len != 1
- raise ArgumentError, "Wrong # of arguments (#{len} for 1)",
- caller(1)
- end
- instance_variable_set(ivar,args[0])
- instance_variable_get(ivar)
- end
- end
- end
- if mname == setter
- self.send(setter,*args)
- else
- if len == 0
- self.send(getter)
- else
- raise NoMethodError, "Undefined method '#{mname}' for #{self}",
- caller(1)
- end
- end
- end
- end
- klass
- end
-
-end
-
+require 'mega/superstruct.rb'
\ No newline at end of file