|
5 | 5 | describe Dentaku::Calculator do
|
6 | 6 | describe 'functions' do
|
7 | 7 | describe 'external functions' do
|
8 |
| - |
9 |
| - let(:with_external_funcs) do |
| 8 | + let(:custom_calculator) do |
10 | 9 | c = described_class.new
|
11 | 10 |
|
12 | 11 | c.add_function(:now, :string, -> { Time.now.to_s })
|
|
22 | 21 | end
|
23 | 22 |
|
24 | 23 | it 'includes NOW' do
|
25 |
| - now = with_external_funcs.evaluate('NOW()') |
| 24 | + now = custom_calculator.evaluate('NOW()') |
26 | 25 | expect(now).not_to be_nil
|
27 | 26 | expect(now).not_to be_empty
|
28 | 27 | end
|
29 | 28 |
|
30 | 29 | it 'includes POW' do
|
31 |
| - expect(with_external_funcs.evaluate('POW(2,3)')).to eq(8) |
32 |
| - expect(with_external_funcs.evaluate('POW(3,2)')).to eq(9) |
33 |
| - expect(with_external_funcs.evaluate('POW(mantissa,exponent)', mantissa: 2, exponent: 4)).to eq(16) |
| 30 | + expect(custom_calculator.evaluate('POW(2,3)')).to eq(8) |
| 31 | + expect(custom_calculator.evaluate('POW(3,2)')).to eq(9) |
| 32 | + expect(custom_calculator.evaluate('POW(mantissa,exponent)', mantissa: 2, exponent: 4)).to eq(16) |
34 | 33 | end
|
35 | 34 |
|
36 | 35 | it 'includes BIGGEST' do
|
37 |
| - expect(with_external_funcs.evaluate('BIGGEST(8,6,7,5,3,0,9)')).to eq(9) |
| 36 | + expect(custom_calculator.evaluate('BIGGEST(8,6,7,5,3,0,9)')).to eq(9) |
38 | 37 | end
|
39 | 38 |
|
40 | 39 | it 'includes SMALLEST' do
|
41 |
| - expect(with_external_funcs.evaluate('SMALLEST(8,6,7,5,3,0,9)')).to eq(0) |
| 40 | + expect(custom_calculator.evaluate('SMALLEST(8,6,7,5,3,0,9)')).to eq(0) |
42 | 41 | end
|
43 | 42 |
|
44 | 43 | it 'includes OPTIONAL' do
|
45 |
| - expect(with_external_funcs.evaluate('OPTIONAL(1,2)')).to eq(3) |
46 |
| - expect(with_external_funcs.evaluate('OPTIONAL(1,2,3)')).to eq(6) |
47 |
| - expect { with_external_funcs.dependencies('OPTIONAL()') }.to raise_error(Dentaku::ParseError) |
48 |
| - expect { with_external_funcs.dependencies('OPTIONAL(1,2,3,4)') }.to raise_error(Dentaku::ParseError) |
| 44 | + expect(custom_calculator.evaluate('OPTIONAL(1,2)')).to eq(3) |
| 45 | + expect(custom_calculator.evaluate('OPTIONAL(1,2,3)')).to eq(6) |
| 46 | + expect { custom_calculator.dependencies('OPTIONAL()') }.to raise_error(Dentaku::ParseError) |
| 47 | + expect { custom_calculator.dependencies('OPTIONAL(1,2,3,4)') }.to raise_error(Dentaku::ParseError) |
49 | 48 | end
|
50 | 49 |
|
51 | 50 | it 'supports array parameters' do
|
|
62 | 61 | end
|
63 | 62 | end
|
64 | 63 |
|
| 64 | + describe 'with callbacks' do |
| 65 | + let(:custom_calculator) do |
| 66 | + c = described_class.new |
| 67 | + |
| 68 | + @counts = Hash.new(0) |
| 69 | + |
| 70 | + @initial_time = "2023-02-03" |
| 71 | + @last_time = @initial_time |
| 72 | + |
| 73 | + c.add_function( |
| 74 | + :reverse, |
| 75 | + :stringl, |
| 76 | + ->(a) { a.reverse }, |
| 77 | + lambda do |args| |
| 78 | + args.each do |arg| |
| 79 | + @counts[arg.value] += 1 if arg.type == :string |
| 80 | + end |
| 81 | + end |
| 82 | + ) |
| 83 | + |
| 84 | + fns = [ |
| 85 | + [:biggest_callback, :numeric, ->(*args) { args.max }, ->(args) { args.each { |arg| raise Dentaku::ArgumentError unless arg.type == :numeric } }], |
| 86 | + [:pythagoras, :numeric, ->(l1, l2) { Math.sqrt(l1**2 + l2**2) }, ->(e) { @last_time = Time.now.to_s }], |
| 87 | + [:callback_lambda, :string, ->() { " " }, ->() { "lambda executed" }], |
| 88 | + [:no_lambda_function, :numeric, ->(a) { a**a }], |
| 89 | + ] |
| 90 | + |
| 91 | + c.add_functions(fns) |
| 92 | + end |
| 93 | + |
| 94 | + it 'includes BIGGEST_CALLBACK' do |
| 95 | + expect(custom_calculator.evaluate('BIGGEST_CALLBACK(1, 2, 5, 4)')).to eq(5) |
| 96 | + expect { custom_calculator.dependencies('BIGGEST_CALLBACK(1, 3, 6, "hi", 10)') }.to raise_error(Dentaku::ArgumentError) |
| 97 | + end |
| 98 | + |
| 99 | + it 'includes REVERSE' do |
| 100 | + expect(custom_calculator.evaluate('REVERSE(\'Dentaku\')')).to eq('ukatneD') |
| 101 | + expect { custom_calculator.evaluate('REVERSE(22)') }.to raise_error(NoMethodError) |
| 102 | + expect(@counts["Dentaku"]).to eq(1) |
| 103 | + end |
| 104 | + |
| 105 | + it 'includes PYTHAGORAS' do |
| 106 | + expect(custom_calculator.evaluate('PYTHAGORAS(8, 7)')).to eq(10.63014581273465) |
| 107 | + expect(custom_calculator.evaluate('PYTHAGORAS(3, 4)')).to eq(5) |
| 108 | + expect(@last_time).not_to eq(@initial_time) |
| 109 | + end |
| 110 | + |
| 111 | + it 'exposes the `callback` method of a function' do |
| 112 | + expect(Dentaku::AST::Function::Callback_lambda.callback.call()).to eq("lambda executed") |
| 113 | + end |
| 114 | + |
| 115 | + it 'does not add a `callback` method to built-in functions' do |
| 116 | + expect { Dentaku::AST::If.callback.call }.to raise_error(NoMethodError) |
| 117 | + end |
| 118 | + |
| 119 | + it 'defaults `callback` method to nil if not specified' do |
| 120 | + expect(Dentaku::AST::Function::No_lambda_function.callback).to eq(nil) |
| 121 | + end |
| 122 | + end |
| 123 | + |
65 | 124 | it 'allows registering "bang" functions' do
|
66 | 125 | calculator = described_class.new
|
67 | 126 | calculator.add_function(:hey!, :string, -> { "hey!" })
|
|
0 commit comments