sweet-moon 0.0.1

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 (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +40 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +61 -0
  7. data/README.md +1149 -0
  8. data/components/api.rb +83 -0
  9. data/components/injections/injections_503.rb +21 -0
  10. data/components/injections/injections_514.rb +29 -0
  11. data/components/injections/injections_542.rb +49 -0
  12. data/components/injections.rb +11 -0
  13. data/components/interpreters/50/function.rb +52 -0
  14. data/components/interpreters/50/interpreter.rb +105 -0
  15. data/components/interpreters/50/reader.rb +65 -0
  16. data/components/interpreters/50/table.rb +99 -0
  17. data/components/interpreters/50/writer.rb +45 -0
  18. data/components/interpreters/51/function.rb +52 -0
  19. data/components/interpreters/51/interpreter.rb +104 -0
  20. data/components/interpreters/51/reader.rb +65 -0
  21. data/components/interpreters/51/table.rb +60 -0
  22. data/components/interpreters/51/writer.rb +45 -0
  23. data/components/interpreters/54/function.rb +52 -0
  24. data/components/interpreters/54/interpreter.rb +100 -0
  25. data/components/interpreters/54/reader.rb +65 -0
  26. data/components/interpreters/54/table.rb +60 -0
  27. data/components/interpreters/54/writer.rb +45 -0
  28. data/components/interpreters.rb +11 -0
  29. data/components/io.rb +11 -0
  30. data/config/tests.sample.yml +15 -0
  31. data/controllers/api.rb +143 -0
  32. data/controllers/cli/cli.rb +32 -0
  33. data/controllers/cli/help.rb +24 -0
  34. data/controllers/cli/signatures.rb +179 -0
  35. data/controllers/cli/version.rb +14 -0
  36. data/controllers/interpreter.rb +68 -0
  37. data/controllers/state.rb +74 -0
  38. data/dsl/api.rb +31 -0
  39. data/dsl/cache.rb +118 -0
  40. data/dsl/concerns/fennel.rb +13 -0
  41. data/dsl/concerns/packages.rb +37 -0
  42. data/dsl/errors.rb +28 -0
  43. data/dsl/fennel.rb +47 -0
  44. data/dsl/global.rb +42 -0
  45. data/dsl/state.rb +104 -0
  46. data/dsl/sweet_moon.rb +53 -0
  47. data/logic/api.rb +17 -0
  48. data/logic/interpreter.rb +84 -0
  49. data/logic/interpreters/interpreter_50.rb +34 -0
  50. data/logic/interpreters/interpreter_51.rb +37 -0
  51. data/logic/interpreters/interpreter_54.rb +41 -0
  52. data/logic/io.rb +6 -0
  53. data/logic/options.rb +14 -0
  54. data/logic/shared_object.rb +52 -0
  55. data/logic/signature.rb +258 -0
  56. data/logic/signatures/ffi_types.rb +27 -0
  57. data/logic/signatures/signatures_322.rb +418 -0
  58. data/logic/signatures/signatures_401.rb +243 -0
  59. data/logic/signatures/signatures_503.rb +575 -0
  60. data/logic/signatures/signatures_514.rb +460 -0
  61. data/logic/signatures/signatures_542.rb +591 -0
  62. data/logic/spec.rb +13 -0
  63. data/logic/tables.rb +32 -0
  64. data/ports/in/dsl/sweet-moon/errors.rb +3 -0
  65. data/ports/in/dsl/sweet-moon.rb +1 -0
  66. data/ports/in/shell/sweet-moon +5 -0
  67. data/ports/in/shell.rb +21 -0
  68. data/ports/out/shell.rb +9 -0
  69. data/sweet-moon.gemspec +35 -0
  70. metadata +137 -0
@@ -0,0 +1,37 @@
1
+ require_relative '../errors'
2
+
3
+ module DSL
4
+ module Concerns
5
+ module Packages
6
+ def add_package_path(path, target = 'package.path')
7
+ _ensure_min_version!(target, '5.1', '2')
8
+
9
+ paths = path
10
+ paths = [path] unless paths.is_a? Array
11
+
12
+ self.eval("#{target} = #{target} .. \";#{paths.join(';')}\"")
13
+ end
14
+
15
+ def package_path(target = 'package.path')
16
+ _ensure_min_version!(target, '5.1', '2')
17
+ self.eval("return #{target}").split(';')
18
+ end
19
+
20
+ def add_package_cpath(path)
21
+ add_package_path(path, 'package.cpath')
22
+ end
23
+
24
+ def package_cpath
25
+ package_path('package.cpath')
26
+ end
27
+
28
+ def require_module(module_name)
29
+ require_module_as(module_name, module_name)
30
+ end
31
+
32
+ def require_module_as(module_name, variable)
33
+ self.eval("#{variable} = require \"#{module_name}\"")
34
+ end
35
+ end
36
+ end
37
+ end
data/dsl/errors.rb ADDED
@@ -0,0 +1,28 @@
1
+ module SweetMoon
2
+ module Errors
3
+ class SweetMoonError < StandardError; end
4
+ class LuaError < SweetMoonError; end
5
+
6
+ class LuaRuntimeError < LuaError; end
7
+ class LuaMemoryAllocationError < LuaError; end
8
+ class LuaMessageHandlerError < LuaError; end
9
+ class LuaSyntaxError < LuaError; end
10
+ class LuaFileError < LuaError; end
11
+
12
+ module SweetMoonErrorHelper
13
+ def for(status)
14
+ case status
15
+ when :runtime then LuaRuntimeError
16
+ when :memory_allocation then LuaMemoryAllocationError
17
+ when :message_handler then LuaMessageHandlerError
18
+ when :syntax then LuaSyntaxError
19
+ when :file then LuaFileError
20
+ else
21
+ LuaError
22
+ end
23
+ end
24
+
25
+ module_function :for
26
+ end
27
+ end
28
+ end
data/dsl/fennel.rb ADDED
@@ -0,0 +1,47 @@
1
+ module DSL
2
+ class Fennel
3
+ attr_reader :meta
4
+
5
+ def initialize(state)
6
+ @state = state
7
+
8
+ @state.require_module(:fennel)
9
+
10
+ @state.eval(
11
+ 'table.insert(package.loaders or package.searchers, fennel.searcher)'
12
+ )
13
+
14
+ @eval = @state.get(:fennel, :eval)
15
+ @dofile = @state.get(:fennel, :dofile)
16
+ @version = @state.get(:fennel, :version)
17
+
18
+ build_meta
19
+ end
20
+
21
+ def eval(input, outputs = 1)
22
+ @eval.([input], outputs)
23
+ end
24
+
25
+ def load(path, outputs = 1)
26
+ @dofile.([path], outputs)
27
+ end
28
+
29
+ def build_meta
30
+ meta_data = @state.meta.to_h
31
+
32
+ meta_data = meta_data.merge(
33
+ runtime: "Fennel #{@version} on #{meta_data[:runtime]}"
34
+ )
35
+
36
+ @meta = Struct.new(*meta_data.keys).new(*meta_data.values)
37
+ end
38
+
39
+ def respond_to_missing?(method_name)
40
+ @state.respond_to? method_name
41
+ end
42
+
43
+ def method_missing(method_name, *arguments, &block)
44
+ @state.public_send(method_name, *arguments, &block)
45
+ end
46
+ end
47
+ end
data/dsl/global.rb ADDED
@@ -0,0 +1,42 @@
1
+ require_relative '../logic/options'
2
+
3
+ require_relative 'cache'
4
+
5
+ module Global
6
+ def api
7
+ Cache.instance.global_api
8
+ end
9
+
10
+ def state
11
+ Cache.instance.global_state
12
+ end
13
+
14
+ def config(options = {})
15
+ options = Logic::Options[:normalize].(options)
16
+
17
+ if options.key?(:shared_objects) || options.key?(:api_reference)
18
+ Cache.instance.global_api(options, recreate: true)
19
+ end
20
+
21
+ return unless
22
+ options.key?(:interpreter) ||
23
+ options.key?(:package_path) ||
24
+ options.key?(:package_cpath)
25
+
26
+ Cache.instance.global_state(options, recreate: true)
27
+
28
+ nil
29
+ end
30
+
31
+ def cached(all: false)
32
+ return Cache.instance.keys if all
33
+
34
+ Cache.instance.keys.select { |key| key[/^global/] }
35
+ end
36
+
37
+ def clear
38
+ Cache.instance.clear_global!
39
+ end
40
+
41
+ module_function :api, :state, :config, :cached, :clear
42
+ end
data/dsl/state.rb ADDED
@@ -0,0 +1,104 @@
1
+ require_relative 'errors'
2
+ require_relative 'concerns/packages'
3
+ require_relative 'concerns/fennel'
4
+
5
+ module DSL
6
+ class State
7
+ include DSL::Concerns::Packages
8
+ include DSL::Concerns::Fennel
9
+
10
+ attr_reader :meta
11
+
12
+ def initialize(api_component, interpreter_component, controller, options = {})
13
+ @api = api_component[:api]
14
+ @interpreter = interpreter_component[:interpreter]
15
+ @controller = controller
16
+
17
+ @state = @controller[:create!].(@api, @interpreter)[:state]
18
+
19
+ build_meta(api_component, interpreter_component)
20
+
21
+ add_package_path(options[:package_path]) if options[:package_path]
22
+ add_package_cpath(options[:package_cpath]) if options[:package_cpath]
23
+ end
24
+
25
+ def eval(input, outputs = 1)
26
+ @controller[:eval!].(@api, @interpreter, state, input, outputs)[:output]
27
+ end
28
+
29
+ def load(path, outputs = 1)
30
+ @controller[:load!].(@api, @interpreter, state, path, outputs)[:output]
31
+ end
32
+
33
+ def get(variable, key = nil)
34
+ @controller[:get!].(@api, @interpreter, state, variable, key)[:output]
35
+ end
36
+
37
+ def set(variable, value)
38
+ @controller[:set!].(@api, @interpreter, state, variable, value)[:output]
39
+ end
40
+
41
+ def destroy
42
+ @controller[:destroy!].(@api, @interpreter, state) if @state
43
+ @state = nil
44
+ end
45
+
46
+ def clear
47
+ @controller[:destroy!].(@api, @interpreter, state) if @state
48
+ @state = @controller[:create!].(@api, @interpreter)[:state]
49
+ nil
50
+ end
51
+
52
+ def _ensure_min_version!(purpose, lua, jit = nil)
53
+ version = lua
54
+ version = jit if meta.interpreter[/jit/] && jit
55
+
56
+ return unless Gem::Version.new(
57
+ meta.interpreter.gsub(/.+:/, '')
58
+ ) < Gem::Version.new(version)
59
+
60
+ message = "#{purpose} requires Lua >= #{lua}"
61
+ message = "#{message} or LuaJIT >= #{jit}" if jit
62
+
63
+ raise SweetMoon::Errors::SweetMoonError,
64
+ "#{message}; Current: #{meta.runtime} (#{meta.interpreter})"
65
+ end
66
+
67
+ def _unsafely_destroy
68
+ @controller[:destroy!].(@api, @interpreter, state)
69
+ @state = nil
70
+ end
71
+
72
+ def inspect
73
+ output = "#<#{self.class}:0x#{format('%016x', object_id)}"
74
+
75
+ variables = ['@meta'].map do |struct_name|
76
+ "#{struct_name}=#{instance_variable_get(struct_name).inspect}"
77
+ end
78
+
79
+ "#{output} #{variables.join(' ')}>"
80
+ end
81
+
82
+ private
83
+
84
+ def build_meta(api_component, interpreter_component)
85
+ meta_data = {
86
+ api_reference: api_component[:meta][:elected][:api_reference],
87
+ shared_objects: api_component[:meta][:elected][:shared_objects],
88
+ interpreter: interpreter_component[:meta][:elected][:interpreter],
89
+ runtime: interpreter_component[:meta][:runtime][:lua]
90
+ }
91
+
92
+ @meta = Struct.new(*meta_data.keys).new(*meta_data.values)
93
+ end
94
+
95
+ def state
96
+ unless @state
97
+ raise SweetMoon::Errors::SweetMoonError,
98
+ 'The state no longer exists.'
99
+ end
100
+
101
+ @state
102
+ end
103
+ end
104
+ end
data/dsl/sweet_moon.rb ADDED
@@ -0,0 +1,53 @@
1
+ require_relative '../logic/options'
2
+ require_relative '../logic/spec'
3
+
4
+ require_relative 'cache'
5
+ require_relative 'state'
6
+ require_relative 'global'
7
+
8
+ require_relative '../logic/api'
9
+ require_relative '../logic/interpreter'
10
+
11
+ module SweetMoon
12
+ module API
13
+ def new(options = {})
14
+ Cache.instance.api(Logic::Options[:normalize].(options))
15
+ end
16
+
17
+ module_function :new
18
+ end
19
+
20
+ module State
21
+ def new(options = {})
22
+ options = Logic::Options[:normalize].(options)
23
+
24
+ api = Cache.instance.api_module(options)
25
+
26
+ interpreter = Cache.instance.interpreter_module(api, options)
27
+
28
+ DSL::State.new(api, interpreter, Controller::State, options)
29
+ end
30
+
31
+ module_function :new
32
+ end
33
+
34
+ def meta
35
+ meta_data = {
36
+ version: Logic::Spec[:version],
37
+ api_references: Logic::API[:candidates].values.map do |candidate|
38
+ candidate[:version]
39
+ end,
40
+ interpreters: Logic::Interpreter[:candidates].values.map do |candidate|
41
+ candidate[:version]
42
+ end
43
+ }
44
+
45
+ Struct.new(*meta_data.keys).new(*meta_data.values)
46
+ end
47
+
48
+ def global
49
+ Global
50
+ end
51
+
52
+ module_function :meta, :global
53
+ end
data/logic/api.rb ADDED
@@ -0,0 +1,17 @@
1
+ require_relative 'signatures/signatures_322'
2
+ require_relative 'signatures/signatures_401'
3
+ require_relative 'signatures/signatures_503'
4
+ require_relative 'signatures/signatures_514'
5
+ require_relative 'signatures/signatures_542'
6
+
7
+ module Logic
8
+ API = {
9
+ candidates: {
10
+ '3.2.2' => { version: '3.2.2', signatures: V322::Signatures },
11
+ '4.0.1' => { version: '4.0.1', signatures: V401::Signatures },
12
+ '5.0.3' => { version: '5.0.3', signatures: V503::Signatures },
13
+ '5.1.4' => { version: '5.1.4', signatures: V514::Signatures },
14
+ '5.4.2' => { version: '5.4.2', signatures: V542::Signatures }
15
+ }
16
+ }
17
+ end
@@ -0,0 +1,84 @@
1
+ require_relative 'interpreters/interpreter_50'
2
+ require_relative 'interpreters/interpreter_51'
3
+ require_relative 'interpreters/interpreter_54'
4
+
5
+ module Logic
6
+ Interpreter = {
7
+ candidates: {
8
+ '5.0' => { version: '5.0', requires: V50::Interpreter[:requires] },
9
+ '5.1' => { version: '5.1', requires: V51::Interpreter[:requires] },
10
+ '5.4' => { version: '5.4', requires: V54::Interpreter[:requires] }
11
+ },
12
+
13
+ elect: ->(signatures, api_version, options = {}) {
14
+ interpreters = Interpreter[:candidates].values
15
+
16
+ if options[:interpreter]
17
+ interpreters = interpreters.select do |interpreter|
18
+ interpreter[:version].to_s == options[:interpreter]
19
+ end
20
+
21
+ if interpreters.size.zero?
22
+ return {
23
+ compatible: false,
24
+ error: "Interpreter #{options[:interpreter]} not available."
25
+ }
26
+ end
27
+ end
28
+
29
+ results = {}
30
+
31
+ interpreters.each do |interpreter|
32
+ results[interpreter[:version]] = Interpreter[:check_compatibility].(
33
+ interpreter, signatures
34
+ )
35
+ end
36
+
37
+ result = Interpreter[:choose_compatible].(results)
38
+
39
+ return result if result
40
+
41
+ { compatible: false,
42
+ error: Interpreter[:closest_error_message].(api_version, results) }
43
+ },
44
+
45
+ closest_error_message: ->(api_version, candidates) {
46
+ closest = candidates.values.sort_by do |candidate|
47
+ Gem::Version.new(candidate[:version].gsub(/.+:/, '') || '0')
48
+ end.reverse
49
+
50
+ closest = closest.min_by { |candidate| candidate[:missing].size }
51
+
52
+ message = "Missing in the closest version (#{closest[:version]}):"
53
+
54
+ closest[:missing].sort.each_slice(4).each do |functions|
55
+ message += "\n #{functions.join(' ')}"
56
+ end
57
+
58
+ "No compatible interpreter found for Lua C API #{api_version}.\n#{message}"
59
+ },
60
+
61
+ choose_compatible: ->(candidates) {
62
+ candidates = candidates.values.select do |candidate|
63
+ candidate[:compatible]
64
+ end
65
+
66
+ candidates.max_by do |candidate|
67
+ Gem::Version.new(candidate[:version].gsub(/.+:/, '') || '0')
68
+ end
69
+ },
70
+
71
+ check_compatibility: ->(interpreter, signatures) {
72
+ result = { version: interpreter[:version], compatible: true, missing: [] }
73
+
74
+ interpreter[:requires].each do |required|
75
+ unless signatures[required]
76
+ result[:compatible] = false
77
+ result[:missing] << required
78
+ end
79
+ end
80
+
81
+ result
82
+ }
83
+ }
84
+ end
@@ -0,0 +1,34 @@
1
+ module Logic
2
+ module V50
3
+ Interpreter = {
4
+ version: '5.0',
5
+
6
+ LUA_REGISTRYINDEX: -10_000,
7
+ LUA_GLOBALSINDEX: -10_001,
8
+
9
+ requires: %i[
10
+ lua_close lua_gettable lua_gettop lua_insert lua_newtable lua_next lua_open
11
+ lua_pcall lua_pushboolean lua_pushcclosure lua_pushnil lua_pushnumber
12
+ lua_pushstring lua_rawgeti lua_settable lua_settop lua_toboolean lua_tonumber
13
+ lua_topointer lua_tostring lua_type lua_typename luaL_loadbuffer luaL_loadfile
14
+ luaL_ref luaopen_base luaopen_io luaopen_math luaopen_string luaopen_table
15
+ ],
16
+
17
+ status: {
18
+ 1 => :LUA_ERRRUN,
19
+ 2 => :LUA_ERRFILE,
20
+ 3 => :LUA_ERRSYNTAX,
21
+ 4 => :LUA_ERRMEM,
22
+ 5 => :LUA_ERRERR
23
+ },
24
+
25
+ error: {
26
+ LUA_ERRRUN: :runtime,
27
+ LUA_ERRFILE: :file,
28
+ LUA_ERRSYNTAX: :syntax,
29
+ LUA_ERRMEM: :memory_allocation,
30
+ LUA_ERRERR: :message_handler
31
+ }
32
+ }
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ module Logic
2
+ module V51
3
+ Interpreter = {
4
+ version: '5.1',
5
+
6
+ LUA_REGISTRYINDEX: -10_000,
7
+ LUA_GLOBALSINDEX: -10_002,
8
+
9
+ # lua_isinteger lua_pushinteger lua_tointeger
10
+ requires: %i[
11
+ lua_close lua_createtable lua_getfield lua_gettable lua_gettop lua_insert
12
+ lua_next lua_pcall lua_pushboolean lua_pushcclosure lua_pushnil lua_pushnumber
13
+ lua_pushstring lua_rawgeti lua_settable lua_settop lua_toboolean lua_tonumber
14
+ lua_topointer lua_tostring lua_type lua_typename luaL_loadfile luaL_loadstring
15
+ luaL_newstate luaL_openlibs luaL_ref
16
+ ],
17
+
18
+ status: {
19
+ 0 => :LUA_OK,
20
+ 1 => :LUA_YIELD,
21
+ 2 => :LUA_ERRRUN,
22
+ 3 => :LUA_ERRSYNTAX,
23
+ 4 => :LUA_ERRMEM,
24
+ 5 => :LUA_ERRERR,
25
+ 6 => :LUA_ERRFILE
26
+ },
27
+
28
+ error: {
29
+ LUA_ERRRUN: :runtime,
30
+ LUA_ERRSYNTAX: :syntax,
31
+ LUA_ERRMEM: :memory_allocation,
32
+ LUA_ERRERR: :message_handler,
33
+ LUA_ERRFILE: :file
34
+ }
35
+ }
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+ module Logic
2
+ module V54
3
+ Interpreter = {
4
+ version: '5.4',
5
+
6
+ LUA_RIDX_GLOBALS: 2,
7
+
8
+ # TODO: It's possible to read C constants?
9
+ # LUAI_MAXSTACK = 1_000_000
10
+ # -LUAI_MAXSTACK - 1000
11
+ LUA_REGISTRYINDEX: -1_000_000 - 1000,
12
+
13
+ # lua_isinteger lua_pushinteger lua_tointeger
14
+ requires: %i[
15
+ lua_close lua_createtable lua_getfield lua_getglobal lua_gettop lua_next
16
+ lua_pcall lua_pushboolean lua_pushcclosure lua_pushnil lua_pushnumber
17
+ lua_pushstring lua_rawgeti lua_setglobal lua_settable lua_settop lua_toboolean
18
+ lua_tonumber lua_topointer lua_tostring lua_type lua_typename luaL_loadfile
19
+ luaL_loadstring luaL_newstate luaL_openlibs luaL_ref
20
+ ],
21
+
22
+ status: {
23
+ 0 => :LUA_OK,
24
+ 1 => :LUA_YIELD,
25
+ 2 => :LUA_ERRRUN,
26
+ 3 => :LUA_ERRSYNTAX,
27
+ 4 => :LUA_ERRMEM,
28
+ 5 => :LUA_ERRERR,
29
+ 6 => :LUA_ERRFILE
30
+ },
31
+
32
+ error: {
33
+ LUA_ERRRUN: :runtime,
34
+ LUA_ERRSYNTAX: :syntax,
35
+ LUA_ERRMEM: :memory_allocation,
36
+ LUA_ERRERR: :message_handler,
37
+ LUA_ERRFILE: :file
38
+ }
39
+ }
40
+ end
41
+ end
data/logic/io.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Logic
2
+ IO = {
3
+ extension: ->(path) { File.extname(path) },
4
+ file_name: ->(path) { File.basename(path) }
5
+ }
6
+ end
data/logic/options.rb ADDED
@@ -0,0 +1,14 @@
1
+ module Logic
2
+ Options = {
3
+ normalize: ->(original_options) {
4
+ options = original_options.clone
5
+
6
+ if options[:shared_object]
7
+ options[:shared_objects] = [options[:shared_object]]
8
+ options.delete(:shared_object)
9
+ end
10
+
11
+ options
12
+ }
13
+ }
14
+ end
@@ -0,0 +1,52 @@
1
+ require_relative './io'
2
+
3
+ module Logic
4
+ SharedObject = {
5
+ choose: ->(candidate_paths, options = {}) {
6
+ candidates = candidate_paths.map do |path|
7
+ SharedObject[:normalize].(path)
8
+ end
9
+
10
+ unless options[:jit].nil?
11
+ candidates = candidates.select do |candidate|
12
+ options[:jit] ? candidate[:inferences][:jit] : !candidate[:inferences][:jit]
13
+ end
14
+ end
15
+
16
+ if options[:version]
17
+ candidates = candidates.select do |candidate|
18
+ if candidate[:inferences][:version]
19
+ !candidate[:inferences][:version][/#{options[:version]}/].nil?
20
+ else
21
+ false
22
+ end
23
+ end
24
+ end
25
+
26
+ elected = candidates.max_by do |candidate|
27
+ Gem::Version.new(candidate[:inferences][:version] || '0')
28
+ end
29
+
30
+ return [] if elected.nil?
31
+
32
+ [elected]
33
+ },
34
+
35
+ normalize: ->(path) {
36
+ inferred_versions = IO[:file_name].(
37
+ path
38
+ ).scan(/(\d+(\.\d+)*)/).map(&:first)
39
+
40
+ inferred_versions = inferred_versions.map do |inferred_version|
41
+ inferred_version.split('.').map { |part| part.chars.join('.') }.join('.')
42
+ end
43
+
44
+ inferred_version = inferred_versions.max_by do |raw_inferred_version|
45
+ Gem::Version.new(raw_inferred_version || '0')
46
+ end
47
+
48
+ { path: path,
49
+ inferences: { jit: !path[/jit/].nil?, version: inferred_version } }
50
+ }
51
+ }
52
+ end