dmn 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,374 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- module Dmn
5
- class LiteralExpression
6
- attr_reader :id, :text
7
-
8
- def self.from_json(json)
9
- LiteralExpression.new(id: json[:id], text: json[:text])
10
- end
11
-
12
- def initialize(id: nil, text:)
13
- @id = id
14
- @text = text&.strip
15
- end
16
-
17
- def tree
18
- @tree ||= SpotFeel::Parser.parse(text)
19
- end
20
-
21
- def valid?
22
- return false if text.blank?
23
- tree.present?
24
- end
25
-
26
- def evaluate(variables = {})
27
- tree.eval(functions.merge(variables))
28
- end
29
-
30
- def functions
31
- builtins = LiteralExpression.builtin_functions
32
- custom = (SpotFeel.config.functions || {})
33
- ActiveSupport::HashWithIndifferentAccess.new(builtins.merge(custom))
34
- end
35
-
36
- def named_functions
37
- # Initialize a set to hold the qualified names
38
- function_names = Set.new
39
-
40
- # Define a lambda for the recursive function
41
- walk_tree = lambda do |node|
42
- # If the node is a qualified name, add it to the set
43
- if node.is_a?(SpotFeel::FunctionInvocation)
44
- function_names << node.fn_name.text_value
45
- end
46
-
47
- # Recursively walk the child nodes
48
- node.elements&.each do |child|
49
- walk_tree.call(child)
50
- end
51
- end
52
-
53
- # Start walking the tree from the root
54
- walk_tree.call(tree)
55
-
56
- # Return the array of functions
57
- function_names.to_a
58
- end
59
-
60
- def named_variables
61
- # Initialize a set to hold the qualified names
62
- qualified_names = Set.new
63
-
64
- # Define a lambda for the recursive function
65
- walk_tree = lambda do |node|
66
- # If the node is a qualified name, add it to the set
67
- if node.is_a?(SpotFeel::QualifiedName)
68
- qualified_names << node.text_value
69
- end
70
-
71
- # Recursively walk the child nodes
72
- node.elements&.each do |child|
73
- walk_tree.call(child)
74
- end
75
- end
76
-
77
- # Start walking the tree from the root
78
- walk_tree.call(tree)
79
-
80
- # Return the array of qualified names
81
- qualified_names.to_a
82
- end
83
-
84
- def self.builtin_functions
85
- HashWithIndifferentAccess.new({
86
- # Conversion functions
87
- "string": ->(from) {
88
- return if from.nil?
89
- from.to_s
90
- },
91
- "number": ->(from) {
92
- return if from.nil?
93
- from.include?(".") ? from.to_f : from.to_i
94
- },
95
- # Boolean functions
96
- "not": ->(value) {
97
- if value == true || value == false
98
- !value
99
- end
100
- },
101
- "is defined": ->(value) {
102
- return if value.nil?
103
- !value.nil?
104
- },
105
- "get or else": ->(value, default) {
106
- value.nil? ? default : value
107
- },
108
- # String functions
109
- "substring": ->(string, start, length) {
110
- return if string.nil? || start.nil?
111
- return "" if length.nil?
112
- string[start - 1, length]
113
- },
114
- "substring before": ->(string, match) {
115
- return if string.nil? || match.nil?
116
- string.split(match).first
117
- },
118
- "substring after": ->(string, match) {
119
- return if string.nil? || match.nil?
120
- string.split(match).last
121
- },
122
- "string length": ->(string) {
123
- return if string.nil?
124
- string.length
125
- },
126
- "upper case": ->(string) {
127
- return if string.nil?
128
- string.upcase
129
- },
130
- "lower case": -> (string) {
131
- return if string.nil?
132
- string.downcase
133
- },
134
- "contains": ->(string, match) {
135
- return if string.nil? || match.nil?
136
- string.include?(match)
137
- },
138
- "starts with": ->(string, match) {
139
- return if string.nil? || match.nil?
140
- string.start_with?(match)
141
- },
142
- "ends with": ->(string, match) {
143
- return if string.nil? || match.nil?
144
- string.end_with?(match)
145
- },
146
- "matches": ->(string, match) {
147
- return if string.nil? || match.nil?
148
- string.match?(match)
149
- },
150
- "replace": ->(string, match, replacement) {
151
- return if string.nil? || match.nil? || replacement.nil?
152
- string.gsub(match, replacement)
153
- },
154
- "split": ->(string, match) {
155
- return if string.nil? || match.nil?
156
- string.split(match)
157
- },
158
- "strip": -> (string) {
159
- return if string.nil?
160
- string.strip
161
- },
162
- "extract": -> (string, pattern) {
163
- return if string.nil? || pattern.nil?
164
- string.match(pattern).captures
165
- },
166
- # Numeric functions
167
- "decimal": ->(n, scale) {
168
- return if n.nil? || scale.nil?
169
- n.round(scale)
170
- },
171
- "floor": ->(n) {
172
- return if n.nil?
173
- n.floor
174
- },
175
- "ceiling": ->(n) {
176
- return if n.nil?
177
- n.ceil
178
- },
179
- "round up": ->(n) {
180
- return if n.nil?
181
- n.ceil
182
- },
183
- "round down": ->(n) {
184
- return if n.nil?
185
- n.floor
186
- },
187
- "abs": ->(n) {
188
- return if n.nil?
189
- n.abs
190
- },
191
- "modulo": ->(n, divisor) {
192
- return if n.nil? || divisor.nil?
193
- n % divisor
194
- },
195
- "sqrt": ->(n) {
196
- return if n.nil?
197
- Math.sqrt(n)
198
- },
199
- "log": ->(n) {
200
- return if n.nil?
201
- Math.log(n)
202
- },
203
- "exp": ->(n) {
204
- return if n.nil?
205
- Math.exp(n)
206
- },
207
- "odd": ->(n) {
208
- return if n.nil?
209
- n.odd?
210
- },
211
- "even": ->(n) {
212
- return if n.nil?
213
- n.even?
214
- },
215
- "random number": ->(n) {
216
- return if n.nil?
217
- rand(n)
218
- },
219
- # List functions
220
- "list contains": ->(list, match) {
221
- return if list.nil?
222
- return false if match.nil?
223
- list.include?(match)
224
- },
225
- "count": ->(list) {
226
- return if list.nil?
227
- return 0 if list.empty?
228
- list.length
229
- },
230
- "min": ->(list) {
231
- return if list.nil?
232
- list.min
233
- },
234
- "max": ->(list) {
235
- return if list.nil?
236
- list.max
237
- },
238
- "sum": ->(list) {
239
- return if list.nil?
240
- list.sum
241
- },
242
- "product": ->(list) {
243
- return if list.nil?
244
- list.inject(:*)
245
- },
246
- "mean": ->(list) {
247
- return if list.nil?
248
- list.sum / list.length
249
- },
250
- "median": ->(list) {
251
- return if list.nil?
252
- list.sort[list.length / 2]
253
- },
254
- "stddev": ->(list) {
255
- return if list.nil?
256
- mean = list.sum / list.length.to_f
257
- Math.sqrt(list.map { |n| (n - mean)**2 }.sum / list.length)
258
- },
259
- "mode": ->(list) {
260
- return if list.nil?
261
- list.group_by(&:itself).values.max_by(&:size).first
262
- },
263
- "all": ->(list) {
264
- return if list.nil?
265
- list.all?
266
- },
267
- "any": ->(list) {
268
- return if list.nil?
269
- list.any?
270
- },
271
- "sublist": ->(list, start, length) {
272
- return if list.nil? || start.nil?
273
- return [] if length.nil?
274
- list[start - 1, length]
275
- },
276
- "append": ->(list, item) {
277
- return if list.nil?
278
- list + [item]
279
- },
280
- "concatenate": ->(list1, list2) {
281
- return [nil, nil] if list1.nil? && list2.nil?
282
- return [nil] + list2 if list1.nil?
283
- return list1 + [nil] if list2.nil?
284
- Array.wrap(list1) + Array.wrap(list2)
285
- },
286
- "insert before": ->(list, position, item) {
287
- return if list.nil? || position.nil?
288
- list.insert(position - 1, item)
289
- },
290
- "remove": ->(list, position) {
291
- return if list.nil? || position.nil?
292
- list.delete_at(position - 1); list
293
- },
294
- "reverse": ->(list) {
295
- return if list.nil?
296
- list.reverse
297
- },
298
- "index of": ->(list, match) {
299
- return if list.nil?
300
- return [] if match.nil?
301
- list.index(match) + 1
302
- },
303
- "union": ->(list1, list2) {
304
- return if list1.nil? || list2.nil?
305
- list1 | list2
306
- },
307
- "distinct values": ->(list) {
308
- return if list.nil?
309
- list.uniq
310
- },
311
- "duplicate values": ->(list) {
312
- return if list.nil?
313
- list.select { |e| list.count(e) > 1 }.uniq
314
- },
315
- "flatten": ->(list) {
316
- return if list.nil?
317
- list.flatten
318
- },
319
- "sort": ->(list) {
320
- return if list.nil?
321
- list.sort
322
- },
323
- "string join": ->(list, separator) {
324
- return if list.nil?
325
- list.join(separator)
326
- },
327
- # Context functions
328
- "get value": ->(context, name) {
329
- return if context.nil? || name.nil?
330
- context[name]
331
- },
332
- "context put": ->(context, name, value) {
333
- return if context.nil? || name.nil?
334
- context[name] = value; context
335
- },
336
- "context merge": ->(context1, context2) {
337
- return if context1.nil? || context2.nil?
338
- context1.merge(context2)
339
- },
340
- "get entries": ->(context) {
341
- return if context.nil?
342
- context.entries
343
- },
344
- # Temporal functions
345
- "now": ->() { Time.now },
346
- "today": ->() { Date.today },
347
- "day of week": ->(date) {
348
- return if date.nil?
349
- date.wday
350
- },
351
- "day of year": ->(date) {
352
- return if date.nil?
353
- date.yday
354
- },
355
- "week of year": ->(date) {
356
- return if date.nil?
357
- date.cweek
358
- },
359
- "month of year": ->(date) {
360
- return if date.nil?
361
- date.month
362
- },
363
- })
364
- end
365
-
366
- def as_json
367
- {
368
- id: id,
369
- text: text,
370
- }
371
- end
372
- end
373
- end
374
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- module Dmn
5
- class Output
6
- attr_reader :id, :label, :name, :type_ref
7
-
8
- def self.from_json(json)
9
- Output.new(id: json[:id], label: json[:label], name: json[:name], type_ref: json[:type_ref])
10
- end
11
-
12
- def initialize(id:, label:, name:, type_ref:)
13
- @id = id
14
- @label = label
15
- @name = name
16
- @type_ref = type_ref
17
- end
18
-
19
- def as_json
20
- {
21
- id: id,
22
- label: label,
23
- name: name,
24
- type_ref: type_ref,
25
- }
26
- end
27
- end
28
- end
29
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- module Dmn
5
- class Rule
6
- attr_accessor :id, :input_entries, :output_entries, :description
7
-
8
- def self.from_json(json)
9
- input_entries = Array.wrap(json[:input_entry]).map { |input_entry| UnaryTests.from_json(input_entry) }
10
- output_entries = Array.wrap(json[:output_entry]).map { |output_entry| LiteralExpression.from_json(output_entry) }
11
- Rule.new(id: json[:id], input_entries:, output_entries:, description: json[:description])
12
- end
13
-
14
- def initialize(id:, input_entries:, output_entries:, description: nil)
15
- @id = id
16
- @input_entries = input_entries
17
- @output_entries = output_entries
18
- @description = description
19
- end
20
-
21
- def evaluate(input_values = [], variables = {})
22
- [].tap do |test_results|
23
- input_entries.each_with_index do |input_entry, index|
24
- test_results.push input_entry.test(input_values[index], variables)
25
- end
26
- end
27
- end
28
-
29
- def as_json
30
- {
31
- id: id,
32
- input_entries: input_entries.map(&:as_json),
33
- output_entries: output_entries.map(&:as_json),
34
- description: description,
35
- }
36
- end
37
-
38
- def output_value(outputs, variables)
39
- HashWithIndifferentAccess.new.tap do |ov|
40
- output_entries.each_with_index do |output_entry, index|
41
- if output_entry.valid?
42
- val = output_entry.evaluate(variables)
43
- nested_hash_value(ov, outputs[index].name, val)
44
- end
45
- end
46
- end
47
- end
48
-
49
- private
50
-
51
- def nested_hash_value(hash, key_string, value)
52
- keys = key_string.split('.')
53
- current = hash
54
- keys[0...-1].each do |key|
55
- current[key] ||= {}
56
- current = current[key]
57
- end
58
- current[keys.last] = value
59
- hash
60
- end
61
- end
62
- end
63
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- module Dmn
5
- class UnaryTests < LiteralExpression
6
- attr_reader :id, :text
7
-
8
- def self.from_json(json)
9
- UnaryTests.new(id: json[:id], text: json[:text])
10
- end
11
-
12
- def tree
13
- @tree ||= Parser.parse_test(text)
14
- end
15
-
16
- def valid?
17
- return true if text.nil? || text == '-'
18
- tree.present?
19
- end
20
-
21
- def test(input, variables = {})
22
- return true if text.nil? || text == '-'
23
- tree.eval(functions.merge(variables)).call(input)
24
- end
25
- end
26
- end
27
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- module Dmn
5
- class Variable
6
- attr_reader :id, :name, :type_ref
7
-
8
- def self.from_json(json)
9
- Variable.new(id: json[:id], name: json[:name], type_ref: json[:type_ref])
10
- end
11
-
12
- def initialize(id:, name:, type_ref:)
13
- @id = id
14
- @name = name
15
- @type_ref = type_ref
16
- end
17
-
18
- def as_json
19
- {
20
- id: id,
21
- name: name,
22
- type_ref: type_ref,
23
- }
24
- end
25
- end
26
- end
27
- end
data/lib/spot_feel/dmn.rb DELETED
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "dmn/variable"
4
- require_relative "dmn/literal_expression"
5
- require_relative "dmn/unary_tests"
6
- require_relative "dmn/input"
7
- require_relative "dmn/output"
8
- require_relative "dmn/rule"
9
- require_relative "dmn/decision_table"
10
- require_relative "dmn/information_requirement"
11
- require_relative "dmn/decision"
12
- require_relative "dmn/definitions"
13
-
14
- module SpotFeel
15
- module Dmn
16
- end
17
- end
@@ -1,5 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- VERSION = '0.0.1'
5
- end