hooker 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/History.rdoc +2 -0
- data/Manifest.txt +10 -0
- data/README.rdoc +81 -0
- data/Rakefile +32 -0
- data/lib/hooker/base.rb +20 -0
- data/lib/hooker.rb +149 -0
- data/test/alt_entry.rb +5 -0
- data/test/config.rb +5 -0
- data/test/setup.rb +24 -0
- data/test/test_hooker.rb +144 -0
- metadata +116 -0
data/History.rdoc
ADDED
data/Manifest.txt
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= Hooker
|
2
|
+
|
3
|
+
* http://github.com/dekellum/hooker
|
4
|
+
|
5
|
+
== Description
|
6
|
+
|
7
|
+
Hooker provides a simple registry of hooks or extension points,
|
8
|
+
enabling decoupled run time configuration in terse but straight ruby
|
9
|
+
syntax.
|
10
|
+
|
11
|
+
Inspiration includes {Emacs Hook
|
12
|
+
Functions}[http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html]
|
13
|
+
(Lisp) and other applications which support configuration
|
14
|
+
files in ruby.
|
15
|
+
|
16
|
+
=== Features
|
17
|
+
|
18
|
+
* Hook Procs may be added by the configuration source in any order.
|
19
|
+
* Hook Procs may be chained and combined via various conventions:
|
20
|
+
Hooker.apply, Hooker.inject, Hooker.merge.
|
21
|
+
* Hook Procs are executed only when applied by the extended
|
22
|
+
application. Thus a single configuration source may include hook
|
23
|
+
Procs that are left unused in certain contexts. This is useful
|
24
|
+
when configuring across several different (contextually loaded)
|
25
|
+
modules from one source.
|
26
|
+
* Optional or implicit scoping of keys, providing a two level
|
27
|
+
Hook [:scope, :key] hierarchy.
|
28
|
+
* Provides an optional logging extension point Hooker.log_with
|
29
|
+
* Can check and list hooks that were not applied, including the call
|
30
|
+
site of where added.
|
31
|
+
|
32
|
+
== Synopsis
|
33
|
+
|
34
|
+
Lets say an application has a 'Job' it would like to support
|
35
|
+
hooks on:
|
36
|
+
|
37
|
+
job = Hooker.apply( :job, Job.new )
|
38
|
+
|
39
|
+
Then the following configuration of the job could optionally be loaded
|
40
|
+
and applied to override Job defaults:
|
41
|
+
|
42
|
+
Hooker.with do |h|
|
43
|
+
h.setup_job do |j|
|
44
|
+
j.workers = 3
|
45
|
+
j.timeout = 10 * 60 #seconds
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
Hooker can be yielded to the config file via an alternative Module
|
50
|
+
name, so as not to scare your mom, or to fully encapsulate its use:
|
51
|
+
|
52
|
+
class Chaplain
|
53
|
+
def self.configure( &block )
|
54
|
+
Hooker.with( :church, &block )
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
Supports the config:
|
59
|
+
|
60
|
+
Chaplain.configure do |c|
|
61
|
+
c.setup_job do |j|
|
62
|
+
j.workers = 3
|
63
|
+
j.timeout = 10 * 60 #seconds
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
== License
|
68
|
+
|
69
|
+
Copyright (c) 2011 David Kellum
|
70
|
+
|
71
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you
|
72
|
+
may not use this file except in compliance with the License. You
|
73
|
+
may obtain a copy of the License at:
|
74
|
+
|
75
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
76
|
+
|
77
|
+
Unless required by applicable law or agreed to in writing, software
|
78
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
79
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
80
|
+
implied. See the License for the specific language governing
|
81
|
+
permissions and limitations under the License.
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
$LOAD_PATH << './lib'
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
gem 'rjack-tarpit', '~> 1.3.0'
|
7
|
+
require 'rjack-tarpit'
|
8
|
+
|
9
|
+
require 'hooker/base'
|
10
|
+
|
11
|
+
t = RJack::TarPit.new( 'hooker', Hooker::VERSION )
|
12
|
+
|
13
|
+
t.specify do |h|
|
14
|
+
h.developer( 'David Kellum', 'dek-oss@gravitext.com' )
|
15
|
+
h.testlib = :minitest
|
16
|
+
h.extra_dev_deps += [ [ 'minitest', '>= 1.7.1', '< 2.1' ] ]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Version/date consistency checks:
|
20
|
+
|
21
|
+
task :check_history_version do
|
22
|
+
t.test_line_match( 'History.rdoc', /^==/, / #{ t.version } / )
|
23
|
+
end
|
24
|
+
task :check_history_date do
|
25
|
+
t.test_line_match( 'History.rdoc', /^==/, /\([0-9\-]+\)$/ )
|
26
|
+
end
|
27
|
+
|
28
|
+
task :gem => [ :check_history_version ]
|
29
|
+
task :tag => [ :check_history_version, :check_history_date ]
|
30
|
+
task :push => [ :check_history_version, :check_history_date ]
|
31
|
+
|
32
|
+
t.define_tasks
|
data/lib/hooker/base.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You may
|
6
|
+
# obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
module Hooker
|
18
|
+
# Hooker version
|
19
|
+
VERSION = '1.0.0'
|
20
|
+
end
|
data/lib/hooker.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You may
|
6
|
+
# obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
require 'hooker/base'
|
18
|
+
|
19
|
+
# A registry of hooks, added and applied for indirect configuration
|
20
|
+
# support.
|
21
|
+
module Hooker
|
22
|
+
|
23
|
+
class << self
|
24
|
+
|
25
|
+
# Yields self under the given scope to block.
|
26
|
+
def with( scp = :default )
|
27
|
+
prior, @scope = @scope, scp
|
28
|
+
yield self
|
29
|
+
ensure
|
30
|
+
@scope = prior
|
31
|
+
end
|
32
|
+
|
33
|
+
# Add hook block by specified hook key. Will only be executed when
|
34
|
+
# apply, inject, or merge is later called with the same key.
|
35
|
+
# Multiple hook blocks for the same key will be called in the
|
36
|
+
# order added.
|
37
|
+
def add( key, clr = nil, &block )
|
38
|
+
applied.delete( sk( key ) )
|
39
|
+
hooks[ sk( key ) ] << [ block, ( clr || caller.first ).to_s ]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Allow method setup_<foo> as alias for add( :foo )
|
43
|
+
def method_missing( method, *args, &block )
|
44
|
+
if method.to_s =~ /^setup_(.*)$/ && args.empty?
|
45
|
+
add( $1.to_sym, caller.first, &block )
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Pass the specified initial value to each previously added Proc
|
52
|
+
# with matching key and returns the mutated value.
|
53
|
+
def apply( key, value )
|
54
|
+
applied << sk( key )
|
55
|
+
hooks[ sk( key ) ].each { |hook| hook[0].call( value ) }
|
56
|
+
value
|
57
|
+
end
|
58
|
+
|
59
|
+
# Inject value (or nil) into the chain of previously added Procs,
|
60
|
+
# which should implement binary operations, returning desired
|
61
|
+
# value. Returns the last value from the last proc.
|
62
|
+
def inject( key, value = nil )
|
63
|
+
applied << sk( key )
|
64
|
+
hooks[ sk( key ) ].inject( value ) { |v, hook| hook[0].call( v ) }
|
65
|
+
end
|
66
|
+
|
67
|
+
# Merge returned values from each added Proc to the initial value
|
68
|
+
# (or empty Hash).
|
69
|
+
def merge( key, value = {} )
|
70
|
+
applied << sk( key )
|
71
|
+
hooks[ sk( key ) ].inject( value ) { |v, hook| v.merge( hook[0].call ) }
|
72
|
+
end
|
73
|
+
|
74
|
+
# Register to yield log messages to the given block.
|
75
|
+
def log_with( &block )
|
76
|
+
@logger = block
|
77
|
+
end
|
78
|
+
|
79
|
+
# Load the specified file via Kernel.load, with a log message if
|
80
|
+
# set.
|
81
|
+
def load_file( file )
|
82
|
+
log "Loading file #{file}."
|
83
|
+
load( file, true ) #wrap in in anonymous module
|
84
|
+
end
|
85
|
+
|
86
|
+
# Register -c/--config flags on given OptionParser to load_file
|
87
|
+
def register_config( opts )
|
88
|
+
opts.on( "-c", "--config FILE", "Load configuration file" ) do |file|
|
89
|
+
load_file( file )
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Log results of check_not_applied, one message per not applied
|
94
|
+
# hook.
|
95
|
+
def log_not_applied
|
96
|
+
check_not_applied do |rkey, calls|
|
97
|
+
k = rkey.map { |s| s.inspect }.compact.join( ', ' )
|
98
|
+
msg = "Hook #{k} was never applied. Added from:\n"
|
99
|
+
calls.each { |cl| msg += " - #{cl}\n" }
|
100
|
+
log msg
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Yields [ [ scope, key ], [ caller, ... ] ] to block for each
|
105
|
+
# hook key added but not applied. Often this suggests a typo or
|
106
|
+
# other mistake by the hook Proc author.
|
107
|
+
def check_not_applied
|
108
|
+
( hooks.keys - applied ).each do |rkey|
|
109
|
+
calls = hooks[ rkey ].map { |blk, clr| clr }
|
110
|
+
yield( rkey, calls )
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
|
116
|
+
# Hash of hook keys to array of procs.
|
117
|
+
def hooks
|
118
|
+
@hooks ||= Hash.new { |h, k| h[k] = [] }
|
119
|
+
end
|
120
|
+
|
121
|
+
# List of hook keys that were applied thus far
|
122
|
+
def applied
|
123
|
+
@applied ||= []
|
124
|
+
end
|
125
|
+
|
126
|
+
# Clears all Hooker state.
|
127
|
+
def clear
|
128
|
+
@hooks = nil
|
129
|
+
@applied = nil
|
130
|
+
@logger = nil
|
131
|
+
end
|
132
|
+
|
133
|
+
def log( msg )
|
134
|
+
@logger.call( msg ) if @logger
|
135
|
+
end
|
136
|
+
|
137
|
+
def sk( key )
|
138
|
+
if key.is_a?( Array ) && ( key.length == 2 )
|
139
|
+
key
|
140
|
+
else
|
141
|
+
[ @scope, key ]
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
@scope = :default
|
148
|
+
|
149
|
+
end
|
data/test/alt_entry.rb
ADDED
data/test/config.rb
ADDED
data/test/setup.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 David Kellum
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
5
|
+
# may not use this file except in compliance with the License. You
|
6
|
+
# may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
13
|
+
# implied. See the License for the specific language governing
|
14
|
+
# permissions and limitations under the License.
|
15
|
+
#++
|
16
|
+
|
17
|
+
#### General test setup: LOAD_PATH, logging, console output ####
|
18
|
+
|
19
|
+
ldir = File.join( File.dirname( __FILE__ ), "..", "lib" )
|
20
|
+
$LOAD_PATH.unshift( ldir ) unless $LOAD_PATH.include?( ldir )
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'minitest/unit'
|
24
|
+
require 'minitest/autorun'
|
data/test/test_hooker.rb
ADDED
@@ -0,0 +1,144 @@
|
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
#.hashdot.profile += jruby-shortlived
|
3
|
+
#--
|
4
|
+
# Copyright (c) 2011 David Kellum
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License"); you
|
7
|
+
# may not use this file except in compliance with the License. You
|
8
|
+
# may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
15
|
+
# implied. See the License for the specific language governing
|
16
|
+
# permissions and limitations under the License.
|
17
|
+
#++
|
18
|
+
|
19
|
+
TESTDIR = File.dirname( __FILE__ )
|
20
|
+
|
21
|
+
require File.join( TESTDIR, "setup" )
|
22
|
+
|
23
|
+
require 'hooker'
|
24
|
+
|
25
|
+
# An alternative entry point from top level
|
26
|
+
class Chaplain
|
27
|
+
def self.configure( &block )
|
28
|
+
Hooker.with( :church, &block )
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class TestContext < MiniTest::Unit::TestCase
|
33
|
+
|
34
|
+
def setup
|
35
|
+
Hooker.log_with { |msg| puts; puts msg }
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
Hooker.send( :clear ) #private
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_not_set
|
43
|
+
assert_nil( Hooker.inject( :test_hook ) )
|
44
|
+
|
45
|
+
assert_equal( :identity, Hooker.inject( :test_hook, :identity ) )
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_no_arg_hook
|
49
|
+
Hooker.add( :test ) { :returned }
|
50
|
+
|
51
|
+
assert_equal( :returned, Hooker.inject( :test ) )
|
52
|
+
assert_equal( :returned, Hooker.inject( :test, :ignored ) )
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_chained_hook
|
56
|
+
Hooker.with do |h|
|
57
|
+
h.add( :test ) { |l| l << :a }
|
58
|
+
h.add( :test ) { |l| l << :b }
|
59
|
+
end
|
60
|
+
|
61
|
+
assert_equal( [ :a, :b ], Hooker.inject( :test, [] ) )
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_setup_method
|
65
|
+
Hooker.setup_test { :returned } # via method_missing
|
66
|
+
assert_equal( :returned, Hooker.inject( :test ) )
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_not_setup_missing
|
70
|
+
assert_raises( NoMethodError ) do
|
71
|
+
Hooker.bogus_method
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_apply
|
76
|
+
Hooker.with do |h|
|
77
|
+
h.add( :test ) { |h| h[ :prop ] = "a" }
|
78
|
+
h.add( :test ) { |h| h[ :prop ] = "b" }
|
79
|
+
end
|
80
|
+
|
81
|
+
h = Hooker.apply( :test, { :prop => "orig" } )
|
82
|
+
|
83
|
+
assert_equal( "b", h[ :prop ] )
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_merge
|
87
|
+
Hooker.add( :test ) { { :a => 1, :b => 2 } }
|
88
|
+
Hooker.add( :test ) { { :c => 3 } }
|
89
|
+
|
90
|
+
h = Hooker.merge( :test,
|
91
|
+
{ :a => 0, :d => 4 } )
|
92
|
+
assert_equal( h, { :a => 1, :b => 2, :c => 3, :d => 4 } )
|
93
|
+
end
|
94
|
+
|
95
|
+
def test_check_not_applied
|
96
|
+
|
97
|
+
Hooker.with( :test_scope ) do |h|
|
98
|
+
h.add( :used ) { :returned }
|
99
|
+
h.add( :not_used ) { flunk "first time" }
|
100
|
+
h.add( :not_used ) { flunk "once more" }
|
101
|
+
end
|
102
|
+
|
103
|
+
assert_equal( :returned,
|
104
|
+
Hooker.inject( [ :test_scope, :used ] ) )
|
105
|
+
|
106
|
+
not_used_keys = []
|
107
|
+
not_used_calls = []
|
108
|
+
Hooker.check_not_applied do |rkey, calls|
|
109
|
+
not_used_keys << rkey
|
110
|
+
not_used_calls += calls
|
111
|
+
end
|
112
|
+
|
113
|
+
assert_equal( [ [ :test_scope, :not_used ] ], not_used_keys )
|
114
|
+
assert_equal( 2, not_used_calls.length )
|
115
|
+
|
116
|
+
Hooker.log_not_applied
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_check_not_applied_if_added_after
|
120
|
+
|
121
|
+
Hooker.with( :test_scope ) do |h|
|
122
|
+
assert_nil( h.inject( :not_used ) )
|
123
|
+
h.add( :not_used ) { :returned }
|
124
|
+
|
125
|
+
not_used_keys = []
|
126
|
+
not_used_keys = Hooker.check_not_applied do |rkey, calls|
|
127
|
+
not_used_keys << rkey
|
128
|
+
end
|
129
|
+
assert_equal( [ [:test_scope, :not_used] ], not_used_keys )
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_load
|
135
|
+
Hooker.load_file( File.join( TESTDIR, 'config.rb' ) )
|
136
|
+
assert_equal( :returned, Hooker.inject( :test ) )
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_load_with_alt_entry
|
140
|
+
Hooker.load_file( File.join( TESTDIR, 'alt_entry.rb' ) )
|
141
|
+
assert_equal( :returned, Hooker.inject( [ :church, :test ] ) )
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: hooker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
version: 1.0.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- David Kellum
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2011-02-06 00:00:00 -08:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: minitest
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 7
|
30
|
+
- 1
|
31
|
+
version: 1.7.1
|
32
|
+
- - <
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
segments:
|
35
|
+
- 2
|
36
|
+
- 1
|
37
|
+
version: "2.1"
|
38
|
+
type: :development
|
39
|
+
version_requirements: *id001
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: rjack-tarpit
|
42
|
+
prerelease: false
|
43
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
segments:
|
48
|
+
- 1
|
49
|
+
- 3
|
50
|
+
- 0
|
51
|
+
version: 1.3.0
|
52
|
+
type: :development
|
53
|
+
version_requirements: *id002
|
54
|
+
description: |-
|
55
|
+
Hooker provides a simple registry of hooks or extension points,
|
56
|
+
enabling decoupled run time configuration in terse but straight ruby
|
57
|
+
syntax.
|
58
|
+
|
59
|
+
Inspiration includes {Emacs Hook
|
60
|
+
Functions}[http://www.gnu.org/software/emacs/manual/html_node/emacs/Hooks.html]
|
61
|
+
(Lisp) and other applications which support configuration
|
62
|
+
files in ruby.
|
63
|
+
email:
|
64
|
+
- dek-oss@gravitext.com
|
65
|
+
executables: []
|
66
|
+
|
67
|
+
extensions: []
|
68
|
+
|
69
|
+
extra_rdoc_files:
|
70
|
+
- Manifest.txt
|
71
|
+
- History.rdoc
|
72
|
+
- README.rdoc
|
73
|
+
files:
|
74
|
+
- History.rdoc
|
75
|
+
- Manifest.txt
|
76
|
+
- README.rdoc
|
77
|
+
- Rakefile
|
78
|
+
- lib/hooker/base.rb
|
79
|
+
- lib/hooker.rb
|
80
|
+
- test/alt_entry.rb
|
81
|
+
- test/config.rb
|
82
|
+
- test/setup.rb
|
83
|
+
- test/test_hooker.rb
|
84
|
+
has_rdoc: true
|
85
|
+
homepage: http://github.com/dekellum/hooker
|
86
|
+
licenses: []
|
87
|
+
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options:
|
90
|
+
- --main
|
91
|
+
- README.rdoc
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
segments:
|
99
|
+
- 0
|
100
|
+
version: "0"
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: hooker
|
111
|
+
rubygems_version: 1.3.6
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Hooker provides a simple registry of hooks or extension points, enabling decoupled run time configuration in terse but straight ruby syntax
|
115
|
+
test_files:
|
116
|
+
- test/test_hooker.rb
|