Leslie Viljoen
6/4/2008 6:53:00 PM
Holy macaroni, thanks for these replies!
What I am trying to accomplish here is the optional modification of
core classes. So my CRC lib can handle useful calculations, and
optionally add convenient methods to String and Fixnum too.
That way people can have the convenience if they like, but they must
explicitly authorise it with String.send(:include ..). It seems like a
good plan to me, but the lack of a public String.include() method
makes me think this is a very rare plan.
These strings with CRC's on the ends are coming in from sockets, and I
have to check them, extract them, use them and then put CRC's on the
end of the replies before sending them out. In this case it's quite
nice to do:
begin
msg, sender = @socket.recvfrom(1500)
end while (!msg.crc16_ok?)
msg.remove_terminating_crc16!
...
- but it's true that I might forget to remove that crc. So perhaps
decend from String like you say:
begin
msg, sender = @socket.recvfrom(1500)
msg = CrcString(msg)
end while (!msg.crc16_ok?)
(now use msg directly)
- and I'd know immediately if I'd forgotten to construct the CrcString
because crc16_ok? would fail.
And then a third option would be to modify Socket:
class Socket
def recv_checked(n)
CrcString(recvfrom(n))
end
end
..which I'd again attempt by providing a module that I'd
Socket.send(:include, CrcSocket)
Or once again I could override both String and Socket to make
CrcString and CrcSocket which returns CrcStrings. You're never short
on options with Ruby!
Les
On 6/4/08, David Masover <ninja@slaphack.com> wrote:
> On Wednesday 04 June 2008 08:49:48 Leslie Viljoen wrote:
>> Sorry to beat a dead horse, but to confirm: the only way to mix a
>> module into an already
>> existing class it to reopen it with something (ugly) like this:
>>
>> class String; include Crc; end
>>
>> (1) Is that right?
>
> Short answer: You'll have to mess with it dynamically, but that is far from
> the only syntax to do so. Other obvious ones:
>
> String.class_eval { include Crc }
> String.send :include, Crc
>
> And there are always stranger things like:
>
> "foo".class.class_eval { include Crc }
>
>> And then to mix a module into an instantiated object, you can use
>> extend, and that
>> modifies the one object.
>
> Yes, but keep in mind: "include"ing a module into a class will affect all
> existing and future instances of that class, and of any subclasses. So
> you're
> probably not going to extend if you include.
>
>> (2) Philosophically, is there any reason why
>> extend can't be used
>> in the same way on classes? (ie. String.extend(Crc))
>
> As others have said, they do different things -- include adds instance
> methods
> to a class, and extend adds methods to an object.
>
> It's a tricky concept, but remember that classes are objects, too. So:
>
> some_string.extend(Crc) # will define some_string.crc16_ok?
> String.extend(Crc) # will define String.crc16_ok?
>
> So, extend works on the actual object you use it on, and include works on
> any
> instances of it. You could do this, for example:
>
> Class.send :include, Crc
> # Now all classes will have a crc16_ok? class method, for example:
> String.crc16_ok?
>
> That's probably not what you want.
>
>> ...is that the right way to make this module work properly? Or are
>> some modules just not suitable for extend?
>
> I think that comes down to personal philosophy -- I haven't seen (or
> used) 'extend' a whole lot. It seems most useful when you'd only want to
> apply it to a single object, and then, I'd usually use instance_eval
> instead.
>
> On the other hand, including it into String means you're affecting all
> Strings, and polluting String's method namespace. It means that no one else
> can define String#get_crc16.
>
> The other way would be to use a separate class -- either something which
> contains both a String and a CRC (as Robert suggested), or something which
> inherits from String.
>
> And either way, depending on how much work you want to do, you could always
> override all methods on String which return a String, and force them to
> either return an extended String, or return a CrcString, depending on how
> you
> decide to do it.
>
>
--
[we need your code-fu] : www.zadic.co.za