require 'spec_helper' require 'dentaku/calculator' describe Dentaku::Calculator do describe 'functions' do describe 'external functions' do let(:with_external_funcs) do c = described_class.new c.add_function(:now, :string, -> { Time.now.to_s }) fns = [ [:pow, :numeric, ->(mantissa, exponent) { mantissa**exponent }], [:biggest, :numeric, ->(*args) { args.max }], [:smallest, :numeric, ->(*args) { args.min }], ] c.add_functions(fns) end it 'includes NOW' do now = with_external_funcs.evaluate('NOW()') expect(now).not_to be_nil expect(now).not_to be_empty end it 'includes POW' do expect(with_external_funcs.evaluate('POW(2,3)')).to eq(8) expect(with_external_funcs.evaluate('POW(3,2)')).to eq(9) expect(with_external_funcs.evaluate('POW(mantissa,exponent)', mantissa: 2, exponent: 4)).to eq(16) end it 'includes BIGGEST' do expect(with_external_funcs.evaluate('BIGGEST(8,6,7,5,3,0,9)')).to eq(9) end it 'includes SMALLEST' do expect(with_external_funcs.evaluate('SMALLEST(8,6,7,5,3,0,9)')).to eq(0) end it 'supports array parameters' do calculator = described_class.new calculator.add_function( :includes, :logical, ->(haystack, needle) { haystack.include?(needle) } ) expect(calculator.evaluate("INCLUDES(list, 2)", list: [1, 2, 3])).to eq(true) end end it 'allows registering "bang" functions' do calculator = described_class.new calculator.add_function(:hey!, :string, -> { "hey!" }) expect(calculator.evaluate("hey!()")).to eq("hey!") end it 'does not store functions across all calculators' do calculator1 = Dentaku::Calculator.new calculator1.add_function(:my_function, :numeric, ->(x) { 2 * x + 1 }) calculator2 = Dentaku::Calculator.new calculator2.add_function(:my_function, :numeric, ->(x) { 4 * x + 3 }) expect(calculator1.evaluate("1 + my_function(2)")). to eq(1 + 2 * 2 + 1) expect(calculator2.evaluate("1 + my_function(2)")). to eq(1 + 4 * 2 + 3) expect { Dentaku::Calculator.new.evaluate!("1 + my_function(2)") }.to raise_error(Dentaku::ParseError) end it 'self.add_function adds to default/global function registry' do Dentaku::Calculator.add_function(:global_function, :numeric, ->(x) { 10 + x**2 }) expect(Dentaku::Calculator.new.evaluate("global_function(3) + 5")).to eq(10 + 3**2 + 5) end end end