require "spec_helper" describe Liquor::Function do it "allows to define a function" do fun = Liquor::Function.new("test", unnamed_arg: :integer, mandatory_named_args: { test: :any, add: :integer }, optional_named_args: { once_more: :any }) do |arg, kw| arg + kw[:add] end fun.unnamed_arg.should == :integer fun.optional_named_args.should == { once_more: :any } fun.call(1, add: 2).should == 3 end it "requires a body" do expect { Liquor::Function.new("test") }.to raise_error end it "checks types" do fun = Liquor::Function.new("test", unnamed_arg: [:string, :tuple], optional_named_args: { some: :integer, other: :any }) do |arg, kw| # nothing end expect { fun.call("a") }.not_to raise_error expect { fun.call([1]) }.not_to raise_error expect { fun.call(1) }.to raise_error(Liquor::ArgumentTypeError) expect { fun.call("a", some: "A") }.to raise_error(Liquor::ArgumentTypeError) expect { fun.call("a", other: 1) }.not_to raise_error expect { fun.call("a", other: Class) }.to raise_error(Liquor::ArgumentTypeError) end it "accepts an indexable external as a tuple" do fun = Liquor::Function.new("test", unnamed_arg: [:tuple]) do |arg, kw| # nothing end ext = Class.new do include Liquor::External def [](index); end def size; 0; end def to_a; []; end export :[], :size, :to_a end ext2 = Class.new do include Liquor::External def nothing; end export :nothing end expect { fun.call(ext.new) }.not_to raise_error expect { fun.call(ext2.new) }.to raise_error(Liquor::ArgumentTypeError) end it "catches host errors" do fun = Liquor::Function.new("test") do |arg, kw| "".to_hash end expect { fun.call() }.to raise_error(Liquor::HostError) end it "provides loc to the inside of functions" do fun = Liquor::Function.new("whereami") do |arg, kw, loc| loc.to_s end fun.call(nil, {}, {rabbit: 'hole'}).should == '{:rabbit=>"hole"}' end end