diff --git a/lib/xls_function/evaluators/functions/switch.rb b/lib/xls_function/evaluators/functions/switch.rb new file mode 100644 index 0000000..cb1570c --- /dev/null +++ b/lib/xls_function/evaluators/functions/switch.rb @@ -0,0 +1,28 @@ +module XlsFunction + module Evaluators + module Functions + class Switch < ::XlsFunction::Evaluators::FunctionEvaluator + function_as :switch + + def eval_arglist + # Skip common argument evaluation and assignment for short-circuit + end + + def eval + condition = arg_list.first.evaluate(context) + + arg_list[1..-1].each_slice(2) do |expr, value| + ex_value = expr&.evaluate(context) + in_value = value&.evaluate(context) + + return in_value if ex_value == condition + + return ex_value if in_value.nil? + end + + XlsFunction::ErrorValue.na(class_info(error_message(:missing_value_for_function))) + end + end + end + end +end diff --git a/lib/xls_function/locales/en.yml b/lib/xls_function/locales/en.yml index 021ca9a..daa207e 100644 --- a/lib/xls_function/locales/en.yml +++ b/lib/xls_function/locales/en.yml @@ -57,6 +57,7 @@ en: upper: UPPER(text) Converts text to uppercase. value: VALUE(text) Converts a text string that represents a number to a number. year: YEAR(serial_number) Returns the year corresponding to a date. The year is returned as an integer in the range 1900-9999. + switch: SWITCH(Value to switch, Value to match1...[2-126], Value to return if there's a match1...[2-126], Value to return if there's no match) Where you can evaluate up to 126 matching values and results. errors: out_of_range: Value is out of range. %{value} missing_target: Missing %{target} in %{source}. @@ -66,3 +67,4 @@ en: cannot_convert_to_time: Cannot convert %{source} to time. cannot_divide_by_zero: "Cannot divide by zero." invalid_value_for_function: Invalid value for formula or function. + missing_value_for_function: "'Value to return if no matching value' is not specified." diff --git a/lib/xls_function/locales/ja.yml b/lib/xls_function/locales/ja.yml index d561a24..6c9c766 100644 --- a/lib/xls_function/locales/ja.yml +++ b/lib/xls_function/locales/ja.yml @@ -57,6 +57,7 @@ ja: upper: UPPER(文字列) 文字列を大文字に変換します。 value: VALUE(文字列) 数値を表す文字列を数値に変換します。 year: YEAR(シリアル値) 日付に対応する年を返します。 戻り値は、1900 (年) ~ 9999 (年) の範囲の整数となります。 + switch: SWITCH(交換する値, 一致する値1...[2-126], 一致する値1...[2-126] がある場合に返す値, 一致する値がない場合に返す値) 最大 126 個の一致する値と結果を評価することができます errors: out_of_range: 範囲外の値が指定されています。%{value} missing_target: 文字列%{source}中に%{target}が見つかりません。 @@ -66,3 +67,4 @@ ja: cannot_convert_to_time: "%{source}は時刻に変換できません。" cannot_divide_by_zero: "0除算が発生しました。" invalid_value_for_function: 値が数式または関数に対して無効です。 + missing_value_for_function: 一致する値がない場合に返す値が指定されていません。 diff --git a/spec/e2e/switch_spec.rb b/spec/e2e/switch_spec.rb new file mode 100644 index 0000000..fa5e212 --- /dev/null +++ b/spec/e2e/switch_spec.rb @@ -0,0 +1,23 @@ +RSpec.describe XlsFunction do + subject { described_class.evaluate(input) } + + describe 'SWITCH' do + context 'when there is a result corresponding to the matching value' do + let(:input) { 'SWITCH("abc", "abc", "match", "not match")' } + + it { is_expected.to eq('match') } + end + + context 'when none match' do + let(:input) { 'SWITCH("abc", "zzz", "match", "not match")' } + + it { is_expected.to eq('not match') } + end + + context 'when there are no matches and no default arguments are specified' do + let(:input) { 'SWITCH("abc", "zzz", "match")' } + + it { is_expected.to eq('#N/A') } + end + end +end