Reputation: 41
Ruby enthusiasts! I am trying to write a DSL in ruby and i would like to be able to create some magic methods (not sure that is the most accurate term for what i want).
I would like to be able to do things like the following:
a = [1, 2, 3]
b = 2
(a contains b)
And have it resolve to true or false.
Essentially, how can i define the function "contains" so that it takes an array a
and a variable b
and performs a.contains?(b)
, but without all of the associated ruby-specific syntax?
Upvotes: 3
Views: 3902
Reputation: 1425
The closest thing I could think of would be:
def contains var, useless_symbol, arr
arr.include? var
end
Then you could call it like:
contains b, :in, a
I don't think there is any way to be able to use infix notation in your own functions.
Upvotes: 0
Reputation: 25984
You can abuse method_missing
. The tricky thing is, that you cannot access the blocks local variables directly. You'll have to capture the blocks inner binding somewhere (unfortunately block.binding
returns the block's outer binding).
You can run this code:
DSL.new do
a = [1, 2, 3]
b = 2
a contains b
end
With the following:
class DSL
attr_reader :last_binding
def initialize(&block)
set_trace_func method(:trace).to_proc
instance_eval(&block)
set_trace_func nil
end
def trace(event, file, line, id, binding, klass)
if event.to_s == "call" and klass == self.class and id.to_s == "method_missing"
@last_binding ||= @current_binding
set_trace_func nil
else
@current_binding = binding
end
end
def lvars
eval('local_variables', last_binding).map(&:to_s)
end
def method_missing(name, *args)
name = name.to_s
if lvars.include? name
eval(name, last_binding).send(*args.flatten)
else
["#{name}?", *args]
end
end
end
class Array
alias contains? include?
end
Upvotes: 2
Reputation: 14195
if you want a DSL that doesn't use ruby syntax, you need to write a parser at the very least to perform the transformation (raganwalds rewrite lib might be a starting point, http://github.com/raganwald/rewrite)
That said, you don't want to do this. This is more code to maintain and Ruby has already made a lot of the tough decisions that make writing a language syntax hard. Natural language programming also isn't much easier for nonprogrammers to use as the exactness of the format is the challenging aspect (see applescript for instance).
Upvotes: 2