attr_callback 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -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.
@@ -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
@@ -0,0 +1,3 @@
1
+ module AttrCallback
2
+ VERSION='1.0.0'
3
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../lib")
@@ -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
+