lib/turnip/placeholder.rb
module Turnip
class Placeholder
class Match < Struct.new(:regexp, :block);end
class << self
def add(name, &block)
if placeholders.key?(name)
location = caller_locations.detect { |l| l.to_s !~ /lib\/turnip\/dsl\.rb/ }
warn "Placeholder :#{name} was replaced at #{location}."
end
placeholders[name] = Placeholder.new(name, &block)
end
def resolve(name)
find(name).regexp
end
def apply(name, value)
find(name).apply(value)
end
def find(name)
placeholders[name] or default
end
private
def placeholders
@placeholders ||= {}
end
def default
@default ||= new(:default) do
default do |value|
value
end
end
end
end
def initialize(name, &block)
@name = name
@matches = []
@default = nil
instance_eval(&block)
end
def apply(value)
match, params = find_match(value)
if match and match.block then match.block.call(*params) else value end
end
def match(regexp, &block)
@matches << Match.new(regexp, block)
end
def default(&block)
@default ||= Match.new(
%r{['"]?((?:(?<=")[^"]*)(?=")|(?:(?<=')[^']*(?='))|(?<!['"])[[:alnum:]_-]+(?!['"]))['"]?},
block
)
end
def regexp
Regexp.new(placeholder_matches.map(&:regexp).join('|'))
end
private
def find_match(value)
@matches.each do |m|
result = value.scan(m.regexp)
return m, result.flatten unless result.empty?
end
#
# value is one of the following:
#
# %{Jhon Doe}
# %{"Jhon Doe"}
# %{'Jhon Doe'}
#
# In any case, it passed to the step block in the state without quotes
return @default, value.sub(/^(["'])([^\1]*)\1$/, '\2')
end
def placeholder_matches
matches = @matches
matches += [@default] if @default
matches
end
end
end