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