ruby_process 0.0.9 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.md +98 -0
- data/Rakefile +2 -2
- data/RubyProcess.gemspec +88 -0
- data/VERSION +1 -1
- data/cmds/blocks.rb +18 -18
- data/cmds/marshal.rb +2 -2
- data/cmds/new.rb +13 -13
- data/cmds/numeric.rb +4 -4
- data/cmds/static.rb +10 -10
- data/cmds/str_eval.rb +4 -4
- data/cmds/system.rb +11 -11
- data/examples/example_csv.rb +13 -0
- data/examples/example_file_write.rb +2 -2
- data/examples/example_knj_db_dump.rb +7 -7
- data/examples/example_strscan.rb +3 -3
- data/include/args_handeling.rb +21 -21
- data/lib/ruby_process.rb +111 -105
- data/lib/{ruby_process_cproxy.rb → ruby_process/class_proxy.rb} +35 -35
- data/lib/{ruby_process_proxyobj.rb → ruby_process/proxy_object.rb} +18 -18
- data/ruby_process.gemspec +17 -10
- data/scripts/ruby_process_script.rb +7 -7
- data/shippable.yml +7 -0
- data/spec/class_proxy_spec.rb +95 -0
- data/spec/hard_load_spec.rb +13 -17
- data/spec/leaks_spec.rb +7 -7
- data/spec/ruby_process_spec.rb +75 -77
- data/spec/spec_helper.rb +3 -1
- metadata +60 -60
- data/README.rdoc +0 -19
- data/spec/cproxy_spec.rb +0 -101
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e972d77dfff80a20f348133747e57615b17e8560
|
4
|
+
data.tar.gz: e92ec8e0657aa7ac65d99588ae98c642baf5b7b4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f82e248057294db13f64812da7704b20b388b1bf2fac5c79ba15964e4f51b87891b752211685a2db11195792dc735e9db8d918d106348b5ef20ade67e802d62b
|
7
|
+
data.tar.gz: 7d6230a58d058c211f8005fc6fdf4f0e01b34b164865ab3425c443e1cabdcd23ed6abbac2e8c0e4c216af34e0ad3a0fce33e719486894cd63b599e3d6dca253f
|
data/Gemfile
CHANGED
@@ -5,6 +5,7 @@ source "http://rubygems.org"
|
|
5
5
|
|
6
6
|
gem "wref"
|
7
7
|
gem "tsafe"
|
8
|
+
gem "string-cases"
|
8
9
|
|
9
10
|
# Add dependencies to develop your gem here.
|
10
11
|
# Include everything needed to run rake, tests, features, etc.
|
@@ -14,3 +15,5 @@ group :development do
|
|
14
15
|
gem "bundler", ">= 1.0.0"
|
15
16
|
gem "jeweler", "~> 1.8.3"
|
16
17
|
end
|
18
|
+
|
19
|
+
gem "codeclimate-test-reporter", group: :test, require: nil
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# RubyProcess
|
2
|
+
|
3
|
+
Start another Ruby process and manipulate it almost seamlessly.
|
4
|
+
|
5
|
+
## Example
|
6
|
+
|
7
|
+
The CSV lib will not be loaded in the main process and the writing of the file will also take place in another process.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
require "rubygems"
|
11
|
+
require "ruby_process"
|
12
|
+
|
13
|
+
RubyProcess.new.spawn_process do |rp|
|
14
|
+
rp.static(:Object, :require, "csv")
|
15
|
+
|
16
|
+
rp.static(:CSV, :open, "test.csv", "w") do |csv|
|
17
|
+
csv << ["ID", "Name"]
|
18
|
+
csv << [1, "Kasper"]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
```
|
22
|
+
|
23
|
+
|
24
|
+
## Install
|
25
|
+
|
26
|
+
Add to your Gemfile and bundle.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
gem "ruby_process"
|
30
|
+
```
|
31
|
+
|
32
|
+
## Usage
|
33
|
+
|
34
|
+
With a block.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
RubyProcess.new.spawn_process do |rp|
|
38
|
+
rp.static(:File, :open, "some_file", "w") do |fp|
|
39
|
+
fp.write("Test!")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Almost seamless mode with ClassProxy.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
RubyProcess::ClassProxy.run do |data|
|
48
|
+
sp = data[:subproc]
|
49
|
+
sp.static(:Object, :require, "tempfile")
|
50
|
+
|
51
|
+
# Tempfile will be created in the subprocess and not in the current process.
|
52
|
+
temp_file = RubyProcess::ClassProxy::Tempfile("temp")
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
As a variable.
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
rp = RubyProcess.new(debug: false)
|
60
|
+
rp.spawn_process
|
61
|
+
test_string = rp.new(:String, "Test")
|
62
|
+
```
|
63
|
+
|
64
|
+
Calling static methods on classes.
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
rp.static(:File, :open, "file_path", "w")
|
68
|
+
```
|
69
|
+
|
70
|
+
Spawning new objects.
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
file = rp.new(:File, "file_path", "r")
|
74
|
+
```
|
75
|
+
|
76
|
+
Serializing objects back to the main process.
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
rp.static(:File, :size, "file_path") #=> RubyProcess::ProxyObject
|
80
|
+
rp.static(:File, :size, "file_path").__rp_marshall #=> 2048
|
81
|
+
```
|
82
|
+
|
83
|
+
|
84
|
+
## Contributing to RubyProcess
|
85
|
+
|
86
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
87
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
88
|
+
* Fork the project.
|
89
|
+
* Start a feature/bugfix branch.
|
90
|
+
* Commit and push until you are happy with your contribution.
|
91
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
92
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
93
|
+
|
94
|
+
## Copyright
|
95
|
+
|
96
|
+
Copyright (c) 2012 Kasper Johansen. See LICENSE.txt for
|
97
|
+
further details.
|
98
|
+
|
data/Rakefile
CHANGED
@@ -36,14 +36,14 @@ RSpec::Core::RakeTask.new(:rcov) do |spec|
|
|
36
36
|
spec.rcov = true
|
37
37
|
end
|
38
38
|
|
39
|
-
task :
|
39
|
+
task default: :spec
|
40
40
|
|
41
41
|
require 'rdoc/task'
|
42
42
|
Rake::RDocTask.new do |rdoc|
|
43
43
|
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
44
|
|
45
45
|
rdoc.rdoc_dir = 'rdoc'
|
46
|
-
rdoc.title = "
|
46
|
+
rdoc.title = "RubyProcess #{version}"
|
47
47
|
rdoc.rdoc_files.include('README*')
|
48
48
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
49
|
end
|
data/RubyProcess.gemspec
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
# stub: RubyProcess 0.0.12 ruby lib
|
6
|
+
|
7
|
+
Gem::Specification.new do |s|
|
8
|
+
s.name = "RubyProcess"
|
9
|
+
s.version = "0.0.12"
|
10
|
+
|
11
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
|
+
s.require_paths = ["lib"]
|
13
|
+
s.authors = ["Kasper Johansen"]
|
14
|
+
s.date = "2015-04-06"
|
15
|
+
s.description = "A framework for spawning and communicating with other Ruby-processes"
|
16
|
+
s.email = "k@spernj.org"
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE.txt",
|
19
|
+
"README.md"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".rspec",
|
24
|
+
"Gemfile",
|
25
|
+
"LICENSE.txt",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"cmds/blocks.rb",
|
30
|
+
"cmds/marshal.rb",
|
31
|
+
"cmds/new.rb",
|
32
|
+
"cmds/numeric.rb",
|
33
|
+
"cmds/static.rb",
|
34
|
+
"cmds/str_eval.rb",
|
35
|
+
"cmds/system.rb",
|
36
|
+
"examples/example_csv.rb",
|
37
|
+
"examples/example_file_write.rb",
|
38
|
+
"examples/example_knj_db_dump.rb",
|
39
|
+
"examples/example_strscan.rb",
|
40
|
+
"include/args_handeling.rb",
|
41
|
+
"lib/ruby_process.rb",
|
42
|
+
"lib/ruby_process/class_proxy.rb",
|
43
|
+
"lib/ruby_process/proxy_object.rb",
|
44
|
+
"ruby_process.gemspec",
|
45
|
+
"scripts/ruby_process_script.rb",
|
46
|
+
"shippable.yml",
|
47
|
+
"spec/class_proxy_spec.rb",
|
48
|
+
"spec/hard_load_spec.rb",
|
49
|
+
"spec/leaks_spec.rb",
|
50
|
+
"spec/ruby_process_spec.rb",
|
51
|
+
"spec/spec_helper.rb"
|
52
|
+
]
|
53
|
+
s.homepage = "http://github.com/kaspernj/ruby_process"
|
54
|
+
s.licenses = ["MIT"]
|
55
|
+
s.rubygems_version = "2.4.0"
|
56
|
+
s.summary = "A framework for spawning and communicating with other Ruby-processes"
|
57
|
+
|
58
|
+
if s.respond_to? :specification_version then
|
59
|
+
s.specification_version = 4
|
60
|
+
|
61
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
62
|
+
s.add_runtime_dependency(%q<wref>, [">= 0"])
|
63
|
+
s.add_runtime_dependency(%q<tsafe>, [">= 0"])
|
64
|
+
s.add_runtime_dependency(%q<string-cases>, [">= 0"])
|
65
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
|
66
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
67
|
+
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
68
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
|
69
|
+
else
|
70
|
+
s.add_dependency(%q<wref>, [">= 0"])
|
71
|
+
s.add_dependency(%q<tsafe>, [">= 0"])
|
72
|
+
s.add_dependency(%q<string-cases>, [">= 0"])
|
73
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
74
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
75
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
76
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
77
|
+
end
|
78
|
+
else
|
79
|
+
s.add_dependency(%q<wref>, [">= 0"])
|
80
|
+
s.add_dependency(%q<tsafe>, [">= 0"])
|
81
|
+
s.add_dependency(%q<string-cases>, [">= 0"])
|
82
|
+
s.add_dependency(%q<rspec>, ["~> 2.8.0"])
|
83
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
84
|
+
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
85
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.13
|
data/cmds/blocks.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class RubyProcess
|
2
2
|
#Calls a block by its block-ID with given arguments.
|
3
3
|
def cmd_block_call(obj)
|
4
4
|
raise "Invalid block-ID: '#{obj}'." if obj[:block_id].to_i <= 0
|
@@ -6,41 +6,41 @@ class Ruby_process
|
|
6
6
|
raise "No block by that ID: '#{obj[:block_id]}'." if !block_ele
|
7
7
|
raise "Not a block? '#{block_ele.class.name}'." if !block_ele.respond_to?(:call)
|
8
8
|
debug "Calling block #{obj[:block_id]}: #{obj}\n" if @debug
|
9
|
-
|
9
|
+
|
10
10
|
answer_id = obj[:answer_id]
|
11
11
|
raise "No ':answer_id' was given (#{obj})." if !answer_id
|
12
|
-
|
12
|
+
|
13
13
|
if answer = @answers[answer_id]
|
14
14
|
#Use a queue to sleep thread until the block has been executed.
|
15
15
|
queue = Queue.new
|
16
|
-
answer.push(:
|
16
|
+
answer.push(type: :proxy_block_call, block: block_ele, args: read_args(obj[:args]), queue: queue)
|
17
17
|
res = queue.pop
|
18
18
|
raise "Expected true but didnt get that: '#{res}'." if res != true
|
19
19
|
else
|
20
20
|
block_ele.call(*read_args(obj[:args]))
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
return nil
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
#Spawns a block and returns its ID.
|
27
27
|
def cmd_spawn_proxy_block(obj)
|
28
28
|
block = proc{
|
29
|
-
send(:
|
29
|
+
send(cmd: :block_call, block_id: obj[:id], answer_id: obj[:answer_id])
|
30
30
|
}
|
31
|
-
|
31
|
+
|
32
32
|
id = block.__id__
|
33
33
|
raise "ID already exists: '#{id}'." if @objects.key?(id)
|
34
34
|
@objects[id] = block
|
35
|
-
|
36
|
-
return {:
|
35
|
+
|
36
|
+
return {id: id}
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
#Dynamically creates a block with a certain arity. If sub-methods measure arity, they will get the correct one from the other process.
|
40
40
|
def block_with_arity(args, &block)
|
41
41
|
eval_str = "proc{"
|
42
42
|
eval_argsarr = "\t\tblock.call("
|
43
|
-
|
43
|
+
|
44
44
|
if args[:arity] > 0
|
45
45
|
eval_str << "|"
|
46
46
|
1.upto(args[:arity]) do |i|
|
@@ -48,21 +48,21 @@ class Ruby_process
|
|
48
48
|
eval_str << ","
|
49
49
|
eval_argsarr << ","
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
eval_str << "arg#{i}"
|
53
53
|
eval_argsarr << "arg#{i}"
|
54
54
|
end
|
55
|
-
|
55
|
+
|
56
56
|
eval_str << "|\n"
|
57
57
|
eval_argsarr << ")\n"
|
58
58
|
end
|
59
|
-
|
59
|
+
|
60
60
|
eval_full = eval_str + eval_argsarr
|
61
61
|
eval_full << "}"
|
62
|
-
|
62
|
+
|
63
63
|
debug "Block eval: #{eval_full}\n" if @debug
|
64
64
|
dynamic_proc = eval(eval_full)
|
65
|
-
|
65
|
+
|
66
66
|
return dynamic_proc
|
67
67
|
end
|
68
|
-
end
|
68
|
+
end
|
data/cmds/marshal.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
class
|
1
|
+
class RubyProcess
|
2
2
|
#This command returns an object as a marshalled string, so it can be re-created on the other side.
|
3
3
|
def cmd_obj_marshal(obj)
|
4
4
|
myobj = @objects[obj[:id]]
|
5
5
|
raise "Object by that ID does not exist: '#{obj[:id]}'." if !myobj
|
6
6
|
return Marshal.dump(myobj)
|
7
7
|
end
|
8
|
-
end
|
8
|
+
end
|
data/cmds/new.rb
CHANGED
@@ -1,44 +1,44 @@
|
|
1
|
-
class
|
1
|
+
class RubyProcess
|
2
2
|
#Spawns a new object in the process and returns a proxy-object for it.
|
3
3
|
def new(classname, *args, &block)
|
4
|
-
return send(:
|
4
|
+
return send(cmd: :new, classname: classname, args: parse_args(args), &block)
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
#This command spawns a new object of a given class and returns its hash-handle, so a proxy-object can be spawned on the other side.
|
8
8
|
def cmd_new(obj)
|
9
9
|
const = obj[:classname].to_s.split("::").inject(Object, :const_get)
|
10
|
-
|
10
|
+
|
11
11
|
debug "New-args-before: #{obj[:args]}\n" if @debug
|
12
12
|
real_args = read_args(obj[:args])
|
13
13
|
debug "New-args-after: #{real_args}\n" if @debug
|
14
|
-
|
14
|
+
|
15
15
|
retobj = const.new(*real_args)
|
16
16
|
return handle_return_object(retobj)
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
#Calls a method on an object.
|
20
20
|
def cmd_obj_method(obj)
|
21
21
|
myobj = @objects[obj[:id]]
|
22
22
|
raise "Object by that ID does not exist: '#{obj[:id]}' '(#{@objects.keys.sort.join(",")})." if !myobj
|
23
|
-
|
23
|
+
|
24
24
|
if obj.key?(:block)
|
25
25
|
real_block = proc{|*args|
|
26
26
|
debug "Block called! #{args}\n" if @debug
|
27
|
-
send(:
|
27
|
+
send(cmd: :block_call, block_id: obj[:block][:id], answer_id: obj[:send_id], args: handle_return_args(args))
|
28
28
|
}
|
29
|
-
|
30
|
-
block = block_with_arity(:
|
29
|
+
|
30
|
+
block = block_with_arity(arity: obj[:block][:arity], &real_block)
|
31
31
|
debug "Spawned fake block with arity: #{block.arity}\n" if @debug
|
32
32
|
else
|
33
33
|
block = nil
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
debug "Obj-method-args-before: #{obj[:args]}\n" if @debug
|
37
37
|
real_args = read_args(obj[:args])
|
38
38
|
debug "Obj-methods-args-after: #{real_args}\n" if @debug
|
39
|
-
|
39
|
+
|
40
40
|
debug "Calling #{myobj.class.name}.#{obj[:method]}(*#{obj[:args]}, &#{block})\n" if @debug
|
41
41
|
res = myobj.__send__(obj[:method], *real_args, &block)
|
42
42
|
return handle_return_object(res)
|
43
43
|
end
|
44
|
-
end
|
44
|
+
end
|
data/cmds/numeric.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
class
|
1
|
+
class RubyProcess
|
2
2
|
#Returns a numeric value like a integer. This methods exists because it isnt possible to do: "Integer.new(5)".
|
3
3
|
#===Examples
|
4
4
|
# proxy_int = rp.numeric(5)
|
5
5
|
# proxy_int.__rp_marshal #=> 5
|
6
6
|
def numeric(val)
|
7
|
-
return send(:
|
7
|
+
return send(cmd: :numeric, val: val)
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
#Process-method for the 'numeric'-method.
|
11
11
|
def cmd_numeric(obj)
|
12
12
|
return handle_return_object(obj[:val].to_i)
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end
|
data/cmds/static.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class
|
1
|
+
class RubyProcess
|
2
2
|
#Calls a static method on the process-side.
|
3
3
|
#===Examples
|
4
4
|
# rp.static(:File, :open, "/tmp/somefile", "w") do |fp|
|
@@ -8,29 +8,29 @@ class Ruby_process
|
|
8
8
|
debug "Args-before: #{args} (#{@my_pid})\n" if @debug
|
9
9
|
real_args = parse_args(args)
|
10
10
|
debug "Real-args: #{real_args}\n" if @debug
|
11
|
-
|
12
|
-
return send(:
|
11
|
+
|
12
|
+
return send(cmd: :static, classname: classname, method: method, args: real_args, &block)
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
#Process-method for the 'static'-method.
|
16
16
|
def cmd_static(obj)
|
17
17
|
if obj.key?(:block)
|
18
18
|
real_block = proc{|*args|
|
19
19
|
debug "Block called! #{args}\n" if @debug
|
20
|
-
send(:
|
20
|
+
send(cmd: :block_call, block_id: obj[:block][:id], answer_id: obj[:send_id], args: handle_return_args(args))
|
21
21
|
}
|
22
|
-
|
23
|
-
block = block_with_arity(:
|
22
|
+
|
23
|
+
block = block_with_arity(arity: obj[:block][:arity], &real_block)
|
24
24
|
else
|
25
25
|
block = nil
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
debug "Static-args-before: #{obj[:args]}\n" if @debug
|
29
29
|
real_args = read_args(obj[:args])
|
30
30
|
debug "Static-args-after: #{real_args}\n" if @debug
|
31
|
-
|
31
|
+
|
32
32
|
const = obj[:classname].to_s.split("::").inject(Object, :const_get)
|
33
33
|
retobj = const.__send__(obj[:method], *real_args, &block)
|
34
34
|
return handle_return_object(retobj)
|
35
35
|
end
|
36
|
-
end
|
36
|
+
end
|