interprocess_attribute 0.1.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.
- data/.pryrc +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +30 -0
- data/README.md +158 -0
- data/Rakefile +9 -0
- data/interprocess_attribute.gemspec +16 -0
- data/lib/interprocess_attribute/core_ext/class.rb +3 -0
- data/lib/interprocess_attribute.rb +43 -0
- data/test/interprocess_attribute_test.rb +61 -0
- data/test/setup.rb +8 -0
- metadata +81 -0
data/.pryrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "./lib/interprocess_attribute"
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
interprocess_attribute (0.1.0)
|
5
|
+
ichannel (~> 5.1.1)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
coderay (1.0.8)
|
11
|
+
ichannel (5.1.1)
|
12
|
+
method_source (0.8.1)
|
13
|
+
pry (0.9.10)
|
14
|
+
coderay (~> 1.0.5)
|
15
|
+
method_source (~> 0.8)
|
16
|
+
slop (~> 3.3.1)
|
17
|
+
rake (10.0.3)
|
18
|
+
redcarpet (2.2.2)
|
19
|
+
slop (3.3.3)
|
20
|
+
yard (0.8.3)
|
21
|
+
|
22
|
+
PLATFORMS
|
23
|
+
ruby
|
24
|
+
|
25
|
+
DEPENDENCIES
|
26
|
+
interprocess_attribute!
|
27
|
+
pry
|
28
|
+
rake
|
29
|
+
redcarpet
|
30
|
+
yard
|
data/README.md
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
__OVERVIEW__
|
2
|
+
|
3
|
+
|
4
|
+
| Project | interprocess\_attribute
|
5
|
+
|:----------------|:--------------------------------------------------
|
6
|
+
| Homepage | https://github.com/robgleeson/interprocess_attribute
|
7
|
+
| Documentation | http://rubydoc.info/gems/interprocess_attribute/frames
|
8
|
+
| CI | [](https://travis-ci.org/robgleeson/ichannel)
|
9
|
+
| Author | Robert Gleeson
|
10
|
+
|
11
|
+
|
12
|
+
__DESCRIPTION__
|
13
|
+
|
14
|
+
interprocess\_attribute persists attributes between processes. That's to say
|
15
|
+
you can change the 'name' attribute to "Rob" in the child process and see that
|
16
|
+
change propagate in the parent process with very little code.
|
17
|
+
|
18
|
+
Attributes are defined through the `interprocess_attribute` method. It
|
19
|
+
behaves just like the `attr_accessor` method in that it defines a getter and
|
20
|
+
a setter. The difference is that attributes set through interprocess\_attribute
|
21
|
+
persist between processes.
|
22
|
+
|
23
|
+
__EXAMPLES__
|
24
|
+
|
25
|
+
__1.__
|
26
|
+
|
27
|
+
The example shows a simple scenario of how you might use interprocess\_attribute
|
28
|
+
to persist the 'name' attribute among a parent process & a subprocess. A monkey
|
29
|
+
patch on Class is used but it is opt-in and can be avoided if you really want.
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require "interprocess_attribute"
|
33
|
+
require "interprocess_attribute/core_ext/class"
|
34
|
+
class Person
|
35
|
+
interprocess_attribute :name
|
36
|
+
end
|
37
|
+
|
38
|
+
person = Person.new
|
39
|
+
pid = fork do
|
40
|
+
person.name = "Rob"
|
41
|
+
end
|
42
|
+
Process.wait pid
|
43
|
+
p person.name # => "Rob"
|
44
|
+
```
|
45
|
+
|
46
|
+
__2.__
|
47
|
+
|
48
|
+
Monkey-patching Class is not everybodys cup of tea, so in that case there is
|
49
|
+
a module you can use with extend(…).
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
require "interprocess_attribute"
|
53
|
+
class Person
|
54
|
+
extend InterProcessAttribute
|
55
|
+
interprocess_attribute :name
|
56
|
+
interprocess_attribute :age
|
57
|
+
end
|
58
|
+
|
59
|
+
person = Person.new
|
60
|
+
pid = fork do
|
61
|
+
person.name = "Rob"
|
62
|
+
person.age = 27
|
63
|
+
end
|
64
|
+
Process.wait pid
|
65
|
+
p person.name # => "Rob"
|
66
|
+
p person.age # => 27
|
67
|
+
```
|
68
|
+
__3.__
|
69
|
+
|
70
|
+
So far all these examples have defined public attributes but it might just be that
|
71
|
+
you don't want to expose attributes at all, you could just want persistence,
|
72
|
+
and to compensate for that it is possible to mark attributes as private or
|
73
|
+
protected:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
class Person
|
77
|
+
extend InterProcessAttribute
|
78
|
+
interprocess_attribute :name, {visibility: :private}
|
79
|
+
|
80
|
+
def initialize
|
81
|
+
self.name = "Rob"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
person = Person.new
|
86
|
+
person.name = "John" # NoMethodError
|
87
|
+
```
|
88
|
+
|
89
|
+
__4.__
|
90
|
+
|
91
|
+
The last example is a bit like inception: what happens when you fork inside a
|
92
|
+
fork and both of those forks call a setter? The behavior for this case is to
|
93
|
+
discard all values but the last one to be set. For example, `person.name` will
|
94
|
+
be "Rob" here:
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
class Person
|
98
|
+
extend InterProcessAttribute
|
99
|
+
interprocess_attribute :name
|
100
|
+
end
|
101
|
+
|
102
|
+
person = Person.new
|
103
|
+
pid = fork do
|
104
|
+
person.name = "John"
|
105
|
+
pid = fork do
|
106
|
+
person.name = "Rob"
|
107
|
+
end
|
108
|
+
Process.wait pid
|
109
|
+
end
|
110
|
+
Process.wait pid
|
111
|
+
p person.name # => "Rob"
|
112
|
+
```
|
113
|
+
|
114
|
+
__GOTCHAS__
|
115
|
+
|
116
|
+
__1.__
|
117
|
+
|
118
|
+
Methods that mutate the receiver won't have their changes persist between
|
119
|
+
processes. You must use the setter if you want persistence. For example:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
class Person
|
123
|
+
extend InterProcessAttribute
|
124
|
+
interprocess_attribute :name
|
125
|
+
end
|
126
|
+
|
127
|
+
person = Person.new
|
128
|
+
person.name = "John"
|
129
|
+
person.name.sub! /J/, "" # does not persist
|
130
|
+
person.name = person.name.sub! /J/, "" # persists
|
131
|
+
```
|
132
|
+
|
133
|
+
__2.__
|
134
|
+
|
135
|
+
The transport of Ruby objects happens through serialization and communication
|
136
|
+
on a UNIXSocket. The serializer being used is Marshal, and it can serialize
|
137
|
+
most Ruby objects but there is a few it can't, so be wary.
|
138
|
+
|
139
|
+
__PLATFORM SUPPORT__
|
140
|
+
|
141
|
+
_supported_
|
142
|
+
|
143
|
+
* CRuby (1.9+)
|
144
|
+
|
145
|
+
_unsupported_
|
146
|
+
|
147
|
+
* CRuby 1.8
|
148
|
+
* MacRuby
|
149
|
+
* JRuby
|
150
|
+
* Rubinius (support for Rubinius will come sometime in the future).
|
151
|
+
|
152
|
+
__INSTALL__
|
153
|
+
|
154
|
+
$ gem install interprocess_attribute
|
155
|
+
|
156
|
+
__LICENSE__
|
157
|
+
|
158
|
+
MIT. See LICENSE.txt.
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
Gem::Specification.new do |gem|
|
3
|
+
gem.name = "interprocess_attribute"
|
4
|
+
gem.version = "0.1.0"
|
5
|
+
gem.authors = ["Robert Gleeson"]
|
6
|
+
gem.email = ["rob@flowof.info"]
|
7
|
+
gem.description = %q{Attributes that persist between processes}
|
8
|
+
gem.summary = gem.description
|
9
|
+
gem.homepage = "https://github.com/robgleeson/interprocess_attribute"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($/)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.require_paths = ["lib"]
|
15
|
+
gem.add_runtime_dependency 'ichannel', '~> 5.1.1'
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "ichannel"
|
2
|
+
module InterProcessAttribute
|
3
|
+
#
|
4
|
+
# @param [#to_s] name
|
5
|
+
# The name of the attribute.
|
6
|
+
#
|
7
|
+
# @param [Hash] opts
|
8
|
+
# @option opts [#to_s] :visibility
|
9
|
+
# "public", "protected", or "private"
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# class Person
|
13
|
+
# extend InterProcessAttribute
|
14
|
+
# interprocess_attribute :name, {visibility: :private}
|
15
|
+
#
|
16
|
+
# def initialize
|
17
|
+
# self.name = "Rob"
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# person = Person.new
|
22
|
+
# person.name = "Rob"
|
23
|
+
# p person.name # => "Rob"
|
24
|
+
#
|
25
|
+
def interprocess_attribute(name, opts = {visibility: "public"})
|
26
|
+
class_eval do
|
27
|
+
channel = IChannel.new Marshal
|
28
|
+
define_method name do
|
29
|
+
while channel.readable?
|
30
|
+
instance_variable_set "@#{name}", channel.get
|
31
|
+
end
|
32
|
+
instance_variable_get "@#{name}"
|
33
|
+
end
|
34
|
+
send opts[:visibility], name.to_sym
|
35
|
+
|
36
|
+
define_method "#{name}=" do |value|
|
37
|
+
channel.put value
|
38
|
+
instance_variable_set "@#{name}", value
|
39
|
+
end
|
40
|
+
send opts[:visibility], "#{name}=".to_sym
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require_relative "setup"
|
2
|
+
class InterProcessAttributeTest < Test::Unit::TestCase
|
3
|
+
class Person
|
4
|
+
interprocess_attribute :name
|
5
|
+
interprocess_attribute :age
|
6
|
+
interprocess_attribute :height, {visibility: :private}
|
7
|
+
interprocess_attribute :weight, {visibility: :protected}
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_defaults
|
11
|
+
person = Person.new
|
12
|
+
assert_equal nil, person.name
|
13
|
+
assert_equal nil, person.age
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_inception
|
17
|
+
person = Person.new
|
18
|
+
pid = fork do
|
19
|
+
person.name = "Rob"
|
20
|
+
pid = fork do
|
21
|
+
person.name = "John"
|
22
|
+
end
|
23
|
+
Process.wait pid
|
24
|
+
end
|
25
|
+
Process.wait pid
|
26
|
+
assert_equal "John", person.name
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_persistence_to_parent
|
30
|
+
person = Person.new
|
31
|
+
pid = fork do
|
32
|
+
person.name = "Rob"
|
33
|
+
person.age = 27
|
34
|
+
end
|
35
|
+
Process.wait pid
|
36
|
+
assert_equal "Rob", person.name
|
37
|
+
assert_equal 27, person.age
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_persistence_to_child
|
41
|
+
person = Person.new
|
42
|
+
person.name = "John"
|
43
|
+
pid = fork do
|
44
|
+
if person.name == "John"
|
45
|
+
person.name = true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
Process.wait pid
|
49
|
+
assert_equal true, person.name
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_visibility
|
53
|
+
is_public = Person.public_instance_methods.include? :name
|
54
|
+
assert is_public
|
55
|
+
is_private = Person.private_instance_methods.include? :height
|
56
|
+
assert is_private
|
57
|
+
is_protected = Person.protected_instance_methods.include? :weight
|
58
|
+
assert is_protected
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/test/setup.rb
ADDED
metadata
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: interprocess_attribute
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Robert Gleeson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-01-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ichannel
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 5.1.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 5.1.1
|
30
|
+
description: Attributes that persist between processes
|
31
|
+
email:
|
32
|
+
- rob@flowof.info
|
33
|
+
executables: []
|
34
|
+
extensions: []
|
35
|
+
extra_rdoc_files: []
|
36
|
+
files:
|
37
|
+
- .pryrc
|
38
|
+
- .travis.yml
|
39
|
+
- Gemfile
|
40
|
+
- Gemfile.lock
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- interprocess_attribute.gemspec
|
44
|
+
- lib/interprocess_attribute.rb
|
45
|
+
- lib/interprocess_attribute/core_ext/class.rb
|
46
|
+
- test/interprocess_attribute_test.rb
|
47
|
+
- test/setup.rb
|
48
|
+
homepage: https://github.com/robgleeson/interprocess_attribute
|
49
|
+
licenses: []
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
require_paths:
|
53
|
+
- lib
|
54
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ! '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
hash: 3577632575707106316
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
segments:
|
70
|
+
- 0
|
71
|
+
hash: 3577632575707106316
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.8.23
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Attributes that persist between processes
|
78
|
+
test_files:
|
79
|
+
- test/interprocess_attribute_test.rb
|
80
|
+
- test/setup.rb
|
81
|
+
has_rdoc:
|