sync_attr 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/examples/class_attribute.rb +6 -7
- data/examples/instance_attribute.rb +35 -0
- data/lib/sync_attr.rb +4 -2
- data/lib/sync_attr/class_attributes.rb +39 -21
- data/lib/sync_attr/instance_attributes.rb +101 -0
- data/lib/sync_attr/version.rb +1 -1
- data/test/class_attributes_test.rb +33 -21
- data/test/instance_attributes_test.rb +88 -0
- metadata +32 -29
- data/nbproject/private/config.properties +0 -0
- data/nbproject/private/private.properties +0 -4
- data/nbproject/private/private.xml +0 -4
- data/nbproject/private/rake-d.txt +0 -0
- data/nbproject/project.properties +0 -10
- data/nbproject/project.xml +0 -16
data/Rakefile
CHANGED
@@ -18,7 +18,7 @@ task :gem do |t|
|
|
18
18
|
s.date = Date.today.to_s
|
19
19
|
s.summary = "Thread safe accessors for Ruby class and instance attributes. Supports thread safe lazy loading of attributes"
|
20
20
|
s.description = "SyncAttr is a mixin to read, write and lazy initialize both class and instance variables in a multi-threaded environment when the attribute could be modified by two threads at the same time, written in Ruby."
|
21
|
-
s.files = FileList[
|
21
|
+
s.files = FileList['**/*'].exclude('*.gem', /nbproject/)
|
22
22
|
s.has_rdoc = true
|
23
23
|
end
|
24
24
|
Gem::Builder.new(gemspec).build
|
data/examples/class_attribute.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'sync_attr'
|
4
4
|
|
5
5
|
# Sample class with lazy initialized Synchronized Class Attributes
|
6
|
-
|
6
|
+
class Person
|
7
7
|
include SyncAttr
|
8
8
|
|
9
9
|
# Thread safe Class Attribute reader for name
|
@@ -20,12 +20,11 @@ def Person
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
person
|
24
|
-
puts "The person is #{person.name} with age #{person.age}"
|
23
|
+
puts "The person is #{Person.name} with age #{Person.age}"
|
25
24
|
|
26
|
-
|
27
|
-
puts "The person is #{
|
25
|
+
Person.age = 22
|
26
|
+
puts "The person is #{Person.name} now has age #{Person.age}"
|
28
27
|
|
29
|
-
|
30
|
-
puts "The person is #{
|
28
|
+
Person.age = Proc.new {|age| age += 1 }
|
29
|
+
puts "The person is #{Person.name} now has age #{Person.age}"
|
31
30
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Class Attribute Example
|
2
|
+
#
|
3
|
+
require 'sync_attr'
|
4
|
+
|
5
|
+
# Sample class with lazy initialized Synchronized Class Attributes
|
6
|
+
class Person
|
7
|
+
include SyncAttr
|
8
|
+
|
9
|
+
# Thread safe Instance Attribute reader for name
|
10
|
+
# Sets :name only when it is first called
|
11
|
+
# Ideal for when name is loaded after startup from a database or config file
|
12
|
+
sync_attr_reader :name do
|
13
|
+
"Joe Bloggs"
|
14
|
+
end
|
15
|
+
|
16
|
+
# Thread safe Instance Attribute reader and writer for age
|
17
|
+
# Sets :age only when it is first called
|
18
|
+
sync_attr_accessor :age do
|
19
|
+
21
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
person = Person.new
|
24
|
+
puts "The person is #{person.name} with age #{person.age}"
|
25
|
+
|
26
|
+
person.age = 22
|
27
|
+
puts "The person is #{person.name} now has age #{person.age}"
|
28
|
+
|
29
|
+
person.age = Proc.new {|age| age += 1 }
|
30
|
+
puts "The person is #{person.name} now has age #{person.age}"
|
31
|
+
|
32
|
+
# Changes to person above do not affect any changes to second_person
|
33
|
+
# Also, the initial value that is lazy loaded into name is unaffected by person above
|
34
|
+
second_person = Person.new
|
35
|
+
puts "The second person is #{second_person.name} with age #{second_person.age}"
|
data/lib/sync_attr.rb
CHANGED
@@ -22,12 +22,14 @@
|
|
22
22
|
require 'sync'
|
23
23
|
require 'sync_attr/version'
|
24
24
|
require 'sync_attr/class_attributes'
|
25
|
-
|
25
|
+
require 'sync_attr/instance_attributes'
|
26
26
|
|
27
27
|
module SyncAttr
|
28
28
|
# Add class methods and initialize mixin
|
29
29
|
def self.included(base)
|
30
30
|
base.extend(SyncAttr::ClassAttributes::ClassMethods)
|
31
|
-
base.
|
31
|
+
base.extend(SyncAttr::InstanceAttributes::ClassMethods)
|
32
|
+
base.send(:sync_cattr_init)
|
33
|
+
base.send(:sync_attr_init)
|
32
34
|
end
|
33
35
|
end
|
@@ -25,19 +25,26 @@ module SyncAttr
|
|
25
25
|
# end
|
26
26
|
def sync_cattr_reader(*attributes, &block)
|
27
27
|
attributes.each do |attribute|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
# Now that we have exclusive access make sure that another thread has
|
36
|
-
# not just initialized this attribute
|
37
|
-
if class_variable_defined?(var_name)
|
38
|
-
class_variable_get(var_name)
|
28
|
+
metaclass.instance_eval do
|
29
|
+
define_method(attribute.to_sym) do
|
30
|
+
var_name = "@@#{attribute}".to_sym
|
31
|
+
if class_variable_defined?(var_name)
|
32
|
+
# If there is no writer then it is not necessary to protect reads
|
33
|
+
if self.respond_to?("#{attribute}=".to_sym, true)
|
34
|
+
sync_cattr_sync.synchronize(:SH) { class_variable_get(var_name) }
|
39
35
|
else
|
40
|
-
|
36
|
+
class_variable_get(var_name)
|
37
|
+
end
|
38
|
+
else
|
39
|
+
return nil unless block
|
40
|
+
sync_cattr_sync.synchronize(:EX) do
|
41
|
+
# Now that we have exclusive access make sure that another thread has
|
42
|
+
# not just initialized this attribute
|
43
|
+
if class_variable_defined?(var_name)
|
44
|
+
class_variable_get(var_name)
|
45
|
+
else
|
46
|
+
class_variable_set(var_name, class_eval(&block))
|
47
|
+
end
|
41
48
|
end
|
42
49
|
end
|
43
50
|
end
|
@@ -52,7 +59,7 @@ module SyncAttr
|
|
52
59
|
attributes.each do |attribute|
|
53
60
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
54
61
|
def self.#{attribute}=(value)
|
55
|
-
|
62
|
+
sync_cattr_sync.synchronize(:EX) do
|
56
63
|
if value.is_a?(Proc)
|
57
64
|
current_value = @@#{attribute} if defined?(@@#{attribute})
|
58
65
|
@@#{attribute} = value.call(current_value)
|
@@ -67,21 +74,32 @@ module SyncAttr
|
|
67
74
|
|
68
75
|
# Generate a class reader and writer for the attribute
|
69
76
|
def sync_cattr_accessor(*attributes, &block)
|
70
|
-
sync_cattr_reader(*attributes, &block)
|
71
77
|
sync_cattr_writer(*attributes)
|
78
|
+
sync_cattr_reader(*attributes, &block)
|
72
79
|
end
|
73
80
|
|
74
|
-
|
81
|
+
# Returns the metaclass or eigenclass so that we
|
82
|
+
# can dynamically generate class methods
|
83
|
+
# With thanks, see: https://gist.github.com/1199817
|
84
|
+
def metaclass
|
85
|
+
class << self;
|
86
|
+
self
|
87
|
+
end
|
88
|
+
end
|
75
89
|
|
76
|
-
#
|
77
|
-
|
78
|
-
|
90
|
+
# Returns the sync used by the included class to synchronize access to the
|
91
|
+
# class attributes
|
92
|
+
def sync_cattr_sync
|
93
|
+
@sync_cattr_sync
|
79
94
|
end
|
80
95
|
|
81
|
-
|
82
|
-
|
96
|
+
protected
|
97
|
+
|
98
|
+
# Give each class that this module is mixed into it's own Sync
|
99
|
+
def sync_cattr_init
|
100
|
+
@sync_cattr_sync = ::Sync.new
|
83
101
|
end
|
84
102
|
|
85
103
|
end
|
86
104
|
end
|
87
|
-
end
|
105
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
puts "Loaded sync_attr_reader"
|
2
|
+
# Synchronize access and lazy initialize one or more attributes
|
3
|
+
#
|
4
|
+
# Author: Reid Morrison <reidmo@gmail.com>
|
5
|
+
module SyncAttr
|
6
|
+
module InstanceAttributes
|
7
|
+
module ClassMethods
|
8
|
+
# Lazy load the specific attribute by calling the supplied block when
|
9
|
+
# the attribute is first read and then return the same value for all subsequent
|
10
|
+
# calls to the variable
|
11
|
+
#
|
12
|
+
# An optional block can be supplied to initialize the attribute
|
13
|
+
# when first read. Acts as a thread safe lazy initializer. The block will only
|
14
|
+
# be called once even if several threads call the reader at the same time
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
# class MyClass
|
18
|
+
# include SyncAttr
|
19
|
+
#
|
20
|
+
# # Generates a reader for the class attribute 'hello'
|
21
|
+
# # and Lazy initializes the value to 'hello world' only on the first
|
22
|
+
# # call to the reader
|
23
|
+
# sync_attr_reader :hello do
|
24
|
+
# 'hello world'
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
def sync_attr_reader(*attributes, &block)
|
28
|
+
attributes.each do |attribute|
|
29
|
+
self.send(:define_method, attribute.to_sym) do
|
30
|
+
var_name = "@#{attribute}".to_sym
|
31
|
+
if instance_variable_defined?(var_name)
|
32
|
+
self.sync_attr_sync.synchronize(:SH) { instance_variable_get(var_name) }
|
33
|
+
# If there is no writer then it is not necessary to protect reads
|
34
|
+
if self.respond_to?("#{attribute}=".to_sym, true)
|
35
|
+
self.sync_attr_sync.synchronize(:SH) { instance_variable_get(var_name) }
|
36
|
+
else
|
37
|
+
instance_variable_get(var_name)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
return nil unless block
|
41
|
+
self.sync_attr_sync.synchronize(:EX) do
|
42
|
+
# Now that we have exclusive access make sure that another thread has
|
43
|
+
# not just initialized this attribute
|
44
|
+
if instance_variable_defined?(var_name)
|
45
|
+
instance_variable_get(var_name)
|
46
|
+
else
|
47
|
+
instance_variable_set(var_name, instance_eval(&block))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Generates a writer to set a synchronized attribute
|
56
|
+
# Supply a Proc ensure an attribute is not being updated by another thread:
|
57
|
+
# my_object.count = Proc.new {|count| (count||0) + 1}
|
58
|
+
def sync_attr_writer(*attributes)
|
59
|
+
attributes.each do |attribute|
|
60
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
61
|
+
def #{attribute}=(value)
|
62
|
+
self.sync_attr_sync.synchronize(:EX) do
|
63
|
+
if value.is_a?(Proc)
|
64
|
+
current_value = @#{attribute} if defined?(@#{attribute})
|
65
|
+
@#{attribute} = value.call(current_value)
|
66
|
+
else
|
67
|
+
@#{attribute} = value
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
EOS
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Generate a reader and writer for the attribute
|
76
|
+
def sync_attr_accessor(*attributes, &block)
|
77
|
+
sync_attr_reader(*attributes, &block)
|
78
|
+
sync_attr_writer(*attributes)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Give every object instance that this module is mixed into it's own Sync
|
82
|
+
# I.e. At an object level, not class level
|
83
|
+
def sync_attr_init
|
84
|
+
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
85
|
+
def sync_attr_sync
|
86
|
+
return @sync_attr_sync if @sync_attr_sync
|
87
|
+
# Use class sync_cattr_sync to ensure multiple @sync_attr_sync instances
|
88
|
+
# are not created when two or more threads call this method for the
|
89
|
+
# first time at the same time
|
90
|
+
self.class.sync_cattr_sync.synchronize(:EX) do
|
91
|
+
# In case another thread already created the sync
|
92
|
+
return @sync_attr_sync if @sync_attr_sync
|
93
|
+
@sync_attr_sync = ::Sync::new
|
94
|
+
end
|
95
|
+
end
|
96
|
+
EOS
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/lib/sync_attr/version.rb
CHANGED
@@ -6,10 +6,10 @@ require 'test/unit'
|
|
6
6
|
require 'shoulda'
|
7
7
|
require 'sync_attr'
|
8
8
|
|
9
|
-
class
|
9
|
+
class SyncCAttrExample
|
10
10
|
include SyncAttr
|
11
11
|
|
12
|
-
sync_cattr_reader :
|
12
|
+
sync_cattr_reader :test1 do
|
13
13
|
'hello world'
|
14
14
|
end
|
15
15
|
sync_cattr_reader :test2
|
@@ -21,11 +21,11 @@ class SynchAttrExample
|
|
21
21
|
sync_cattr_accessor :test5
|
22
22
|
end
|
23
23
|
|
24
|
-
class
|
24
|
+
class SyncCAttrExample2
|
25
25
|
include SyncAttr
|
26
26
|
|
27
|
-
sync_cattr_reader :
|
28
|
-
'
|
27
|
+
sync_cattr_reader :test1 do
|
28
|
+
'another world'
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -33,43 +33,55 @@ class ClassAttributesTest < Test::Unit::TestCase
|
|
33
33
|
context "with example" do
|
34
34
|
|
35
35
|
should 'lazy initialize class attribute' do
|
36
|
-
assert_equal 'hello world',
|
36
|
+
assert_equal 'hello world', SyncCAttrExample.test1
|
37
37
|
end
|
38
38
|
|
39
39
|
should 'return nil on class attribute without initializer' do
|
40
|
-
assert_nil
|
40
|
+
assert_nil SyncCAttrExample.test2
|
41
41
|
end
|
42
42
|
|
43
43
|
should 'set and then return a value for a class attribute without an initializer' do
|
44
|
-
assert_nil
|
45
|
-
assert_equal 'test3', (
|
46
|
-
assert_equal 'test3',
|
44
|
+
assert_nil SyncCAttrExample.test3
|
45
|
+
assert_equal 'test3', (SyncCAttrExample.test3 = 'test3')
|
46
|
+
assert_equal 'test3', SyncCAttrExample.test3
|
47
47
|
end
|
48
48
|
|
49
49
|
should 'lazy initialize class attribute and also have writer' do
|
50
|
-
assert_equal 'hello world 4',
|
51
|
-
assert_equal 'test4', (
|
52
|
-
assert_equal 'test4',
|
50
|
+
assert_equal 'hello world 4', SyncCAttrExample.test4
|
51
|
+
assert_equal 'test4', (SyncCAttrExample.test4 = 'test4')
|
52
|
+
assert_equal 'test4', SyncCAttrExample.test4
|
53
53
|
end
|
54
54
|
|
55
55
|
should 'support setting a Proc within a synch block' do
|
56
|
-
assert_nil
|
56
|
+
assert_nil SyncCAttrExample.test5
|
57
57
|
|
58
58
|
# Returns the Proc
|
59
|
-
|
60
|
-
assert_equal 1,
|
59
|
+
SyncCAttrExample.test5 = Proc.new {|val| (val||0) + 1}
|
60
|
+
assert_equal 1, SyncCAttrExample.test5
|
61
61
|
|
62
|
-
|
63
|
-
assert_equal 2,
|
62
|
+
SyncCAttrExample.test5 = Proc.new {|val| (val||0) + 1}
|
63
|
+
assert_equal 2, SyncCAttrExample.test5
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
context "with example2" do
|
68
68
|
|
69
69
|
should 'ensure that different classes have their own synch instances' do
|
70
|
-
assert ex1 =
|
71
|
-
assert ex2 =
|
72
|
-
assert ex1.class.send(:
|
70
|
+
assert ex1 = SyncCAttrExample.new
|
71
|
+
assert ex2 = SyncCAttrExample2.new
|
72
|
+
assert ex1.class.send(:sync_cattr_sync).object_id != ex2.class.send(:sync_cattr_sync).object_id
|
73
|
+
end
|
74
|
+
|
75
|
+
should 'ensure that different classes have their own class attributes' do
|
76
|
+
assert ex1 = SyncCAttrExample.new
|
77
|
+
assert_equal 'hello world', ex1.class.test1
|
78
|
+
assert ex2 = SyncCAttrExample2.new
|
79
|
+
assert_equal 'another world', ex2.class.test1
|
80
|
+
assert_equal 'hello world', ex1.class.test1
|
81
|
+
|
82
|
+
assert !defined? ex2.class.test2
|
83
|
+
assert !defined? ex2.class.test3
|
84
|
+
assert !defined? ex2.class.test4
|
73
85
|
end
|
74
86
|
end
|
75
87
|
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# Allow examples to be run in-place without requiring a gem install
|
2
|
+
$LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'shoulda'
|
7
|
+
require 'sync_attr'
|
8
|
+
|
9
|
+
class SyncAttrExample
|
10
|
+
include SyncAttr
|
11
|
+
|
12
|
+
sync_attr_reader :test1 do
|
13
|
+
'hello world'
|
14
|
+
end
|
15
|
+
sync_attr_reader :test2
|
16
|
+
sync_attr_accessor :test3
|
17
|
+
sync_attr_accessor :test4 do
|
18
|
+
'hello world 4'
|
19
|
+
end
|
20
|
+
|
21
|
+
sync_attr_accessor :test5
|
22
|
+
end
|
23
|
+
|
24
|
+
# Ensure that class and instance attributes are distinct
|
25
|
+
class SyncAttrExample2
|
26
|
+
include SyncAttr
|
27
|
+
|
28
|
+
sync_attr_reader :test1 do
|
29
|
+
'hello world instance'
|
30
|
+
end
|
31
|
+
sync_cattr_reader :test1 do
|
32
|
+
'hello world class'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class InstanceAttributesTest < Test::Unit::TestCase
|
37
|
+
context "with example" do
|
38
|
+
|
39
|
+
should 'lazy initialize attribute' do
|
40
|
+
assert_equal 'hello world', SyncAttrExample.new.test1
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'return nil on attribute without initializer' do
|
44
|
+
assert_nil SyncAttrExample.new.test2
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'set and then return a value for a class attribute without an initializer' do
|
48
|
+
assert example = SyncAttrExample.new
|
49
|
+
assert_nil example.test3
|
50
|
+
assert_equal 'test3', (example.test3 = 'test3')
|
51
|
+
assert_equal 'test3', example.test3
|
52
|
+
end
|
53
|
+
|
54
|
+
should 'lazy initialize attribute and also have writer' do
|
55
|
+
assert example = SyncAttrExample.new
|
56
|
+
assert_equal 'hello world 4', example.test4
|
57
|
+
assert_equal 'test4', (example.test4 = 'test4')
|
58
|
+
assert_equal 'test4', example.test4
|
59
|
+
end
|
60
|
+
|
61
|
+
should 'support setting a Proc within a synch block' do
|
62
|
+
assert example = SyncAttrExample.new
|
63
|
+
assert_nil example.test5
|
64
|
+
|
65
|
+
# Returns the Proc
|
66
|
+
example.test5 = Proc.new {|val| (val||0) + 1}
|
67
|
+
assert_equal 1, example.test5
|
68
|
+
|
69
|
+
example.test5 = Proc.new {|val| (val||0) + 1}
|
70
|
+
assert_equal 2, example.test5
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context "with example2" do
|
75
|
+
|
76
|
+
should 'have distinct class and instance attributes when they have the same name' do
|
77
|
+
assert s = SyncAttrExample2.new
|
78
|
+
assert_equal 'hello world instance', s.test1
|
79
|
+
assert_equal 'hello world class', s.class.test1
|
80
|
+
end
|
81
|
+
|
82
|
+
should 'ensure that different classes have their own synch instances' do
|
83
|
+
assert ex1 = SyncAttrExample.new
|
84
|
+
assert ex2 = SyncAttrExample2.new
|
85
|
+
assert ex1.class.send(:sync_cattr_sync).object_id != ex2.class.send(:sync_cattr_sync).object_id
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
CHANGED
@@ -1,22 +1,26 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sync_attr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
6
10
|
platform: ruby
|
7
11
|
authors:
|
8
|
-
|
12
|
+
- Reid Morrison
|
9
13
|
autorequire:
|
10
14
|
bindir: bin
|
11
15
|
cert_chain: []
|
12
16
|
|
13
|
-
date: 2012-
|
17
|
+
date: 2012-03-05 00:00:00 -05:00
|
14
18
|
default_executable:
|
15
19
|
dependencies: []
|
16
20
|
|
17
21
|
description: SyncAttr is a mixin to read, write and lazy initialize both class and instance variables in a multi-threaded environment when the attribute could be modified by two threads at the same time, written in Ruby.
|
18
22
|
email:
|
19
|
-
|
23
|
+
- reidmo@gmail.com
|
20
24
|
executables: []
|
21
25
|
|
22
26
|
extensions: []
|
@@ -24,20 +28,17 @@ extensions: []
|
|
24
28
|
extra_rdoc_files: []
|
25
29
|
|
26
30
|
files:
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
- nbproject/private/private.xml
|
39
|
-
- nbproject/private/rake-d.txt
|
40
|
-
- test/class_attributes_test.rb
|
31
|
+
- examples/class_attribute.rb
|
32
|
+
- examples/instance_attribute.rb
|
33
|
+
- lib/sync_attr/class_attributes.rb
|
34
|
+
- lib/sync_attr/instance_attributes.rb
|
35
|
+
- lib/sync_attr/version.rb
|
36
|
+
- lib/sync_attr.rb
|
37
|
+
- LICENSE.txt
|
38
|
+
- Rakefile
|
39
|
+
- README.md
|
40
|
+
- test/class_attributes_test.rb
|
41
|
+
- test/instance_attributes_test.rb
|
41
42
|
has_rdoc: true
|
42
43
|
homepage: https://github.com/ClarityServices/sync_attr
|
43
44
|
licenses: []
|
@@ -46,23 +47,25 @@ post_install_message:
|
|
46
47
|
rdoc_options: []
|
47
48
|
|
48
49
|
require_paths:
|
49
|
-
|
50
|
+
- lib
|
50
51
|
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
52
|
requirements:
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
56
58
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
59
|
requirements:
|
59
|
-
|
60
|
-
|
61
|
-
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
62
65
|
requirements: []
|
63
66
|
|
64
67
|
rubyforge_project:
|
65
|
-
rubygems_version: 1.
|
68
|
+
rubygems_version: 1.3.6
|
66
69
|
signing_key:
|
67
70
|
specification_version: 3
|
68
71
|
summary: Thread safe accessors for Ruby class and instance attributes. Supports thread safe lazy loading of attributes
|
File without changes
|
File without changes
|
@@ -1,10 +0,0 @@
|
|
1
|
-
file.reference.synch_attr-examples=examples
|
2
|
-
file.reference.synch_attr-lib=lib
|
3
|
-
file.reference.synch_attr-test=test
|
4
|
-
javac.classpath=
|
5
|
-
main.file=
|
6
|
-
platform.active=JRuby_0
|
7
|
-
source.encoding=UTF-8
|
8
|
-
src.examples.dir=examples
|
9
|
-
src.lib.dir=lib
|
10
|
-
test.test.dir=test
|
data/nbproject/project.xml
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
-
<project xmlns="http://www.netbeans.org/ns/project/1">
|
3
|
-
<type>org.netbeans.modules.ruby.rubyproject</type>
|
4
|
-
<configuration>
|
5
|
-
<data xmlns="http://www.netbeans.org/ns/ruby-project/1">
|
6
|
-
<name>sync_attr</name>
|
7
|
-
<source-roots>
|
8
|
-
<root id="src.lib.dir" name="Source Files"/>
|
9
|
-
<root id="src.examples.dir" name="Examples"/>
|
10
|
-
</source-roots>
|
11
|
-
<test-roots>
|
12
|
-
<root id="test.test.dir" name="Test Files"/>
|
13
|
-
</test-roots>
|
14
|
-
</data>
|
15
|
-
</configuration>
|
16
|
-
</project>
|