On Tue, 2006-02-28 at 20:18 +0900, Mc Osten wrote: > On Tue, 28 Feb 2006 07:57:19 +0900, Ross Bamford wrote: > > > Answering a later question you had, the above singleton method could be > > defined like: > > > > class << test2 > > def size > > 10 > > end > > end > > Quite interesting. I understand its semantic, but not its syntax. That is > to say "class" is a keyword. So this is a "new syntax"? > 'class' here is doing what you expect it to do - defining a class. But the class that's being defined is a singleton class belonging to the object on the rhs of the <<. Basically, objects in ruby can have two classes - the class of which they are an instance, and a singleton class that relates to (and supplies methods for) just that object. This syntax is for use with the latter. > I think that since I can << array the syntax is not *that* new. Still quite > impressive... well as I said > > Every time I do > > class << something > code > end > > I'm evaluating "code" in the "something" context? No.. this is not correct. > I understand the example, but I'm not able to make abstraction. > Not quite. You're actually evaluating it in the context of an instance of Class, that being the singleton class for 'something'. Try this: class << something p self end Since almost everything in Ruby is an expression, you can also do this: class SomeClass def singclass class << self self end end end s = SomeClass.new # => #<SomeClass:0xb7e85d9c> s.singclass # => #<Class:#<SomeClass:0xb7e85d9c>> Notice how the Class returned relates to just that SomeClass instance. (this for the sake of example, if you were to need it you'd probably define it elsewhere). > I also suppose i can > > module << something > code > end > No, singleton modules aren't (AFAIK) supported. > So I suppose than > > class Something > # code > end > > is "synactic sugar" for > > Somtheing = Class::new do > # code > end > Mostly that's true, but there is at least one difference to keep in mind - multiple class SomeClass ... definitions will 'reopen' the existing class and allow new methods to be added: class TooClz def a; "a"; end end # => nil TooClz.new.a # => "a" class TooClz def b; "b"; end end # => nil TooClz.new.a # => "a" TooClz.new.b # => "b" While the assignment here scuppers that (notice Ruby complaining about the constant being already initialized): Clz = Class.new { def a; "a"; end } # => Clz Clz.new.a # => "a" Clz = Class.new { def b; "b"; end } (irb):24: warning: already initialized constant Clz # => Clz Clz.new.a NoMethodError: undefined method `a' for #<Clz:0xb7e7ad34> from (irb):26 > > Well, you can't subclass Class. You can do a bit of this kind of thing > > with Module (a superclass of Class), but bear in mind that class names > > are just like any other constant in Ruby, so you could do > > > > class OtherClass > > def new > > "Aha!" > > end > > end > > > > Foo = OtherClass.new > > > > Foo.class > > # => OtherClass > > > > Foo.new > > # => "Aha!" > > > > which is all very confusing, so probably best not to (outside of a few > > cases you'll find later I guess). > > Well it looks like a factory object, since then if I Foo.new.class I get > (correctly) String. > Exactly, which is kind of how I see classes in Ruby, too (especially since instances can change after instantiation thanks to the singleton class). > > Yes, everything in Ruby is an object, at least from the point of view of > > your Ruby code. > > I knew it was an object. I suppose I can say it is an Object. > Yes, sorry, I meant both object and Object there :) > Then the main question: am I supposed to do this sort of things or is > someone gonna kill me? For example suppose I want to create kind of > synchronized methods (in the Java sense). > Syntactically it is quite beautiful to > > synchronize :foo > > [ and I think in Monitor.synchronize I would alias :foo, define a > synchronized version of foo that wraps the old :foo ] > Yes, you could do something like that: class Module def synchronize(sym) alias_method("__orig_#{sym}", sym) define_method(sym) do |*args| puts "Sync" send("__orig_#{sym}", *args) puts "Done" end end end class SomeClass def syncme(a) puts a end synchronize :syncme end SomeClass.new.syncme("hello") # output: # Sync # hello # done And no, no-one is going to get upset about it (well, no-one who does Ruby anyway). I consider this kind of metaprogrammability to be one of Ruby's sleekest features. Whether your boss, or your customer, or whoever else, gets upset about it depends on too many external factors to predict :) As you mentioned, there are other tools to help with synchronization (e.g. Mutex) - this is just an example of what you _could_ do. > > For most purposes you'll want to define on Module instead, which allows > > your method in both class and module definition contexts. > > I never thought to modules that way. I'm quite used to Python, where > namespaces are authomatically managed using files. Good. > > > In Ruby Mammal would have to be a module, and I'd say > > self.kind_of?(Mammal) :-) > > Why it would be a Module? In fact I could have functions and methods that > manipulate mammals and I may want to have the forementioned Donkey class to > subclass it. > It's probably a question of Ruby style I've not yet encountered. > The more I thought about this, the more I imagined an enormous class hierarchy representing the natural world, so I decided to stop thinking about it in the end :) > > As you saw, a lot of stuff in Ruby is done with blocks. You can attach > > blocks to method calls, and one of the ways this is done is by declaring > > the final argument with a leading ampersand. > > Yes. And I do like them a lot. It's one of those things you say "how have I > done _before_?". > > But it does work even without... > > def blrun(a) > puts a > yield > end > > def blrun2(a, &b) > puts a > yield b > end > > > blrun("a") { puts "b" } > blrun2("a") { puts "b" } > > I suppose it is useful if you want to "give a name" to the block. Am I > correct? 'yield' is usually the way I'd recommend you go, but yes, sometimes you need to do something with the block other than call it right away. The & can also be used with block methods to allow an existing Proc to be used as the method's block, e.g. blk = lambda { puts "b" } blrun("a", &blk) This comes in handy too when you want to pass a block attached to one method to another method. (Aside, the 'yield b' in your second example above will actually pass the block as an argument to itself). > > Well, in Ruby functions are methods :). > > Whose methods are them? I suppose it should be Object or maybe Kernel > (which in fact should be the same since Object includes Kernel, right?) > > But I tried to define a method and call it with Object.method and gives > error... > Top-level 'functions' are private methods on Object (I was sure it was Kernel but it doesn't appear so): def amethod "Hey!" end p Object.private_instance_methods.include?('amethod') # => true Object.new.send(:amethod) # => "Hey!" Since they're private, and on Object, you get the expected behaviour that you can only call them with no receiver, and from anywhere. -- Ross Bamford - rosco / roscopeco.REMOVE.co.uk