This is a multipart message in MIME format --07557043-POCO-66642815 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable On Wed, 5 Nov 2003 13:27:05 +0900, Simon Kitching wrote: > On Wed, 2003-11-05 at 17:09, Austin Ziegler wrote: > One of the goals of xmldigester is to be able to instantiate and > initialise objects from some input xml without making any changes > to the classes themselves. > Thus if you already have a library of warehouse management > classes, I can write some rules that can take an xml description > of the contents of that warehouse and build appropriately > configured objects without changing that library. And once the > parsing is complete, the resulting tree of objects should look no > different than one created using normal calls to the library API. You're right, they shouldn't. But if your warehouse management classes don't do what they can to ensure their data integrity, then there's a problem with the classes -- not with the XML library. I'm not trying to be difficult here; just pointing out that I think you're trying to fix the problem from the wrong end. > In addition, the approach you suggest is quite labour-intensive; > for every attribute, a "wrapper" method needs to be written. Not really. See below for one option. The way that I've implemented this makes it easy to drop into place. > I feel Ryan's MetaTags approach is easier to use; a simple string > format can be used to document the types to which strings from the > xml input should be converted before assignment to various > attributes. Ryan's MetaTags really does not do anything different than I'm talking about except that it could can it (although I think StrongTyping does that better). See, you can make a simple metamethod that wraps this for you and it becomes a relatively simple change to make it "simple." If you don't want to create a method for each, define a proc and use the following extension to attr_accessor. (Does anyone else think that this is a good idea? I do. I'd love to see it become part of "standard" Ruby.) class Module alias_method :__attr_accessor, :attr_accessor def attr_accessor(block, *symbols) if block.kind_of?(Symbol) symbols.unshift(block) __attr_accessor(*symbols) else symbols.each do |get| var = "@#{get}" set = "#{get}=".intern self.class_eval do define_method(get) { self.instance_variable_get(var) } define_method(set) { |*val| self.instance_variable_set(var, block.call(*val)) } end end end end end class Foo attr_accessor :item attr_accessor proc { |x| x.to_i }, :item_id attr_accessor proc { |x| x.to_f }, :cost end f = Foo.new f.item = "item" f.item_id = "37352" f.cost = "12.50" p f.inspect (I've actually attached a further enhanced and unit-tested version of this extension to this message. If anyone wants to add to the test cases, such as for array parameters, feel free.) On Wed, 5 Nov 2003 14:06:55 +0900, Simon Kitching wrote: >> As you can see, any code that that relies on this kind of "type >> checking" in Ruby is naive. Worse than that, the desire to >> shoe-horn Ruby into Java-like "strictness" can blind the user >> into missing the point, and therefore the full benefit, of what >> Ruby has to offer. > Yep. I can't see how to offer what I want without some type info, > though. > > If you look at my original example, how to I know that > item.cost = '3.50' > is wrong (the instance will eventually trigger some error), and > item.cost = '3.50'.to_f > is the right thing to do? > > With Java it just happens magically and "does the right thing" > (except in the abstract type case mentioned above). Surely Ruby > can't be inferior :-). It isn't inferior, and you don't need type info. Remember -- an object should validate or transform its own data. Using the method I described above, it becomes "cheap" to fix the problem as I see it without imposing a requirement for the use of type strictness that IMO, is a really bad idea for a Ruby library. > Yep. Tedious indeed. And as mentioned in my reply to Austin, it is a goal > to instantiate and initialise objects without requiring any changes to > their code. Digester manages this fine. Digest manages this because the objects in Java automatically take care of their own type. Sort of. The compiler prevents you from using any type except those that are signaled. If you have not massaged your own type attributes to make sure that they are receiving valid data, then there's something wrong with the classes themselves. NOT with Ruby for not providing type strictness. In several libraries I've written, I have either rejected types that I can't handle, or I have transformed types into what I can handle, or I have operated on the data and thrown an error because it can't be handled. I prefer being proactive, so I choose the former two methods most often. > The problem is : in order to automatically generate the filters, I need > to know what type of object is required for each attribute. Full circle! Again, not really. The class you're building has to know what it expects. It's an inverse of what you'd expect from a statically typed language, but I have found it easier to understand in the long run. > That code in the Person class you show above could only be generated > because a human "knew" that Integer was an appropriate type to store into > the age attribute (and String was not). I just want to represent that > info in the code somehow... But defining the Person class to convert its "age" parameter into an Integer does exactly that. Not as meta-data, to be sure, but in the only way that matters, IMO. -austin -- austin ziegler * austin / halostatue.ca * Toronto, ON, Canada software designer * pragmatic programmer * 2003.11.05 * 02.12.59 --07557043-POCO-66642815 Content-Type: application/octet-stream; name="extend.rb" Content-Transfer-Encoding: Base64 Content-Disposition: attachment; filename="extend.rb" Y2xhc3MgTW9kdWxlCiAgYWxpYXNfbWV0aG9kIDpfX2F0dHJfYWNjZXNzb3IsIDphdHRyX2FjY2Vz c29yCgogIGRlZiBfX2F0dHJfY29udmVydG9yKHN5bWJvbCwgY29udmVydG9yKQogICAgdmFyID0g IkAje3N5bWJvbH0iCiAgICBzZXQgPSAiI3tzeW1ib2x9PSIuaW50ZXJuCiAgICBkZWZpbmVfbWV0 aG9kKHN5bWJvbCkgeyBzZWxmLmluc3RhbmNlX3ZhcmlhYmxlX2dldCh2YXIpIH0KCiAgICBpZiBj b252ZXJ0b3Iua2luZF9vZj8oU3ltYm9sKQogICAgICBkZWZpbmVfbWV0aG9kKHNldCkgeyB8KnZh bHwgdmFsID0gKnZhbDsgc2VsZi5pbnN0YW5jZV92YXJpYWJsZV9zZXQodmFyLCB2YWwuc2VuZChj b252ZXJ0b3IpKSB9CiAgICBlbHNlCiAgICAgIGRlZmluZV9tZXRob2Qoc2V0KSB7IHwqdmFsfCBz ZWxmLmluc3RhbmNlX3ZhcmlhYmxlX3NldCh2YXIsIGNvbnZlcnRvci5jYWxsKCp2YWwpKSB9CiAg ICBlbmQKICBlbmQKICBwcml2YXRlIDphdHRyX2NvbnZlcnRvcgoKICBkZWYgYXR0cl9hY2Nlc3Nv cihibG9jaywgKnN5bWJvbHMpCiAgICBpZiBibG9jay5raW5kX29mPyhTeW1ib2wpCiAgICAgIHN5 bWJvbHMudW5zaGlmdChibG9jaykKICAgICAgX19hdHRyX2FjY2Vzc29yKCpzeW1ib2xzKQogICAg ZWxzaWYgYmxvY2sua2luZF9vZj8oSGFzaCkKICAgICAgYmxvY2suZWFjaCB7IHxzeW1zLCBjb252 ZXJ0b3J8IHN5bXMuZWFjaCB7IHxnZXR8IF9fYXR0cl9jb252ZXJ0b3IoZ2V0LCBjb252ZXJ0b3Ip IH0gfQogICAgZWxzZQogICAgICBzeW1ib2xzLmVhY2ggeyB8Z2V0fCBfX2F0dHJfY29udmVydG9y KGdldCwgYmxvY2spIH0KICAgIGVuZAogIGVuZAplbmQKCmlmIF9fRklMRV9fID09ICQwCiAgcmVx dWlyZSAndGVzdC91bml0JwoKICBjbGFzcyBUZXN0Q29udmVydG9ycyA8IFRlc3Q6OlVuaXQ6OlRl c3RDYXNlCiAgICBkZWYgdGVzdF9ub3JtYWwKICAgICAgZiA9IG5pbAogICAgICBhc3NlcnRfbm90 aGluZ19yYWlzZWQgZG8KICAgICAgICBpdGVtID0gQ2xhc3MubmV3CiAgICAgICAgaXRlbS5pbnN0 YW5jZV9ldmFsIGRvCiAgICAgICAgICBhdHRyX2FjY2Vzc29yIDpjb3N0LCA6aXRlbSwgOm5hbWUK ICAgICAgICBlbmQKICAgICAgICBmID0gaXRlbS5uZXcKICAgICAgICBmLml0ZW0gPSAiMyIKICAg ICAgICBmLm5hbWUgPSAiICBmb28gICIKICAgICAgICBmLmNvc3QgPSAiMy41MiIKICAgICAgZW5k CiAgICAgIGFzc2VydF9lcXVhbCgiMyIsIGYuaXRlbSkKICAgICAgYXNzZXJ0X2VxdWFsKCIgIGZv byAgIiwgZi5uYW1lKQogICAgICBhc3NlcnRfZXF1YWwoIjMuNTIiLCBmLmNvc3QpCiAgICBlbmQK CiAgICBkZWYgdGVzdF9wcm9jCiAgICAgIGYgPSBuaWwKICAgICAgYXNzZXJ0X25vdGhpbmdfcmFp c2VkIGRvCiAgICAgICAgaXRlbSA9IENsYXNzLm5ldwogICAgICAgIGl0ZW0uaW5zdGFuY2VfZXZh bCBkbwogICAgICAgICAgYXR0cl9hY2Nlc3NvciBwcm9jIHsgfHh8IHgudG9fZiB9LCA6Y29zdAog ICAgICAgICAgYXR0cl9hY2Nlc3NvciBwcm9jIHsgfHh8IHgudG9faSB9LCA6aXRlbQogICAgICAg ICAgYXR0cl9hY2Nlc3NvciBwcm9jIHsgfHh8IHgudG9fcy5zdHJpcCB9LCA6bmFtZQogICAgICAg IGVuZAogICAgICAgIGYgPSBpdGVtLm5ldwogICAgICAgIGYuaXRlbSA9ICIzIgogICAgICAgIGYu bmFtZSA9ICIgIGZvbyAgIgogICAgICAgIGYuY29zdCA9ICIzLjUyIgogICAgICBlbmQKICAgICAg YXNzZXJ0X2VxdWFsKDMsIGYuaXRlbSkKICAgICAgYXNzZXJ0X2VxdWFsKCJmb28iLCBmLm5hbWUp CiAgICAgIGFzc2VydF9lcXVhbCgzLjUyLCBmLmNvc3QpCiAgICBlbmQKCiAgICBkZWYgdGVzdF9o YXNoCiAgICAgIGYgPSBuaWwKICAgICAgYXNzZXJ0X25vdGhpbmdfcmFpc2VkIGRvCiAgICAgICAg aXRlbSA9IENsYXNzLm5ldwogICAgICAgIGl0ZW0uaW5zdGFuY2VfZXZhbCBkbwogICAgICAgICAg YXR0cl9hY2Nlc3NvciBbOmNvc3RdID0+IDp0b19mLCBbOml0ZW1dID0+IDp0b19pLCBbOm5hbWVd ID0+IHByb2MgeyB8eHwgeC50b19zLnN0cmlwIH0KICAgICAgICBlbmQKICAgICAgICBmID0gaXRl bS5uZXcKICAgICAgICBmLml0ZW0gPSAiMyIKICAgICAgICBmLm5hbWUgPSAiICBmb28gICIKICAg ICAgICBmLmNvc3QgPSAiMy41MiIKICAgICAgZW5kCiAgICAgIGFzc2VydF9lcXVhbCgzLCBmLml0 ZW0pCiAgICAgIGFzc2VydF9lcXVhbCgiZm9vIiwgZi5uYW1lKQogICAgICBhc3NlcnRfZXF1YWwo My41MiwgZi5jb3N0KQogICAgZW5kCiAgZW5kCmVuZAo-07557043-POCO-66642815--