dmn 0.0.1 → 0.0.3

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.
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module SpotFeel
4
- module Dmn
5
- class Input
6
- attr_reader :id, :label, :input_expression
7
-
8
- def self.from_json(json)
9
- input_expression = LiteralExpression.from_json(json[:input_expression]) if json[:input_expression]
10
- Input.new(id: json[:id], label: json[:label], input_expression:)
11
- end
12
-
13
- def initialize(id:, label:, input_expression:)
14
- @id = id
15
- @label = label
16
- @input_expression = input_expression
17
- end
18
-
19
- def as_json
20
- {
21
- id: id,
22
- label: label,
23
- input_expression: input_expression.as_json,
24
- }
25
- end
26
- end
27
- end
28
- end
@@ -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