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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/amplitude-experiment.gemspec +5 -5
  3. data/lib/amplitude-experiment.rb +6 -1
  4. data/lib/experiment/deployment/deployment_runner.rb +3 -3
  5. data/lib/experiment/evaluation/evaluation.rb +311 -0
  6. data/lib/experiment/evaluation/flag.rb +123 -0
  7. data/lib/experiment/evaluation/murmur3.rb +104 -0
  8. data/lib/experiment/evaluation/select.rb +16 -0
  9. data/lib/experiment/evaluation/semantic_version.rb +52 -0
  10. data/lib/experiment/evaluation/topological_sort.rb +56 -0
  11. data/lib/experiment/flag/flag_config_fetcher.rb +1 -1
  12. data/lib/experiment/flag/flag_config_storage.rb +1 -1
  13. data/lib/experiment/local/client.rb +7 -8
  14. data/lib/experiment/persistent_http_client.rb +1 -1
  15. data/lib/experiment/remote/client.rb +8 -6
  16. data/lib/experiment/remote/config.rb +8 -1
  17. data/lib/experiment/util/flag_config.rb +10 -10
  18. data/lib/experiment/version.rb +1 -1
  19. metadata +20 -24
  20. data/lib/experiment/local/evaluation/evaluation.rb +0 -76
  21. data/lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop.so +0 -0
  22. data/lib/experiment/local/evaluation/lib/linuxArm64/libevaluation_interop_api.h +0 -110
  23. data/lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop.so +0 -0
  24. data/lib/experiment/local/evaluation/lib/linuxX64/libevaluation_interop_api.h +0 -110
  25. data/lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop.dylib +0 -0
  26. data/lib/experiment/local/evaluation/lib/macosArm64/libevaluation_interop_api.h +0 -110
  27. data/lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop.dylib +0 -0
  28. data/lib/experiment/local/evaluation/lib/macosX64/libevaluation_interop_api.h +0 -110
  29. 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.
@@ -40,7 +40,7 @@ module AmplitudeExperiment
40
40
 
41
41
  def put_flag_config(flag_config)
42
42
  @flag_configs_lock.synchronize do
43
- @flag_configs[flag_config['key']] = flag_config
43
+ @flag_configs[flag_config.key] = flag_config
44
44
  end
45
45
  end
46
46
 
@@ -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 = AmplitudeExperiment.topological_sort(flags, flag_keys.to_set)
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: #{context_json} - Rules: #{flags}") if @config.debug
78
- result = evaluation(flags_json, context_json)
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['key']} dependent on cohorts #{cohort_ids_str} without #{missing_cohorts_str} in storage"
115
+ "Evaluating flag #{flag.key} dependent on cohorts #{cohort_ids_str} without #{missing_cohorts_str} in storage"
117
116
  else
118
- "Evaluating flag #{flag['key']} dependent on cohorts #{cohort_ids_str} without cohort syncing configured"
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] timeout_millis
127
- def do_fetch(user, timeout_millis)
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
- read_timeout = timeout_millis.to_f / 1000 if (timeout_millis.to_f / 1000) > 0
135
- http = PersistentHttpClient.get(@uri, { read_timeout: read_timeout }, @api_key)
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['op']) &&
4
- condition['selector'] &&
5
- condition['selector'][-1] == 'cohort_ids'
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['conditions'] || []
10
+ conditions = segment.conditions || []
11
11
  conditions.each do |condition|
12
12
  condition = condition[0]
13
- next unless cohort_filter?(condition) && (condition['selector'][1].length > 2)
13
+ next unless cohort_filter?(condition) && (condition.selector[1].length > 2)
14
14
 
15
- context_subtype = condition['selector'][1]
15
+ context_subtype = condition.selector[1]
16
16
  group_type =
17
17
  if context_subtype == 'user'
18
18
  USER_GROUP_TYPE
19
- elsif condition['selector'].include?('groups')
20
- condition['selector'][2]
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['values'])
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['segments'] || []
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
@@ -1,3 +1,3 @@
1
1
  module AmplitudeExperiment
2
- VERSION = '1.5.0'.freeze
2
+ VERSION = '1.6.0'.freeze
3
3
  end
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.5.0
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: 2024-08-27 00:00:00.000000000 Z
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: :development
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.4'
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.4'
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: ffi
154
+ name: jar-dependencies
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - "~>"
157
+ - - '='
158
158
  - !ruby/object:Gem::Version
159
- version: '1.15'
160
- type: :runtime
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: '1.15'
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
@@ -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 */