attr_callback 1.0.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/MIT-LICENSE +20 -0
- data/README.rdoc +42 -0
- data/Rakefile +26 -0
- data/lib/attr_callback.rb +80 -0
- data/lib/attr_callback/version.rb +3 -0
- data/test/test_helper.rb +3 -0
- data/test/unit/attr_callback_test.rb +84 -0
- metadata +79 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Infonium Inc.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
= attr_callback - Convenience method for providing user-definable callbacks.
|
2
|
+
|
3
|
+
The attr_callback gem lets you conveniently create user-definable callback
|
4
|
+
method attributes, using a single line of code.
|
5
|
+
|
6
|
+
= Example Usage
|
7
|
+
|
8
|
+
You can use attr_callback to define a callback attribute on an object:
|
9
|
+
|
10
|
+
require 'attr_callback'
|
11
|
+
|
12
|
+
class Foo
|
13
|
+
attr_callback :on_receive_message
|
14
|
+
end
|
15
|
+
|
16
|
+
f = Foo.new
|
17
|
+
|
18
|
+
# Getter and setter behave the same as they would using attr_attribute
|
19
|
+
f.on_receive_message = 1 #=> 1
|
20
|
+
f.on_receive_message #=> 1
|
21
|
+
|
22
|
+
# Passing a block to the getter makes it behave as a setter
|
23
|
+
f.on_receive_message { |msg| puts msg } #=> #<Proc:0x0006bfd0@(irb):1>
|
24
|
+
f.on_receive_message #=> #<Proc:0x0006bfd0@(irb):1>
|
25
|
+
|
26
|
+
# Invoking the callback
|
27
|
+
f.on_receive_message.call("hello world")
|
28
|
+
|
29
|
+
= Options
|
30
|
+
|
31
|
+
By default, a Mutex object will be used to guard access to the callback. This
|
32
|
+
Mutex is created the first time the attribute is accessed. Use :lock=>false to
|
33
|
+
disable this behaviour.
|
34
|
+
|
35
|
+
By default, a no-op Proc is returned by the getter in place of nil. Use
|
36
|
+
:noop=>false to disable this behaviour.
|
37
|
+
|
38
|
+
= License
|
39
|
+
|
40
|
+
Copyright © 2010 Infonium Inc.
|
41
|
+
|
42
|
+
License: See the MIT-LICENSE file.
|
data/Rakefile
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift "lib"
|
3
|
+
require 'attr_callback/version'
|
4
|
+
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
Rake::RDocTask.new do |t|
|
7
|
+
t.rdoc_files = Dir.glob(%w( README* MIT-LICENSE lib/**/*.rb *.rdoc )).uniq
|
8
|
+
t.main = "README.rdoc"
|
9
|
+
t.title = "attr_callback - RDoc Documentation"
|
10
|
+
t.options = %w( --charset -UTF-8 --line-numbers )
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'rake/testtask'
|
14
|
+
Rake::TestTask.new(:test) do |t|
|
15
|
+
t.pattern = 'test/**/*_test.rb'
|
16
|
+
end
|
17
|
+
|
18
|
+
task :build do
|
19
|
+
system "gem build attr_callback.gemspec"
|
20
|
+
end
|
21
|
+
|
22
|
+
task :clobber do
|
23
|
+
rm_f "attr_callback-#{AttrCallback::VERSION}.gem"
|
24
|
+
end
|
25
|
+
|
26
|
+
task :default => :build
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module AttrCallback
|
2
|
+
def self.included(base)
|
3
|
+
base.extend(ClassMethods)
|
4
|
+
end
|
5
|
+
|
6
|
+
module Util
|
7
|
+
NoopProc = Proc.new{}
|
8
|
+
|
9
|
+
class <<self
|
10
|
+
def get_or_create_mutex(obj, name)
|
11
|
+
mutex = obj.instance_variable_get("@#{name}_lock")
|
12
|
+
if mutex.nil?
|
13
|
+
obj.instance_variable_set("@#{name}_lock", Mutex.new)
|
14
|
+
else
|
15
|
+
mutex
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def define_callback_on_class(klass, name, options={})
|
20
|
+
name = name.to_sym
|
21
|
+
locking = options[:lock].nil? ? true : options[:lock]
|
22
|
+
noop = options[:noop].nil? ? true : options[:noop]
|
23
|
+
|
24
|
+
# Define the setter. If the user specified :lock=>true, then the
|
25
|
+
# setter will synchronize on @name_lock; otherwise, we just use
|
26
|
+
# the standard attr_writer.
|
27
|
+
if locking
|
28
|
+
klass.__send__(:define_method, "#{name}=") do |value|
|
29
|
+
AttrCallback::Util.get_or_create_mutex(self, name).synchronize {
|
30
|
+
instance_variable_set("@#{name}", value)
|
31
|
+
}
|
32
|
+
end
|
33
|
+
else
|
34
|
+
klass.__send__(:attr_writer, name)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Define the getter. If the user specified :lock=>true, then the
|
38
|
+
# getter will synchronize on @name_lock; otherwise, it won't.
|
39
|
+
klass.__send__(:define_method, name) do |*args, &block|
|
40
|
+
raise ArgumentError, "wrong number of arguments (#{args.length} for 0)" unless args.empty?
|
41
|
+
|
42
|
+
if block.nil?
|
43
|
+
if locking
|
44
|
+
callback = AttrCallback::Util.get_or_create_mutex(self, name).synchronize { instance_variable_get("@#{name}") }
|
45
|
+
else
|
46
|
+
callback = instance_variable_get("@#{name}")
|
47
|
+
end
|
48
|
+
if noop and callback.nil?
|
49
|
+
NoopProc
|
50
|
+
else
|
51
|
+
callback
|
52
|
+
end
|
53
|
+
else
|
54
|
+
__send__("#{name}=", block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
module ClassMethods
|
62
|
+
def attr_callback(*args)
|
63
|
+
# Last argument may be a hash of options.
|
64
|
+
if args[-1].is_a?(Hash)
|
65
|
+
options = args.pop
|
66
|
+
else
|
67
|
+
options = {}
|
68
|
+
end
|
69
|
+
|
70
|
+
for name in args
|
71
|
+
AttrCallback::Util.define_callback_on_class(self, name, options)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
class Module
|
79
|
+
include AttrCallback::ClassMethods # Make attr_callback available in every module.
|
80
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../test_helper.rb"
|
2
|
+
require 'attr_callback'
|
3
|
+
|
4
|
+
class AttrCallbackTest < Test::Unit::TestCase
|
5
|
+
def test_simple
|
6
|
+
klass = Class.new do
|
7
|
+
attr_callback :cb
|
8
|
+
end
|
9
|
+
obj = klass.new
|
10
|
+
assert_equal AttrCallback::Util::NoopProc, obj.cb, "initial callback should be NoopProc"
|
11
|
+
assert_kind_of Mutex, obj.instance_variable_get("@cb_lock"), "lock should be created when :lock option is unspecified"
|
12
|
+
|
13
|
+
obj.cb = 1
|
14
|
+
assert_equal 1, obj.cb, "setter should work"
|
15
|
+
|
16
|
+
block = Proc.new{ nil }
|
17
|
+
obj.cb(&block)
|
18
|
+
assert_equal block, obj.cb, "block setter should work"
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_simple_without_locking
|
22
|
+
klass = Class.new do
|
23
|
+
attr_callback :cb, :lock=>false
|
24
|
+
end
|
25
|
+
obj = klass.new
|
26
|
+
assert_equal AttrCallback::Util::NoopProc, obj.cb, "initial callback should be NoopProc"
|
27
|
+
assert_nil obj.instance_variable_get("@cb_lock"), "lock should not be created when :lock=>false"
|
28
|
+
|
29
|
+
obj.cb = 1
|
30
|
+
assert_equal 1, obj.cb, "setter should work"
|
31
|
+
|
32
|
+
block = Proc.new{ nil }
|
33
|
+
obj.cb(&block)
|
34
|
+
assert_equal block, obj.cb, "block setter should work"
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_multiple_callbacks_should_be_independent
|
38
|
+
klass = Class.new do
|
39
|
+
attr_callback :a, :b
|
40
|
+
attr_callback :c, :d
|
41
|
+
end
|
42
|
+
obj = klass.new
|
43
|
+
|
44
|
+
obj.a = 1
|
45
|
+
obj.b = 2
|
46
|
+
obj.c = 3
|
47
|
+
obj.d = 4
|
48
|
+
|
49
|
+
assert_equal [1, 2, 3, 4], [obj.a, obj.b, obj.c, obj.d]
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_multiple_callbacks_should_be_independent_without_locking
|
53
|
+
klass = Class.new do
|
54
|
+
attr_callback :a, :b, :lock=>false
|
55
|
+
attr_callback :c, :d, :lock=>false
|
56
|
+
end
|
57
|
+
obj = klass.new
|
58
|
+
|
59
|
+
obj.a = 1
|
60
|
+
obj.b = 2
|
61
|
+
obj.c = 3
|
62
|
+
obj.d = 4
|
63
|
+
|
64
|
+
assert_equal [1, 2, 3, 4], [obj.a, obj.b, obj.c, obj.d]
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_no_noop
|
68
|
+
klass = Class.new do
|
69
|
+
attr_callback :cb, :noop=>false
|
70
|
+
end
|
71
|
+
obj = klass.new
|
72
|
+
assert_nil obj.cb
|
73
|
+
assert_kind_of Mutex, obj.instance_variable_get("@cb_lock"), "lock should be created when :lock option is unspecified"
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_no_noop_without_locking
|
77
|
+
klass = Class.new do
|
78
|
+
attr_callback :cb, :noop=>false, :lock=>false
|
79
|
+
end
|
80
|
+
obj = klass.new
|
81
|
+
assert_nil obj.cb
|
82
|
+
assert_nil obj.instance_variable_get("@cb_lock"), "lock should not be created when :lock=>false"
|
83
|
+
end
|
84
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attr_callback
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dwayne Litzenberger
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-10-19 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: |
|
23
|
+
The attr_callback gem lets you create user-definable callback method attributes
|
24
|
+
conveniently.
|
25
|
+
|
26
|
+
email:
|
27
|
+
- dlitz@infonium.ca
|
28
|
+
executables: []
|
29
|
+
|
30
|
+
extensions: []
|
31
|
+
|
32
|
+
extra_rdoc_files:
|
33
|
+
- README.rdoc
|
34
|
+
files:
|
35
|
+
- lib/attr_callback/version.rb
|
36
|
+
- lib/attr_callback.rb
|
37
|
+
- test/test_helper.rb
|
38
|
+
- test/unit/attr_callback_test.rb
|
39
|
+
- MIT-LICENSE
|
40
|
+
- README.rdoc
|
41
|
+
- Rakefile
|
42
|
+
has_rdoc: true
|
43
|
+
homepage: http://github.com/rubinaut/attr_callback
|
44
|
+
licenses: []
|
45
|
+
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
hash: 23
|
66
|
+
segments:
|
67
|
+
- 1
|
68
|
+
- 3
|
69
|
+
- 6
|
70
|
+
version: 1.3.6
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.3.7
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: Convenience method for providing user-definable callbacks.
|
78
|
+
test_files: []
|
79
|
+
|