# encoding: us-ascii
#-----------------------------------------------------------
# RArg - utility for validating named arguments
#
#   Version: 0.1 (2009-01-31)
#   Author: Dice <tetradice@gmail.com>
#   License: NYSL 0.9982 <http://www.kmonos.net/nysl/>
#            (this license is like Public Domain)
#-----------------------------------------------------------

module RArg
	VERSION = '0.1'
	VERSION_NUMBER = 0.1

	class << self
		# parse arguments with definition block. Return: ParseResult
		def parse(args, &definition)
			context = DefinitionContext.new
			context.instance_eval(&definition)
			context.parse(args)
		end
		
		alias parse_named_arguments parse
	end
	
	# error of definition or parsing
	class Error < ::StandardError
	end
	
	
	class DefinitionContext
		def initialize
			@required = []
			@defaults = {}
			@aliases = {}
		end
		
		def parse(args)
			base = {}
		
			@defaults.each_pair do |name, value|
				unless args.include?(name) then
					base[name] = value
				end
			end
			
			args.each_pair do |name, value|
				# solve aliases
				if @aliases.include?(name) then
					real_name = @aliases[name]
				else
					real_name = name
				end
				
				# check defined or not
				if not @required.include?(real_name) and not @defaults.include?(real_name) then
					raise Error, "'#{real_name}' is not defined"
				end
				
				base[real_name] = value
			end
			
			if (missing = @required.find{|x| not base.include?(x)}) then
				raise Error, "argument of '#{missing}' is required, but missing"
			end
			

			
			return ParseResult.new(base)
		end
	
		private
		
		# define a required argument
		def require_arg(*names)
			@required.concat(names)
		end
		
		# define a default argument, name and value
		def default_arg(name, value = nil)
			@defaults[name] = value
		end
		
		# define an alias of argument
		def alias_arg(new, orig)
			if @required.include?(orig) or @defaults.include?(orig) then
				@aliases[new] = orig
			else
				raise Error, "alias: '#{orig}' -> '#{new}', but '#{orig}' is not defined"
			end
		end
	end
	
	# return of parsing
	class ParseResult
		attr_reader :base
		alias arguments base
	
		def initialize(base)
			@base = base
		end
		
		def [](name)
			if @base.include?(name) then
				@base[name]
			else
				raise Error, "argument name '#{name}' is not defined"
			end
		end
		
	end
end