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.
- checksums.yaml +7 -0
- data/.github/workflows/publish_gem.yml +25 -0
- data/.github/workflows/rspec.yml +30 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +41 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/LICENSE +201 -0
- data/README.md +48 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/xls_function/class_dictionary.rb +7 -0
- data/lib/xls_function/converter.rb +24 -0
- data/lib/xls_function/converters/date_converter.rb +30 -0
- data/lib/xls_function/converters/date_serial_converter.rb +17 -0
- data/lib/xls_function/converters/number_converter.rb +28 -0
- data/lib/xls_function/converters/time_converter.rb +158 -0
- data/lib/xls_function/converters/time_serial_converter.rb +97 -0
- data/lib/xls_function/default_logger.rb +7 -0
- data/lib/xls_function/error.rb +49 -0
- data/lib/xls_function/evaluators/arguments_definable.rb +39 -0
- data/lib/xls_function/evaluators/binary_operation_evaluator.rb +20 -0
- data/lib/xls_function/evaluators/binary_operations/add.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/concat.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/divide.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/equal.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/greater_than.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/greater_than_or_equal_to.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/less_than.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/less_than_or_equal_to.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/multiple.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/not_equal.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/power.rb +13 -0
- data/lib/xls_function/evaluators/binary_operations/subtract.rb +13 -0
- data/lib/xls_function/evaluators/class_dictionary.rb +30 -0
- data/lib/xls_function/evaluators/error_detector.rb +29 -0
- data/lib/xls_function/evaluators/evaluable.rb +37 -0
- data/lib/xls_function/evaluators/false_evaluator.rb +19 -0
- data/lib/xls_function/evaluators/function_evaluator.rb +133 -0
- data/lib/xls_function/evaluators/functions/and.rb +21 -0
- data/lib/xls_function/evaluators/functions/asc.rb +17 -0
- data/lib/xls_function/evaluators/functions/char.rb +19 -0
- data/lib/xls_function/evaluators/functions/clean.rb +22 -0
- data/lib/xls_function/evaluators/functions/code.rb +18 -0
- data/lib/xls_function/evaluators/functions/concat.rb +27 -0
- data/lib/xls_function/evaluators/functions/date.rb +57 -0
- data/lib/xls_function/evaluators/functions/date_value.rb +17 -0
- data/lib/xls_function/evaluators/functions/day.rb +15 -0
- data/lib/xls_function/evaluators/functions/dbcs.rb +18 -0
- data/lib/xls_function/evaluators/functions/e_date.rb +19 -0
- data/lib/xls_function/evaluators/functions/e_o_month.rb +20 -0
- data/lib/xls_function/evaluators/functions/exact.rb +16 -0
- data/lib/xls_function/evaluators/functions/find.rb +28 -0
- data/lib/xls_function/evaluators/functions/fixed.rb +46 -0
- data/lib/xls_function/evaluators/functions/hour.rb +15 -0
- data/lib/xls_function/evaluators/functions/if.rb +24 -0
- data/lib/xls_function/evaluators/functions/ifs.rb +20 -0
- data/lib/xls_function/evaluators/functions/int.rb +15 -0
- data/lib/xls_function/evaluators/functions/iserror.rb +20 -0
- data/lib/xls_function/evaluators/functions/isnumber.rb +15 -0
- data/lib/xls_function/evaluators/functions/lambda.rb +57 -0
- data/lib/xls_function/evaluators/functions/left.rb +16 -0
- data/lib/xls_function/evaluators/functions/len.rb +15 -0
- data/lib/xls_function/evaluators/functions/let.rb +24 -0
- data/lib/xls_function/evaluators/functions/lower.rb +15 -0
- data/lib/xls_function/evaluators/functions/mid.rb +23 -0
- data/lib/xls_function/evaluators/functions/minute.rb +15 -0
- data/lib/xls_function/evaluators/functions/month.rb +15 -0
- data/lib/xls_function/evaluators/functions/not.rb +15 -0
- data/lib/xls_function/evaluators/functions/now.rb +19 -0
- data/lib/xls_function/evaluators/functions/or.rb +21 -0
- data/lib/xls_function/evaluators/functions/power.rb +16 -0
- data/lib/xls_function/evaluators/functions/proper.rb +17 -0
- data/lib/xls_function/evaluators/functions/replace.rb +19 -0
- data/lib/xls_function/evaluators/functions/rept.rb +25 -0
- data/lib/xls_function/evaluators/functions/right.rb +16 -0
- data/lib/xls_function/evaluators/functions/round.rb +16 -0
- data/lib/xls_function/evaluators/functions/round_down.rb +16 -0
- data/lib/xls_function/evaluators/functions/round_up.rb +16 -0
- data/lib/xls_function/evaluators/functions/second.rb +15 -0
- data/lib/xls_function/evaluators/functions/sqrt.rb +17 -0
- data/lib/xls_function/evaluators/functions/substitute.rb +44 -0
- data/lib/xls_function/evaluators/functions/text.rb +17 -0
- data/lib/xls_function/evaluators/functions/time.rb +54 -0
- data/lib/xls_function/evaluators/functions/timevalue.rb +17 -0
- data/lib/xls_function/evaluators/functions/today.rb +19 -0
- data/lib/xls_function/evaluators/functions/trim.rb +16 -0
- data/lib/xls_function/evaluators/functions/trunc.rb +16 -0
- data/lib/xls_function/evaluators/functions/unichar.rb +19 -0
- data/lib/xls_function/evaluators/functions/unicode.rb +18 -0
- data/lib/xls_function/evaluators/functions/upper.rb +15 -0
- data/lib/xls_function/evaluators/functions/value.rb +26 -0
- data/lib/xls_function/evaluators/functions/year.rb +15 -0
- data/lib/xls_function/evaluators/number_evaluator.rb +18 -0
- data/lib/xls_function/evaluators/string_evaluator.rb +18 -0
- data/lib/xls_function/evaluators/true_evaluator.rb +19 -0
- data/lib/xls_function/evaluators/variant_evaluator.rb +24 -0
- data/lib/xls_function/extensions/array_extension.rb +22 -0
- data/lib/xls_function/extensions/big_decimal_extension.rb +15 -0
- data/lib/xls_function/extensions/date_extension.rb +11 -0
- data/lib/xls_function/extensions/hash_extension.rb +24 -0
- data/lib/xls_function/extensions/time_extension.rb +11 -0
- data/lib/xls_function/format_string/evaluators/elapsed_time_evaluator.rb +42 -0
- data/lib/xls_function/format_string/evaluators/number_evaluator.rb +243 -0
- data/lib/xls_function/format_string/evaluators/time_evaluator.rb +103 -0
- data/lib/xls_function/format_string/parse_rules/dates.rb +53 -0
- data/lib/xls_function/format_string/parse_rules/numbers.rb +31 -0
- data/lib/xls_function/format_string/parse_rules/texts.rb +25 -0
- data/lib/xls_function/format_string/parse_rules/times.rb +55 -0
- data/lib/xls_function/format_string/parser.rb +27 -0
- data/lib/xls_function/format_string/transform.rb +87 -0
- data/lib/xls_function/format_string/transform_rules/dates.rb +98 -0
- data/lib/xls_function/format_string/transform_rules/numbers.rb +59 -0
- data/lib/xls_function/format_string/transform_rules/texts.rb +25 -0
- data/lib/xls_function/format_string/transform_rules/times.rb +97 -0
- data/lib/xls_function/format_string.rb +24 -0
- data/lib/xls_function/i18n.rb +4 -0
- data/lib/xls_function/locales/en.yml +65 -0
- data/lib/xls_function/locales/ja.yml +65 -0
- data/lib/xls_function/parse_rules/binary_operation.rb +28 -0
- data/lib/xls_function/parse_rules/common.rb +34 -0
- data/lib/xls_function/parser.rb +12 -0
- data/lib/xls_function/transform.rb +58 -0
- data/lib/xls_function/transform_rules/binary_operation_transform.rb +16 -0
- data/lib/xls_function/transform_rules/boolean_transform.rb +12 -0
- data/lib/xls_function/transform_rules/function_call_transform.rb +16 -0
- data/lib/xls_function/transform_rules/number_transform.rb +11 -0
- data/lib/xls_function/transform_rules/string_transform.rb +17 -0
- data/lib/xls_function/transform_rules/variant_transform.rb +13 -0
- data/lib/xls_function/user_defined_function_factory.rb +59 -0
- data/lib/xls_function/version.rb +3 -0
- data/lib/xls_function.rb +82 -0
- data/xls_function.gemspec +30 -0
- 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,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,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,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,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
|