On Nov 2, 2008, at 3:40 PM, Caleb Clausen wrote:
>>
>
> Sorry for the late reply... I thought this thread had died.
>
> You seem to have left out inline methods, for whatever they're worth.

yeah - if they are really a lot faster it's worth considering but, for  
now, i'll assume they're not...

>
>
> Yes, DSLs in ruby are currently very easy to create and use; I
> anticipate that macros will make DSLs slightly harder to write, but
> easier to use. Ruby DSLs tend to be very natural looking to users, but
> there are often small compromises to usability that won't make much
> sense to domain users, such as the need to begin some words with a
> colon and the need to use 'do' at certain places in the language for
> no apparent reason. If you use macros to define your DSL, it should be
> possible to rid oneself of those features. The situation is already
> pretty good, but macros will make it slightly better. I say "will",
> because, to be honest, at the moment most of the sugary convenience
> features needed for nicer DSLs are not present.
>
>

that's an interesting point.  not sure about it though - if people are  
writing dsls that are not ruby support debugging becomes quite  
difficult.  still, i get it.


>
>> cfp:~ > cat a.rb
>> def context &block
>>   eval 'a += 40', block
>>   block.call
>> end
>
> This is a slick way of getting to your caller's lvars. I would have
> passed in a Binding myself, but this way is probably a little cleaner.
>
> But, the caller must pass a block (or binding) in order to make this
> work. Sometimes, that's not a problem. Sometimes it is. For instance
> (I've run into this) if you want to create an api that works exactly
> like Regexp#match, you'll find that it can't be done. #match sets its
> caller's $~ (a local variable); methods can't do that. In the past,
> I've passed in an optional Binding to handle this case, but
> practically speaking, it was a little too clumsy. Using a block
> instead is a better idea, but you're still changing the interface used
> by your custom  #match. The whole point is to re-use your user's
> existing knowledge about #match.... if he has to remember, "oh yeah,
> and if you use $~ or other matching variables, you have to pass an
> extra block to #match", then that's not an effective re-use of
> existing knowledge; it might as well be a new interface.
>

i wouldn't strictly agree with your analysis, but i do agree that it's  
very hard to do so.  the key is having a context or marker which  
allows the method to be safely used on all objects, this is what tagz  
does for html/xml generation to avoid this - basically methods called  
on any 'self' have easy access to the caller.  for instance

class Object
   def LikeRegexp
     LikeRegexpObject.new(self)
   end
ed

LikeRegexp.match .....


is one workaround.  i do clearly see the value of being inside an  
object though.  however, is the implication that all macros are global?


>> can you show us something that cannot be done using ruby currently,
>> which macros make possible?
>
> A recently requested new feature on ruby-core was __DIR__, which acts
> like __FILE__, but returns the directory containing the current source
> file. As a macro, that is:
>
> macro __DIR__
>  :( File.dirname __FILE__ )
> end
>
> Now maybe (now that I've seen your block-as-binding trick) you can
> actually write this as a method, something like,
>
> def __DIR__(&ctx)
>  File.dirname(eval("__FILE__",ctx))
> end
>
> I have no ruby ATM, and can't check if that works or not, sorry. But
> if it does, it will have to be called like __DIR__{}, instead of
> __DIR__. I'd find that a little jarring.
>

         def __DIR__
           filename = caller[0][/^(.*):/, 1]
           File.expand_path(File.dirname(filename))
         end


stolen wholesale from Ramaze (lot's of good stuff in there ;-) )


> Another recent request was a 'with' keyword, which operates like
> instance_eval, but only changes the default receiver for code in the
> block passed in, and not self as seen by instance variables. I have an
> implementation of this as well (in the example directory of
> RubyMacros), but for various reasons I'm unsatisfied with it right
> now, so I'd rather not post it.
>


def with &block
   scope = Scope.new

   instance_variables.each do |ivar|
     scope.instance_variable_set ivar, instance_variable_get(ivar)
   end

   scope.instance_eval &block
end

hacky?  yes.  but it works well enough for ActionView...



> I'm not claiming that either of these macros is actually a good idea;
> I'm just trying to illustrate the possible.
>
> It's likely that quite a few of the features for ruby that get
> requested could actually be implemented by macros. It's probably
> appropriate that most of these requests are rejected; we don't really
> need a lot of global changes to the language. However, if users can
> write their own macros to scratch some of these itches, that's a
> better solution. They get the feature they want in just the program
> that needs it, and the rest of us get a stable, predictable language
> without a lot of weird new features in all other ruby programs.
>


well now that's something everyone can agree on!  seriously, the  
project looks super interesting - just trying to think of a real use  
case.

hrrrrm.  could we possibly use it to skin the

   self.ivar = value

problem?


and, to repeat from above, are the global?  i'm hoping macros can be  
scoped to an object like instance methods....


cheers.


a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being  
better. simply reflect on that.
h.h. the 14th dalai lama