From: Jim Menard Date: 2005-11-23T22:12:18+09:00 Subject: Re: Ron Jeffries implementing Extended Sets ------=_Part_6998_25250935.1132751532399 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Content-Disposition: inline I sent Ron the following two files to Ron a couple of days ago, and received a nice reply. This quick-and-dirty implementation only uses an Array to store objects. Ron pointed out that it will be much more interesting if the objects were stored in files, perhaps mapping objects to things like fixed-length records. Jim -- Jim Menard, jim.menard@gmail.com, jimm@io.com http://www.io.com/~jimm "Any sufficiently complicated C or Fortran program contains an ad hoc informally-specified bug-ridden slow implementation of half of Common Lisp.= " -- Greenspun's Tenth Rule of Programming ------=_Part_6998_25250935.1132751532399 Content-Type: application/octet-stream; name=record_set.rb Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="record_set.rb" # http://www.xprogramming.com/xpmag/xstSomeThoughts.htm require 'delegate' class Object # Return true if self's instance variables match def xst_match(restrict_query_obj) restrict_query_obj.instance_variables.each { | name | restrict_value = restrict_query_obj.instance_variable_get(name) return false if restrict_value != nil && !(restrict_value === self.instance_variable_get(name)) } return true end end class RecordSet < DelegateClass(Array) def initialize(array=[]) super(array) end def restrict(*restrictions) return select { | item | restrictions.detect { | restriction | item.xst_match(restriction) } } end end ------=_Part_6998_25250935.1132751532399 Content-Type: application/octet-stream; name=test.rb Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="test.rb" #!/usr/bin/env ruby require 'test/unit' require 'test/unit/ui/console/testrunner' # Only required on Windows require 'record_set' # For testing: a class with a few attributes. class Something attr_accessor :name, :email, :age # Not required for XST to work def initialize(name=nil, email=nil, age=nil) @name, @email, @age = name, email, age end def to_s "name = #@name, age = #@age, email = #@email" end end class RecordSetTest < Test::Unit::TestCase def setup @rs = RecordSet.new @rs << (@jimmy = Something.new('Jimmy Neutron', 'jimmy@example.com', 12)) @rs << Something.new('Spongebob Squarepants') @rs << Something.new(nil, 'foo@example.com', 22) end def test_match_self @rs.each { | obj | assert obj.xst_match(obj) } end def test_match_nil assert nil.xst_match(nil) assert @jimmy.xst_match(nil) end def test_not_match_nil assert !nil.xst_match(@jimmy) end def test_match assert_equal 'Jimmy Neutron', @jimmy.name assert @jimmy.xst_match(Something.new) # All nil values assert @jimmy.xst_match(Something.new('Jimmy Neutron')) assert @jimmy.xst_match(Something.new(nil, 'jimmy@example.com')) assert @jimmy.xst_match(Something.new(nil, nil, 12)) assert @jimmy.xst_match(Something.new('Jimmy Neutron', 'jimmy@example.com')) assert @jimmy.xst_match(Something.new('Jimmy Neutron', 'jimmy@example.com', 12)) assert @jimmy.xst_match(Something.new(nil, 'jimmy@example.com', 12)) assert @jimmy.xst_match(Something.new('Jimmy Neutron', nil, 12)) end def test_not_match assert !@jimmy.xst_match(Something.new('Jimmy Neutron', nil, 99)) assert !@jimmy.xst_match(Something.new('Jimmy Neutron', 'jimmy@example.com', 99)) assert !@jimmy.xst_match(Something.new(/N..tron/, nil, 99)) end def test_regex_match assert @jimmy.xst_match(Something.new(/N..tron/)) end def test_simple_restrict found = @rs.restrict(Something.new('Jimmy Neutron')) assert_not_nil found assert_equal 1, found.length assert_equal 'Jimmy Neutron', found[0].name end def test_restrict_array found = @rs.restrict(Something.new('Jimmy Neutron'), Something.new(nil, 'foo@example.com')) assert_not_nil found assert_equal 2, found.length # These tests rely upon the ordering of the records in the record set assert_equal 'Jimmy Neutron', found[0].name assert_equal 'foo@example.com', found[1].email end def test_regex_restrict found = @rs.restrict(Something.new(/Ne..ron/)) assert_not_nil found assert_equal 1, found.length assert_equal 'Jimmy Neutron', found[0].name end def test_regex_array_restrict found = @rs.restrict(Something.new(/Ne..ron/), Something.new(nil, 'foo@example.com')) assert_not_nil found assert_equal 2, found.length # These tests rely upon the ordering of the records in the record set assert_equal 'Jimmy Neutron', found[0].name assert_equal 'foo@example.com', found[1].email end def test_length assert_equal 3, @rs.length end end # This is required on Windows; not on *nix if __FILE__ == $0 Test::Unit::UI::Console::TestRunner.run(RecordSetTest) end ------=_Part_6998_25250935.1132751532399--