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.
@@ -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
+