kicker 3.0.0 → 4.0.0.p1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYING +20 -0
- data/README.rdoc +0 -150
- data/bin/kicker +1 -3
- data/lib/kicker.rb +16 -117
- data/lib/kicker/cli.rb +130 -0
- data/lib/kicker/core_ext/array.rb +40 -0
- data/lib/kicker/debug.rb +5 -0
- data/lib/kicker/deprecated.rb +14 -0
- data/lib/kicker/formatter.rb +15 -0
- data/lib/kicker/option_parser.rb +37 -0
- data/lib/kicker/recipe/ignore.rb +2 -0
- data/lib/kicker/recipe/peck.rb +54 -0
- data/lib/kicker/recipe/reload.rb +0 -0
- data/lib/kicker/{recipes → recipe}/ruby.rb +10 -10
- data/lib/kicker/script.rb +77 -0
- data/lib/kicker/version.rb +2 -2
- data/lib/kicker/watcher.rb +113 -0
- metadata +32 -120
- data/LICENSE +0 -54
- data/lib/kicker/callback_chain.rb +0 -95
- data/lib/kicker/core_ext.rb +0 -38
- data/lib/kicker/fsevents.rb +0 -36
- data/lib/kicker/job.rb +0 -57
- data/lib/kicker/notification.rb +0 -31
- data/lib/kicker/options.rb +0 -96
- data/lib/kicker/recipes.rb +0 -98
- data/lib/kicker/recipes/could_not_handle_file.rb +0 -7
- data/lib/kicker/recipes/dot_kick.rb +0 -47
- data/lib/kicker/recipes/execute_cli_command.rb +0 -9
- data/lib/kicker/recipes/ignore.rb +0 -41
- data/lib/kicker/recipes/jstest.rb +0 -10
- data/lib/kicker/recipes/rails.rb +0 -109
- data/lib/kicker/utils.rb +0 -127
data/LICENSE
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
Kicker:
|
2
|
-
|
3
|
-
Copyright (c) 2009 Eloy Duran <eloy.de.enige@gmail.com>
|
4
|
-
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
-
a copy of this software and associated documentation files (the
|
7
|
-
"Software"), to deal in the Software without restriction, including
|
8
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
the following conditions:
|
12
|
-
|
13
|
-
The above copyright notice and this permission notice shall be
|
14
|
-
included in all copies or substantial portions of the Software.
|
15
|
-
|
16
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23
|
-
|
24
|
-
======================================================================
|
25
|
-
|
26
|
-
Rucola: http://github.com/alloy/rucola/tree/master
|
27
|
-
|
28
|
-
Copyright (c) 2008 Eloy Duran <eloy.de.enige@gmail.com>
|
29
|
-
|
30
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
31
|
-
a copy of this software and associated documentation files (the
|
32
|
-
"Software"), to deal in the Software without restriction, including
|
33
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
34
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
35
|
-
permit persons to whom the Software is furnished to do so, subject to
|
36
|
-
the following conditions:
|
37
|
-
|
38
|
-
The above copyright notice and this permission notice shall be
|
39
|
-
included in all copies or substantial portions of the Software.
|
40
|
-
|
41
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
42
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
43
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
44
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
45
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
46
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
47
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
48
|
-
|
49
|
-
======================================================================
|
50
|
-
|
51
|
-
growlnotifier: http://github.com/psychs/growlnotifier/tree/master
|
52
|
-
|
53
|
-
Copyright (c) 2007-2008 Satoshi Nakagawa <psychs@limechat.net>, Eloy Duran <e.duran@superalloy.nl>
|
54
|
-
You can redistribute it and/or modify it under the same terms as Ruby.
|
@@ -1,95 +0,0 @@
|
|
1
|
-
class Kicker
|
2
|
-
class CallbackChain < Array #:nodoc:
|
3
|
-
alias_method :append_callback, :push
|
4
|
-
alias_method :prepend_callback, :unshift
|
5
|
-
|
6
|
-
def call(files, stop_when_empty = true)
|
7
|
-
each do |callback|
|
8
|
-
break if stop_when_empty and files.empty?
|
9
|
-
callback.call(files)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
class << self
|
15
|
-
attr_writer :startup_chain
|
16
|
-
def startup_chain
|
17
|
-
@startup_chain ||= CallbackChain.new
|
18
|
-
end
|
19
|
-
|
20
|
-
attr_writer :pre_process_chain
|
21
|
-
def pre_process_chain
|
22
|
-
@pre_process_chain ||= CallbackChain.new
|
23
|
-
end
|
24
|
-
|
25
|
-
attr_writer :process_chain
|
26
|
-
def process_chain
|
27
|
-
@process_chain ||= CallbackChain.new
|
28
|
-
end
|
29
|
-
|
30
|
-
attr_writer :post_process_chain
|
31
|
-
def post_process_chain
|
32
|
-
@post_process_chain ||= CallbackChain.new
|
33
|
-
end
|
34
|
-
|
35
|
-
attr_writer :full_chain
|
36
|
-
def full_chain
|
37
|
-
@full_chain ||= CallbackChain.new([pre_process_chain, process_chain, post_process_chain])
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def startup_chain
|
42
|
-
self.class.startup_chain
|
43
|
-
end
|
44
|
-
|
45
|
-
def pre_process_chain
|
46
|
-
self.class.pre_process_chain
|
47
|
-
end
|
48
|
-
|
49
|
-
def process_chain
|
50
|
-
self.class.process_chain
|
51
|
-
end
|
52
|
-
|
53
|
-
def post_process_chain
|
54
|
-
self.class.post_process_chain
|
55
|
-
end
|
56
|
-
|
57
|
-
def full_chain
|
58
|
-
self.class.full_chain
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
module Kernel
|
63
|
-
# Adds a handler to the startup chain. This chain is ran once Kicker is done
|
64
|
-
# loading _before_ starting the normal operations. Note that an empty files
|
65
|
-
# array is given to the callback.
|
66
|
-
#
|
67
|
-
# Takes a +callback+ object that responds to <tt>#call</tt>, or a block.
|
68
|
-
def startup(callback = nil, &block)
|
69
|
-
Kicker.startup_chain.append_callback(block ? block : callback)
|
70
|
-
end
|
71
|
-
|
72
|
-
# Adds a handler to the pre_process chain. This chain is ran before the
|
73
|
-
# process chain and is processed from first to last.
|
74
|
-
#
|
75
|
-
# Takes a +callback+ object that responds to <tt>#call</tt>, or a block.
|
76
|
-
def pre_process(callback = nil, &block)
|
77
|
-
Kicker.pre_process_chain.append_callback(block ? block : callback)
|
78
|
-
end
|
79
|
-
|
80
|
-
# Adds a handler to the process chain. This chain is ran in between the
|
81
|
-
# pre_process and post_process chains. It is processed from first to last.
|
82
|
-
#
|
83
|
-
# Takes a +callback+ object that responds to <tt>#call</tt>, or a block.
|
84
|
-
def process(callback = nil, &block)
|
85
|
-
Kicker.process_chain.append_callback(block ? block : callback)
|
86
|
-
end
|
87
|
-
|
88
|
-
# Adds a handler to the post_process chain. This chain is ran after the
|
89
|
-
# process chain and is processed from last to first.
|
90
|
-
#
|
91
|
-
# Takes a +callback+ object that responds to <tt>#call</tt>, or a block.
|
92
|
-
def post_process(callback = nil, &block)
|
93
|
-
Kicker.post_process_chain.prepend_callback(block ? block : callback)
|
94
|
-
end
|
95
|
-
end
|
data/lib/kicker/core_ext.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
class Kicker
|
2
|
-
module ArrayExt
|
3
|
-
# Deletes elements from self for which the block evaluates to +true+. A new
|
4
|
-
# array is returned with those values the block returned. So basically, a
|
5
|
-
# combination of reject! and map.
|
6
|
-
#
|
7
|
-
# a = [1,2,3]
|
8
|
-
# b = a.take_and_map { |x| x * 2 if x == 2 }
|
9
|
-
# b # => [4]
|
10
|
-
# a # => [1, 3]
|
11
|
-
#
|
12
|
-
# If +pattern+ is specified then files matching the pattern will be taken.
|
13
|
-
#
|
14
|
-
# a = [ 'bar', 'foo/bar' ]
|
15
|
-
# b = a.take_and_map('*/bar') { |x| x }
|
16
|
-
# b # => ['foo/bar']
|
17
|
-
# a # => ['bar']
|
18
|
-
#
|
19
|
-
# If +flatten_and_compact+ is +true+, the result array will be flattened
|
20
|
-
# and compacted. The default is +true+.
|
21
|
-
def take_and_map(pattern = nil, flatten_and_compact = true)
|
22
|
-
took = []
|
23
|
-
reject! do |x|
|
24
|
-
next if pattern and !File.fnmatch?(pattern, x)
|
25
|
-
if result = yield(x)
|
26
|
-
took << result
|
27
|
-
end
|
28
|
-
end
|
29
|
-
if flatten_and_compact
|
30
|
-
took.flatten!
|
31
|
-
took.compact!
|
32
|
-
end
|
33
|
-
took
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
Array.send(:include, Kicker::ArrayExt)
|
data/lib/kicker/fsevents.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'listen'
|
4
|
-
|
5
|
-
class Kicker
|
6
|
-
class FSEvents
|
7
|
-
class FSEvent
|
8
|
-
attr_reader :path
|
9
|
-
|
10
|
-
def initialize(path)
|
11
|
-
@path = path
|
12
|
-
end
|
13
|
-
|
14
|
-
def files
|
15
|
-
Dir.glob("#{File.expand_path(path)}/*").map do |filename|
|
16
|
-
begin
|
17
|
-
[File.mtime(filename), filename]
|
18
|
-
rescue Errno::ENOENT
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
end.compact.sort.reverse.map { |_, filename| filename }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.start_watching(paths, options={}, &block)
|
26
|
-
listener = Listen.to(*(paths.dup << options))
|
27
|
-
listener.change do |modified, added, removed|
|
28
|
-
files = modified + added + removed
|
29
|
-
directories = files.map { |file| File.dirname(file) }.uniq
|
30
|
-
yield directories.map { |directory| Kicker::FSEvents::FSEvent.new(directory) }
|
31
|
-
end
|
32
|
-
listener.start
|
33
|
-
listener
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
data/lib/kicker/job.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
class Kicker
|
2
|
-
class Job
|
3
|
-
def self.attr_with_default(name, merge_hash = false, &default)
|
4
|
-
# If `nil` this returns the `default`, unless explicitely set to `nil` by
|
5
|
-
# the user.
|
6
|
-
define_method(name) do
|
7
|
-
if instance_variable_get("@#{name}_assigned")
|
8
|
-
if assigned_value = instance_variable_get("@#{name}")
|
9
|
-
merge_hash ? instance_eval(&default).merge(assigned_value) : assigned_value
|
10
|
-
end
|
11
|
-
else
|
12
|
-
instance_eval(&default)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
define_method("#{name}=") do |value|
|
16
|
-
instance_variable_set("@#{name}_assigned", true)
|
17
|
-
instance_variable_set("@#{name}", value)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
attr_accessor :command, :exit_code, :output
|
22
|
-
|
23
|
-
def initialize(attributes)
|
24
|
-
@exit_code = 0
|
25
|
-
@output = ''
|
26
|
-
attributes.each { |k,v| send("#{k}=", v) }
|
27
|
-
end
|
28
|
-
|
29
|
-
def success?
|
30
|
-
exit_code == 0
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_with_default(:print_before) do
|
34
|
-
"Executing: #{command}"
|
35
|
-
end
|
36
|
-
|
37
|
-
attr_with_default(:print_after) do
|
38
|
-
# Show all output if it wasn't shown before and the command fails.
|
39
|
-
"\n#{output}\n\n" if Kicker.silent? && !success?
|
40
|
-
end
|
41
|
-
|
42
|
-
# TODO default titles??
|
43
|
-
|
44
|
-
attr_with_default(:notify_before, true) do
|
45
|
-
{ :title => "Kicker: Executing", :message => command }
|
46
|
-
end
|
47
|
-
|
48
|
-
attr_with_default(:notify_after, true) do
|
49
|
-
message = Kicker.silent? ? "" : output
|
50
|
-
if success?
|
51
|
-
{ :title => "Kicker: Success", :message => message }
|
52
|
-
else
|
53
|
-
{ :title => "Kicker: Failed (#{exit_code})", :message => message }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/lib/kicker/notification.rb
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'notify'
|
2
|
-
|
3
|
-
class Kicker
|
4
|
-
module Notification #:nodoc:
|
5
|
-
TITLE = 'Kicker'
|
6
|
-
|
7
|
-
class << self
|
8
|
-
attr_accessor :use, :app_bundle_identifier
|
9
|
-
alias_method :use?, :use
|
10
|
-
|
11
|
-
def notify(options)
|
12
|
-
return unless use?
|
13
|
-
|
14
|
-
unless message = options.delete(:message)
|
15
|
-
raise "A notification requires a `:message'"
|
16
|
-
end
|
17
|
-
|
18
|
-
options = {
|
19
|
-
:group => Dir.pwd,
|
20
|
-
:activate => app_bundle_identifier
|
21
|
-
}.merge(options)
|
22
|
-
|
23
|
-
Notify.notify(TITLE, message, options)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Notification.use = ENV['NOTIFY'].to_s != ''
|
29
|
-
Notification.app_bundle_identifier = 'com.apple.Terminal'
|
30
|
-
end
|
31
|
-
|
data/lib/kicker/options.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
require 'optparse'
|
2
|
-
|
3
|
-
class Kicker
|
4
|
-
class << self
|
5
|
-
attr_accessor :latency, :paths, :silent, :quiet, :clear_console
|
6
|
-
|
7
|
-
def silent?
|
8
|
-
@silent
|
9
|
-
end
|
10
|
-
|
11
|
-
def quiet?
|
12
|
-
@quiet
|
13
|
-
end
|
14
|
-
|
15
|
-
def clear_console?
|
16
|
-
@clear_console
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
|
-
def osx?
|
21
|
-
RUBY_PLATFORM.downcase.include?("darwin")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
self.latency = 1
|
26
|
-
self.paths = %w{ . }
|
27
|
-
self.silent = false
|
28
|
-
self.quiet = false
|
29
|
-
self.clear_console = false
|
30
|
-
|
31
|
-
module Options #:nodoc:
|
32
|
-
DONT_SHOW_RECIPES = %w{ could_not_handle_file execute_cli_command dot_kick }
|
33
|
-
|
34
|
-
def self.recipes_for_display
|
35
|
-
Kicker::Recipes.recipe_files.map { |f| File.basename(f, '.rb') } - DONT_SHOW_RECIPES
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.parser
|
39
|
-
@parser ||= OptionParser.new do |opt|
|
40
|
-
opt.banner = "Usage: #{$0} [options] [paths to watch]"
|
41
|
-
opt.separator " "
|
42
|
-
opt.separator " Available recipes: #{recipes_for_display.join(", ")}."
|
43
|
-
opt.separator " "
|
44
|
-
|
45
|
-
opt.on('-v', 'Print the Kicker version') do
|
46
|
-
puts Kicker::VERSION
|
47
|
-
exit
|
48
|
-
end
|
49
|
-
|
50
|
-
opt.on('-s', '--silent', 'Keep output to a minimum.') do |silent|
|
51
|
-
Kicker.silent = true
|
52
|
-
end
|
53
|
-
|
54
|
-
opt.on('-q', '--quiet', "Quiet output. Don't print timestamps when logging.") do |quiet|
|
55
|
-
Kicker.silent = Kicker.quiet = true
|
56
|
-
end
|
57
|
-
|
58
|
-
opt.on('-c', '--clear', "Clear console before each run.") do |clear|
|
59
|
-
Kicker.clear_console = true
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
opt.on('--[no-]notification', 'Whether or not to send user notifications (on Mac OS X). Defaults to enabled.') do |notifications|
|
64
|
-
Notification.use = notifications
|
65
|
-
end
|
66
|
-
|
67
|
-
if Kicker.osx?
|
68
|
-
opt.on('--activate-app [BUNDLE ID]', "The application to activate when a notification is clicked. Defaults to `com.apple.Terminal'.") do |bundle_id|
|
69
|
-
Kicker::Notification.app_bundle_identifier = bundle_id
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
opt.on('-l', '--latency [FLOAT]', "The time to collect file change events before acting on them. Defaults to #{Kicker.latency} second.") do |latency|
|
74
|
-
Kicker.latency = Float(latency)
|
75
|
-
end
|
76
|
-
|
77
|
-
opt.on('-r', '--recipe [NAME]', 'A named recipe to load.') do |name|
|
78
|
-
recipe(name)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.parse(argv)
|
84
|
-
parser.parse!(argv)
|
85
|
-
Kicker.paths = argv unless argv.empty?
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
module Kernel
|
91
|
-
# Returns the global OptionParser instance that recipes can use to add
|
92
|
-
# options.
|
93
|
-
def options
|
94
|
-
Kicker::Options.parser
|
95
|
-
end
|
96
|
-
end
|
data/lib/kicker/recipes.rb
DELETED
@@ -1,98 +0,0 @@
|
|
1
|
-
module Kernel
|
2
|
-
# If only given a <tt>name</tt>, the specified recipe will be loaded. For
|
3
|
-
# instance, the following, in a <tt>.kick</tt> file, will load the Rails
|
4
|
-
# recipe:
|
5
|
-
#
|
6
|
-
# recipe :rails
|
7
|
-
#
|
8
|
-
# However, this same method is used to define a callback that is called _if_
|
9
|
-
# the recipe is loaded. For instance, the following, in a recipe file, will
|
10
|
-
# be called if the recipe is actually used:
|
11
|
-
#
|
12
|
-
# recipe :rails do
|
13
|
-
# # Load anything needed for the recipe.
|
14
|
-
# process do
|
15
|
-
# # ...
|
16
|
-
# end
|
17
|
-
# end
|
18
|
-
def recipe(name, &block)
|
19
|
-
Kicker::Recipes.recipe(name, &block)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Kicker
|
24
|
-
module Recipes #:nodoc:
|
25
|
-
RECIPES_DIR = Pathname.new('../recipes').expand_path(__FILE__)
|
26
|
-
USER_RECIPES_DIR = Pathname.new('~/.kick').expand_path
|
27
|
-
CURRENT_RECIPES_DIR = Pathname.pwd.join('.kick').expand_path
|
28
|
-
|
29
|
-
RECIPES_DIRS = [RECIPES_DIR, USER_RECIPES_DIR, CURRENT_RECIPES_DIR]
|
30
|
-
|
31
|
-
class << self
|
32
|
-
def reset!
|
33
|
-
@recipes = nil
|
34
|
-
# Always load all the base recipes
|
35
|
-
load_recipe :execute_cli_command
|
36
|
-
load_recipe :could_not_handle_file
|
37
|
-
load_recipe :dot_kick
|
38
|
-
end
|
39
|
-
|
40
|
-
def recipes
|
41
|
-
@recipes ||= {}
|
42
|
-
end
|
43
|
-
|
44
|
-
def recipe_filename(name)
|
45
|
-
[
|
46
|
-
USER_RECIPES_DIR,
|
47
|
-
RECIPES_DIR
|
48
|
-
].each do |directory|
|
49
|
-
filename = directory.join("#{name}.rb")
|
50
|
-
return filename if filename.exist?
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def recipe_names
|
55
|
-
recipe_files.map { |filename| filename.basename('.rb').to_s.to_sym }
|
56
|
-
end
|
57
|
-
|
58
|
-
def recipe_files
|
59
|
-
RECIPES_DIRS.map{|dir| Pathname.glob(dir.join('*.rb')) }.flatten.uniq.map(&:expand_path)
|
60
|
-
end
|
61
|
-
|
62
|
-
def define_recipe(name, &block)
|
63
|
-
recipes[name] = block
|
64
|
-
end
|
65
|
-
|
66
|
-
def load_recipe(name)
|
67
|
-
if recipe_names.include?(name)
|
68
|
-
load recipe_filename(name)
|
69
|
-
else
|
70
|
-
raise LoadError, "Can't load recipe `#{name}', it doesn't exist on disk. Loadable recipes are: #{recipe_names[0..-2].join(', ')}, and #{recipe_names[-1]}"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def activate_recipe(name)
|
75
|
-
unless recipes.has_key?(name)
|
76
|
-
load_recipe(name)
|
77
|
-
end
|
78
|
-
if recipe = recipes[name]
|
79
|
-
recipe.call
|
80
|
-
else
|
81
|
-
raise ArgumentError, "Can't activate the recipe `#{name}' because it hasn't been defined yet."
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# See Kernel#recipe for more information about the usage.
|
86
|
-
def recipe(name, &block)
|
87
|
-
name = name.to_sym
|
88
|
-
if block_given?
|
89
|
-
define_recipe(name, &block)
|
90
|
-
else
|
91
|
-
activate_recipe(name)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
reset!
|
97
|
-
end
|
98
|
-
end
|