Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SWITCH #16

Merged
merged 11 commits into from
Feb 9, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions lib/xls_function/evaluators/functions/switch.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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)
count = 0

arg_list[1..-1].each_slice(2) do |expr, value|
count += 1
break if count > 126
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[imo] Original one is restricted to 126 as you implemented. But I think our function does not need to be restricted as well. I don't restrict similar functions such as ifs and let. How do you think ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First of all, I tried to reproduce it faithfully, but I also think that restrictions are unnecessary.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I deleted it in the commit below.
4a009cd


return value&.evaluate(context) if expr&.evaluate(context) == condition

return expr&.evaluate(context) if value&.evaluate(context).nil?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expr&.evaluate(context) runs twice. Plz fix it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed in the commit below.
b066e5d

end

XlsFunction::ErrorValue.na
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to add some messages with class_info. See also other ErrorValue usage.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a message in the commit below.
a230f0f

end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗒

  • 基本的に関数追加する場合は、 eval メソッドの中に関数処理を実装すれば良い
  • arg_list で入力した式をいい感じに取得できる
    def arg_list
    @arg_list ||= Array(context[:arglist])
    end
    • expr: 一致する値、 value: 一致した時に出力したい値、が入る想定
    • value&.evaluate(context).nil? であれば、最後の一致する値がない場合に返す値とみなしている

end
end
end
end
1 change: 1 addition & 0 deletions lib/xls_function/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}.
Expand Down
1 change: 1 addition & 0 deletions lib/xls_function/locales/ja.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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}が見つかりません。
Expand Down
29 changes: 29 additions & 0 deletions spec/e2e/switch_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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

context 'when there are more than 126 arguments' do
let(:input) { 'SWITCH("abc", ' + (1..127).map { |i| "\"#{i}\", \"match\"" }.join(', ') + ', "not match")' }

it { is_expected.to eq('#N/A') }
end
end
end
Loading