xls_function 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/publish_gem.yml +25 -0
  3. data/.github/workflows/rspec.yml +30 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +41 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +8 -0
  9. data/LICENSE +201 -0
  10. data/README.md +48 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/setup +8 -0
  14. data/lib/xls_function/class_dictionary.rb +7 -0
  15. data/lib/xls_function/converter.rb +24 -0
  16. data/lib/xls_function/converters/date_converter.rb +30 -0
  17. data/lib/xls_function/converters/date_serial_converter.rb +17 -0
  18. data/lib/xls_function/converters/number_converter.rb +28 -0
  19. data/lib/xls_function/converters/time_converter.rb +158 -0
  20. data/lib/xls_function/converters/time_serial_converter.rb +97 -0
  21. data/lib/xls_function/default_logger.rb +7 -0
  22. data/lib/xls_function/error.rb +49 -0
  23. data/lib/xls_function/evaluators/arguments_definable.rb +39 -0
  24. data/lib/xls_function/evaluators/binary_operation_evaluator.rb +20 -0
  25. data/lib/xls_function/evaluators/binary_operations/add.rb +13 -0
  26. data/lib/xls_function/evaluators/binary_operations/concat.rb +13 -0
  27. data/lib/xls_function/evaluators/binary_operations/divide.rb +13 -0
  28. data/lib/xls_function/evaluators/binary_operations/equal.rb +13 -0
  29. data/lib/xls_function/evaluators/binary_operations/greater_than.rb +13 -0
  30. data/lib/xls_function/evaluators/binary_operations/greater_than_or_equal_to.rb +13 -0
  31. data/lib/xls_function/evaluators/binary_operations/less_than.rb +13 -0
  32. data/lib/xls_function/evaluators/binary_operations/less_than_or_equal_to.rb +13 -0
  33. data/lib/xls_function/evaluators/binary_operations/multiple.rb +13 -0
  34. data/lib/xls_function/evaluators/binary_operations/not_equal.rb +13 -0
  35. data/lib/xls_function/evaluators/binary_operations/power.rb +13 -0
  36. data/lib/xls_function/evaluators/binary_operations/subtract.rb +13 -0
  37. data/lib/xls_function/evaluators/class_dictionary.rb +30 -0
  38. data/lib/xls_function/evaluators/error_detector.rb +29 -0
  39. data/lib/xls_function/evaluators/evaluable.rb +37 -0
  40. data/lib/xls_function/evaluators/false_evaluator.rb +19 -0
  41. data/lib/xls_function/evaluators/function_evaluator.rb +133 -0
  42. data/lib/xls_function/evaluators/functions/and.rb +21 -0
  43. data/lib/xls_function/evaluators/functions/asc.rb +17 -0
  44. data/lib/xls_function/evaluators/functions/char.rb +19 -0
  45. data/lib/xls_function/evaluators/functions/clean.rb +22 -0
  46. data/lib/xls_function/evaluators/functions/code.rb +18 -0
  47. data/lib/xls_function/evaluators/functions/concat.rb +27 -0
  48. data/lib/xls_function/evaluators/functions/date.rb +57 -0
  49. data/lib/xls_function/evaluators/functions/date_value.rb +17 -0
  50. data/lib/xls_function/evaluators/functions/day.rb +15 -0
  51. data/lib/xls_function/evaluators/functions/dbcs.rb +18 -0
  52. data/lib/xls_function/evaluators/functions/e_date.rb +19 -0
  53. data/lib/xls_function/evaluators/functions/e_o_month.rb +20 -0
  54. data/lib/xls_function/evaluators/functions/exact.rb +16 -0
  55. data/lib/xls_function/evaluators/functions/find.rb +28 -0
  56. data/lib/xls_function/evaluators/functions/fixed.rb +46 -0
  57. data/lib/xls_function/evaluators/functions/hour.rb +15 -0
  58. data/lib/xls_function/evaluators/functions/if.rb +24 -0
  59. data/lib/xls_function/evaluators/functions/ifs.rb +20 -0
  60. data/lib/xls_function/evaluators/functions/int.rb +15 -0
  61. data/lib/xls_function/evaluators/functions/iserror.rb +20 -0
  62. data/lib/xls_function/evaluators/functions/isnumber.rb +15 -0
  63. data/lib/xls_function/evaluators/functions/lambda.rb +57 -0
  64. data/lib/xls_function/evaluators/functions/left.rb +16 -0
  65. data/lib/xls_function/evaluators/functions/len.rb +15 -0
  66. data/lib/xls_function/evaluators/functions/let.rb +24 -0
  67. data/lib/xls_function/evaluators/functions/lower.rb +15 -0
  68. data/lib/xls_function/evaluators/functions/mid.rb +23 -0
  69. data/lib/xls_function/evaluators/functions/minute.rb +15 -0
  70. data/lib/xls_function/evaluators/functions/month.rb +15 -0
  71. data/lib/xls_function/evaluators/functions/not.rb +15 -0
  72. data/lib/xls_function/evaluators/functions/now.rb +19 -0
  73. data/lib/xls_function/evaluators/functions/or.rb +21 -0
  74. data/lib/xls_function/evaluators/functions/power.rb +16 -0
  75. data/lib/xls_function/evaluators/functions/proper.rb +17 -0
  76. data/lib/xls_function/evaluators/functions/replace.rb +19 -0
  77. data/lib/xls_function/evaluators/functions/rept.rb +25 -0
  78. data/lib/xls_function/evaluators/functions/right.rb +16 -0
  79. data/lib/xls_function/evaluators/functions/round.rb +16 -0
  80. data/lib/xls_function/evaluators/functions/round_down.rb +16 -0
  81. data/lib/xls_function/evaluators/functions/round_up.rb +16 -0
  82. data/lib/xls_function/evaluators/functions/second.rb +15 -0
  83. data/lib/xls_function/evaluators/functions/sqrt.rb +17 -0
  84. data/lib/xls_function/evaluators/functions/substitute.rb +44 -0
  85. data/lib/xls_function/evaluators/functions/text.rb +17 -0
  86. data/lib/xls_function/evaluators/functions/time.rb +54 -0
  87. data/lib/xls_function/evaluators/functions/timevalue.rb +17 -0
  88. data/lib/xls_function/evaluators/functions/today.rb +19 -0
  89. data/lib/xls_function/evaluators/functions/trim.rb +16 -0
  90. data/lib/xls_function/evaluators/functions/trunc.rb +16 -0
  91. data/lib/xls_function/evaluators/functions/unichar.rb +19 -0
  92. data/lib/xls_function/evaluators/functions/unicode.rb +18 -0
  93. data/lib/xls_function/evaluators/functions/upper.rb +15 -0
  94. data/lib/xls_function/evaluators/functions/value.rb +26 -0
  95. data/lib/xls_function/evaluators/functions/year.rb +15 -0
  96. data/lib/xls_function/evaluators/number_evaluator.rb +18 -0
  97. data/lib/xls_function/evaluators/string_evaluator.rb +18 -0
  98. data/lib/xls_function/evaluators/true_evaluator.rb +19 -0
  99. data/lib/xls_function/evaluators/variant_evaluator.rb +24 -0
  100. data/lib/xls_function/extensions/array_extension.rb +22 -0
  101. data/lib/xls_function/extensions/big_decimal_extension.rb +15 -0
  102. data/lib/xls_function/extensions/date_extension.rb +11 -0
  103. data/lib/xls_function/extensions/hash_extension.rb +24 -0
  104. data/lib/xls_function/extensions/time_extension.rb +11 -0
  105. data/lib/xls_function/format_string/evaluators/elapsed_time_evaluator.rb +42 -0
  106. data/lib/xls_function/format_string/evaluators/number_evaluator.rb +243 -0
  107. data/lib/xls_function/format_string/evaluators/time_evaluator.rb +103 -0
  108. data/lib/xls_function/format_string/parse_rules/dates.rb +53 -0
  109. data/lib/xls_function/format_string/parse_rules/numbers.rb +31 -0
  110. data/lib/xls_function/format_string/parse_rules/texts.rb +25 -0
  111. data/lib/xls_function/format_string/parse_rules/times.rb +55 -0
  112. data/lib/xls_function/format_string/parser.rb +27 -0
  113. data/lib/xls_function/format_string/transform.rb +87 -0
  114. data/lib/xls_function/format_string/transform_rules/dates.rb +98 -0
  115. data/lib/xls_function/format_string/transform_rules/numbers.rb +59 -0
  116. data/lib/xls_function/format_string/transform_rules/texts.rb +25 -0
  117. data/lib/xls_function/format_string/transform_rules/times.rb +97 -0
  118. data/lib/xls_function/format_string.rb +24 -0
  119. data/lib/xls_function/i18n.rb +4 -0
  120. data/lib/xls_function/locales/en.yml +65 -0
  121. data/lib/xls_function/locales/ja.yml +65 -0
  122. data/lib/xls_function/parse_rules/binary_operation.rb +28 -0
  123. data/lib/xls_function/parse_rules/common.rb +34 -0
  124. data/lib/xls_function/parser.rb +12 -0
  125. data/lib/xls_function/transform.rb +58 -0
  126. data/lib/xls_function/transform_rules/binary_operation_transform.rb +16 -0
  127. data/lib/xls_function/transform_rules/boolean_transform.rb +12 -0
  128. data/lib/xls_function/transform_rules/function_call_transform.rb +16 -0
  129. data/lib/xls_function/transform_rules/number_transform.rb +11 -0
  130. data/lib/xls_function/transform_rules/string_transform.rb +17 -0
  131. data/lib/xls_function/transform_rules/variant_transform.rb +13 -0
  132. data/lib/xls_function/user_defined_function_factory.rb +59 -0
  133. data/lib/xls_function/version.rb +3 -0
  134. data/lib/xls_function.rb +82 -0
  135. data/xls_function.gemspec +30 -0
  136. metadata +221 -0
@@ -0,0 +1,133 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ class FunctionEvaluator
4
+ include Evaluable
5
+ include ArgumentsDefinable
6
+ include ErrorDetector
7
+ include ClassDictionary
8
+
9
+ using ::XlsFunction::Extensions::ArrayExtension
10
+ using ::XlsFunction::Extensions::HashExtension
11
+
12
+ def initialize(context)
13
+ @context = context
14
+ end
15
+
16
+ def arg_list
17
+ @arg_list ||= Array(context[:arglist])
18
+ end
19
+
20
+ # @override
21
+ def evaluate(runtime_context = nil)
22
+ rescue_with StandardError do
23
+ merge_context(runtime_context) do
24
+ before_eval
25
+ # Don't evaluate when returns error
26
+ return error_value if error?
27
+
28
+ eval_or_map_eval
29
+ end
30
+ end
31
+ end
32
+
33
+ def before_eval
34
+ eval_arglist
35
+ end
36
+
37
+ def eval_arglist
38
+ definitions = self.class.arg_definitions
39
+ return if definitions.empty?
40
+
41
+ definitions.zip(arg_list).each do |(name, default, type), arg|
42
+ value = arg ? evaluate_or_self(arg) : default
43
+ value = convert_to(value, type)
44
+ instance_variable_set(:"@#{name}", value)
45
+ detect_error(value)
46
+ break if error?
47
+ end
48
+ end
49
+
50
+ def evaluate_or_self(arg)
51
+ arg.respond_to?(:evaluate) ? arg.evaluate(context) : arg
52
+ end
53
+
54
+ def convert_to(value, type)
55
+ return value unless type
56
+
57
+ succeed, result = XlsFunction::Converter.try_convert_to(type, value)
58
+ succeed ? result : XlsFunction::ErrorValue.value!(class_info(result))
59
+ end
60
+
61
+ def eval_or_map_eval
62
+ args = defined_args
63
+ if args.any? { |arg| arg.is_a?(Array) }
64
+ map_eval(args)
65
+ else
66
+ eval
67
+ end
68
+ end
69
+
70
+ def map_eval(args)
71
+ arg_array = args.map { |x| Array(x) }
72
+ .then { |xs| xs.length == 1 ? xs : xs[0].product(*xs[1..]) }
73
+ return XlsFunction::ErrorValue.na(class_info(error_message(:invalid_value_for_function))) if arg_array.max_depth > 2
74
+
75
+ arg_array.map do |arg|
76
+ to_proc.call(*arg) # Executes each created arguments as argument of self.
77
+ end
78
+ end
79
+
80
+ def detect_error(value)
81
+ return unless value.is_a?(XlsFunction::ErrorValue)
82
+
83
+ @error_value = value
84
+ end
85
+
86
+ def error?
87
+ !!error_value
88
+ end
89
+
90
+ def variant_context
91
+ context[:variants]
92
+ end
93
+
94
+ def to_proc
95
+ self.class.to_proc(context)
96
+ end
97
+
98
+ def error_message(key, **placeholders)
99
+ I18n.t("xls_function.errors.#{key}", **placeholders)
100
+ end
101
+
102
+ class << self
103
+ alias function_as register_dictionary
104
+
105
+ def create(context)
106
+ new(context)
107
+ end
108
+
109
+ def to_h
110
+ {
111
+ class: name,
112
+ proc: to_proc,
113
+ description: translated_description
114
+ }
115
+ end
116
+
117
+ def translated_description
118
+ I18n.t("xls_function.descriptions.#{@register_key}", default: @description)
119
+ end
120
+
121
+ def to_proc(context = {})
122
+ proc do |*arglist|
123
+ new(arglist, context).evaluate
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ Dir[File.expand_path('functions', __dir__) << '/*.rb'].sort.each do |file|
132
+ require file
133
+ end
@@ -0,0 +1,21 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class And < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :and
6
+
7
+ def eval_arglist
8
+ # Skip common argument evaluation and assignment for short-circuit
9
+ end
10
+
11
+ def eval
12
+ arg_list.each do |arg|
13
+ return false unless arg.evaluate(context)
14
+ end
15
+
16
+ true
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require 'nkf'
2
+
3
+ module XlsFunction
4
+ module Evaluators
5
+ module Functions
6
+ class Asc < ::XlsFunction::Evaluators::FunctionEvaluator
7
+ function_as :asc
8
+
9
+ define_arg :source
10
+
11
+ def eval
12
+ NKF.nkf('-w -Z4 -x --ic=UTF-8 --oc=UTF-8', source)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,19 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Char < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :char
6
+
7
+ define_arg :number
8
+
9
+ def eval
10
+ return '' unless number.respond_to?(:to_i)
11
+
12
+ number.to_i.chr
13
+ rescue RangeError => e
14
+ e.message
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require 'nkf'
2
+
3
+ module XlsFunction
4
+ module Evaluators
5
+ module Functions
6
+ class Clean < ::XlsFunction::Evaluators::FunctionEvaluator
7
+ function_as :clean
8
+
9
+ define_arg :source
10
+
11
+ TARGET_CHARS = (0..31).map(&:chr).join
12
+ # Remove nonprinting characters in the Unicode character set.
13
+ TARGET_CHARS_UNI = [127, 129, 141, 143, 144, 157].map { |n| n.chr(Encoding::UTF_8) }.join
14
+
15
+ def eval
16
+ s = source.delete(TARGET_CHARS)
17
+ s.delete!(TARGET_CHARS_UNI) || s
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Code < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :code
6
+
7
+ define_arg :source
8
+
9
+ def eval
10
+ s = source.to_s
11
+ return if s.empty?
12
+
13
+ s.ord
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,27 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Concat < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :concat
6
+
7
+ MAX_ARGUMENTS_COUNT = 253
8
+ MAX_ARGUMENTS_COUNT.times do |n|
9
+ text_name = :"text#{n + 1}"
10
+ define_arg text_name
11
+ end
12
+
13
+ def text_of(number)
14
+ send(:"text#{number}")
15
+ end
16
+
17
+ def eval
18
+ arr = Array.new(MAX_ARGUMENTS_COUNT) do |index|
19
+ text_of(index + 1)
20
+ end
21
+
22
+ arr.compact.join
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class DateFn < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :date
6
+
7
+ define_arg :year
8
+ define_arg :month
9
+ define_arg :day
10
+
11
+ using ::XlsFunction::Extensions::DateExtension
12
+
13
+ def eval
14
+ return ::XlsFunction::ErrorValue.num!(out_of_range) if year_i >= 10_000
15
+
16
+ date = Date.new(year_value, 1, 1)
17
+ date >>= month_value
18
+ date += day_value
19
+
20
+ date_value = date.to_serial
21
+ return ::XlsFunction::ErrorValue.num!(out_of_range) if date_value.negative?
22
+
23
+ date_value
24
+ end
25
+
26
+ def year_value
27
+ year_i >= 1900 ? year_i : year_i + 1900
28
+ end
29
+
30
+ def month_value
31
+ month_i - 1
32
+ end
33
+
34
+ def day_value
35
+ day_i - 1
36
+ end
37
+
38
+ def year_i
39
+ @year_i ||= year.to_i
40
+ end
41
+
42
+ def month_i
43
+ @month_i ||= month.to_i
44
+ end
45
+
46
+ def day_i
47
+ @day_i ||= day.to_i
48
+ end
49
+
50
+ def out_of_range
51
+ message = error_message(:out_of_range, value: "#{year}, #{month}, #{day}")
52
+ class_info(message)
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,17 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Datevalue < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :datevalue
6
+
7
+ define_arg :date_value, type: :date
8
+
9
+ using XlsFunction::Extensions::DateExtension
10
+
11
+ def eval
12
+ date_value.to_serial
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Day < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :day
6
+
7
+ define_arg :date_value, type: :date
8
+
9
+ def eval
10
+ date_value.day
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ require 'nkf'
2
+
3
+ module XlsFunction
4
+ module Evaluators
5
+ module Functions
6
+ class Dbcs < ::XlsFunction::Evaluators::FunctionEvaluator
7
+ function_as :dbcs
8
+
9
+ define_arg :source
10
+
11
+ def eval
12
+ NKF.nkf('-w -X --ic=UTF-8 --oc=UTF-8', source)
13
+ .tr('A-Z0-9', 'A-Z0-9')
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class EDate < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :edate
6
+
7
+ define_arg :date_value, type: :date
8
+ define_arg :month, type: :number
9
+
10
+ using XlsFunction::Extensions::DateExtension
11
+
12
+ def eval
13
+ new_date = date_value >> month.to_i
14
+ new_date.to_serial
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class EOMonth < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :eomonth
6
+
7
+ define_arg :date_value, type: :date
8
+ define_arg :month, type: :number
9
+
10
+ using XlsFunction::Extensions::DateExtension
11
+
12
+ def eval
13
+ new_date = date_value >> month.to_i
14
+ last_date_of_month = Date.new(new_date.year, new_date.month, -1)
15
+ last_date_of_month.to_serial
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Exact < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :exact
6
+
7
+ define_arg :source_1
8
+ define_arg :source_2
9
+
10
+ def eval
11
+ source_1 == source_2
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Find < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :find
6
+
7
+ define_arg :find_text
8
+ define_arg :within_text
9
+ define_arg :start, default: 1
10
+
11
+ def eval
12
+ index = within_text.index(find_text, start - 1)
13
+
14
+ if index
15
+ index + 1
16
+ else
17
+ ::XlsFunction::ErrorValue.value!(missing_target)
18
+ end
19
+ end
20
+
21
+ def missing_target
22
+ message = error_message(:missing_target, source: within_text, target: find_text)
23
+ class_info(message)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,46 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Fixed < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :fixed
6
+
7
+ define_arg :number
8
+ define_arg :digits, default: 2
9
+ define_arg :no_format, default: false
10
+ define_arg :delimiter, default: ','
11
+ define_arg :separator, default: '.'
12
+
13
+ DELIMITER_REGEX = /(\d)(?=(\d\d\d)+(?!\d))/.freeze
14
+
15
+ def eval
16
+ rounded = round
17
+
18
+ if no_format
19
+ rounded.to_s
20
+ else
21
+ delimit(rounded)
22
+ end
23
+ end
24
+
25
+ def round
26
+ n = number.round(digits)
27
+ if digits.positive?
28
+ n.to_f
29
+ else
30
+ n.to_i
31
+ end
32
+ end
33
+
34
+ def delimit(num)
35
+ i, f = num.to_s.split('.')
36
+ i.gsub!(DELIMITER_REGEX) do |digit|
37
+ "#{digit}#{delimiter}"
38
+ end
39
+
40
+ [i, f].compact
41
+ .join(separator)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Hour < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :hour
6
+
7
+ define_arg :time_value, type: :time
8
+
9
+ def eval
10
+ time_value.hour
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,24 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class If < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :if
6
+
7
+ define_arg :condition
8
+ define_arg :if_true
9
+ define_arg :if_false
10
+
11
+ def eval_arglist
12
+ # Skip common argument evaluation and assignment for short-circuit
13
+ @condition = arg_list[0]
14
+ @if_true = arg_list[1]
15
+ @if_false = arg_list[2]
16
+ end
17
+
18
+ def eval
19
+ condition.evaluate(context) ? if_true.evaluate(context) : if_false.evaluate(context)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,20 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Ifs < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :ifs
6
+
7
+ def eval_arglist
8
+ # Skip common argument evaluation and assignment for short-circuit
9
+ end
10
+
11
+ def eval
12
+ # Return the first result expr is true
13
+ arg_list.each_slice(2) do |expr, value|
14
+ return value&.evaluate(context) if expr&.evaluate(context)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Int < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :int
6
+
7
+ define_arg :number, type: :number
8
+
9
+ def eval
10
+ number.floor(0).to_d
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Iserror < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :iserror
6
+
7
+ define_arg :value
8
+
9
+ def eval
10
+ value.is_a?(::XlsFunction::ErrorValue)
11
+ end
12
+
13
+ # return false to avoid skip eval
14
+ def error?
15
+ false
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Isnumber < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :isnumber
6
+
7
+ define_arg :source
8
+
9
+ def eval
10
+ source.is_a?(Numeric)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,57 @@
1
+ module XlsFunction
2
+ module Evaluators
3
+ module Functions
4
+ class Lambda < ::XlsFunction::Evaluators::FunctionEvaluator
5
+ function_as :lambda
6
+
7
+ def eval_arglist
8
+ # Skip common argument evaluation and assignment
9
+ end
10
+
11
+ def eval
12
+ # arguments at lambda
13
+ # the last one is calculation
14
+ calculation = arg_list.pop
15
+ # returns as anonymous class
16
+ klass = Class.new(Function)
17
+
18
+ klass.define_singleton_method(:create) do |context|
19
+ klass.new(context, calculation)
20
+ end
21
+
22
+ # define variant as argument
23
+ arg_list.each do |variant|
24
+ klass.define_arg variant.name.to_sym
25
+ end
26
+
27
+ klass
28
+ end
29
+
30
+ class Function < ::XlsFunction::Evaluators::FunctionEvaluator
31
+ # use in lambda
32
+ attr_reader :calculation
33
+
34
+ def initialize(context, calculation)
35
+ super(context)
36
+ @calculation = calculation
37
+ end
38
+
39
+ def eval_arglist
40
+ super
41
+ return if error?
42
+
43
+ # set to variant
44
+ self.class.arg_definitions.each do |name, _default, _type|
45
+ variant_context[name.to_s] = instance_variable_get("@#{name}")
46
+ end
47
+ end
48
+
49
+ def eval
50
+ # run with composed context
51
+ calculation.evaluate(context)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end