interprocess_attribute 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.pryrc ADDED
@@ -0,0 +1 @@
1
+ require "./lib/interprocess_attribute"
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ rvm:
2
+ - 1.9.2
3
+ - 1.9.3
4
+ - ruby-head
5
+ # UNIXSocket#recvmsg is not implemented on Rubinius yet.
6
+ # - rbx-19mode
7
+
8
+ notifications:
9
+ email: true
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source :rubygems
2
+ group :default, :development do
3
+ gem 'rake'
4
+ gem 'yard'
5
+ gem 'redcarpet'
6
+ gem 'pry'
7
+ end
8
+ gemspec
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 | [![Build Status](https://travis-ci.org/robgleeson/interprocess_attribute.png)](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,9 @@
1
+ require "bundler/gem_tasks"
2
+ desc 'Run the test suite.'
3
+ task :test do
4
+ $LOAD_PATH.unshift 'lib'
5
+ Dir["test/*_test.rb"].each do |file|
6
+ require_relative file
7
+ end
8
+ end
9
+ task :default => :test
@@ -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,3 @@
1
+ class Class
2
+ include InterProcessAttribute
3
+ 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
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+ require 'pry'
3
+ require 'test/unit'
4
+ require 'interprocess_attribute'
5
+ require 'interprocess_attribute/core_ext/class'
6
+ Dir["test/support/**/*.rb"].each do |file|
7
+ require "./#{file}"
8
+ end
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: