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--