amplitude-experiment 1.5.0 → 1.6.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 +4 -4
- data/amplitude-experiment.gemspec +5 -5
- data/lib/amplitude-experiment.rb +6 -1
- data/lib/experiment/deployment/deployment_runner.rb +3 -3
- data/lib/experiment/evaluation/evaluation.rb +311 -0
- data/lib/experiment/evaluation/flag.rb +123 -0
- data/lib/experiment/evaluation/murmur3.rb +104 -0
- data/lib/experiment/evaluation/select.rb +16 -0
- data/lib/experiment/evaluation/semantic_version.rb +52 -0
- data/lib/experiment/evaluation/topological_sort.rb +56 -0
- data/lib/experiment/flag/flag_config_fetcher.rb +1 -1
- data/lib/experiment/flag/flag_config_storage.rb +1 -1
- data/lib/experiment/local/client.rb +7 -8
- data/lib/experiment/persistent_http_client.rb +1 -1
- data/lib/experiment/remote/client.rb +8 -6
- data/lib/experiment/remote/config.rb +8 -1
- data/lib/experiment/util/flag_config.rb +10 -10
- data/lib/experiment/version.rb +1 -1
- metadata +20 -24
- data/lib/experiment/local/evaluation/evaluation.rb +0 -76
- data/lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop.so +0 -0
- data/lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop_api.h +0 -110
- data/lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop.so +0 -0
- data/lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop_api.h +0 -110
- data/lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop.dylib +0 -0
- data/lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop_api.h +0 -110
- data/lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop.dylib +0 -0
- data/lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop_api.h +0 -110
- data/lib/experiment/util/topological_sort.rb +0 -39
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CycleError < StandardError
|
4
|
+
attr_accessor :path
|
5
|
+
|
6
|
+
def initialize(path)
|
7
|
+
super("Detected a cycle between flags #{path}")
|
8
|
+
self.path = path
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Performs topological sorting of feature flags based on their dependencies
|
13
|
+
class TopologicalSort
|
14
|
+
# Sort flags topologically based on their dependencies
|
15
|
+
def self.sort(flags, flag_keys = nil)
|
16
|
+
available = flags.clone
|
17
|
+
result = []
|
18
|
+
starting_keys = flag_keys.nil? || flag_keys.empty? ? flags.keys : flag_keys
|
19
|
+
|
20
|
+
starting_keys.each do |flag_key|
|
21
|
+
traversal = parent_traversal(flag_key, available)
|
22
|
+
result.concat(traversal) if traversal
|
23
|
+
end
|
24
|
+
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
# Perform depth-first traversal of flag dependencies
|
29
|
+
def self.parent_traversal(flag_key, available, path = [])
|
30
|
+
flag = available[flag_key]
|
31
|
+
return nil unless flag
|
32
|
+
|
33
|
+
# No dependencies - return flag and remove from available
|
34
|
+
if !flag.dependencies || flag.dependencies.empty?
|
35
|
+
available.delete(flag.key)
|
36
|
+
return [flag]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Check for cycles
|
40
|
+
path.push(flag.key)
|
41
|
+
result = []
|
42
|
+
|
43
|
+
flag.dependencies.each do |parent_key|
|
44
|
+
raise CycleError, path if path.any? { |p| p == parent_key }
|
45
|
+
|
46
|
+
traversal = parent_traversal(parent_key, available, path)
|
47
|
+
result.concat(traversal) if traversal
|
48
|
+
end
|
49
|
+
|
50
|
+
result.push(flag)
|
51
|
+
path.pop
|
52
|
+
available.delete(flag.key)
|
53
|
+
|
54
|
+
result
|
55
|
+
end
|
56
|
+
end
|
@@ -44,7 +44,7 @@ module AmplitudeExperiment
|
|
44
44
|
raise "flagConfigs - received error response: #{response.code}: #{response.body}" unless response.is_a?(Net::HTTPOK)
|
45
45
|
|
46
46
|
@logger.debug("[Experiment] Fetch flag configs: #{response.body}")
|
47
|
-
JSON.parse(response.body)
|
47
|
+
JSON.parse(response.body).map { |f| Evaluation::Flag.from_hash(f) }
|
48
48
|
end
|
49
49
|
|
50
50
|
# Fetch local evaluation mode flag configs from the Experiment API server.
|
@@ -12,7 +12,6 @@ module AmplitudeExperiment
|
|
12
12
|
# @param [LocalEvaluationConfig] config The config object
|
13
13
|
|
14
14
|
def initialize(api_key, config = nil)
|
15
|
-
require 'experiment/local/evaluation/evaluation'
|
16
15
|
@api_key = api_key
|
17
16
|
@config = config || LocalEvaluationConfig.new
|
18
17
|
@flags = nil
|
@@ -25,6 +24,8 @@ module AmplitudeExperiment
|
|
25
24
|
end
|
26
25
|
raise ArgumentError, 'Experiment API key is empty' if @api_key.nil? || @api_key.empty?
|
27
26
|
|
27
|
+
@engine = Evaluation::Engine.new
|
28
|
+
|
28
29
|
@assignment_service = nil
|
29
30
|
@assignment_service = AssignmentService.new(AmplitudeAnalytics::Amplitude.new(config.assignment_config.api_key, configuration: config.assignment_config), AssignmentFilter.new(config.assignment_config.cache_capacity)) if config&.assignment_config
|
30
31
|
|
@@ -67,15 +68,13 @@ module AmplitudeExperiment
|
|
67
68
|
flags = @flag_config_storage.flag_configs
|
68
69
|
return {} if flags.nil?
|
69
70
|
|
70
|
-
sorted_flags =
|
71
|
+
sorted_flags = TopologicalSort.sort(flags, flag_keys)
|
71
72
|
required_cohorts_in_storage(sorted_flags)
|
72
|
-
flags_json = sorted_flags.to_json
|
73
73
|
user = enrich_user_with_cohorts(user, flags) if @config.cohort_sync_config
|
74
74
|
context = AmplitudeExperiment.user_to_evaluation_context(user)
|
75
|
-
context_json = context.to_json
|
76
75
|
|
77
|
-
@logger.debug("[Experiment] Evaluate: User: #{
|
78
|
-
result =
|
76
|
+
@logger.debug("[Experiment] Evaluate: User: #{context} - Rules: #{flags}") if @config.debug
|
77
|
+
result = @engine.evaluate(context, sorted_flags)
|
79
78
|
@logger.debug("[Experiment] evaluate - result: #{result}") if @config.debug
|
80
79
|
variants = AmplitudeExperiment.evaluation_variants_json_to_variants(result)
|
81
80
|
@assignment_service&.track(Assignment.new(user, variants))
|
@@ -113,9 +112,9 @@ module AmplitudeExperiment
|
|
113
112
|
missing_cohorts_str = "[#{missing_cohorts.map(&:to_s).join(', ')}]"
|
114
113
|
|
115
114
|
message = if @config.cohort_sync_config
|
116
|
-
"Evaluating flag #{flag
|
115
|
+
"Evaluating flag #{flag.key} dependent on cohorts #{cohort_ids_str} without #{missing_cohorts_str} in storage"
|
117
116
|
else
|
118
|
-
"Evaluating flag #{flag
|
117
|
+
"Evaluating flag #{flag.key} dependent on cohorts #{cohort_ids_str} without cohort syncing configured"
|
119
118
|
end
|
120
119
|
|
121
120
|
@logger.warn(message)
|
@@ -5,7 +5,7 @@ module AmplitudeExperiment
|
|
5
5
|
# WARNING: these connections are not safe for concurrent requests. Callers
|
6
6
|
# must synchronize requests per connection.
|
7
7
|
class PersistentHttpClient
|
8
|
-
DEFAULT_OPTIONS = { read_timeout: 80 }.freeze
|
8
|
+
DEFAULT_OPTIONS = { open_timeout: 60, read_timeout: 80 }.freeze
|
9
9
|
|
10
10
|
class << self
|
11
11
|
# url: URI / String
|
@@ -89,7 +89,7 @@ module AmplitudeExperiment
|
|
89
89
|
# @param [User] user
|
90
90
|
def fetch_internal(user)
|
91
91
|
@logger.debug("[Experiment] Fetching variants for user: #{user.as_json}")
|
92
|
-
do_fetch(user, @config.fetch_timeout_millis)
|
92
|
+
do_fetch(user, @config.connect_timeout_millis, @config.fetch_timeout_millis)
|
93
93
|
rescue StandardError => e
|
94
94
|
@logger.error("[Experiment] Fetch failed: #{e.message}")
|
95
95
|
if should_retry_fetch?(e)
|
@@ -112,7 +112,7 @@ module AmplitudeExperiment
|
|
112
112
|
@config.fetch_retries.times do
|
113
113
|
sleep(delay_millis.to_f / 1000.0)
|
114
114
|
begin
|
115
|
-
return do_fetch(user, @config.fetch_retry_timeout_millis)
|
115
|
+
return do_fetch(user, @config.connect_timeout_millis, @config.fetch_retry_timeout_millis)
|
116
116
|
rescue StandardError => e
|
117
117
|
@logger.error("[Experiment] Retry failed: #{e.message}")
|
118
118
|
err = e
|
@@ -123,16 +123,18 @@ module AmplitudeExperiment
|
|
123
123
|
end
|
124
124
|
|
125
125
|
# @param [User] user
|
126
|
-
# @param [Integer]
|
127
|
-
|
126
|
+
# @param [Integer] connect_timeout_millis
|
127
|
+
# @param [Integer] fetch_timeout_millis
|
128
|
+
def do_fetch(user, connect_timeout_millis, fetch_timeout_millis)
|
128
129
|
start_time = Time.now
|
129
130
|
user_context = add_context(user)
|
130
131
|
headers = {
|
131
132
|
'Authorization' => "Api-Key #{@api_key}",
|
132
133
|
'Content-Type' => 'application/json;charset=utf-8'
|
133
134
|
}
|
134
|
-
|
135
|
-
|
135
|
+
connect_timeout = connect_timeout_millis.to_f / 1000 if (connect_timeout_millis.to_f / 1000) > 0
|
136
|
+
read_timeout = fetch_timeout_millis.to_f / 1000 if (fetch_timeout_millis.to_f / 1000) > 0
|
137
|
+
http = PersistentHttpClient.get(@uri, { open_timeout: connect_timeout, read_timeout: read_timeout }, @api_key)
|
136
138
|
request = Net::HTTP::Post.new(@uri, headers)
|
137
139
|
request.body = user_context.to_json
|
138
140
|
@logger.warn("[Experiment] encoded user object length #{request.body.length} cannot be cached by CDN; must be < 8KB") if request.body.length > 8000
|
@@ -12,6 +12,10 @@ module AmplitudeExperiment
|
|
12
12
|
# @return [Boolean] the value of server url
|
13
13
|
attr_accessor :server_url
|
14
14
|
|
15
|
+
# The request connection open timeout, in milliseconds, used when fetching variants triggered by calling start() or setUser().
|
16
|
+
# @return [Integer] the value of connect_timeout_millis
|
17
|
+
attr_accessor :connect_timeout_millis
|
18
|
+
|
15
19
|
# The request timeout, in milliseconds, used when fetching variants triggered by calling start() or setUser().
|
16
20
|
# @return [Integer] the value of fetch_timeout_millis
|
17
21
|
attr_accessor :fetch_timeout_millis
|
@@ -40,6 +44,8 @@ module AmplitudeExperiment
|
|
40
44
|
|
41
45
|
# @param [Boolean] debug Set to true to log some extra information to the console.
|
42
46
|
# @param [String] server_url The server endpoint from which to request variants.
|
47
|
+
# @param [Integer] connect_timeout_millis The request connection open timeout, in milliseconds, used when
|
48
|
+
# fetching variants triggered by calling start() or setUser().
|
43
49
|
# @param [Integer] fetch_timeout_millis The request timeout, in milliseconds, used when fetching variants
|
44
50
|
# triggered by calling start() or setUser().
|
45
51
|
# @param [Integer] fetch_retries The number of retries to attempt before failing.
|
@@ -49,11 +55,12 @@ module AmplitudeExperiment
|
|
49
55
|
# greater than the max, the max is used for all subsequent retries.
|
50
56
|
# @param [Float] fetch_retry_backoff_scalar Scales the minimum backoff exponentially.
|
51
57
|
# @param [Integer] fetch_retry_timeout_millis The request timeout for retrying fetch requests.
|
52
|
-
def initialize(debug: false, server_url: DEFAULT_SERVER_URL, fetch_timeout_millis: 10_000, fetch_retries: 0,
|
58
|
+
def initialize(debug: false, server_url: DEFAULT_SERVER_URL, connect_timeout_millis: 60_000, fetch_timeout_millis: 10_000, fetch_retries: 0,
|
53
59
|
fetch_retry_backoff_min_millis: 500, fetch_retry_backoff_max_millis: 10_000,
|
54
60
|
fetch_retry_backoff_scalar: 1.5, fetch_retry_timeout_millis: 10_000)
|
55
61
|
@debug = debug
|
56
62
|
@server_url = server_url
|
63
|
+
@connect_timeout_millis = connect_timeout_millis
|
57
64
|
@fetch_timeout_millis = fetch_timeout_millis
|
58
65
|
@fetch_retries = fetch_retries
|
59
66
|
@fetch_retry_backoff_min_millis = fetch_retry_backoff_min_millis
|
@@ -1,35 +1,35 @@
|
|
1
1
|
module AmplitudeExperiment
|
2
2
|
def self.cohort_filter?(condition)
|
3
|
-
['set contains any', 'set does not contain any'].include?(condition
|
4
|
-
condition
|
5
|
-
condition
|
3
|
+
['set contains any', 'set does not contain any'].include?(condition.op) &&
|
4
|
+
condition.selector &&
|
5
|
+
condition.selector[-1] == 'cohort_ids'
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.get_grouped_cohort_condition_ids(segment)
|
9
9
|
cohort_ids = {}
|
10
|
-
conditions = segment
|
10
|
+
conditions = segment.conditions || []
|
11
11
|
conditions.each do |condition|
|
12
12
|
condition = condition[0]
|
13
|
-
next unless cohort_filter?(condition) && (condition
|
13
|
+
next unless cohort_filter?(condition) && (condition.selector[1].length > 2)
|
14
14
|
|
15
|
-
context_subtype = condition
|
15
|
+
context_subtype = condition.selector[1]
|
16
16
|
group_type =
|
17
17
|
if context_subtype == 'user'
|
18
18
|
USER_GROUP_TYPE
|
19
|
-
elsif condition
|
20
|
-
condition
|
19
|
+
elsif condition.selector.include?('groups')
|
20
|
+
condition.selector[2]
|
21
21
|
else
|
22
22
|
next
|
23
23
|
end
|
24
24
|
cohort_ids[group_type] ||= Set.new
|
25
|
-
cohort_ids[group_type].merge(condition
|
25
|
+
cohort_ids[group_type].merge(condition.values)
|
26
26
|
end
|
27
27
|
cohort_ids
|
28
28
|
end
|
29
29
|
|
30
30
|
def self.get_grouped_cohort_ids_from_flag(flag)
|
31
31
|
cohort_ids = {}
|
32
|
-
segments = flag
|
32
|
+
segments = flag.segments || []
|
33
33
|
segments.each do |segment|
|
34
34
|
get_grouped_cohort_condition_ids(segment).each do |key, values|
|
35
35
|
cohort_ids[key] ||= Set.new
|
data/lib/experiment/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: amplitude-experiment
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amplitude
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -17,7 +17,7 @@ dependencies:
|
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 1.2.2
|
20
|
-
type: :
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - '='
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '6.
|
61
|
+
version: '6.10'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - '='
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '6.
|
68
|
+
version: '6.10'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,19 +151,19 @@ dependencies:
|
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: 2.8.1
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
|
-
name:
|
154
|
+
name: jar-dependencies
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- -
|
157
|
+
- - '='
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version:
|
160
|
-
type: :
|
159
|
+
version: 0.4.1
|
160
|
+
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
|
-
- -
|
164
|
+
- - '='
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
166
|
+
version: 0.4.1
|
167
167
|
description: Amplitude Experiment Ruby Server SDK
|
168
168
|
email:
|
169
169
|
- sdk@amplitude.com
|
@@ -197,6 +197,12 @@ files:
|
|
197
197
|
- lib/experiment/cookie.rb
|
198
198
|
- lib/experiment/deployment/deployment_runner.rb
|
199
199
|
- lib/experiment/error.rb
|
200
|
+
- lib/experiment/evaluation/evaluation.rb
|
201
|
+
- lib/experiment/evaluation/flag.rb
|
202
|
+
- lib/experiment/evaluation/murmur3.rb
|
203
|
+
- lib/experiment/evaluation/select.rb
|
204
|
+
- lib/experiment/evaluation/semantic_version.rb
|
205
|
+
- lib/experiment/evaluation/topological_sort.rb
|
200
206
|
- lib/experiment/factory.rb
|
201
207
|
- lib/experiment/flag/flag_config_fetcher.rb
|
202
208
|
- lib/experiment/flag/flag_config_storage.rb
|
@@ -206,15 +212,6 @@ files:
|
|
206
212
|
- lib/experiment/local/assignment/assignment_service.rb
|
207
213
|
- lib/experiment/local/client.rb
|
208
214
|
- lib/experiment/local/config.rb
|
209
|
-
- lib/experiment/local/evaluation/evaluation.rb
|
210
|
-
- lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop.so
|
211
|
-
- lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop_api.h
|
212
|
-
- lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop.so
|
213
|
-
- lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop_api.h
|
214
|
-
- lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop.dylib
|
215
|
-
- lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop_api.h
|
216
|
-
- lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop.dylib
|
217
|
-
- lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop_api.h
|
218
215
|
- lib/experiment/persistent_http_client.rb
|
219
216
|
- lib/experiment/remote/client.rb
|
220
217
|
- lib/experiment/remote/config.rb
|
@@ -223,7 +220,6 @@ files:
|
|
223
220
|
- lib/experiment/util/hash.rb
|
224
221
|
- lib/experiment/util/lru_cache.rb
|
225
222
|
- lib/experiment/util/poller.rb
|
226
|
-
- lib/experiment/util/topological_sort.rb
|
227
223
|
- lib/experiment/util/user.rb
|
228
224
|
- lib/experiment/util/variant.rb
|
229
225
|
- lib/experiment/variant.rb
|
@@ -233,7 +229,7 @@ licenses:
|
|
233
229
|
- MIT
|
234
230
|
metadata:
|
235
231
|
rubygems_mfa_required: 'false'
|
236
|
-
post_install_message:
|
232
|
+
post_install_message:
|
237
233
|
rdoc_options: []
|
238
234
|
require_paths:
|
239
235
|
- lib
|
@@ -249,7 +245,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
249
245
|
version: '0'
|
250
246
|
requirements: []
|
251
247
|
rubygems_version: 3.1.6
|
252
|
-
signing_key:
|
248
|
+
signing_key:
|
253
249
|
specification_version: 4
|
254
250
|
summary: Amplitude Experiment Ruby Server SDK
|
255
251
|
test_files: []
|
@@ -1,76 +0,0 @@
|
|
1
|
-
# rubocop:disable all
|
2
|
-
require 'ffi'
|
3
|
-
require 'json'
|
4
|
-
|
5
|
-
# The evaluation wrapper
|
6
|
-
module EvaluationInterop
|
7
|
-
extend FFI::Library
|
8
|
-
host_os = RbConfig::CONFIG['host_os']
|
9
|
-
cpu = RbConfig::CONFIG['host_cpu']
|
10
|
-
evaluation_dir = File.dirname(__FILE__)
|
11
|
-
ffi_lib ["#{evaluation_dir}/lib/macosX64/libevaluation_interop.dylib"] if host_os =~ /darwin|mac os/ && cpu =~ /x86_64/
|
12
|
-
ffi_lib ["#{evaluation_dir}/lib/macosArm64/libevaluation_interop.dylib"] if host_os =~ /darwin|mac os/ && cpu =~ /arm64/
|
13
|
-
ffi_lib ["#{evaluation_dir}/lib/linuxX64/libevaluation_interop.so"] if host_os =~ /linux/ && cpu =~ /x86_64/
|
14
|
-
ffi_lib ["#{evaluation_dir}/lib/linuxArm64/libevaluation_interop.so"] if host_os =~ /linux/ && cpu =~ /arm64|aarch64/
|
15
|
-
|
16
|
-
class Root < FFI::Struct
|
17
|
-
layout :evaluate, callback([:string, :string], :pointer)
|
18
|
-
end
|
19
|
-
|
20
|
-
class Kotlin < FFI::Struct
|
21
|
-
layout :root, Root
|
22
|
-
end
|
23
|
-
|
24
|
-
class Libevaluation_interop_ExportedSymbols < FFI::Struct
|
25
|
-
layout :DisposeStablePointer, callback([:pointer], :void),
|
26
|
-
:DisposeString, callback([:pointer], :void),
|
27
|
-
:IsInstance, callback([:pointer, :string], :pointer),
|
28
|
-
:createNullableByte, callback([:string], :pointer),
|
29
|
-
:getNonNullValueOfByte, callback([:pointer], :pointer),
|
30
|
-
:createNullableShort, callback([:pointer], :pointer),
|
31
|
-
:getNonNullValueOfShort, callback([:pointer], :pointer),
|
32
|
-
:createNullableInt, callback([:pointer], :pointer),
|
33
|
-
:getNonNullValueOfInt, callback([:pointer], :pointer),
|
34
|
-
:createNullableLong, callback([:pointer], :pointer),
|
35
|
-
:getNonNullValueOfLong, callback([:pointer], :pointer),
|
36
|
-
:createNullableFloat, callback([:pointer], :pointer),
|
37
|
-
:getNonNullValueOfFloat, callback([:pointer], :pointer),
|
38
|
-
:createNullableDouble, callback([:pointer], :pointer),
|
39
|
-
:getNonNullValueOfDouble, callback([:pointer], :pointer),
|
40
|
-
:createNullableChar, callback([:pointer], :pointer),
|
41
|
-
:getNonNullValueOfChar, callback([:pointer], :pointer),
|
42
|
-
:createNullableBoolean, callback([:pointer], :pointer),
|
43
|
-
:getNonNullValueOfBoolean, callback([:pointer], :pointer),
|
44
|
-
:createNullableUnit, callback([], :pointer),
|
45
|
-
:createNullableUByte, callback([:pointer], :pointer),
|
46
|
-
:getNonNullValueOfUByte, callback([:pointer], :pointer),
|
47
|
-
:createNullableUShort, callback([:pointer], :pointer),
|
48
|
-
:getNonNullValueOfUShort, callback([:pointer], :pointer),
|
49
|
-
:createNullableUInt, callback([:pointer], :pointer),
|
50
|
-
:getNonNullValueOfUInt, callback([:pointer], :pointer),
|
51
|
-
:createNullableULong, callback([:pointer], :pointer),
|
52
|
-
:getNonNullValueOfULong, callback([:pointer], :pointer),
|
53
|
-
|
54
|
-
:kotlin, Kotlin
|
55
|
-
end
|
56
|
-
|
57
|
-
attach_function :libevaluation_interop_symbols, [], Libevaluation_interop_ExportedSymbols.by_ref
|
58
|
-
end
|
59
|
-
|
60
|
-
def evaluation(rule_json, context_json)
|
61
|
-
lib = EvaluationInterop.libevaluation_interop_symbols()
|
62
|
-
evaluate = lib[:kotlin][:root][:evaluate]
|
63
|
-
dispose = lib[:DisposeString]
|
64
|
-
result_raw = evaluate.call(rule_json, context_json)
|
65
|
-
result_json = result_raw.read_string
|
66
|
-
result = JSON.parse(result_json)
|
67
|
-
dispose.call(result_raw)
|
68
|
-
|
69
|
-
if result["error"] != nil
|
70
|
-
raise "#{result["error"]}"
|
71
|
-
elsif result["result"] == nil
|
72
|
-
raise "Evaluation result is nil."
|
73
|
-
end
|
74
|
-
result["result"]
|
75
|
-
end
|
76
|
-
# rubocop:disable all
|
Binary file
|
@@ -1,110 +0,0 @@
|
|
1
|
-
#ifndef KONAN_LIBEVALUATION_INTEROP_H
|
2
|
-
#define KONAN_LIBEVALUATION_INTEROP_H
|
3
|
-
#ifdef __cplusplus
|
4
|
-
extern "C" {
|
5
|
-
#endif
|
6
|
-
#ifdef __cplusplus
|
7
|
-
typedef bool libevaluation_interop_KBoolean;
|
8
|
-
#else
|
9
|
-
typedef _Bool libevaluation_interop_KBoolean;
|
10
|
-
#endif
|
11
|
-
typedef unsigned short libevaluation_interop_KChar;
|
12
|
-
typedef signed char libevaluation_interop_KByte;
|
13
|
-
typedef short libevaluation_interop_KShort;
|
14
|
-
typedef int libevaluation_interop_KInt;
|
15
|
-
typedef long long libevaluation_interop_KLong;
|
16
|
-
typedef unsigned char libevaluation_interop_KUByte;
|
17
|
-
typedef unsigned short libevaluation_interop_KUShort;
|
18
|
-
typedef unsigned int libevaluation_interop_KUInt;
|
19
|
-
typedef unsigned long long libevaluation_interop_KULong;
|
20
|
-
typedef float libevaluation_interop_KFloat;
|
21
|
-
typedef double libevaluation_interop_KDouble;
|
22
|
-
typedef float __attribute__ ((__vector_size__ (16))) libevaluation_interop_KVector128;
|
23
|
-
typedef void* libevaluation_interop_KNativePtr;
|
24
|
-
struct libevaluation_interop_KType;
|
25
|
-
typedef struct libevaluation_interop_KType libevaluation_interop_KType;
|
26
|
-
|
27
|
-
typedef struct {
|
28
|
-
libevaluation_interop_KNativePtr pinned;
|
29
|
-
} libevaluation_interop_kref_kotlin_Byte;
|
30
|
-
typedef struct {
|
31
|
-
libevaluation_interop_KNativePtr pinned;
|
32
|
-
} libevaluation_interop_kref_kotlin_Short;
|
33
|
-
typedef struct {
|
34
|
-
libevaluation_interop_KNativePtr pinned;
|
35
|
-
} libevaluation_interop_kref_kotlin_Int;
|
36
|
-
typedef struct {
|
37
|
-
libevaluation_interop_KNativePtr pinned;
|
38
|
-
} libevaluation_interop_kref_kotlin_Long;
|
39
|
-
typedef struct {
|
40
|
-
libevaluation_interop_KNativePtr pinned;
|
41
|
-
} libevaluation_interop_kref_kotlin_Float;
|
42
|
-
typedef struct {
|
43
|
-
libevaluation_interop_KNativePtr pinned;
|
44
|
-
} libevaluation_interop_kref_kotlin_Double;
|
45
|
-
typedef struct {
|
46
|
-
libevaluation_interop_KNativePtr pinned;
|
47
|
-
} libevaluation_interop_kref_kotlin_Char;
|
48
|
-
typedef struct {
|
49
|
-
libevaluation_interop_KNativePtr pinned;
|
50
|
-
} libevaluation_interop_kref_kotlin_Boolean;
|
51
|
-
typedef struct {
|
52
|
-
libevaluation_interop_KNativePtr pinned;
|
53
|
-
} libevaluation_interop_kref_kotlin_Unit;
|
54
|
-
typedef struct {
|
55
|
-
libevaluation_interop_KNativePtr pinned;
|
56
|
-
} libevaluation_interop_kref_kotlin_UByte;
|
57
|
-
typedef struct {
|
58
|
-
libevaluation_interop_KNativePtr pinned;
|
59
|
-
} libevaluation_interop_kref_kotlin_UShort;
|
60
|
-
typedef struct {
|
61
|
-
libevaluation_interop_KNativePtr pinned;
|
62
|
-
} libevaluation_interop_kref_kotlin_UInt;
|
63
|
-
typedef struct {
|
64
|
-
libevaluation_interop_KNativePtr pinned;
|
65
|
-
} libevaluation_interop_kref_kotlin_ULong;
|
66
|
-
|
67
|
-
|
68
|
-
typedef struct {
|
69
|
-
/* Service functions. */
|
70
|
-
void (*DisposeStablePointer)(libevaluation_interop_KNativePtr ptr);
|
71
|
-
void (*DisposeString)(const char* string);
|
72
|
-
libevaluation_interop_KBoolean (*IsInstance)(libevaluation_interop_KNativePtr ref, const libevaluation_interop_KType* type);
|
73
|
-
libevaluation_interop_kref_kotlin_Byte (*createNullableByte)(libevaluation_interop_KByte);
|
74
|
-
libevaluation_interop_KByte (*getNonNullValueOfByte)(libevaluation_interop_kref_kotlin_Byte);
|
75
|
-
libevaluation_interop_kref_kotlin_Short (*createNullableShort)(libevaluation_interop_KShort);
|
76
|
-
libevaluation_interop_KShort (*getNonNullValueOfShort)(libevaluation_interop_kref_kotlin_Short);
|
77
|
-
libevaluation_interop_kref_kotlin_Int (*createNullableInt)(libevaluation_interop_KInt);
|
78
|
-
libevaluation_interop_KInt (*getNonNullValueOfInt)(libevaluation_interop_kref_kotlin_Int);
|
79
|
-
libevaluation_interop_kref_kotlin_Long (*createNullableLong)(libevaluation_interop_KLong);
|
80
|
-
libevaluation_interop_KLong (*getNonNullValueOfLong)(libevaluation_interop_kref_kotlin_Long);
|
81
|
-
libevaluation_interop_kref_kotlin_Float (*createNullableFloat)(libevaluation_interop_KFloat);
|
82
|
-
libevaluation_interop_KFloat (*getNonNullValueOfFloat)(libevaluation_interop_kref_kotlin_Float);
|
83
|
-
libevaluation_interop_kref_kotlin_Double (*createNullableDouble)(libevaluation_interop_KDouble);
|
84
|
-
libevaluation_interop_KDouble (*getNonNullValueOfDouble)(libevaluation_interop_kref_kotlin_Double);
|
85
|
-
libevaluation_interop_kref_kotlin_Char (*createNullableChar)(libevaluation_interop_KChar);
|
86
|
-
libevaluation_interop_KChar (*getNonNullValueOfChar)(libevaluation_interop_kref_kotlin_Char);
|
87
|
-
libevaluation_interop_kref_kotlin_Boolean (*createNullableBoolean)(libevaluation_interop_KBoolean);
|
88
|
-
libevaluation_interop_KBoolean (*getNonNullValueOfBoolean)(libevaluation_interop_kref_kotlin_Boolean);
|
89
|
-
libevaluation_interop_kref_kotlin_Unit (*createNullableUnit)(void);
|
90
|
-
libevaluation_interop_kref_kotlin_UByte (*createNullableUByte)(libevaluation_interop_KUByte);
|
91
|
-
libevaluation_interop_KUByte (*getNonNullValueOfUByte)(libevaluation_interop_kref_kotlin_UByte);
|
92
|
-
libevaluation_interop_kref_kotlin_UShort (*createNullableUShort)(libevaluation_interop_KUShort);
|
93
|
-
libevaluation_interop_KUShort (*getNonNullValueOfUShort)(libevaluation_interop_kref_kotlin_UShort);
|
94
|
-
libevaluation_interop_kref_kotlin_UInt (*createNullableUInt)(libevaluation_interop_KUInt);
|
95
|
-
libevaluation_interop_KUInt (*getNonNullValueOfUInt)(libevaluation_interop_kref_kotlin_UInt);
|
96
|
-
libevaluation_interop_kref_kotlin_ULong (*createNullableULong)(libevaluation_interop_KULong);
|
97
|
-
libevaluation_interop_KULong (*getNonNullValueOfULong)(libevaluation_interop_kref_kotlin_ULong);
|
98
|
-
|
99
|
-
/* User functions. */
|
100
|
-
struct {
|
101
|
-
struct {
|
102
|
-
const char* (*evaluate)(const char* flags, const char* context);
|
103
|
-
} root;
|
104
|
-
} kotlin;
|
105
|
-
} libevaluation_interop_ExportedSymbols;
|
106
|
-
extern libevaluation_interop_ExportedSymbols* libevaluation_interop_symbols(void);
|
107
|
-
#ifdef __cplusplus
|
108
|
-
} /* extern "C" */
|
109
|
-
#endif
|
110
|
-
#endif /* KONAN_LIBEVALUATION_INTEROP_H */
|
Binary file
|