class Bake::Recipe

Structured access to an instance method in a bakefile.

def <=> other

Sort by location in source file.
def <=> other
	self.source_location <=> other.source_location
end

def arity

The method's arity, the required number of positional arguments.
def arity
	if @arity.nil?
		@arity = method.parameters.count{|type, name| type == :req}
	end
	
	return @arity
end

def call(*arguments, **options)

Call the recipe with the specified arguments and options.
def call(*arguments, **options)
	if options?
		@instance.send(@name, *arguments, **options)
	else
		# Ignore options...
		@instance.send(@name, *arguments)
	end
end

def command

The command name for this recipe.
def command
	@command ||= compute_command
end

def comments

@returns [Array(String)] The comment lines.
Any comments associated with the source code which defined the method.
def comments
	@comments ||= read_comments
end

def compute_command

def compute_command
	path = @instance.path
	
	if path.empty?
		@name.to_s
	elsif path.last.to_sym == @name
		path.join(':')
	else
		(path + [@name]).join(':')
	end
end

def documentation

@returns [Documentation]
The documentation object which provides structured access to the {comments}.
def documentation
	@documentation ||= Documentation.new(self.comments)
end

def initialize(instance, name, method = nil)

@parameter method [Method | Nil] The method if already known.
@parameter name [String] The method name.
@parameter instance [Base] The instance this recipe is attached to.

Initialize the recipe.
def initialize(instance, name, method = nil)
	@instance = instance
	@name = name
	@command = nil
	@comments = nil
	@types = nil
	@documentation = nil
	
	@method = method
	@arity = nil
end

def method

The method implementation.
def method
	@method ||= @instance.method(@name)
end

def options?

@returns [Boolean]
Whether this recipe has optional arguments.
def options?
	if parameters = self.parameters
		type, name = parameters.last
		
		return type == :keyrest || type == :keyreq || type == :key
	end
end

def parameters

@returns [Array | Nil]
The recipe's formal parameters, if any.
def parameters
	parameters = method.parameters
	
	unless parameters.empty?
		return parameters
	end
end

def prepare(arguments)

@returns options [Hash]
@returns ordered [Array]
@parameter arguments [Array(String)] The command line arguments
Process command line arguments into the ordered and optional arguments.
def prepare(arguments)
	offset = 0
	ordered = []
	options = {}
	parameters = method.parameters.dup
	types = self.types
	
	while argument = arguments.first
		name, value = argument.split('=', 2)
		
		if name and value
			# Consume it:
			arguments.shift
			
			if type = types[name.to_sym]
				value = type.parse(value)
			end
			
			options[name.to_sym] = value
		elsif ordered.size < self.arity
			_, name = parameters.shift
			value = arguments.shift
			
			if type = types[name]
				value = type.parse(value)
			end
			
			# Consume it:
			ordered << value
		else
			break
		end
	end
	
	return ordered, options
end

def read_comments

def read_comments
	file, line_number = self.method.source_location
	
	lines = File.readlines(file)
	line_index = line_number - 1
	
	description = []
	line_index -= 1
	
	# Extract comment preceeding method:
	while line = lines[line_index]
		# \Z matches a trailing newline:
		if match = line.match(COMMENT)
			description.unshift(match[1])
		else
			break
		end
		
		line_index -= 1
	end
	
	return description
end

def read_types

def read_types
	types = {}
	
	self.documentation.parameters do |parameter|
		types[parameter[:name].to_sym] = Types.parse(parameter[:type])
	end
	
	return types
end

def source_location

The source location of this recipe.
def source_location
	self.method.source_location
end

def to_s

def to_s
	self.command
end

def types

@returns [Array] An array of {Types} instances.
The documented type signature of the recipe.
def types
	@types ||= read_types
end