virtual_module 0.2.1 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bd5f0e87cb8b078374f942887d00b5d32e3f2245
4
- data.tar.gz: f350813eb2781d0158ac0d1a931c8a9bd0643ccf
3
+ metadata.gz: ac2dd86960d57e8ca74b66f23d706aa38413ebb6
4
+ data.tar.gz: 870312de88c44be64424e91b4cb507554454c273
5
5
  SHA512:
6
- metadata.gz: a05517f26f04375b0241986354bd9008960f1d57dc3146580165b17d608a4d4e47056605993b40d94f856d07729c7a4e9547fc1fce9a21214c578fa53fa6fe69
7
- data.tar.gz: 7bdf2a597339e02a8fc40a919b79edbddd4de11aabe7a997979e07cb4e280f69632649b82ef1cd5009869a7cd252009683dbafb264a027d7abb01604bf8f86a5
6
+ metadata.gz: 05988bd3c35c324b49600615c9fff85c917d007b604c6799382b460a04241bdf25be0356e649183a54b4c68d8a05d7757cda184cbc70db335a83bbac258a8072
7
+ data.tar.gz: a3c47595572bea85f6f818f55da750d96bb31133e79e7c239aca69adbb2f7ab24f88dec121803e80495253b4aa68e309303057ec5cb6445312008a417478466e
@@ -10,14 +10,24 @@ module VirtualModule
10
10
  require 'virtual_module/version'
11
11
 
12
12
  class << self
13
- def new(methods, **args)
14
- option = {:lang=>:julia, :pkgs=>[], :ipc=>:file}.merge(args)
15
- vm_builder = Builder.new(option[:lang], option[:pkgs], option[:ipc])
16
- vm_builder.add(methods)
13
+ def new(**args)
14
+ format_args = ->(key){
15
+ if args.keys.include?(key)
16
+ args[:lang] = key
17
+ args[:pkgs] = args[key]
18
+ args[:transpiler] ||= nil if key == :python
19
+ end
20
+ }
21
+ [:python, :julia].map{|e| format_args.call(e)}
22
+ option = {:lang=>:julia, :methods=>"", :transpiler=>->(s){Julializer.ruby2julia(s)}, :pkgs=>[], :ipc=>:file}.merge(args)
23
+ vm_builder = Builder.new(option)
24
+ vm_builder.add(option[:methods])
17
25
  vm_builder.build
18
26
  end
19
27
  end
20
28
 
29
+ class RuntimeException < Exception; end
30
+
21
31
  module SexpParser
22
32
  def extract_defs(s)
23
33
  if s.instance_of?(Array) && s[0].instance_of?(Symbol) then
@@ -47,9 +57,20 @@ module VirtualModule
47
57
  class Builder
48
58
  include SexpParser
49
59
 
50
- def initialize(lang=:julia, pkgs=[], ipc=:file)
51
- @provider = instance_eval("#{lang.capitalize}SourceProvider").new(pkgs)
52
- @ipc = instance_eval("#{ipc.to_s.capitalize}IpcInterface").new(@provider)
60
+ ProxyObjectTransmitter = Struct.new(:vmbuilder, :receiver) do
61
+ def convert_to(target_oid)
62
+ (target_oid == vmbuilder.object_id) ?
63
+ receiver :
64
+ ((receiver[0..5] == "\xC1VMOBJ") ? vmbuilder.serialize(receiver[6..-1]) : receiver)
65
+ end
66
+ def get_index(target_oid)
67
+ (target_oid == vmbuilder.object_id && receiver[0..5] == "\xC1VMOBJ") ? receiver[6..-1] : nil
68
+ end
69
+ end
70
+
71
+ def initialize(option)
72
+ @provider = instance_eval("#{option[:lang].capitalize}SourceProvider").new(self, option[:pkgs], option[:transpiler])
73
+ @ipc = instance_eval("#{option[:ipc].to_s.capitalize}IpcInterface").new(@provider)
53
74
  end
54
75
 
55
76
  def add(methods="")
@@ -59,45 +80,35 @@ module VirtualModule
59
80
  end
60
81
 
61
82
  def build
62
- vm_builder = self
63
- ipc = @ipc
64
- @vm = Module.new{
65
- @vm_builder = vm_builder
66
- @ipc = ipc
67
- def self.virtual_module_eval(*args)
68
- @vm_builder.send(:virtual_module_eval, *args)
69
- end
70
- def self.method_missing(key, *args, &block)
71
- @vm_builder.send(:call, key, *args)
72
- end
73
- def self.___get_serialized___
74
- @ipc.serialized
75
- end
76
- }
77
- extract_defs(Ripper.sexp(@provider.source.join(";"))).split(",").each{|e|
78
- @vm.class_eval {
79
- define_method e.to_sym, Proc.new { |*args|
80
- vm_builder.call(e.to_sym, *args)
81
- }
82
- }
83
- }
83
+ @vm = new_vm(nil)
84
84
  @vm
85
85
  end
86
86
 
87
- def call(name, *args)
87
+ def call(receiver, name, *args)
88
+ if args.last.class==Hash
89
+ kwargs = args.pop
90
+ else
91
+ kwargs = {}
92
+ end
88
93
  begin
89
- @ipc.call(name, *args)
90
- rescue StandardError => e
91
- @ipc.serialized = e.message
92
- @vm
94
+ @ipc.call(receiver, name, *args, **kwargs)
95
+ rescue => e
96
+ new_vm(e.message)
97
+ rescue RuntimeException => e
98
+ raise e.message
93
99
  end
94
100
  end
95
101
 
96
- def virtual_module_eval(script, auto_binding=true)
102
+ def serialize(object_lookup_id)
103
+ @ipc.serialize(object_lookup_id)
104
+ end
105
+
106
+ def virtual_module_eval(receiver, script, auto_binding=true)
97
107
  vars, type_info, params = inspect_local_vars(binding.of_caller(2), script)
98
108
  @provider.compile(vars, type_info, params, script, auto_binding)
99
109
  @ipc.reset @provider
100
- evaluated = self.call(:___main, params, type_info)
110
+ evaluated = self.call(receiver, :vm_builtin_eval_func, [params, type_info])
111
+
101
112
  if auto_binding
102
113
  binding.of_caller(2).eval(evaluated[1].map{|k,v| "#{k}=#{v};" if !v.nil? }.join)
103
114
  end
@@ -109,8 +120,50 @@ module VirtualModule
109
120
  alias_method :virtual_eval, :virtual_module_eval
110
121
 
111
122
  private
123
+ def new_vm(receiver)
124
+ vm_builder, provider, transmitter = [self, @provider, ProxyObjectTransmitter.new(self, receiver)]
125
+ vm = Module.new{
126
+ @vm_builder, @provider, @transmitter, @receiver = [vm_builder, provider, transmitter, receiver]
127
+ def self.virtual_module_eval(*args)
128
+ @vm_builder.send(:virtual_module_eval, @receiver, *args)
129
+ end
130
+ def self.method_missing(key, *args, &block)
131
+ @vm_builder.send(:call, @receiver, key, *args)
132
+ end
133
+ def self.___proxy_object_transmitter
134
+ @transmitter
135
+ end
136
+ def self.to_s
137
+ @vm_builder.send(:call, nil, @provider.to_s, self)
138
+ end
139
+ def self.to_a
140
+ @vm_builder.send(:call, nil, @provider.to_a, self)
141
+ end
142
+ def self.vclass
143
+ @vm_builder.send(:call, nil, @provider.to_s,
144
+ @vm_builder.send(:call, nil, @provider.vclass, self)
145
+ )
146
+ end
147
+ def self.vmethods
148
+ @vm_builder.send(:call, nil, @provider.vmethods, self)
149
+ end
150
+ }
151
+ includables = (
152
+ (defs = extract_defs(Ripper.sexp(@provider.source.join(";")))).nil? ? [] : defs.split(",") +
153
+ provider.pkgs.map{|e| e.class==Hash ? e.values : e}.flatten
154
+ )
155
+ includables.each{|e|
156
+ vm.class_eval {
157
+ define_method e.to_sym, Proc.new { |*args|
158
+ vm_builder.call(receiver, e.to_sym, *args)
159
+ }
160
+ }
161
+ } if !includables.nil?
162
+ vm
163
+ end
164
+
112
165
  def inspect_local_vars(context, script)
113
- vars = extract_args(Ripper.sexp(script)).split(",").uniq.map{|e| e.to_sym} & context.eval("local_variables")
166
+ vars = (args = extract_args(Ripper.sexp(script))).nil? ? [] : args.split(",").uniq.map{|e| e.to_sym} & context.eval("local_variables")
114
167
 
115
168
  type_info = {}
116
169
  type_info[:params] = context.eval("Hash[ *#{vars}.collect { |e| [ e, eval(e.to_s).class.to_s ] }.flatten ]").select{|k,v| ["FloatArray", "IntArray"].include?(v)}
@@ -127,34 +180,249 @@ EOS
127
180
 
128
181
  class BaseSourceProvider
129
182
  attr_accessor :source
130
- def initialize(pkgs)
131
- @source = load_packages(pkgs)
183
+ attr_accessor :pkgs
184
+ KwargsConverter = Struct.new(:initializer, :setter, :varargs)
185
+
186
+ def initialize(builder, pkgs, transpiler=nil)
187
+ @builder = builder
188
+ @pkgs = pkgs
189
+ @transpiler = transpiler.nil? ? ->(s){s} : transpiler
190
+ @source = []
132
191
  @compiled_lib = ""
133
192
  end
134
193
 
135
- def load_packages(pkgs)
194
+ def load_packages
136
195
  [] #to be overrieded
137
196
  end
197
+
198
+ def lang
199
+ self.class.name.match(/\:\:(.*)SourceProvider/)[1].downcase.to_sym
200
+ end
201
+
202
+ def vclass
203
+ raise Exception.new("An equivalent method for #{__method__} seems not supported in #{lang}.")
204
+ end
205
+ alias_method :vmethods, :vclass
206
+ alias_method :to_s, :vclass
207
+ alias_method :to_a, :vclass
208
+
209
+ private
210
+ def prepare_params(input_queue_path, gen_driver, conv_kwargs, name, *args, **kwargs)
211
+ script, params = ["", []]
212
+ if args.count == 1 && args[0].class == Symbol
213
+ # do nothing - this will be called as "#name()"
214
+ else
215
+ type = ->(arg){
216
+ arg.class == Module ? "serialized" : "msgpack"
217
+ }
218
+ args.each_with_index do |arg, i|
219
+ File.write(
220
+ "#{input_queue_path}.#{i}.#{type.call(arg)}",
221
+ arg.class == Module ?
222
+ arg.___proxy_object_transmitter.convert_to(@builder.object_id):
223
+ MessagePack.pack(arg)
224
+ )
225
+ params << "params_#{i}"
226
+ script += gen_driver.call(arg, input_queue_path, i, type.call(arg), params.last)
227
+ end
228
+ if kwargs.count>0
229
+ script += "kwargs=#{conv_kwargs.initializer};"
230
+ kwargs.each_with_index do |(k,v), i|
231
+ File.write(
232
+ "#{input_queue_path}.#{params.count+i}.#{type.call(v)}",
233
+ v.class == Module ?
234
+ v.___proxy_object_transmitter.convert_to(@builder.object_id):
235
+ MessagePack.pack(v)
236
+ )
237
+ script += gen_driver.call(v, input_queue_path, params.count+i, type.call(v), conv_kwargs.setter.call(k))
238
+ end
239
+ params << conv_kwargs.varargs
240
+ end
241
+ end
242
+ [script, name==:[] ? "[#{params.join(',')}]" : "(#{params.join(',')})"]
243
+ end
244
+
245
+ end
246
+
247
+ class PythonSourceProvider < BaseSourceProvider
248
+ EXT = "py"
249
+
250
+ def load_packages
251
+ @pkgs.map{|e|
252
+ if e.class==Hash
253
+ e.map{|k,v| "from #{k} import #{ v.class==Array ? v.join(",") : v}"}
254
+ else
255
+ "import #{e}"
256
+ end
257
+ }.flatten
258
+ end
259
+
260
+ def to_a
261
+ :list
262
+ end
263
+
264
+ def to_s
265
+ :str
266
+ end
267
+
268
+ def vclass
269
+ :type
270
+ end
271
+
272
+ def vmethods
273
+ :dir
274
+ end
275
+
276
+ def main_loop(input_queue_path, output_queue_path, lib_script=nil)
277
+ <<EOS
278
+ # coding: utf-8
279
+ import sys
280
+ sys.path.append('#{File.dirname(input_queue_path)}')
281
+ from #{lib_script} import *
282
+ import dill
283
+ import msgpack
284
+
285
+ object_lookup_table = {}
286
+ while True :
287
+ try:
288
+ f = open('#{input_queue_path}', 'r')
289
+ source = f.read()
290
+ f.close()
291
+ if source[0]=='\\n':
292
+ f = open('#{output_queue_path}', 'w')
293
+ f.write(dill.dumps(object_lookup_table[int(source[1:len(source)])]))
294
+ f.close()
295
+ else:
296
+ exec(source)
297
+ f = open('#{output_queue_path}', 'w')
298
+ try:
299
+ f.write(msgpack.packb(___result))
300
+ except:
301
+ object_lookup_table[id(___result)] = ___result
302
+ f.write('\\xc1VMOBJ'+str(id(___result)))
303
+ f.close()
304
+ except KeyboardInterrupt:
305
+ print(object_lookup_table.keys())
306
+ exit(0);
307
+ except Exception as e:
308
+ f = open('#{output_queue_path}', 'w')
309
+ f.write('\\xc1VMERR'+str(type(e))+','+str(e.message))
310
+ f.close()
311
+ EOS
312
+ end
313
+
314
+ def lib_script(ipc=nil)
315
+ if ipc!=:rpc
316
+ @compiled_lib
317
+ else
318
+ # :rpc mode is to be implemented
319
+ @compiled_lib
320
+ end
321
+ end
322
+
323
+ def compile(vars=nil, type_info=nil, params=nil, script=nil, auto_binding=nil)
324
+ @compiled_lib = (load_packages + @source).join("\n")
325
+ if !vars.nil? && !type_info.nil? && !params.nil? && !script.nil? && !auto_binding.nil?
326
+ preprocess = vars.map{|e| e.to_s + '=params[0]["'+e.to_s+'"]'}
327
+ postprocess = auto_binding ? vars.map{|e| 'params[0]["'+e.to_s+'"]='+e.to_s } : []
328
+ @compiled_lib += <<EOS
329
+ def vm_builtin_eval_func(params):
330
+ #{(preprocess.join(";") + ";") if preprocess.count>0} #{script};
331
+ #{(postprocess.join(";") + ";") if postprocess.count>0} return (None,#{auto_binding ? "params[0]" : "-1" });
332
+
333
+ EOS
334
+ end
335
+ end
336
+
337
+ def generate_message(input_queue_path, receiver, name, *args, **kwargs)
338
+ script, params = ["", ""]
339
+ if args.count + kwargs.count > 0
340
+ gen_driver = ->(arg, input_queue_path, i, type, param_name){
341
+ val = arg.class == Module ?
342
+ (
343
+ (table_index = arg.___proxy_object_transmitter.get_index(@builder.object_id)).nil? ?
344
+ "dill.loads(f.read())" :
345
+ "object_lookup_table[#{table_index}]"
346
+ ) :
347
+ "msgpack.unpackb(f.read())"
348
+ "f=open('#{input_queue_path}.#{i}.#{type}', 'r'); #{param_name}=#{val}; f.close();"
349
+ }
350
+ conv_kwargs = KwargsConverter.new("{}", ->(k){"kwargs['#{k}']"}, "**kwargs")
351
+ script, params = prepare_params(input_queue_path, gen_driver, conv_kwargs, name, *args, **kwargs)
352
+ end
353
+ callee = "#{name}"
354
+ if !receiver.nil?
355
+ if receiver[0..5]=="\xC1VMOBJ"
356
+ script += "receiver=object_lookup_table[#{receiver[6..-1]}];"
357
+ else
358
+ File.write("#{input_queue_path}_serialized", receiver)
359
+ script += "f=open('#{input_queue_path}_serialized', 'r'); receiver=dill.load(f); f.close();"
360
+ end
361
+ if name==:[]
362
+ callee = "receiver"
363
+ else
364
+ callee = "receiver.#{name}"
365
+ end
366
+ end
367
+ script += "___result = #{callee}#{params};"
368
+ end
138
369
  end
139
370
 
140
371
  class JuliaSourceProvider < BaseSourceProvider
141
- def load_packages(pkgs)
142
- pkgs.map{|e| "import #{e}"}
372
+ EXT = "jl"
373
+
374
+ def load_packages
375
+ @pkgs.map{|e| "import #{e}"}
376
+ end
377
+
378
+ def to_a
379
+ :tuple
143
380
  end
144
381
 
145
- def main_loop(input_queue_path, output_queue_path)
382
+ def to_s
383
+ :string
384
+ end
385
+
386
+ def vclass
387
+ :summary
388
+ end
389
+
390
+ def main_loop(input_queue_path, output_queue_path, lib_script=nil)
146
391
  <<EOS
147
392
  using MsgPack
393
+ object_lookup_table = Dict()
148
394
  while true
149
- source = open( "#{input_queue_path}", "r" ) do fp
150
- readall(fp)
151
- end
152
- result = eval(parse(source))
153
- open( "#{output_queue_path}", "w" ) do fp
154
- try
155
- write(fp,pack(result))
156
- catch
157
- serialize(fp,result)
395
+ try
396
+ source = open( "#{input_queue_path}", "r" ) do fp
397
+ readall(fp)
398
+ end
399
+ if source[1]=='\n'
400
+ open( "#{output_queue_path}", "w" ) do fp
401
+ serialize(fp, object_lookup_table[parse(Int,source[2:length(source)])])
402
+ end
403
+ else
404
+ result = eval(parse(source))
405
+ open( "#{output_queue_path}", "w" ) do fp
406
+ try
407
+ write(fp,pack(result))
408
+ catch
409
+ object_lookup_table[object_id(result)] = result
410
+ write(fp, 0xc1)
411
+ write(fp, "VMOBJ")
412
+ write(fp, string(object_id(result)))
413
+ end
414
+ end
415
+ end
416
+ catch err
417
+ print(typeof(err))
418
+ if !isa(err, InterruptException)
419
+ open( "#{output_queue_path}", "w" ) do fp
420
+ write(fp, 0xc1)
421
+ write(fp, "VMERR")
422
+ write(fp, string(err))
423
+ end
424
+ else
425
+ exit
158
426
  end
159
427
  end
160
428
  end
@@ -176,10 +444,9 @@ EOS
176
444
  end
177
445
 
178
446
  def compile(vars=nil, type_info=nil, params=nil, script=nil, auto_binding=nil)
179
- @compiled_lib = File.read(
180
- File.dirname(__FILE__)+"/virtual_module/bridge.jl") + ";" +
181
- Julializer.ruby2julia(@source.join(";\n")
182
- )
447
+ @compiled_lib =
448
+ File.read(File.dirname(__FILE__)+"/virtual_module/bridge.jl") + ";" +
449
+ load_packages.join(";\n") + @transpiler.call(@source.join(";\n"))
183
450
  if !vars.nil? && !type_info.nil? && !params.nil? && !script.nil? && !auto_binding.nil?
184
451
  @compiled_lib += <<EOS
185
452
  function ___convert_type(name, typename, params)
@@ -194,39 +461,60 @@ EOS
194
461
  end
195
462
  end
196
463
 
197
- function ___main(params, type_info)
198
- #{vars.map{|e| e.to_s + '=___convert_type("'+e.to_s+'","'+(type_info[:params][e]||"")+'", params)'}.join(";")}
464
+ function vm_builtin_eval_func(params)
465
+ #{vars.map{|e| e.to_s + '=___convert_type("'+e.to_s+'","'+(type_info[:params][e]||"")+'", params[1])'}.join(";")}
199
466
  ##{vars.map{|e| 'println("'+e.to_s+'=", typeof('+e.to_s+'))' }.join(";")}
200
- ___evaluated = (#{Julializer.ruby2julia(script)})
467
+ ___evaluated = (#{@transpiler.call(script)})
201
468
 
202
- #{vars.map{|e| 'params["'+e.to_s+'"]='+e.to_s }.join(";") if auto_binding}
469
+ #{vars.map{|e| 'params[1]["'+e.to_s+'"]='+e.to_s }.join(";") if auto_binding}
203
470
 
204
- (___evaluated,#{auto_binding ? "params" : "-1" })
471
+ (___evaluated,#{auto_binding ? "params[1]" : "-1" })
205
472
  end
206
473
  EOS
207
474
  end
208
475
  end
209
476
 
210
- def generate_message(input_queue_path, name, *args)
211
- script = ""
212
- params = []
213
- args.each_with_index do |arg, i|
214
- type = arg.class == Module ? "serialized" : "msgpack"
215
- File.write("#{input_queue_path}.#{i}.#{type}", arg.class == Module ? arg.___get_serialized___ : MessagePack.pack(arg))
216
- params << "params_#{i}"
217
- val = arg.class == Module ? "deserialize(fp)" : "unpack(readall(fp))"
218
- script += "#{params.last} =open( \"#{input_queue_path}.#{i}.#{type}\", \"r\" ) do fp; #{val}; end;"
477
+ def generate_message(input_queue_path, receiver, name, *args, **kwargs)
478
+ script, params = ["", ""]
479
+ if args.count + kwargs.count > 0
480
+ gen_driver = ->(arg, input_queue_path, i, type, param_name){
481
+ val = case arg.class.to_s
482
+ when "Module" then (
483
+ (table_index = arg.___proxy_object_transmitter.get_index(@builder.object_id)).nil? ?
484
+ "deserialize(fp)" :
485
+ "object_lookup_table[#{table_index}]"
486
+ )
487
+ when "Symbol" then "convert(Symbol, unpack(readall(fp)))"
488
+ else "unpack(readall(fp))"
489
+ end
490
+ script += "#{param_name} =open( \"#{input_queue_path}.#{i}.#{type}\", \"r\" ) do fp; #{val}; end;"
491
+ }
492
+ conv_kwargs = KwargsConverter.new("Dict{Symbol,Any}()", ->(k){"kwargs[:#{k}]"}, ";kwargs...")
493
+ script, params = prepare_params(input_queue_path, gen_driver, conv_kwargs, name, *args, **kwargs)
219
494
  end
220
- script += "#{name}(#{params.join(',')});"
495
+ callee = "#{name}"
496
+ if !receiver.nil?
497
+ if receiver[0..5]=="\xC1VMOBJ"
498
+ script += "receiver=object_lookup_table[#{receiver[6..-1]}];"
499
+ else
500
+ File.write("#{input_queue_path}_serialized", receiver)
501
+ script += "receiver =open( \"#{input_queue_path}_serialized\", \"r\" ) do fp; deserialize(fp); end;"
502
+ end
503
+ if name==:[]
504
+ callee = "receiver"
505
+ else
506
+ callee = "receiver.#{name}"
507
+ end
508
+ end
509
+ script += "#{callee}#{params};"
221
510
  end
222
511
 
223
512
  end
224
513
 
225
514
  class BaseIpcInterface
226
- LIB_SCRIPT = "vm-lib"
515
+ LIB_SCRIPT = "vmlib"
227
516
 
228
517
  attr_accessor :work_dir
229
- attr_accessor :serialized
230
518
 
231
519
  def initialize(provider)
232
520
  @provider = provider
@@ -241,39 +529,48 @@ EOS
241
529
  end
242
530
 
243
531
  class FileIpcInterface < BaseIpcInterface
244
- INPUT = "vm-input"
245
- OUTPUT = "vm-output"
246
- MAIN_LOOP = "vm-main"
532
+ INPUT = "vminput"
533
+ OUTPUT = "vmoutput"
534
+ MAIN_LOOP = "vmmain"
247
535
 
248
536
  def initialize(provider)
249
537
  super
250
538
  File.mkfifo("#{@work_dir}/#{INPUT}")
251
539
  File.mkfifo("#{@work_dir}/#{OUTPUT}")
252
540
  at_exit do
253
- Process.kill(:INT, @pid) if !@pid.nil?
541
+ Process.kill(:KILL, @pid) if !@pid.nil?
254
542
  FileUtils.remove_entry @work_dir if File.directory?(@work_dir)
255
543
  end
256
544
  end
257
545
 
258
- def call(name, *args)
546
+ def call(receiver, name, *args, **kwargs)
259
547
  #require 'byebug'
260
548
  #byebug
261
- if Helper.is_installed?(:julia)
262
- enqueue @provider.generate_message("#{@work_dir}/#{INPUT}", name, *args)
549
+ if Helper.is_installed?(@provider.lang)
550
+ enqueue @provider.generate_message("#{@work_dir}/#{INPUT}", receiver, name, *args, **kwargs)
263
551
  elsif Helper.is_installed?(:docker)
264
- enqueue @provider.generate_message("/opt/#{INPUT}", name, *args)
552
+ enqueue @provider.generate_message("/opt/#{INPUT}", receiver, name, *args, **kwargs)
265
553
  else
266
- raise Exception.new("Either julia or docker command is required to run virtual_module")
554
+ raise Exception.new("Either #{@provider.lang} or docker command is required to run virtual_module")
267
555
  end
268
- #byebug
269
556
  response = dequeue
270
- begin
271
- MessagePack.unpack(response)
272
- rescue
273
- raise StandardError.new(response)
557
+ case response[0..5]
558
+ when "\xC1VMERR" then raise RuntimeException, "wrong wrong!: " + response[6..-1]
559
+ when "\xC1VMOBJ" then raise StandardError.new(response)
560
+ else
561
+ begin
562
+ MessagePack.unpack(response)
563
+ rescue
564
+ raise StandardError.new(response)
565
+ end
274
566
  end
275
567
  end
276
568
 
569
+ def serialize(object_lookup_id)
570
+ enqueue "\n#{object_lookup_id}"
571
+ dequeue
572
+ end
573
+
277
574
  def reset(source)
278
575
  super
279
576
  restart_server_process
@@ -281,17 +578,33 @@ EOS
281
578
 
282
579
  private
283
580
  def restart_server_process
284
- Process.kill(:KILL, @pid) if !@pid.nil?
285
- File.write("#{@work_dir}/#{LIB_SCRIPT}", @provider.lib_script)
286
- File.write("#{@work_dir}/#{MAIN_LOOP}", @provider.main_loop("#{@work_dir}/#{INPUT}", "#{@work_dir}/#{OUTPUT}"))
287
- if Helper.is_installed?(:julia)
288
- command = "julia --depwarn=no -L #{@work_dir}/#{LIB_SCRIPT} #{@work_dir}/#{MAIN_LOOP}"
289
- elsif Helper.is_installed?(:docker)
290
- command = "docker run -v #{@work_dir}/:/opt/ remore/virtual_module julia --depwarn=no -L /opt/#{LIB_SCRIPT} /opt/#{MAIN_LOOP}"
581
+ if !@pid.nil?
582
+ begin
583
+ Process.getpgid(@pid)
584
+ Process.kill(:KILL, @pid)
585
+ rescue Errno::ESRCH
586
+ end
587
+ @pid=nil
588
+ end
589
+ File.write("#{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT}", @provider.lib_script)
590
+ File.write("#{@work_dir}/#{MAIN_LOOP}.#{@provider.class::EXT}", @provider.main_loop("#{@work_dir}/#{INPUT}", "#{@work_dir}/#{OUTPUT}", LIB_SCRIPT))
591
+ case @provider.lang
592
+ when :julia
593
+ if Helper.is_installed?(:julia)
594
+ command = "julia --depwarn=no -L #{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT} #{@work_dir}/#{MAIN_LOOP}.#{@provider.class::EXT}"
595
+ elsif Helper.is_installed?(:docker)
596
+ command = "docker run -v #{@work_dir}/:/opt/ remore/virtual_module julia --depwarn=no -L /opt/#{LIB_SCRIPT}.#{@provider.class::EXT} /opt/#{MAIN_LOOP}.#{@provider.class::EXT}"
597
+ else
598
+ raise Exception.new("Either julia or docker command is required to run virtual_module")
599
+ end
600
+ when :python
601
+ # -B : Prevent us from creating *.pyc cache - this will be problematic when we call #virtual_module_eval repeatedly.
602
+ command = "python -B #{@work_dir}/#{MAIN_LOOP}.#{@provider.class::EXT}"
291
603
  else
292
- raise Exception.new("Either julia or docker command is required to run virtual_module")
604
+ raise Exception.new("Unsupported language was specified")
293
605
  end
294
606
  @pid = Process.spawn(command, :err => :out,:out => "/dev/null") # , :pgroup => Process.pid)
607
+ #@pid = Process.spawn(command) # , :pgroup => Process.pid)
295
608
  Process.detach @pid
296
609
  end
297
610
 
@@ -313,14 +626,14 @@ EOS
313
626
  @timeout = 10
314
627
  end
315
628
 
316
- def call(name, *args)
629
+ def call(name, *args, **kwargs)
317
630
  restart_server_process
318
631
  while `echo exit | telnet #{@server} #{@port} 2>&1`.chomp[-5,5]!="host." do
319
632
  sleep(0.05)
320
633
  end
321
634
  @client = MessagePack::RPC::Client.new(@server, @port) if @client.nil?
322
635
  @client.timeout = @timeout
323
- args.count>0 ? @client.call(name, *args) : @client.call(name)
636
+ args.count>0 || kwargs.count>0 ? @client.call(name, *args, **kwargs) : @client.call(name)
324
637
  end
325
638
 
326
639
  private
@@ -330,7 +643,7 @@ EOS
330
643
  @client = nil
331
644
  at_exit do
332
645
  @client.close if !@client.nil?
333
- Process.kill(:INT, @pid) if !@pid.nil?
646
+ Process.kill(:KILL, @pid) if !@pid.nil?
334
647
  FileUtils.remove_entry @work_dir if File.directory?(@work_dir)
335
648
  end
336
649
  end
@@ -339,8 +652,8 @@ EOS
339
652
  Process.kill(:KILL, @pid) if !@pid.nil?
340
653
  `lsof -wni tcp:#{@port} | cut -f 4 -d ' ' | sed -ne '2,$p' | xargs kill -9`
341
654
  init_connection
342
- File.write("#{@work_dir}/#{LIB_SCRIPT}", @provider.lib_script(:rpc))
343
- @pid = Process.spawn("julia --depwarn=no #{@work_dir}/#{LIB_SCRIPT} #{@port}", :err => :out,:out => "/dev/null") #, :pgroup=>Process.pid)
655
+ File.write("#{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT}", @provider.lib_script(:rpc))
656
+ @pid = Process.spawn("julia --depwarn=no #{@work_dir}/#{LIB_SCRIPT}.#{@provider.class::EXT} #{@port}", :err => :out,:out => "/dev/null") #, :pgroup=>Process.pid)
344
657
  Process.detach @pid
345
658
  end
346
659
  end
@@ -1,3 +1,3 @@
1
1
  module VirtualModule
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: virtual_module
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kei Sawada(@remore)
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-19 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: msgpack