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