Search code examples
rubydsl

How to make beautiful DSL in ruby with just words in arguments, without commas


I want to achieve something like that:

something.configure do
  on arg1 arg2 "real_arg" do
    
  end
end

Without commas just like that.

I assume Ruby interprets this code as:

something.configure do
  on(arg1)(arg2 "real_arg") do

  end
end

In the end I want method .on to receive *args, :arg1, :arg2, "real_arg", &block

At first I tried utilising .method_missing method to return symbols as I wanted until I realised how Ruby interprets my DSL and that it basically wraps separate words as method calls.

If I'm not mistaken in the perfect world I would need to return "anonymous functions" in .method_missing so they would actually chain-wrap arguments but as far as I know Ruby required procs to be called with .call

How can I achieve mentioned DSL with elegance?


Solution

  • It turns out this is not the most elegant way to write DSL in ruby, it is better to utilize symbols and named arguments.

    Anyway, if anyone really wishes to do the thing I asked:

    look into gem "method_source"

    At the method .configure I would read string of source code of proc. Then I would populate objects that will be called with .method_missing with defined at runtime methods (self.class.send(:define_method, name, &block))

    Basically objects now would have methods named .arg1, .arg2

    What next? Create ArgumentWrapper class that gets any argument inside and method_name argument, create them in all defined at runtime methods (.arg1, .arg2)

    In the end you will have something like this:

    ArgumentWrapper(
      method_name: :arg1,
      argument: ArgumentWrapper(
        method_name: :arg2,
        argument: "real_arg"
      )
    )
    

    Then you can traverse everything back up and have array of real arguments.

    After that in the end of .configure method you can remove defined at runtime methods.

    This is not an encouragement, just info how this one can be done.