hooks 0.1

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/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # A sample Gemfile
2
+ source :gemcutter
3
+
4
+ gem "activesupport", "~>2.3"
5
+
6
+ group :test do
7
+ gem "shoulda"
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,12 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (2.3.9)
5
+ shoulda (2.11.3)
6
+
7
+ PLATFORMS
8
+ ruby
9
+
10
+ DEPENDENCIES
11
+ activesupport (~> 2.3)
12
+ shoulda
data/README.rdoc ADDED
@@ -0,0 +1,87 @@
1
+ = Hooks
2
+
3
+ <em>Generic hooks with callbacks for Ruby.</em>
4
+
5
+
6
+ == Introduction
7
+
8
+ Hooks lets you define hooks declaratively in your ruby class. You can add callbacks to your hook, which will be
9
+ run as soon as _you_ run the hook!
10
+
11
+ It's almost like ActiveSupport::Callbacks but 76,6% less complex.
12
+
13
+ Instead, it is not more than 80 lines of code, one method compilation, no +method_missing+ and no magic.
14
+
15
+
16
+ == Example
17
+
18
+ Let's take... a cat.
19
+
20
+ class Cat
21
+ include Hooks
22
+
23
+ define_hook :after_dinner
24
+
25
+ Now you can add callbacks to your hook declaratively in your class.
26
+
27
+ after_dinner do
28
+ puts "Ice cream!"
29
+ end
30
+
31
+ after_dinner :have_a_desert # => refers to Cat#have_a_desert
32
+
33
+
34
+ def have_a_desert
35
+ puts "Hell, yeah!"
36
+ end
37
+
38
+ Running the callbacks happens on instances. It will run the block and +#have_a_desert+ from above.
39
+
40
+ cat.run_hook :after_dinner
41
+ # => Ice cream!
42
+ Hell, yeah!
43
+
44
+
45
+ == Options
46
+
47
+ You're free to pass any number of arguments to #run_callback.
48
+
49
+ cat.run_hook :before_dinner, cat, Time.now
50
+
51
+ The callbacks should be ready for receiving parameters.
52
+
53
+ before_dinner :wash_pawns
54
+ before_dinner do |who, when|
55
+ ...
56
+ end
57
+
58
+ def wash_pawns(who, when)
59
+
60
+
61
+ Not sure why a cat should have ice cream for dinner. Beside that, I was tempted naming this gem _hooker_.
62
+
63
+
64
+ == Installation
65
+
66
+ gem install hooks
67
+
68
+
69
+ == Dependencies
70
+
71
+ The current gem requires
72
+
73
+ * active_support 2.3.x
74
+
75
+
76
+ == Similar libraries
77
+
78
+ * http://github.com/nakajima/aspectory/tree/master/lib/aspectory/
79
+ * http://github.com/auser/backcall
80
+ * http://github.com/mmcgrana/simple_callbacks
81
+
82
+
83
+ == License
84
+
85
+ Copyright (c) 2010, Nick Sutterer
86
+
87
+ Released under the MIT License.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the hooks plugin.'
9
+ Rake::TestTask.new(:test) do |test|
10
+ test.libs << 'test'
11
+ test.test_files = FileList['test/*_test.rb']
12
+ test.verbose = true
13
+ end
14
+
15
+ require 'jeweler'
16
+ $:.unshift File.dirname(__FILE__) # add current dir to LOAD_PATHS
17
+ require 'lib/hooks'
18
+
19
+ Jeweler::Tasks.new do |spec|
20
+ spec.name = "hooks"
21
+ spec.version = ::Hooks::VERSION
22
+ spec.summary = %{Generic hooks with callbacks for Ruby. }
23
+ spec.description = "Declaratively define hooks, add callbacks and run them with the options you like."
24
+ spec.homepage = "http://nicksda.apotomo.de/category/hooks"
25
+ spec.authors = ["Nick Sutterer"]
26
+ spec.email = "apotonick@gmail.com"
27
+
28
+ spec.files = FileList["[A-Z]*", File.join(*%w[{lib} ** *]).to_s]
29
+
30
+ spec.add_dependency 'activesupport', '>= 2.3.0'
31
+ end
32
+
33
+ Jeweler::GemcutterTasks.new
data/lib/hooks.rb ADDED
@@ -0,0 +1,67 @@
1
+ require 'active_support/core_ext/class/inheritable_attributes.rb'
2
+
3
+ # Almost like ActiveSupport::Callbacks but 76,6% less complex.
4
+ #
5
+ # Example:
6
+ #
7
+ # class CatWidget < Apotomo::Widget
8
+ # define_hook :after_dinner
9
+ #
10
+ # Now you can add callbacks to your hook declaratively in your class.
11
+ #
12
+ # after_dinner do puts "Ice cream!" end
13
+ # after_dinner :have_a_desert # => refers to CatWidget#have_a_desert
14
+ #
15
+ # Running the callbacks happens on instances. It will run the block and #have_a_desert from above.
16
+ #
17
+ # cat.run_hook :after_dinner
18
+ module Hooks
19
+ VERSION = "0.1"
20
+
21
+ def self.included(base)
22
+ base.extend ClassMethods
23
+ end
24
+
25
+ module ClassMethods
26
+ def define_hook(name)
27
+ accessor_name = "_#{name}_callbacks"
28
+
29
+ setup_hook_accessors(accessor_name)
30
+ define_hook_writer(name, accessor_name)
31
+ end
32
+
33
+ private
34
+ def define_hook_writer(hook, accessor_name)
35
+ instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
36
+ def #{hook}(method=nil, &block)
37
+ callback = block_given? ? block : method
38
+ #{accessor_name} << callback
39
+ end
40
+ RUBY_EVAL
41
+ end
42
+
43
+ def setup_hook_accessors(accessor_name)
44
+ class_inheritable_array(accessor_name, :instance_writer => false)
45
+ send("#{accessor_name}=", []) # initialize ivar.
46
+ end
47
+
48
+ end
49
+
50
+ # Runs the callbacks (method/block) for the specified hook +name+. Additional arguments will
51
+ # be passed to the callback.
52
+ #
53
+ # Example:
54
+ #
55
+ # cat.run_hook :after_dinner, "i want ice cream!"
56
+ #
57
+ # will invoke the callbacks like
58
+ #
59
+ # desert("i want ice cream!")
60
+ # block.call("i want ice cream!")
61
+ def run_hook(name, *args)
62
+ self.class.send("_#{name}_callbacks").each do |callback|
63
+ send(callback, *args) and next if callback.kind_of? Symbol
64
+ callback.call(*args)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,64 @@
1
+ require 'test_helper'
2
+
3
+ class HooksTest < ActiveSupport::TestCase
4
+ context "Hooks.define_hook" do
5
+ setup do
6
+ @klass = Class.new(Object) do
7
+ include Hooks
8
+
9
+ def executed
10
+ @executed ||= [];
11
+ end
12
+ end
13
+
14
+ @mum = @klass.new
15
+ @mum.class.define_hook :after_eight
16
+ end
17
+
18
+ should "provide accessors to the stored callbacks" do
19
+ assert_equal [], @klass._after_eight_callbacks
20
+ @klass._after_eight_callbacks << :dine
21
+ assert_equal [:dine], @klass._after_eight_callbacks
22
+ end
23
+
24
+ context "creates a public writer for the hook that" do
25
+ should "accepts method names" do
26
+ @klass.after_eight :dine
27
+ assert_equal [:dine], @klass._after_eight_callbacks
28
+ end
29
+
30
+ should "accepts blocks" do
31
+ @klass.after_eight do true; end
32
+ assert @klass._after_eight_callbacks.first.kind_of? Proc
33
+ end
34
+ end
35
+
36
+ context "Hooks.run_hook"do
37
+ should "run without parameters" do
38
+ @mum.instance_eval do
39
+ def a; executed << :a; end
40
+ def b; executed << :b; end
41
+
42
+ self.class.after_eight :b
43
+ self.class.after_eight :a
44
+ end
45
+
46
+ @mum.run_hook(:after_eight)
47
+
48
+ assert_equal [:b, :a], @mum.executed
49
+ end
50
+
51
+ should "accept arbitrary parameters" do
52
+ @mum.instance_eval do
53
+ def a(me, arg); executed << arg+1; end
54
+ end
55
+ @mum.class.after_eight :a
56
+ @mum.class.after_eight lambda { |me, arg| me.executed << arg-1 }
57
+
58
+ @mum.run_hook(:after_eight, @mum, 1)
59
+
60
+ assert_equal [2, 0], @mum.executed
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+
3
+ # wycats says...
4
+ require 'bundler'
5
+ Bundler.setup
6
+ require 'test/unit'
7
+ require 'shoulda'
8
+ require 'active_support/test_case'
9
+ require 'hooks'
10
+
11
+ $:.unshift File.dirname(__FILE__) # add current dir to LOAD_PATHS
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hooks
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ version: "0.1"
9
+ platform: ruby
10
+ authors:
11
+ - Nick Sutterer
12
+ autorequire:
13
+ bindir: bin
14
+ cert_chain: []
15
+
16
+ date: 2010-09-24 00:00:00 +02:00
17
+ default_executable:
18
+ dependencies:
19
+ - !ruby/object:Gem::Dependency
20
+ name: activesupport
21
+ prerelease: false
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 0
31
+ version: 2.3.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ description: Declaratively define hooks, add callbacks and run them with the options you like.
35
+ email: apotonick@gmail.com
36
+ executables: []
37
+
38
+ extensions: []
39
+
40
+ extra_rdoc_files:
41
+ - README.rdoc
42
+ files:
43
+ - Gemfile
44
+ - Gemfile.lock
45
+ - README.rdoc
46
+ - Rakefile
47
+ - lib/hooks.rb
48
+ - test/test_helper.rb
49
+ - test/hooks_test.rb
50
+ has_rdoc: true
51
+ homepage: http://nicksda.apotomo.de/category/hooks
52
+ licenses: []
53
+
54
+ post_install_message:
55
+ rdoc_options:
56
+ - --charset=UTF-8
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ none: false
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.7
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Generic hooks with callbacks for Ruby.
82
+ test_files:
83
+ - test/test_helper.rb
84
+ - test/hooks_test.rb