xls_function 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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