[
  {
    "path": ".gitignore",
    "content": ".*.sw?\n*.gem\n/.rbenv-version\n.DS_Store\n/coverage\n/rdoc\n/pkg\n/html\n/Gemfile.lock\n/tmp/\n/.idea\n"
  },
  {
    "path": ".kick",
    "content": "recipe :ignore\nrecipe :ruby\n\nKicker::Recipes::Ruby.runner_bin = 'bacon'\n\nprocess do |files|\n  test_files = files.take_and_map do |file|\n    case file\n    when %r{^lib/kicker(\\.rb|/validate\\.rb|/growl\\.rb)$}\n      [\"spec/initialization_spec.rb\", (\"spec/filesystem_change_spec.rb\" if $1 == '.rb')]\n    when %r{^lib/kicker/(.+)\\.rb$}\n      \"spec/#{$1}_spec.rb\"\n    end\n  end\n  \n  Kicker::Recipes::Ruby.run_tests test_files\nend\n\nprocess do |files|\n  execute(\"rake docs:generate && open -a Safari html/index.html\") if files.delete(\"README.rdoc\")\nend\n\nstartup do\n  log \"Good choice mate!\"\nend\n\n# process do\n#   execute \"ls -l\" do |status|\n#     if status.before?\n#       status.stdout? ? \"Here we go!: #{status.command}\" : \"Here we go! GROWL\"\n#     elsif status.after?\n#       if status.success?\n#         status.stdout? ? \"Nice!\\n\\n#{status.output}\" : \"Nice!\"\n#       else\n#         status.stdout? ? \"Damn brow!\\n\\n#{status.output}\" : \"Damn bro!\"\n#       end\n#     end\n#   end\n# end\n"
  },
  {
    "path": ".travis.yml",
    "content": "rvm:\n  - 2.1.3\n  - 2.0.0\n  - 1.9.3\n\nscript: \"rake\"\n"
  },
  {
    "path": "Gemfile",
    "content": "source \"https://rubygems.org\"\ngemspec\n\ngem 'rake'\n\nplatforms :mri_18 do\n  gem 'rdoc'\nend\n"
  },
  {
    "path": "LICENSE",
    "content": "Kicker:\n\nCopyright (c) 2009 Eloy Duran <eloy.de.enige@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n======================================================================\n\nRucola: http://github.com/alloy/rucola/tree/master\n\nCopyright (c) 2008 Eloy Duran <eloy.de.enige@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n======================================================================\n\ngrowlnotifier: http://github.com/psychs/growlnotifier/tree/master\n\nCopyright (c) 2007-2008 Satoshi Nakagawa <psychs@limechat.net>, Eloy Duran <e.duran@superalloy.nl>\nYou can redistribute it and/or modify it under the same terms as Ruby."
  },
  {
    "path": "README.rdoc",
    "content": "= Kicker\n\n{<img src=\"https://travis-ci.org/alloy/kicker.svg?branch=master\" alt=\"Build Status\" />}[https://travis-ci.org/alloy/kicker]\n\nA lean, agnostic, flexible file-change watcher.\n\n== Installation\n\n  $ gem install kicker -s http://gemcutter.org\n\n== The short version\n\n  Usage: ./bin/kicker [options] [paths to watch]\n\n    Available recipes: ignore, jstest, rails, ruby.\n\n      -s, --silent                     Keep output to a minimum.\n      -q, --quiet                      Quiet output. Don't print timestamps when logging.\n      -c, --clear                      Clear console before each run.\n      -l, --latency [FLOAT]            The time to collect file change events before acting on them. Defaults to 1 second.\n      -r, --recipe [NAME]              A named recipe to load.\n      -e, --execute [COMMAND]          The command to execute.\n      -b, --ruby [PATH]                Use an alternate Ruby binary for spawned test runners. (Default is `ruby')\n\n\n== The long version\n\n=== Execute a shell command\n\nShow all files, whenever a change occurs in the current work directory:\n\n  $ kicker -e \"ls -l\" .\n\nShow all files, whenever a change occurs to a specific file:\n\n  $ kicker -e \"ls -l\" foo.txt\n\nOr use it as a ghetto-autotest, running tests whenever files change:\n\n  $ kicker -e \"ruby test/test_case.rb\" test/test_case.rb lib/file.rb\n\nEt cetera.\n\n=== Using recipes\n\nA recipe is a predefined handler. You can use as many as you like, by\nspecifying them with the <tt>--recipe</tt> (<tt>-r</tt>) option.\n\nFor instance, when in the root of a typical Ruby on Rails application, using\nthe <tt>rails</tt> recipe will map models, concerns, controllers, helpers, and\nviews to their respective test files. These will then all be ran with Ruby.\n\nA few recipes come shipped with Kicker:\n* Typical Ruby library.\n* Ruby on Rails, as aforementioned.\n* JavaScript tests, to run it needs\n  HeadlessSquirrel[http://github.com/Fingertips/Headless-squirrel].\n* Ignore, ignores logs, tmp, and svn and git files.\n\nAdd your own shared recipes to <tt>~/.kick</tt> folder or\ncurrent working directory <tt>.kick</tt>.\n\n=== Project specific handlers\n\nMost of the time, you’ll want to create handlers specific to the project at\nhand. This can be done by adding your handlers to a <tt>.kick</tt> file and\nrunning Kicker from the directory containing it.\n\nThis file is reloaded once saved. No need to stop Kicker.\n\n== Writing handlers\n\nWhenever file-change events occur, Kicker will go through a chain of handlers\nuntil that the files list is empty, or the end of the chain is reached.\n\nHandlers are objects that respond to <tt>#call</tt>. These are typically Proc\nobjects. (If you know Rack, you’re familiar with this concept.) Every handler\ngets passed a list of changed files and can decide whether or not to act on\nthem. Normally when handling a file, you should remove it from the files list,\nunless you want to let the file fall through to another handler. In the same\nway, one can add files to handler to the files list.\n\n==== Time for a simple example\n\n  process do |files|\n    execute(\"rake docs:generate && open -a Safari html/index.html\") if files.delete(\"README.rdoc\")\n  end\n\nA handler is defined by passing a block to <tt>process</tt>. Which is one of\nthree possible callback chains to add your handlers to, the others being:\n<tt>pre_process</tt> and <tt>post_process</tt>. See Kernel for more info.\n\nThen <tt>README.rdoc</tt> is deleted from the files array. If it did exist in\nthe array and was deleted, a shell command is executed which runs a rake task\nto generate rdoc and open the docs with Safari.\n\n==== Something more elaborate.\n\nConsider a Rails application with a mailer. Since the naming convention of\nmailer views tend to be fairly application specific, a specific handler has to\nbe added:\n\n  process do |files|\n    test_files = files.take_and_map do |file|\n      if path =~ %r{^app/views/mailer/\\w+\\.erb$}\n        'test/unit/mailer_test.rb'\n\n      # elsif ... handle more app specific stuff\n      end\n    end\n\n    Ruby.run_tests test_files\n  end\n\nThe files list is iterated over with the Array#take_and_map method, which both\nremoves and maps the results. This is an easy way to do a common thing in\nrecipes. See Kicker::ArrayExt for details.\n\nThe handler then checks if the file is a mailer view and if so runs the\nmailers test case. Ruby.run_tests runs them with something like the following\ncommand:\n\n  execute \"ruby -r #{test_files.join(' -r ')} -e ''\" unless test_files.empty?\n\nSee Kernel for more info on the utility methods.\n\nTo load recipes from your <tt>~/.kick</tt> file:\n\n  recipe :ignore\n  ignore(/^data\\//)\n\nThat’s basically it, just remember that the order of specifying handlers _can_\nbe important in your decision on where to specify handlers.\n\n== Notifiers\n\nFor platform specific notifications we use the notify gem. For supported\nbackends see: https://github.com/jugyo/notify#feature.\n\nYou select the notify backend by setting the NOTIFY environment variable.\n\n  gem install terminal-notifier\n  env NOTIFY=terminal-notifier kicker\n\n== Contributors\n\n* Manfred Stienstra (@manfred)\n* Cristi Balan (@evilchelu)\n* Damir Zekic (@sidonath)\n* Adam Keys (@therealadam)\n"
  },
  {
    "path": "Rakefile",
    "content": "require 'rdoc/task'\n\ndesc \"Run specs\"\ntask :spec do\n  # shuffle to ensure that tests are run in different order\n  files = FileList['spec/**/*_spec.rb'].shuffle\n  sh \"bundle exec bacon #{files.map { |file| \"'#{file}'\" }.join(' ')}\"\nend\n\nnamespace :docs do\n  RDoc::Task.new('generate') do |t|\n    t.main = \"README.rdoc\"\n    t.rdoc_files.include(\"README.rdoc\", \"lib/**/*.rb\")\n    t.options << '--charset=utf8'\n  end\nend\n\ntask :docs => 'docs:generate' do\n  FileUtils.cp_r('images', 'html')\nend\n\ntask :default => :spec\n"
  },
  {
    "path": "TODO.rdoc",
    "content": "* Move larger parts of README to the GitHub wiki so the README is to the point.\n* Add a recipe which implements the basic autotest mapping API.\n* Make the loggers, stdout and growl, work in a chain so one can add others.\n  This should improve portability as well, as people can easily insert growl\n  alternatives for their platform."
  },
  {
    "path": "bin/kicker",
    "content": "#!/usr/bin/env ruby\n\nif $0 == __FILE__\n  $:.unshift File.expand_path('../../lib', __FILE__)\n  $:.unshift File.expand_path('../../vendor', __FILE__)\n  require 'rubygems'\nend\n\nrequire 'kicker'\nKicker.run\n"
  },
  {
    "path": "kicker.gemspec",
    "content": "# -*- encoding: utf-8 -*-\n\n$:.unshift File.expand_path('../lib', __FILE__)\nrequire 'kicker/version'\nrequire 'date'\n\nGem::Specification.new do |s|\n  s.name     = \"kicker\"\n  s.version  = Kicker::VERSION\n  s.date     = Time.new\n  s.license  = 'MIT'\n\n  s.summary  = \"A lean, agnostic, flexible file-change watcher.\"\n  s.description = \"Allows you to fire specific command on file-system change.\"\n  s.authors  = [\"Eloy Duran\", \"Manfred Stienstra\"]\n  s.homepage = \"http://github.com/alloy/kicker\"\n  s.email    = %w{ eloy.de.enige@gmail.com manfred@fngtps.com }\n\n  s.executables      = %w{ kicker }\n  s.require_paths    = %w{ lib vendor }\n  s.files            = Dir['bin/kicker',\n                           'lib/**/*.rb',\n                           'README.rdoc',\n                           'LICENSE',\n                           'html/images/kikker.jpg']\n  s.extra_rdoc_files = %w{ LICENSE README.rdoc }\n\n  s.add_runtime_dependency(\"listen\", '~> 2.7.9')\n  s.add_runtime_dependency(\"notify\", '~> 0.5.2')\n\n  s.add_development_dependency(\"bacon\")\n  s.add_development_dependency(\"mocha-on-bacon\")\n  s.add_development_dependency(\"activesupport\")\n  s.add_development_dependency(\"fakefs\", '>= 0.5')\nend\n\n"
  },
  {
    "path": "lib/kicker/callback_chain.rb",
    "content": "class Kicker\n  class CallbackChain < Array #:nodoc:\n    alias_method :append_callback,  :push\n    alias_method :prepend_callback, :unshift\n\n    def call(files, stop_when_empty = true)\n      each do |callback|\n        break if stop_when_empty and files.empty?\n        callback.call(files)\n      end\n    end\n  end\n\n  class << self\n    attr_writer :startup_chain\n    def startup_chain\n      @startup_chain ||= CallbackChain.new\n    end\n\n    attr_writer :pre_process_chain\n    def pre_process_chain\n      @pre_process_chain ||= CallbackChain.new\n    end\n\n    attr_writer :process_chain\n    def process_chain\n      @process_chain ||= CallbackChain.new\n    end\n\n    attr_writer :post_process_chain\n    def post_process_chain\n      @post_process_chain ||= CallbackChain.new\n    end\n\n    attr_writer :full_chain\n    def full_chain\n      @full_chain ||= CallbackChain.new([pre_process_chain, process_chain, post_process_chain])\n    end\n  end\n\n  def startup_chain\n    self.class.startup_chain\n  end\n\n  def pre_process_chain\n    self.class.pre_process_chain\n  end\n\n  def process_chain\n    self.class.process_chain\n  end\n\n  def post_process_chain\n    self.class.post_process_chain\n  end\n\n  def full_chain\n    self.class.full_chain\n  end\nend\n\nmodule Kernel\n  # Adds a handler to the startup chain. This chain is ran once Kicker is done\n  # loading _before_ starting the normal operations. Note that an empty files\n  # array is given to the callback.\n  #\n  # Takes a +callback+ object that responds to <tt>#call</tt>, or a block.\n  def startup(callback = nil, &block)\n    Kicker.startup_chain.append_callback(block ? block : callback)\n  end\n\n  # Adds a handler to the pre_process chain. This chain is ran before the\n  # process chain and is processed from first to last.\n  #\n  # Takes a +callback+ object that responds to <tt>#call</tt>, or a block.\n  def pre_process(callback = nil, &block)\n    Kicker.pre_process_chain.append_callback(block ? block : callback)\n  end\n\n  # Adds a handler to the process chain. This chain is ran in between the\n  # pre_process and post_process chains. It is processed from first to last.\n  #\n  # Takes a +callback+ object that responds to <tt>#call</tt>, or a block.\n  def process(callback = nil, &block)\n    Kicker.process_chain.append_callback(block ? block : callback)\n  end\n\n  # Adds a handler to the post_process chain. This chain is ran after the\n  # process chain and is processed from last to first.\n  #\n  # Takes a +callback+ object that responds to <tt>#call</tt>, or a block.\n  def post_process(callback = nil, &block)\n    Kicker.post_process_chain.prepend_callback(block ? block : callback)\n  end\nend\n"
  },
  {
    "path": "lib/kicker/core_ext.rb",
    "content": "class Kicker\n  module ArrayExt\n    # Deletes elements from self for which the block evaluates to +true+. A new\n    # array is returned with those values the block returned. So basically, a\n    # combination of reject! and map.\n    #\n    #   a = [1,2,3]\n    #   b = a.take_and_map { |x| x * 2 if x == 2 }\n    #   b # => [4]\n    #   a # => [1, 3]\n    #\n    # If +pattern+ is specified then files matching the pattern will be taken.\n    #\n    #   a = [ 'bar', 'foo/bar' ]\n    #   b = a.take_and_map('*/bar') { |x| x }\n    #   b # => ['foo/bar']\n    #   a # => ['bar']\n    #\n    # If +flatten_and_compact+ is +true+, the result array will be flattened\n    # and compacted. The default is +true+.\n    def take_and_map(pattern = nil, flatten_and_compact = true)\n      took = []\n      reject! do |x|\n        next if pattern and !File.fnmatch?(pattern, x)\n        if result = yield(x)\n          took << result\n        end\n      end\n      if flatten_and_compact\n        took.flatten!\n        took.compact!\n      end\n      took\n    end\n  end\nend\n\nArray.send(:include, Kicker::ArrayExt)\n"
  },
  {
    "path": "lib/kicker/fsevents.rb",
    "content": "# encoding: utf-8\n\nrequire 'listen'\n\nclass Kicker\n  class FSEvents\n    class FSEvent\n      attr_reader :path\n\n      def initialize(path)\n        @path = path\n      end\n\n      def files\n        Dir.glob(\"#{File.expand_path(path)}/*\").map do |filename|\n          begin\n            [File.mtime(filename), filename]\n          rescue Errno::ENOENT\n            nil\n          end\n        end.compact.sort.reverse.map { |_, filename| filename }\n      end\n    end\n\n    def self.start_watching(paths, options={}, &block)\n      listener = Listen.to(*(paths.dup << options)) do |modified, added, removed|\n        files = modified + added + removed\n        directories = files.map { |file| File.dirname(file) }.uniq\n        yield directories.map { |directory| Kicker::FSEvents::FSEvent.new(directory) }\n      end\n      listener.start\n      listener\n    end\n  end\nend\n"
  },
  {
    "path": "lib/kicker/job.rb",
    "content": "class Kicker\n  class Job\n    def self.attr_with_default(name, merge_hash = false, &default)\n      # If `nil` this returns the `default`, unless explicitely set to `nil` by\n      # the user.\n      define_method(name) do\n        if instance_variable_get(\"@#{name}_assigned\")\n          if assigned_value = instance_variable_get(\"@#{name}\")\n            merge_hash ? instance_eval(&default).merge(assigned_value) : assigned_value\n          end\n        else\n          instance_eval(&default)\n        end\n      end\n      define_method(\"#{name}=\") do |value|\n        instance_variable_set(\"@#{name}_assigned\", true)\n        instance_variable_set(\"@#{name}\", value)\n      end\n    end\n\n    attr_accessor :command, :exit_code, :output\n\n    def initialize(attributes)\n      @exit_code = 0\n      @output = ''\n      attributes.each { |k,v| send(\"#{k}=\", v) }\n    end\n\n    def success?\n      exit_code == 0\n    end\n\n    attr_with_default(:print_before) do\n      \"Executing: #{command}\"\n    end\n\n    attr_with_default(:print_after) do\n      # Show all output if it wasn't shown before and the command fails.\n      \"\\n#{output}\\n\\n\" if Kicker.silent? && !success?\n    end\n\n    # TODO default titles??\n\n    attr_with_default(:notify_before, true) do\n      { :title => \"Kicker: Executing\", :message => command }\n    end\n\n    attr_with_default(:notify_after, true)  do\n      message = Kicker.silent? ? \"\" : output\n      if success?\n        { :title => \"Kicker: Success\", :message => message }\n      else\n        { :title => \"Kicker: Failed (#{exit_code})\", :message => message }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/kicker/notification.rb",
    "content": "require 'notify'\n\nclass Kicker\n  module Notification #:nodoc:\n    TITLE = 'Kicker'\n\n    class << self\n      attr_accessor :use, :app_bundle_identifier\n      alias_method :use?, :use\n\n      def notify(options)\n        return unless use?\n\n        unless message = options.delete(:message)\n          raise \"A notification requires a `:message'\"\n        end\n\n        options = {\n          :group    => Dir.pwd,\n          :activate => app_bundle_identifier\n        }.merge(options)\n\n        Notify.notify(TITLE, message, options)\n      end\n    end\n  end\n\n  Notification.use = ENV['NOTIFY'].to_s != ''\n  Notification.app_bundle_identifier = 'com.apple.Terminal'\nend\n\n"
  },
  {
    "path": "lib/kicker/options.rb",
    "content": "require 'optparse'\n\nclass Kicker\n  class << self\n    attr_accessor :latency, :paths, :silent, :quiet, :clear_console\n\n    def silent?\n      @silent\n    end\n\n    def quiet?\n      @quiet\n    end\n\n    def clear_console?\n      @clear_console\n    end\n\n\n    def osx?\n      RUBY_PLATFORM.downcase.include?(\"darwin\")\n    end\n  end\n\n  self.latency = 1\n  self.paths = %w{ . }\n  self.silent = false\n  self.quiet = false\n  self.clear_console = false\n\n  module Options #:nodoc:\n    DONT_SHOW_RECIPES = %w{ could_not_handle_file execute_cli_command dot_kick }\n\n    def self.recipes_for_display\n      Kicker::Recipes.recipe_files.map { |f| File.basename(f, '.rb') } - DONT_SHOW_RECIPES\n    end\n\n    def self.parser\n      @parser ||= OptionParser.new do |opt|\n        opt.banner =  \"Usage: #{$0} [options] [paths to watch]\"\n        opt.separator \" \"\n        opt.separator \"  Available recipes: #{recipes_for_display.join(\", \")}.\"\n        opt.separator \" \"\n\n        opt.on('-v', 'Print the Kicker version') do\n          puts Kicker::VERSION\n          exit\n        end\n\n        opt.on('-s', '--silent', 'Keep output to a minimum.') do |silent|\n          Kicker.silent = true\n        end\n\n        opt.on('-q', '--quiet', \"Quiet output. Don't print timestamps when logging.\") do |quiet|\n          Kicker.silent = Kicker.quiet = true\n        end\n\n        opt.on('-c', '--clear', \"Clear console before each run.\") do |clear|\n          Kicker.clear_console = true\n        end\n\n\n        opt.on('--[no-]notification', 'Whether or not to send user notifications (on Mac OS X). Defaults to enabled.') do |notifications|\n          Notification.use = notifications\n        end\n\n        if Kicker.osx?\n          opt.on('--activate-app [BUNDLE ID]', \"The application to activate when a notification is clicked. Defaults to `com.apple.Terminal'.\") do |bundle_id|\n            Kicker::Notification.app_bundle_identifier = bundle_id\n          end\n        end\n\n        opt.on('-l', '--latency [FLOAT]', \"The time to collect file change events before acting on them. Defaults to #{Kicker.latency} second.\") do |latency|\n          Kicker.latency = Float(latency)\n        end\n\n        opt.on('-r', '--recipe [NAME]', 'A named recipe to load.') do |name|\n          recipe(name)\n        end\n      end\n    end\n\n    def self.parse(argv)\n      parser.parse!(argv)\n      Kicker.paths = argv unless argv.empty?\n    end\n  end\nend\n\nmodule Kernel\n  # Returns the global OptionParser instance that recipes can use to add\n  # options.\n  def options\n    Kicker::Options.parser\n  end\nend\n"
  },
  {
    "path": "lib/kicker/recipes/could_not_handle_file.rb",
    "content": "post_process do |files|\n  unless Kicker.silent?\n    log('')\n    log(\"Could not handle: #{files.join(', ')}\")\n    log('')\n  end\nend\n"
  },
  {
    "path": "lib/kicker/recipes/dot_kick.rb",
    "content": "module ReloadDotKick #:nodoc\n  class << self\n    def save_state\n      @features_before_dot_kick = $LOADED_FEATURES.dup\n      @chains_before_dot_kick = Kicker.full_chain.map { |c| c.dup }\n    end\n\n    def call(files)\n      reset! if files.delete('.kick')\n    end\n\n    def use?\n      File.exist?('.kick')\n    end\n\n    def load!\n      load '.kick'\n    end\n\n    def reset!\n      remove_loaded_features!\n      reset_chains!\n      load!\n    end\n\n    def reset_chains!\n      Kicker.full_chain = nil\n\n      chains = @chains_before_dot_kick.map { |c| c.dup }\n      Kicker.pre_process_chain, Kicker.process_chain, Kicker.post_process_chain = *chains\n    end\n\n    def remove_loaded_features!\n      ($LOADED_FEATURES - @features_before_dot_kick).each do |feat|\n        $LOADED_FEATURES.delete(feat)\n      end\n    end\n  end\nend\n\nif ReloadDotKick.use?\n  startup do\n    pre_process ReloadDotKick\n    ReloadDotKick.save_state\n    ReloadDotKick.load!\n  end\nend\n"
  },
  {
    "path": "lib/kicker/recipes/execute_cli_command.rb",
    "content": "options.on('-e', '--execute [COMMAND]', 'The command to execute.') do |command|\n  callback = lambda do |files|\n    files.clear\n    execute \"sh -c #{command.inspect}\"\n  end\n\n  startup callback\n  pre_process callback\nend\n"
  },
  {
    "path": "lib/kicker/recipes/ignore.rb",
    "content": "# A recipe which removes files from the files array, thus “ignoring” them.\n#\n# By default ignores logs, tmp, and svn and git files.\n#\n# See Kernel#ignore for info on how to ignore files.\nmodule Ignore\n  def self.call(files) #:nodoc:\n    files.reject! { |file| ignores.any? { |ignore| file =~ ignore } }\n  end\n\n  def self.ignores #:nodoc:\n    @ignores ||= []\n  end\n\n  def self.ignore(regexp_or_string) #:nodoc:\n    ignores << (regexp_or_string.is_a?(Regexp) ? regexp_or_string : /^#{regexp_or_string}$/)\n  end\nend\n\nmodule Kernel\n  # Adds +regexp_or_string+ as an ignore rule.\n  #\n  #   require 'ignore'\n  #\n  #   ignore /^data\\//\n  #   ignore 'Rakefile'\n  #\n  # <em>Only available if the `ignore' recipe is required.</em>\n  def ignore(regexp_or_string)\n    Ignore.ignore(regexp_or_string)\n  end\nend\n\nrecipe :ignore do\n  pre_process Ignore\n\n  ignore(\"tmp\")\n  ignore(/\\w+\\.log/)\n  ignore(/\\.(svn|git)\\//)\n  ignore(\"svn-commit.tmp\")\nend\n"
  },
  {
    "path": "lib/kicker/recipes/jstest.rb",
    "content": "recipe :jstest do\n  process do |files|\n    test_files = files.take_and_map do |file|\n      if file =~ %r{^(test|public)/javascripts/(\\w+?)(_test)*\\.(js|html)$}\n        \"test/javascripts/#{$2}_test.html\"\n      end\n    end\n    execute \"jstest #{test_files.join(' ')}\" unless test_files.empty?\n  end\nend\n"
  },
  {
    "path": "lib/kicker/recipes/rails.rb",
    "content": "recipe :ruby\n\nclass Kicker::Recipes::Rails < Kicker::Recipes::Ruby\n  class << self\n    # Call these options on the Ruby class which takes the cli options.\n    %w{ test_type runner_bin test_cases_root test_options }.each do |delegate|\n      define_method(delegate) { Kicker::Recipes::Ruby.send(delegate) }\n    end\n\n    # Maps +type+, for instance `models', to a test directory.\n    def type_to_test_dir(type)\n      if test_type == 'test'\n        case type\n        when \"models\"\n          \"unit\"\n        when \"concerns\"\n          \"unit/concerns\"\n        when \"controllers\", \"views\"\n          \"functional\"\n        when \"helpers\"\n          \"unit/helpers\"\n        end\n      elsif test_type == 'spec'\n        case type\n        when \"models\"\n          \"models\"\n        when \"concerns\"\n          \"models/concerns\"\n        when \"controllers\", \"views\"\n          \"controllers\"\n        when \"helpers\"\n          \"helpers\"\n        end\n      end\n    end\n\n    # Returns an array consiting of all controller tests.\n    def all_controller_tests\n      if test_type == 'test'\n        Dir.glob(\"#{test_cases_root}/functional/**/*_test.rb\")\n      else\n        Dir.glob(\"#{test_cases_root}/controllers/**/*_spec.rb\")\n      end\n    end\n  end\n\n  # Returns an array of all tests related to the given model.\n  def tests_for_model(model)\n    if test_type == 'test'\n      %W{\n        unit/#{ActiveSupport::Inflector.singularize(model)}\n        unit/helpers/#{ActiveSupport::Inflector.pluralize(model)}_helper\n        functional/#{ActiveSupport::Inflector.pluralize(model)}_controller\n      }\n    else\n      %W{\n        models/#{ActiveSupport::Inflector.singularize(model)}\n        helpers/#{ActiveSupport::Inflector.pluralize(model)}_helper\n        controllers/#{ActiveSupport::Inflector.pluralize(model)}_controller\n      }\n    end.map { |f| test_file f }\n  end\n\n  def handle!\n    @tests.concat(@files.take_and_map do |file|\n      case file\n      # Run all functional tests when routes.rb is saved\n      when 'config/routes.rb'\n        Kicker::Recipes::Rails.all_controller_tests\n\n      # Match lib/*\n      when /^(lib\\/.+)\\.rb$/\n        test_file($1)\n\n      # Map fixtures to their related tests\n      when %r{^#{test_cases_root}/fixtures/(\\w+)\\.yml$}\n        tests_for_model($1)\n\n      # Match any file in app/ and map it to a test file\n      when %r{^app/(\\w+)([\\w/]*)/([\\w\\.]+)\\.\\w+$}\n        type, namespace, file = $1, $2, $3\n\n        if dir = Kicker::Recipes::Rails.type_to_test_dir(type)\n          if type == \"views\"\n            namespace = namespace.split('/')[1..-1]\n            file = \"#{namespace.pop}_controller\"\n          end\n\n          test_file File.join(dir, namespace, file)\n        end\n      end\n    end)\n\n    # And let the Ruby handler match other stuff.\n    super\n  end\nend\n\nrecipe :rails do\n  require 'rubygems' rescue LoadError\n  require 'active_support/inflector'\n\n  process Kicker::Recipes::Rails\n\n  # When changing the schema, prepare the test database.\n  process do |files|\n    execute 'rake db:test:prepare' if files.delete('db/schema.rb')\n  end\nend\n"
  },
  {
    "path": "lib/kicker/recipes/ruby.rb",
    "content": "class Kicker::Recipes::Ruby\n  class << self\n    # Assigns the type of tests to run. Eg: `test' or `spec'.\n    attr_writer :test_type\n\n    # Returns the type of tests to run. Eg: `test' or `spec'.\n    #\n    # Defaults to `test' if no `spec' directory exists.\n    def test_type\n      @test_type ||= File.exist?('spec') ? 'spec' : 'test'\n    end\n\n    # Assigns the ruby command to run the tests with. Eg: `ruby19' or `specrb'.\n    #\n    # This can be set from the command line with the `-b' or `--ruby' options.\n    attr_writer :runner_bin\n\n    # Returns the ruby command to run the tests with. Eg: `ruby' or `spec'.\n    #\n    # Defaults to `ruby' if test_type is `test' and `spec' if test_type is\n    # `spec'.\n    def runner_bin\n      @runner_bin ||= test_type == 'test' ? 'ruby' : 'rspec'\n    end\n\n    # Assigns the root directory of where test cases will be looked up.\n    attr_writer :test_cases_root\n\n    # Returns the root directory of where test cases will be looked up.\n    #\n    # Defaults to the value of test_type. Eg: `test' or `spec'.\n    def test_cases_root\n      @test_cases_root ||= test_type\n    end\n\n    attr_writer :test_options #:nodoc:\n\n    # Assigns extra options that are to be passed on to the runner_bin.\n    #\n    #   Ruby.test_options << '-I ./lib/foo'\n    def test_options\n      @test_options ||= []\n    end\n\n    def reset!\n      @test_type = nil\n      @runner_bin = nil\n      @test_cases_root = nil\n      @test_options = nil\n    end\n\n    def runner_command(*parts)\n      parts.map do |part|\n        case part\n        when Array\n          part.empty? ? nil : part.join(' ')\n        else\n          part.to_s\n        end\n      end.compact.join(' ')\n    end\n\n    # Runs the given tests, if there are any, with the method defined by\n    # test_type. If test_type is `test' the run_with_test_runner method is\n    # used. The same applies when test_type is `spec'.\n    def run_tests(tests)\n      send(\"run_with_#{test_type}_runner\", tests) unless tests.empty?\n    end\n\n    def test_runner_command(tests)\n      tests_without_ext = tests.map { |f| f[0,f.size-3] }\n      runner_command(runner_bin, %w{ -I. } + test_options, '-r', tests_without_ext.join(' -r '), \"-e ''\")\n    end\n\n    # Runs the given tests with `ruby' as unit-test tests.\n    def run_with_test_runner(tests)\n      execute(test_runner_command(tests))\n    end\n\n    def spec_runner_command(tests)\n      runner_command(runner_bin, test_options, tests)\n    end\n\n    # Runs the given tests with `spec' as RSpec tests.\n    def run_with_spec_runner(tests)\n      execute(spec_runner_command(tests))\n    end\n  end\n\n  def self.call(files) #:nodoc:\n    handler = new(files)\n    handler.handle!\n    run_tests(handler.tests)\n  end\n\n  # The list of collected tests.\n  attr_reader :tests\n\n  def initialize(files) #:nodoc:\n    @files = files\n    @tests = []\n  end\n\n  # A shortcut to Ruby.test_type.\n  def test_type\n    self.class.test_type\n  end\n\n  # A shortcut to Ruby.runner_bin.\n  def runner_bin\n    self.class.runner_bin\n  end\n\n  # A shortcut to Ruby.test_cases_root.\n  def test_cases_root\n    self.class.test_cases_root\n  end\n\n  # Returns the file for +name+ if it exists.\n  #\n  #   test_file('foo') # => \"test/foo_test.rb\"\n  #   test_file('foo/bar') # => \"test/foo/bar_test.rb\"\n  #   test_file('does/not/exist') # => nil\n  def test_file(name)\n    file = File.join(test_cases_root, \"#{name}_#{test_type}.rb\")\n    file if File.exist?(file)\n  end\n\n  # This method is called to collect tests. Override this if you're subclassing\n  # and make sure to call +super+.\n  def handle!\n    @tests.concat(@files.take_and_map do |file|\n      case file\n      # Match any ruby test file\n      when /^#{test_cases_root}\\/.+_#{test_type}\\.rb$/\n        file\n\n      # A file such as ./lib/namespace/foo.rb is mapped to:\n      # * ./test/namespace/foo_test.rb\n      # * ./test/foo_test.rb\n      when /^lib\\/(.+)\\.rb$/\n        if namespaced = test_file($1)\n          namespaced\n        elsif in_test_root = test_file(File.basename(file, '.rb'))\n          in_test_root\n        end\n      end\n    end)\n  end\nend\n\noptions.on('-b', '--ruby [PATH]', \"Use an alternate Ruby binary for spawned test runners. (Default is `ruby')\") do |command|\n  Kicker::Recipes::Ruby.runner_bin = command\nend\n\nrecipe :ruby do\n  process Kicker::Recipes::Ruby\n\n  # When changing the Gemfile, install dependencies\n  process do |files|\n    execute 'bundle install' if files.delete('Gemfile')\n  end\nend\n"
  },
  {
    "path": "lib/kicker/recipes.rb",
    "content": "module Kernel\n  # If only given a <tt>name</tt>, the specified recipe will be loaded. For\n  # instance, the following, in a <tt>.kick</tt> file, will load the Rails\n  # recipe:\n  #\n  #   recipe :rails\n  #\n  # However, this same method is used to define a callback that is called _if_\n  # the recipe is loaded. For instance, the following, in a recipe file, will\n  # be called if the recipe is actually used:\n  #\n  #   recipe :rails do\n  #     # Load anything needed for the recipe.\n  #     process do\n  #       # ...\n  #     end\n  #   end\n  def recipe(name, &block)\n    Kicker::Recipes.recipe(name, &block)\n  end\nend\n\nclass Kicker\n  module Recipes #:nodoc:\n    RECIPES_DIR      = Pathname.new('../recipes').expand_path(__FILE__)\n    USER_RECIPES_DIR = Pathname.new('~/.kick').expand_path\n    CURRENT_RECIPES_DIR = Pathname.pwd.join('.kick').expand_path\n\n    RECIPES_DIRS = [RECIPES_DIR, USER_RECIPES_DIR, CURRENT_RECIPES_DIR]\n\n    class << self\n      def reset!\n        @recipes = nil\n        # Always load all the base recipes\n        load_recipe :execute_cli_command\n        load_recipe :could_not_handle_file\n        load_recipe :dot_kick\n      end\n\n      def recipes\n        @recipes ||= {}\n      end\n\n      def recipe_filename(name)\n        [\n          USER_RECIPES_DIR,\n          RECIPES_DIR\n        ].each do |directory|\n          filename = directory.join(\"#{name}.rb\")\n          return filename if filename.exist?\n        end\n      end\n\n      def recipe_names\n        recipe_files.map { |filename| filename.basename('.rb').to_s.to_sym }\n      end\n\n      def recipe_files\n        RECIPES_DIRS.map{|dir| Pathname.glob(dir.join('*.rb')) }.flatten.uniq.map(&:expand_path)\n      end\n\n      def define_recipe(name, &block)\n        recipes[name] = block\n      end\n\n      def load_recipe(name)\n        if recipe_names.include?(name)\n          load recipe_filename(name)\n        else\n          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]}\"\n        end\n      end\n\n      def activate_recipe(name)\n        unless recipes.has_key?(name)\n          load_recipe(name)\n        end\n        if recipe = recipes[name]\n          recipe.call\n        else\n          raise ArgumentError, \"Can't activate the recipe `#{name}' because it hasn't been defined yet.\"\n        end\n      end\n\n      # See Kernel#recipe for more information about the usage.\n      def recipe(name, &block)\n        name = name.to_sym\n        if block_given?\n          define_recipe(name, &block)\n        else\n          activate_recipe(name)\n        end\n      end\n    end\n\n    reset!\n  end\nend\n"
  },
  {
    "path": "lib/kicker/utils.rb",
    "content": "require 'shellwords' if RUBY_VERSION >= \"1.9\"\n\nclass Kicker\n  module Utils #:nodoc:\n    extend self\n\n    attr_accessor :should_clear_screen\n    alias_method :should_clear_screen?, :should_clear_screen\n\n    def perform_work(command_or_options)\n      if command_or_options.is_a?(Hash)\n        options = command_or_options\n      elsif command_or_options.is_a?(String)\n        options = { :command => command_or_options }\n      else\n        raise ArgumentError, \"Should be a string or a hash.\"\n      end\n      job = Job.new(options)\n      will_execute_command(job)\n      yield job\n      did_execute_command(job)\n      job\n    end\n\n    def execute(command_or_options)\n      perform_work(command_or_options) do |job|\n        _execute(job)\n        yield job if block_given?\n      end\n    end\n\n    def log(message)\n      if Kicker.quiet\n        puts message\n      else\n        now = Time.now\n        puts \"#{now.strftime('%H:%M:%S')}.#{now.usec.to_s[0,2]} | #{message}\"\n      end\n    end\n\n    def clear_console!\n      puts(CLEAR) if Kicker.clear_console?\n    end\n\n    private\n\n    CLEAR = \"\\e[H\\e[2J\"\n\n    def _execute(job)\n      silent = Kicker.silent?\n      unless silent\n        puts\n        sync_before, $stdout.sync = $stdout.sync, true\n      end\n      output = \"\"\n      popen(job.command) do |io|\n        while str = io.read(1)\n          output << str\n          $stdout.print str unless silent\n        end\n      end\n      job.output = output.strip\n      job.exit_code = $?.exitstatus\n      job\n    ensure\n      unless silent\n        $stdout.sync = sync_before\n        puts(\"\\n\\n\")\n      end\n    end\n\n    def popen(command, &block)\n      if RUBY_VERSION >= \"1.9\"\n        args = Shellwords.shellsplit(command)\n        args << { :err => [:child, :out] }\n        IO.popen(args, &block)\n      else\n        IO.popen(\"#{command} 2>&1\", &block)\n      end\n    end\n\n    def will_execute_command(job)\n      puts(CLEAR) if Kicker.clear_console? && should_clear_screen?\n      @should_clear_screen = false\n\n      if message = job.print_before\n        log(message)\n      end\n\n      if notification = job.notify_before\n        Notification.notify(notification)\n      end\n    end\n\n    def did_execute_command(job)\n      if message = job.print_after\n        puts(message)\n      end\n\n      log(job.success? ? \"Success\" : \"Failed (#{job.exit_code})\")\n\n      if notification = job.notify_after\n        Notification.notify(notification)\n      end\n    end\n  end\nend\n\nmodule Kernel\n  # Prints a +message+ with timestamp to stdout.\n  def log(message)\n    Kicker::Utils.log(message)\n  end\n\n  # When you perform some work (like shelling out a command to run without\n  # using +execute+) you need to call this method, with a block in which you\n  # perform your work, which will take care of logging the work appropriately.\n  def perform_work(command, &block)\n    Kicker::Utils.perform_work(command, &block)\n  end\n\n  # Executes the +command+, logs the output, and optionally sends user\n  # notifications on Mac OS X (10.8 or higher).\n  def execute(command, &block)\n    Kicker::Utils.execute(command, &block)\n  end\nend\n"
  },
  {
    "path": "lib/kicker/version.rb",
    "content": "class Kicker\n  VERSION = \"3.0.0\"\nend\n"
  },
  {
    "path": "lib/kicker.rb",
    "content": "require 'kicker/version'\nrequire 'kicker/fsevents'\nrequire 'kicker/callback_chain'\nrequire 'kicker/core_ext'\nrequire 'kicker/job'\nrequire 'kicker/notification'\nrequire 'kicker/options'\nrequire 'kicker/utils'\nrequire 'kicker/recipes'\n\nclass Kicker #:nodoc:\n  def self.run(argv = ARGV)\n    Kicker::Options.parse(argv)\n    new.start.loop!\n  end\n\n  attr_reader :last_event_processed_at\n\n  def initialize\n    finished_processing!\n  end\n\n  def paths\n    @paths ||= Kicker.paths.map { |path| File.expand_path(path) }\n  end\n\n  def start\n    validate_options!\n\n    log \"Watching for changes on: #{paths.join(', ')}\"\n    log ''\n\n    run_startup_chain\n    run_watch_dog!\n\n    self\n  end\n\n  def loop!\n    (Thread.list - [Thread.current, Thread.main]).each(&:join)\n  end\n\n  private\n\n  def validate_options!\n    validate_paths_and_command!\n    validate_paths_exist!\n  end\n\n  def validate_paths_and_command!\n    if startup_chain.empty? && process_chain.empty? && pre_process_chain.empty?\n      puts Kicker::Options.parser.help\n      exit\n    end\n  end\n\n  def validate_paths_exist!\n    paths.each do |path|\n      unless File.exist?(path)\n        puts \"The given path `#{path}' does not exist\"\n        exit 1\n      end\n    end\n  end\n\n  def run_watch_dog!\n    dirs = @paths.map { |path| File.directory?(path) ? path : File.dirname(path) }\n    Kicker::FSEvents.start_watching(dirs, :latency => self.class.latency) do |events|\n      process events\n    end\n    trap('INT') do\n      log 'Exiting ...'\n      exit\n    end\n  end\n\n  def run_startup_chain\n    startup_chain.call([], false)\n  end\n\n  def finished_processing!\n    @last_event_processed_at = Time.now\n  end\n\n  def process(events)\n    unless (files = changed_files(events)).empty?\n      Utils.should_clear_screen = true\n      full_chain.call(files)\n      finished_processing!\n    end\n  end\n\n  def changed_files(events)\n    make_paths_relative(events.map do |event|\n      files_in_directory(event.path).select { |file| file_changed_since_last_event? file }\n    end.flatten.uniq.sort)\n  end\n\n  def files_in_directory(dir)\n    Dir.entries(dir).sort[2..-1].map { |f| File.join(dir, f) }\n  rescue Errno::ENOENT\n    []\n  end\n\n  def file_changed_since_last_event?(file)\n    File.mtime(file) > @last_event_processed_at\n  rescue Errno::ENOENT\n    false\n  end\n\n  def make_paths_relative(files)\n    return files if files.empty?\n    wd = Dir.pwd\n    files.map do |file|\n      if file[0..wd.length-1] == wd\n        file[wd.length+1..-1]\n      else\n        file\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "rakelib/gem_release.rake",
    "content": "NAME = 'Kicker'\nLOWERCASE_NAME = NAME.downcase\nGEM_NAME = LOWERCASE_NAME\n\ndef gem_version\n  require File.expand_path(\"../../lib/#{LOWERCASE_NAME}/version\", __FILE__)\n  Object.const_get(NAME).const_get('VERSION')\nend\n\ndef gem_file\n  \"#{GEM_NAME}-#{gem_version}.gem\"\nend\n\ndesc \"Build gem\"\ntask :build do\n  sh \"gem build #{GEM_NAME}.gemspec\"\nend\n\ndesc \"Clean gems\"\ntask :clean do\n  sh \"rm -f *.gem\"\nend\n\ndesc \"Install gem\"\ntask :install => :build do\n  sh \"gem install #{gem_file}\"\nend\n\ndesc \"Clean, build, install, and push gem to rubygems.org\"\ntask :release => [:clean, :install] do\n  sh \"git tag -a #{gem_version} -m 'Release #{gem_version}'\"\n  sh \"git push --tags\"\n  sh \"gem push #{gem_file}\"\nend\n"
  },
  {
    "path": "spec/callback_chain_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\ndescribe \"Kicker, concerning its callback chains\" do\n  before do\n    @chains = [:startup_chain, :pre_process_chain, :process_chain, :post_process_chain, :full_chain]\n  end\n\n  it \"should return the callback chain instances\" do\n    @chains.each do |chain|\n      Kicker.send(chain).should.be.instance_of Kicker::CallbackChain\n    end\n  end\n\n  it \"should be accessible by an instance\" do\n    kicker = Kicker.new\n\n    @chains.each do |chain|\n      kicker.send(chain).should == Kicker.send(chain)\n    end\n  end\n\n  it \"should provide a shortcut method which appends a callback to the startup chain\" do\n    Kicker.startup_chain.expects(:append_callback).with do |callback|\n      callback.call == :from_callback\n    end\n\n    startup { :from_callback }\n  end\n\n  it \"should provide a shortcut method which appends a callback to the pre-process chain\" do\n    Kicker.pre_process_chain.expects(:append_callback).with do |callback|\n      callback.call == :from_callback\n    end\n\n    pre_process { :from_callback }\n  end\n\n  it \"should provide a shortcut method which appends a callback to the process chain\" do\n    Kicker.process_chain.expects(:append_callback).with do |callback|\n      callback.call == :from_callback\n    end\n\n    process { :from_callback }\n  end\n\n  it \"should provide a shortcut method which prepends a callback to the post-process chain\" do\n    Kicker.post_process_chain.expects(:prepend_callback).with do |callback|\n      callback.call == :from_callback\n    end\n\n    post_process { :from_callback }\n  end\n\n  it \"should have assigned the chains to the `full_chain' (except startup_chain)\" do\n    Kicker.full_chain.length.should == 3\n    Kicker.full_chain.each_with_index do |chain, index|\n      chain.should == Kicker.send(@chains[index + 1])\n    end\n  end\nend\n\ndescribe \"Kicker::CallbackChain\" do\n  it \"should be a subclass of Array\" do\n    Kicker::CallbackChain.superclass.should == Array\n  end\nend\n\ndescribe \"An instance of Kicker::CallbackChain, concerning it's API\" do\n  before do\n    @chain = Kicker::CallbackChain.new\n\n    @callback1 = lambda {}\n    @callback2 = lambda {}\n  end\n\n  it \"should append a callback\" do\n    @chain << @callback1\n    @chain.append_callback(@callback2)\n\n    @chain.should == [@callback1, @callback2]\n  end\n\n  it \"should prepend a callback\" do\n    @chain << @callback1\n    @chain.prepend_callback(@callback2)\n\n    @chain.should == [@callback2, @callback1]\n  end\nend\n\ndescribe \"An instance of Kicker::CallbackChain, when calling the chain\" do\n  before do\n    @chain = Kicker::CallbackChain.new\n    @result = []\n  end\n\n  it \"should call the callbacks from first to last\" do\n    @chain.append_callback lambda { |files| @result << 1 }\n    @chain.append_callback lambda { |files| @result << 2 }\n    @chain.call(%w{ file })\n    @result.should == [1, 2]\n  end\n\n  it \"should pass the files array given to #call to each callback in the chain\" do\n    array = %w{ /file/1 }\n\n    @chain.append_callback lambda { |files|\n      files.should == array\n      files.concat(%w{ /file/2 })\n    }\n\n    @chain.append_callback lambda { |files|\n      files.should == array\n      @result.concat(files)\n    }\n\n    @chain.call(array)\n    @result.should == %w{ /file/1 /file/2 }\n  end\n\n  it \"should halt the callback chain once the given array is empty\" do\n    @chain.append_callback lambda { |files| @result << 1; files.clear }\n    @chain.append_callback lambda { |files| @result << 2 }\n    @chain.call(%w{ /file/1 /file/2 })\n    @result.should == [1]\n  end\n\n  it \"should not halt the chain if the array is empty if specified\" do\n    @chain.append_callback lambda { |files| @result << 1; files.clear }\n    @chain.append_callback lambda { |files| @result << 2 }\n    @chain.call(%w{ /file/1 /file/2 }, false)\n    @result.should == [1, 2]\n  end\n\n  it \"should not call any callback if the given array is empty\" do\n    @chain.append_callback lambda { |files| @result << 1 }\n    @chain.call([])\n    @result.should == []\n  end\n\n  it \"should work with a chain of chains as well\" do\n    array = %w{ file }\n\n    kicker_and_files = lambda do |kicker, files|\n      kicker.should.be @kicker\n      files.should.be array\n    end\n\n    chain1 = Kicker::CallbackChain.new([\n      lambda { |files| files.should == array; @result << 1 },\n      lambda { |files| files.should == array; @result << 2 }\n    ])\n\n    chain2 = Kicker::CallbackChain.new([\n      lambda { |files| files.should == array; @result << 3 },\n      lambda { |files| files.should == array; @result << 4 }\n    ])\n\n    @chain.append_callback chain1\n    @chain.append_callback chain2\n\n    @chain.call(array)\n    @result.should == [1, 2, 3, 4]\n  end\nend\n"
  },
  {
    "path": "spec/core_ext_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\ndescribe \"Array#take_and_map\" do\n  before do\n    @array = %w{ foo bar baz foo/bar.baz foo/bar/baz }\n  end\n\n  it \"should remove elements from the array for which the block evaluates to true\" do\n    @array.take_and_map { |x| x =~ /^ba/ }\n    @array.should == %w{ foo foo/bar.baz foo/bar/baz }\n  end\n\n  it \"should return a new array of the return values of each block call that evaluates to true\" do\n    @array.take_and_map { |x| $1 if x =~ /^ba(\\w)/ }.should == %w{ r z }\n  end\n\n  it \"should flatten and compact the result array\" do\n    @array.take_and_map do |x|\n      x =~ /^ba/ ? %w{ f o o } : [nil]\n    end.should == %w{ f o o f o o }\n  end\n\n  it \"should not flatten and compact the result array if specified\" do\n    @array.take_and_map(nil, false) do |x|\n      x =~ /^ba/ ? %w{ f o o } : [nil]\n    end.should == [[nil], %w{ f o o }, %w{ f o o }, [nil], [nil]]\n  end\n\n  it \"should take only files matching the pattern\" do\n    @array.take_and_map('**/*') { |x| x.reverse }.should ==\n      %w{ foo/bar.baz foo/bar/baz }.map { |s| s.reverse }\n  end\n\n  it \"should not remove files not matching the pattern\" do\n    @array.take_and_map('**/*') { |x| x }\n    @array.should == %w{ foo bar baz }\n  end\nend\n"
  },
  {
    "path": "spec/filesystem_change_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\nrequire 'stringio'\ndescribe \"Kicker, when a change occurs\" do\n  def silent(&block)\n    stdout = $stdout\n    $stdout = StringIO.new\n    yield\n  ensure\n    $stdout = stdout\n  end\n  def touch(file)\n    file = \"/tmp/kicker_test_tmp_#{file}\"\n    `touch #{file}`\n    file\n  end\n\n  def event(*files)\n    event = stub('FSEvent')\n    event.stubs(:path).returns('/tmp')\n    event\n  end\n\n  def remove_tmp_files!\n    Dir.glob(\"/tmp/kicker_test_tmp_*\").each { |f| File.delete(f) }\n  end\n\n  before do\n    remove_tmp_files!\n\n    Kicker::Notification.stubs(:`)\n\n    Kicker.any_instance.stubs(:last_command_succeeded?).returns(true)\n    Kicker.any_instance.stubs(:log)\n    @kicker = Kicker.new\n  end\n\n  it \"should store the current time as when the last change occurred\" do\n    now = Time.now\n    Time.stubs(:now).returns(now)\n\n    @kicker.send(:finished_processing!)\n    @kicker.last_event_processed_at.should == now\n  end\n\n  it \"should return an array of files that have changed since the last event\" do\n    file1 = touch('1')\n    file2 = touch('2')\n    file3 = touch('3')\n    file4 = touch('4')\n    @kicker.send(:finished_processing!)\n\n    events = [event(file1, file2), event(file3, file4)]\n\n    @kicker.send(:changed_files, events).should == []\n    @kicker.send(:finished_processing!)\n\n    sleep(1)\n    touch('2')\n\n    @kicker.send(:changed_files, events).should == [file2]\n    @kicker.send(:finished_processing!)\n\n    sleep(1)\n    touch('1')\n    touch('3')\n\n    @kicker.send(:changed_files, events).should == [file1, file3]\n  end\n\n  it \"should return an empty array when a directory doesn't exist while collecting the files in it\" do\n    @kicker.send(:files_in_directory, '/does/not/exist').should == []\n  end\n\n  it \"should not break when determining changed files from events with missing files\" do\n    file1 = touch('1')\n    file2 = touch('2')\n    @kicker.send(:finished_processing!)\n    sleep(1)\n    touch('2')\n\n    events = [event(file1, file2), event('/does/not/exist')]\n    @kicker.send(:changed_files, events).should == [file2]\n  end\n\n  it \"should return relative file paths if the path is relative to the current work dir\" do\n    sleep(1)\n    file = touch('1')\n\n    Dir.stubs(:pwd).returns('/tmp')\n    @kicker.send(:changed_files, [event(file)]).should == [File.basename(file)]\n  end\n\n  it \"should call the full_chain with all changed files\" do\n    files = %w{ /file/1 /file/2 }\n    events = [event('/file/1'), event('/file/2')]\n\n    @kicker.expects(:changed_files).with(events).returns(files)\n    @kicker.full_chain.expects(:call).with(files)\n    @kicker.expects(:finished_processing!)\n\n    @kicker.send(:process, events)\n  end\n\n  it \"should not call the full_chain if there were no changed files\" do\n    @kicker.stubs(:changed_files).returns([])\n    @kicker.full_chain.expects(:call).never\n    @kicker.expects(:finished_processing!).never\n\n    @kicker.send(:process, [event()])\n  end\n\n  it \"should not break when directory entries are not sorted\" do\n    sleep(1)\n    file = touch('1')\n\n    Dir.stubs(:entries).returns([File.basename(file), \".\", \"..\"])\n    @kicker.send(:changed_files, [event(file)]).should == [file]\n  end\n\n  it \"clears the console only once during running the chain\" do\n    Kicker.clear_console = true\n    Kicker.silent = true\n    Kicker::Utils.stubs(:log)\n    Kicker::Utils.expects(:puts).with(\"\\e[H\\e[2J\").once\n\n    files = %w{ /file/1 /file/2 }\n    @kicker.stubs(:changed_files).returns(files)\n\n    @kicker.process_chain.append_callback lambda { |files| Kicker::Utils.perform_work('ls -l') {} }\n    @kicker.process_chain.append_callback lambda { |files| Kicker::Utils.perform_work('ls -l') {} }\n\n    silent do\n      @kicker.send(:process, files.map { |f| event(f) })\n    end\n  end\n\n  it \"does not clear the console if no work is ever performed\" do\n    Kicker.clear_console = true\n    Kicker::Utils.expects(:puts).with(\"\\e[H\\e[2J\").never\n\n    files = %w{ /file/1 /file/2 }\n    @kicker.stubs(:changed_files).returns(files)\n    @kicker.full_chain.stubs(:call)\n    @kicker.send(:process, files.map { |f| event(f) })\n  end\nend\n"
  },
  {
    "path": "spec/fixtures/a_file_thats_reloaded.rb",
    "content": "$FROM_RELOADED_FILE ||= 0\n$FROM_RELOADED_FILE += 1\n"
  },
  {
    "path": "spec/fsevents_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\nclass FakeListener\n  def initialize(paths, options={})\n    @paths = paths\n  end\n\n  def change(&block)\n    @block = block\n    self\n  end\n\n  def start blocking=true\n    self\n  end\n\n  def fake_event(paths)\n    @block.call(paths, [], [])\n  end\nend\n\ndescribe \"Kicker::FSEvents\" do\n  it \"calls the provided block with changed directories wrapped in an event instance\" do\n    tmp = Pathname.new('tmp').join('test')\n    test = tmp.join('what')\n    test.mkpath\n\n    FileUtils.touch(tmp.join('file'))\n\n    watch_dog = Kicker::FSEvents.start_watching([tmp.to_s]) { |e| events = e }\n    Kicker::FSEvents::FSEvent.expects(:new).with(File.expand_path(test.to_s))\n\n    FileUtils.touch(test.join('file'))\n\n    sleep 1\n  end\nend\n\ndescribe \"Kicker::FSEvents::FSEvent\" do\n  it \"returns the files from the changed directory ordered by mtime and filename\" do\n    fsevent = Kicker::FSEvents::FSEvent.new(File.expand_path('../fixtures', __FILE__))\n    fsevent.files.should == [File.expand_path('../fixtures/a_file_thats_reloaded.rb', __FILE__)]\n  end\nend\n"
  },
  {
    "path": "spec/initialization_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\nmodule ReloadDotKick; end\n\ndescribe \"Kicker\" do\n  before do\n    Kicker.any_instance.stubs(:start)\n  end\n\n  it \"should return the default paths to watch\" do\n    Kicker.paths.should == %w{ . }\n  end\n\n  it \"should default the FSEvents latency to 1\" do\n    Kicker.latency.should == 1\n  end\nend\n\ndescribe \"Kicker, when initializing\" do\n  after do\n    Kicker.paths = %w{ . }\n  end\n\n  it \"should return the extended paths to watch\" do\n    Kicker.paths = %w{ /some/dir a/relative/path }\n    Kicker.new.paths.should == ['/some/dir', File.expand_path('a/relative/path')]\n  end\n\n  it \"should have assigned the current time to last_event_processed_at\" do\n    now = Time.now; Time.stubs(:now).returns(now)\n    Kicker.new.last_event_processed_at.should == now\n  end\n\n  it \"should use the default paths if no paths were given\" do\n    Kicker.new.paths.should == [File.expand_path('.')]\n  end\nend\n\ndescribe \"Kicker, when starting\" do\n  before do\n    Kicker.paths = %w{ /some/file.rb }\n    @kicker = Kicker.new\n    @kicker.stubs(:log)\n    @kicker.startup_chain.stubs(:call)\n    Kicker::FSEvents.stubs(:start_watching)\n  end\n\n  after do\n    Kicker.latency = 1\n    Kicker.paths = %w{ . }\n  end\n\n  it \"should show the usage banner and exit when there are no callbacks defined at all\" do\n    @kicker.stubs(:validate_paths_exist!)\n    Kicker.stubs(:startup_chain).returns(Kicker::CallbackChain.new)\n    Kicker.stubs(:process_chain).returns(Kicker::CallbackChain.new)\n    Kicker.stubs(:pre_process_chain).returns(Kicker::CallbackChain.new)\n\n    Kicker::Options.stubs(:parser).returns(mock('OptionParser', :help => 'help'))\n    @kicker.expects(:puts).with(\"help\")\n    @kicker.expects(:exit)\n\n    @kicker.start\n  end\n\n  it \"should warn the user and exit if any of the given paths doesn't exist\" do\n    @kicker.stubs(:validate_paths_and_command!)\n\n    @kicker.expects(:puts).with(\"The given path `/some/file.rb' does not exist\")\n    @kicker.expects(:exit).with(1)\n\n    @kicker.start\n  end\n\n  it \"should start a FSEvents stream with the assigned latency\" do\n    @kicker.stubs(:validate_options!)\n\n    Kicker.latency = 2.34\n    Kicker::FSEvents.expects(:start_watching).with(['/some'], :latency => 2.34)\n    @kicker.start\n  end\n\n  it \"should start a FSEvents stream which watches all paths, but the dirnames of paths if they're files\" do\n    @kicker.stubs(:validate_options!)\n    File.stubs(:directory?).with('/some/file.rb').returns(false)\n\n    Kicker::FSEvents.expects(:start_watching).with(['/some'], :latency => Kicker.latency)\n    @kicker.start\n  end\n\n  it \"should start a FSEvents stream with a block which calls #process with any generated events\" do\n    @kicker.stubs(:validate_options!)\n\n    Kicker::FSEvents.expects(:start_watching).yields(['event'])\n    @kicker.expects(:process).with(['event'])\n\n    @kicker.start\n  end\n\n  it \"should setup a signal handler for `INT' which stops the FSEvents stream and exits\" do\n    @kicker.stubs(:validate_options!)\n\n    Kicker::FSEvents.stubs(:start_watching).returns(stub)\n\n    @kicker.expects(:trap).with('INT').yields\n    @kicker.expects(:exit)\n\n    @kicker.start\n  end\n\n  it \"should call the startup chain\" do\n    @kicker.stubs(:validate_options!)\n\n    @kicker.startup_chain.expects(:call).with([], false)\n    @kicker.start\n  end\nend\n"
  },
  {
    "path": "spec/job_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\ndescribe \"Kicker::Job\" do\n  before do\n    @job = Kicker::Job.new(:command => 'ls -l', :exit_code => 0, :output => \"line 1\\nline2\")\n  end\n\n  after do\n    Kicker.silent = true\n  end\n\n  it \"initializes with an options hash\" do\n    @job.command.should == 'ls -l'\n    @job.exit_code.should == 0\n    @job.output.should == \"line 1\\nline2\"\n  end\n\n  it \"returns wether or not the job was a success\" do\n    @job.should.be.success\n    @job.exit_code = 123\n    @job.should.not.be.success\n  end\n\n  describe \"concerning the default print and notification messages\" do\n    describe \"for before a command is executed\" do\n      it \"returns what command will be executed (for print)\" do\n        @job.print_before.should == 'Executing: ls -l'\n      end\n\n      it \"returns what command will be executed (for notification)\" do\n        Kicker.silent = false\n        @job.notify_before.should == { :title => 'Kicker: Executing', :message => 'ls -l' }\n      end\n\n      # TODO what if the user *does* want to send a notification?\n      #it \"does not send a notification about what command will be executed if Kicker is silent\" do\n        #Kicker.silent = true\n        #@job.notify_before.should == nil\n      #end\n    end\n\n    describe \"for after a command is executed\" do\n      describe \"for print\" do\n        it \"does not return the output if the output has already been logged\" do\n          Kicker.silent = false\n          @job.exit_code = 123\n          @job.print_after.should == nil\n        end\n\n        it \"does not return the output if the command succeeded\" do\n          Kicker.silent = true\n          @job.exit_code = 0\n          @job.print_after.should == nil\n        end\n\n        it \"returns all output if it wasn't printed before and the command failed\" do\n          Kicker.silent = true\n          @job.exit_code = 123\n          @job.print_after.should == \"\\nline 1\\nline2\\n\\n\"\n        end\n      end\n\n      describe \"for notification\" do\n        it \"returns the status of the command and its output\" do\n          Kicker.silent = false\n          @job.exit_code = 0\n          @job.notify_after.should == { :title => 'Kicker: Success', :message => \"line 1\\nline2\" }\n          @job.exit_code = 123\n          @job.notify_after.should == { :title => 'Kicker: Failed (123)', :message => \"line 1\\nline2\" }\n        end\n\n        it \"never returns the output if Kicker is silent\" do\n          Kicker.silent = true\n          @job.exit_code = 0\n          @job.notify_after.should == { :title => 'Kicker: Success', :message => '' }\n          @job.exit_code = 123\n          @job.notify_after.should == { :title => 'Kicker: Failed (123)', :message => '' }\n        end\n      end\n    end\n  end\n\n  describe \"concerning explicit print and notification messages\" do\n    before { Kicker.silent = false }\n\n    it \"returns `nil' if that was explicitely assigned\" do\n      %w{ print_before print_after notify_before notify_after }.each do |attr|\n        @job.send(\"#{attr}=\", nil)\n        @job.send(attr).should == nil\n      end\n    end\n\n    it \"returns the assigned message when explicitely assigned\" do\n      @job.print_before = 'BEFORE'\n      @job.print_before.should == 'BEFORE'\n      @job.print_after = 'AFTER'\n      @job.print_after.should == 'AFTER'\n    end\n\n    it \"merges the assigned notification options with the default ones\" do\n      @job.notify_before = { :message => 'Checking file list' }\n      @job.notify_before.should == { :title => 'Kicker: Executing', :message => 'Checking file list' }\n      @job.notify_after = { :title => 'OMG' }\n      @job.notify_after.should ==  {:title => 'OMG', :message => \"line 1\\nline2\" }\n    end\n  end\nend\n"
  },
  {
    "path": "spec/kicker_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\nrequire 'stringio'\n\ndescribe \"Kicker\" do\n  before { @stdout = $stdout }\n  after { $stdout = @stdout }\n\n  it \"should start\" do\n    $stdout = StringIO.new\n    thread = Thread.new { Kicker.run([]) }\n    thread.abort_on_exception = true\n    sleep 5\n    thread.alive?.should == true\n    thread.exit\n  end\nend\n"
  },
  {
    "path": "spec/notification_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\ndescribe \"Kicker::Notification\" do\n  it \"sends a notification, grouped by the project (identified by the working dir)\" do\n    Kicker::Notification.stubs(:use?).returns(true)\n    Notify.expects(:notify)\n    Kicker::Notification.notify(:title => 'Kicker: Executing', :message => 'ls -l')\n  end\n\n  it \"does not send a notification if notifying is disabled\" do\n    Kicker::Notification.stubs(:use?).returns(false)\n    Notify.expects(:notify).never\n    Kicker::Notification.notify(:title => 'Kicker: Executing', :message => 'ls -l')\n  end\nend\n"
  },
  {
    "path": "spec/options_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\ndescribe \"Kicker::Options.parse\" do\n  after do\n    Kicker.latency = 1\n    Kicker.paths = %w{ . }\n    Kicker.silent = false\n    Kicker.quiet = false\n    Kicker.clear_console = false\n    Kicker::Notification.use = true\n    Kicker::Notification.app_bundle_identifier = 'com.apple.Terminal'\n  end\n\n  it \"should parse the paths\" do\n    Kicker::Options.parse([])\n    Kicker.paths.should == %w{ . }\n\n    Kicker::Options.parse(%w{ /some/file.rb })\n    Kicker.paths.should == %w{ /some/file.rb }\n\n    Kicker::Options.parse(%w{ /some/file.rb /a/dir /and/some/other/file.rb })\n    Kicker.paths.should == %w{ /some/file.rb /a/dir /and/some/other/file.rb }\n  end\n\n  it \"parses wether or not user notifications should be used\" do\n    Kicker::Options.parse([])\n    Kicker::Notification.should.use\n\n    Kicker::Options.parse(%w{ --no-notification })\n    Kicker::Notification.should.not.use\n  end\n\n  it \"should parse if we should keep output to a minimum\" do\n    Kicker::Options.parse([])\n    Kicker.should.not.be.silent\n\n    Kicker::Options.parse(%w{ -s })\n    Kicker.should.be.silent\n  end\n\n  it 'should parse whether or not to run in quiet mode and enable silent mode if quiet' do\n    Kicker::Options.parse([])\n    Kicker.should.not.be.quiet\n    Kicker.should.not.be.silent\n\n    Kicker::Options.parse(%w{ --quiet })\n    Kicker.should.be.quiet\n    Kicker.should.be.silent\n  end\n\n  it \"should parse whether or not to clear the console before running\" do\n    Kicker::Options.parse([])\n    Kicker.should.not.clear_console\n\n    Kicker::Options.parse(%w{ --clear })\n    Kicker.should.clear_console\n  end\n\n  if Kicker.osx?\n    it \"parses the application to activate when a user notification is clicked\" do\n      Kicker::Options.parse(%w{ --activate-app com.apple.Safari })\n      Kicker::Notification.app_bundle_identifier.should == 'com.apple.Safari'\n    end\n  end\n\n  it \"should parse the latency to pass to FSEvents\" do\n    Kicker::Options.parse(%w{ -l 2.5 })\n    Kicker.latency.should == 2.5\n\n    Kicker::Options.parse(%w{ --latency 3.5 })\n    Kicker.latency.should == 3.5\n  end\n\n  it \"should parse recipe requires\" do\n    Kicker::Recipes.expects(:recipe).with('rails')\n    Kicker::Recipes.expects(:recipe).with('jstest')\n    Kicker::Options.parse(%w{ -r rails --recipe jstest })\n  end\nend\n"
  },
  {
    "path": "spec/recipes/could_not_handle_file_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"Kicker, concerning the default `could not handle file' callback\" do\n  before do\n    Kicker.silent = false\n  end\n\n  it \"should log that it could not handle the given files\" do\n    Kicker::Utils.expects(:log).with('')\n    Kicker::Utils.expects(:log).with(\"Could not handle: /file/1, /file/2\")\n    Kicker::Utils.expects(:log).with('')\n\n    Kicker.post_process_chain.last.call(%w{ /file/1 /file/2 })\n  end\n\n  it \"should not log in silent mode\" do\n    Kicker.silent = true\n    Kicker::Utils.expects(:log).never\n    Kicker.post_process_chain.last.call(%w{ /file/1 /file/2 })\n  end\nend\n"
  },
  {
    "path": "spec/recipes/dot_kick_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"The .kick handler\" do\n  it \"should reset $LOADED_FEATURES and callback chains to state before loading .kick and reload .kick\" do\n    ReloadDotKick.save_state\n\n    features_before_dot_kick = $LOADED_FEATURES.dup\n    chains_before_dot_kick = Kicker.full_chain.map { |c| c.dup }\n\n    ReloadDotKick.expects(:load).with('.kick').twice\n\n    2.times do\n      require File.expand_path('../../fixtures/a_file_thats_reloaded', __FILE__)\n      process {}\n      ReloadDotKick.call(%w{ .kick })\n    end\n\n    $FROM_RELOADED_FILE.should == 2\n    $LOADED_FEATURES.should == features_before_dot_kick\n    Kicker.full_chain.should == chains_before_dot_kick\n  end\nend\n"
  },
  {
    "path": "spec/recipes/execute_cli_command_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\ndescribe \"Kicker, concerning the `execute a command-line' callback\" do\n  it \"should parse the command and add the callback\" do\n    before = Kicker.pre_process_chain.length\n\n    Kicker::Options.parse(%w{ -e ls })\n    Kicker.pre_process_chain.length.should == before + 1\n\n    Kicker::Options.parse(%w{ --execute ls })\n    Kicker.pre_process_chain.length.should == before + 2\n  end\n\n  it \"should call execute with the given command\" do\n    Kicker::Options.parse(%w{ -e ls })\n\n    callback = Kicker.pre_process_chain.last\n    callback.should.be.instance_of Proc\n\n    Kicker::Utils.expects(:execute).with('sh -c \"ls\"')\n\n    callback.call(%w{ /file/1 /file/2 }).should.not.be.instance_of Array\n  end\n\n  it \"should clear the files array to halt the chain\" do\n    Kicker::Utils.stubs(:execute)\n\n    files = %w{ /file/1 /file/2 }\n    Kicker.pre_process_chain.last.call(files)\n    files.should.be.empty\n  end\n\n  it \"should run the command directly once Kicker is done loading\" do\n    callback = Kicker.pre_process_chain.last\n    Kicker.startup_chain.should.include callback\n  end\nend\n"
  },
  {
    "path": "spec/recipes/ignore_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\nrecipe :ignore\n\nIGNORE = Kicker.pre_process_chain.find{|callback| callback == Ignore }\n\ndescribe \"The Ignore handler\" do\n  it \"should remove files that match the given regexp\" do\n    ignore(/^fo{2}bar/)\n\n    files = %w{ Rakefile foobar foobarbaz }\n    IGNORE.call(files)\n    files.should == %w{ Rakefile }\n  end\n\n  it \"should remove files that match the given string\" do\n    ignore('bazbla')\n\n    files = %w{ Rakefile bazbla bazblabla }\n    IGNORE.call(files)\n    files.should == %w{ Rakefile bazblabla }\n  end\n\n  it \"should ignore a few file types by default\" do\n    files = %w{ Rakefile foo/bar/dev.log .svn/foo svn-commit.tmp .git/foo tmp }\n    IGNORE.call(files)\n    files.should == %w{ Rakefile }\n  end\nend\n"
  },
  {
    "path": "spec/recipes/jstest_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\n\nbefore = Kicker.process_chain.dup\nrecipe :jstest\nJSTEST = (Kicker.process_chain - before).first\n\ndescribe \"The HeadlessSquirrel handler\" do\n  before do\n    @files = %w{ Rakefile }\n  end\n\n  it \"should match any test case files\" do\n    @files += %w{ test/javascripts/ui_test.html test/javascripts/admin_test.js }\n\n    Kicker::Utils.expects(:execute).\n      with(\"jstest test/javascripts/ui_test.html test/javascripts/admin_test.html\")\n\n    JSTEST.call(@files)\n    @files.should == %w{ Rakefile }\n  end\n\n  it \"should map public/javascripts libs to test/javascripts\" do\n    @files += %w{ public/javascripts/ui.js public/javascripts/admin.js }\n\n    Kicker::Utils.expects(:execute).\n      with(\"jstest test/javascripts/ui_test.html test/javascripts/admin_test.html\")\n\n    JSTEST.call(@files)\n    @files.should == %w{ Rakefile }\n  end\nend\n"
  },
  {
    "path": "spec/recipes/rails_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\nrecipe :rails\n\nclass Kicker::Recipes::Rails\n  class << self\n    attr_accessor :tests_ran\n    def run_tests(tests)\n      self.tests_ran ||= []\n      self.tests_ran << tests\n    end\n  end\nend\n\ndescribe \"The Rails handler\" do\n  it \"should return all controller tests when test_type is `test'\" do\n    tests = %w{ test.rb }\n\n    File.use_original_exist = false\n    File.existing_files = tests\n\n    Kicker::Recipes::Ruby.test_type = 'test'\n    Kicker::Recipes::Ruby.test_cases_root = nil\n\n    Dir.expects(:glob).with(\"test/functional/**/*_test.rb\").returns(tests)\n    Kicker::Recipes::Rails.all_controller_tests.should == tests\n  end\n\n  it \"should return all controller tests when test_type is `spec'\" do\n    specs = %w{ spec.rb }\n\n    File.use_original_exist = false\n    File.existing_files = specs\n\n    Kicker::Recipes::Ruby.test_type = 'spec'\n    Kicker::Recipes::Ruby.test_cases_root = nil\n\n    Dir.expects(:glob).with(\"spec/controllers/**/*_spec.rb\").returns(specs)\n    Kicker::Recipes::Rails.all_controller_tests.should == specs\n  end\nend\n\ndescribe \"The Rails schema handler\" do\n  before do\n    # We assume the Rails schema handler is in the chain after the Rails handler\n    # because it's defined in the same recipe\n    @handler = Kicker.process_chain[Kicker.process_chain.index(Kicker::Recipes::Rails) + 1]\n  end\n\n  it \"should prepare the test database if db/schema.rb is modified\" do\n    Kicker::Utils.expects(:execute).with('rake db:test:prepare')\n    @handler.call(%w{ db/schema.rb })\n  end\n\n  it \"should not prepare the test database if another file than db/schema.rb is modified\" do\n    Kicker::Utils.expects(:execute).never\n    @handler.call(%w{ Rakefile })\n  end\nend\n\nmodule SharedRailsHandlerHelper\n  def should_match(files, tests, existing_files=nil)\n    File.use_original_exist = false\n    File.existing_files = existing_files || tests\n    @files += files\n    Kicker::Recipes::Rails.call(@files)\n    @files.should == %w{ Rakefile }\n  end\nend\n\ndescribe \"An instance of the Rails handler, with test type `test'\" do\n  extend SharedRailsHandlerHelper\n\n  before do\n    Kicker::Recipes::Ruby.reset!\n    @files = %w{ Rakefile }\n  end\n\n  after do\n    File.use_original_exist = true\n  end\n\n  it \"should map model files to test/unit\" do\n    should_match %w{ app/models/member.rb     app/models/article.rb },\n                 %w{ test/unit/member_test.rb test/unit/article_test.rb }\n  end\n\n  it \"should map concern files to test/unit/concerns\" do\n    should_match %w{ app/concerns/authenticate.rb            app/concerns/nested_resource.rb },\n                 %w{ test/unit/concerns/authenticate_test.rb test/unit/concerns/nested_resource_test.rb }\n  end\n\n  it \"should map helper files to test/unit/helpers\" do\n    should_match %w{ app/helpers/members_helper.rb             app/helpers/articles_helper.rb },\n                 %w{ test/unit/helpers/members_helper_test.rb  test/unit/helpers/articles_helper_test.rb }\n  end\n\n  it \"should map controller files to test/functional\" do\n    should_match %w{ app/controllers/application_controller.rb      app/controllers/members_controller.rb },\n                 %w{ test/functional/application_controller_test.rb test/functional/members_controller_test.rb }\n  end\n\n  it \"should map view templates to test/functional\" do\n    should_match %w{ app/views/members/index.html.erb           app/views/admin/articles/show.html.erb },\n                 %w{ test/functional/members_controller_test.rb test/functional/admin/articles_controller_test.rb }\n  end\n\n  it \"should run all functional tests when config/routes.rb is saved\" do\n    tests = %w{ test/functional/members_controller_test.rb test/functional/admin/articles_controller_test.rb }\n    Kicker::Recipes::Rails.expects(:all_controller_tests).returns(tests)\n    should_match %w{ config/routes.rb }, tests\n  end\n\n  it \"should map lib files to test/lib\" do\n    should_match %w{ lib/money.rb           lib/views/date.rb },\n                 %w{ test/lib/money_test.rb test/lib/views/date_test.rb }\n  end\n\n  it \"should map fixtures to their unit, helper and functional tests if they exist\" do\n    tests = %w{ test/unit/member_test.rb test/unit/helpers/members_helper_test.rb test/functional/members_controller_test.rb }\n    should_match %w{ test/fixtures/members.yml }, tests, []\n    Kicker::Recipes::Rails.tests_ran.last.should == []\n  end\n\n  it \"should map fixtures to their unit, helper and functional tests if they exist\" do\n    tests = %w{ test/unit/member_test.rb test/unit/helpers/members_helper_test.rb test/functional/members_controller_test.rb }\n    should_match %w{ test/fixtures/members.yml }, tests\n    Kicker::Recipes::Rails.tests_ran.last.should == tests\n  end\nend\n\ndescribe \"An instance of the Rails handler, with test type `spec'\" do\n  extend SharedRailsHandlerHelper\n\n  before do\n    Kicker::Recipes::Ruby.reset!\n    Kicker::Recipes::Ruby.test_type = 'spec'\n    @files = %w{ Rakefile }\n  end\n\n  after do\n    File.use_original_exist = true\n  end\n\n  it \"should map model files to spec/models\" do\n    should_match %w{ app/models/member.rb       app/models/article.rb },\n                 %w{ spec/models/member_spec.rb spec/models/article_spec.rb }\n  end\n\n  it \"should map concern files to spec/models/concerns\" do\n    should_match %w{ app/concerns/authenticate.rb              app/concerns/nested_resource.rb },\n                 %w{ spec/models/concerns/authenticate_spec.rb spec/models/concerns/nested_resource_spec.rb }\n  end\n\n  it \"should map helper files to spec/helpers\" do\n    should_match %w{ app/helpers/members_helper.rb       app/helpers/articles_helper.rb },\n                 %w{ spec/helpers/members_helper_spec.rb spec/helpers/articles_helper_spec.rb }\n  end\n\n  it \"should map controller files to spec/controllers\" do\n    should_match %w{ app/controllers/application_controller.rb       app/controllers/members_controller.rb },\n                 %w{ spec/controllers/application_controller_spec.rb spec/controllers/members_controller_spec.rb }\n  end\n\n  it \"should map view templates to spec/controllers\" do\n    should_match %w{ app/views/members/index.html.erb            app/views/admin/articles/show.html.erb },\n                 %w{ spec/controllers/members_controller_spec.rb spec/controllers/admin/articles_controller_spec.rb }\n  end\n\n  it \"should run all controller tests when config/routes.rb is saved\" do\n    specs = %w{ spec/controllers/members_controller_test.rb spec/controllers/admin/articles_controller_test.rb }\n    Kicker::Recipes::Rails.expects(:all_controller_tests).returns(specs)\n    should_match %w{ config/routes.rb }, specs\n  end\n\n  it \"should map lib files to spec/lib\" do\n    should_match %w{ lib/money.rb           lib/views/date.rb },\n                 %w{ spec/lib/money_spec.rb spec/lib/views/date_spec.rb }\n  end\n\n  it \"should map fixtures to their model, helper and controller specs\" do\n    specs = %w{ spec/models/member_spec.rb spec/helpers/members_helper_spec.rb spec/controllers/members_controller_spec.rb }\n    should_match %w{ spec/fixtures/members.yml }, specs\n  end\n\n  it \"should map fixtures to their model, helper and controller specs if they exist\" do\n    specs = %w{ spec/models/member_spec.rb spec/helpers/members_helper_spec.rb spec/controllers/members_controller_spec.rb }\n    should_match %w{ spec/fixtures/members.yml }, specs\n  end\nend\n"
  },
  {
    "path": "spec/recipes/ruby_spec.rb",
    "content": "require File.expand_path('../../spec_helper', __FILE__)\nrecipe :ruby\n\nclass Kicker::Recipes::Ruby\n  class << self\n    attr_accessor :executed\n    attr_accessor :blocks\n    def execute(command, &block)\n      self.executed ||= []\n      self.blocks ||= []\n\n      self.executed << command\n      self.blocks << block\n    end\n  end\nend\n\ndescribe \"The Ruby handler\" do\n  before do\n    @handler = Kicker::Recipes::Ruby\n    @handler.reset!\n    @handler.test_type = 'test'\n  end\n\n  after do\n    File.use_original_exist = true\n  end\n\n  it \"should instantiate a handler instance when called\" do\n    tests = %w{ test/1_test.rb Rakefile test/namespace/2_test.rb }\n    instance = @handler.new(tests)\n    @handler.expects(:new).with(tests).returns(instance)\n    @handler.call(tests)\n  end\n\n  it \"should discover whether to use `ruby' or `spec' as the test_type\" do\n    File.use_original_exist = false\n\n    File.existing_files = []\n    @handler.test_type.should == 'test'\n\n    @handler.reset!\n\n    File.existing_files = ['spec']\n    @handler.test_type.should == 'spec'\n  end\n\n  it \"should run the given tests with a test-unit runner\" do\n    @handler.run_tests(%w{ test/1_test.rb test/namespace/2_test.rb })\n    @handler.executed.last.should == \"ruby -I. -r test/1_test -r test/namespace/2_test -e ''\"\n  end\n\n  it \"should run the given tests with a spec runner\" do\n    @handler.test_type = 'spec'\n    @handler.run_tests(%w{ test/1_test.rb test/namespace/2_test.rb })\n    @handler.executed.last.should == \"rspec test/1_test.rb test/namespace/2_test.rb\"\n  end\n\n  it \"should not try to run the tests if none were given\" do\n    @handler.executed = []\n    @handler.run_tests([])\n    @handler.executed.should.be.empty\n  end\n\n  it \"should be possible to override the bin path\" do\n    @handler.runner_bin = '/some/other/runner'\n    @handler.run_tests(%w{ test/1_test.rb test/namespace/2_test.rb })\n    @handler.executed.last.should == \"/some/other/runner -I. -r test/1_test -r test/namespace/2_test -e ''\"\n  end\n\n  it \"should set the alternative ruby bin path\" do\n    Kicker::Options.parse(%w{ -b /opt/ruby-1.9.2/bin/ruby })\n    @handler.runner_bin.should == '/opt/ruby-1.9.2/bin/ruby'\n\n    @handler.reset!\n\n    Kicker::Options.parse(%w{ --ruby /opt/ruby-1.9.2/bin/ruby })\n    @handler.runner_bin.should == '/opt/ruby-1.9.2/bin/ruby'\n  end\n\n  it \"should be possible to add runner options when test_type is `test'\" do\n    @handler.test_type = 'test'\n    @handler.test_options << '-I ./other'\n    @handler.run_tests(%w{ test/1_test.rb })\n    @handler.executed.last.should == \"ruby -I. -I ./other -r test/1_test -e ''\"\n  end\n\n  it \"should be possible to add runner options when test_type is `spec'\" do\n    @handler.test_type = 'spec'\n    @handler.test_options << '-I ./other'\n    @handler.run_tests(%w{ spec/1_spec.rb })\n    @handler.executed.last.should == \"rspec -I ./other spec/1_spec.rb\"\n  end\nend\n\n%w{ test spec }.each do |type|\n  describe \"An instance of the Ruby handler, with test type `#{type}'\" do\n    before do\n      @handler = Kicker::Recipes::Ruby\n      @test_type, @test_cases_root = @handler.test_type, @handler.test_cases_root\n      @handler.test_type = type\n      @handler.test_cases_root = type\n\n      File.use_original_exist = false\n      File.existing_files = %W(#{type}/1_#{type}.rb #{type}/namespace/2_#{type}.rb)\n    end\n\n    after do\n      @handler.test_type, @handler.test_cases_root = @test_type, @test_cases_root\n      File.use_original_exist = true\n    end\n\n    it \"should match any test case files\" do\n      files = %w(Rakefile) + File.existing_files\n      handler = @handler.new(files)\n      handler.handle!\n\n      handler.tests.should == File.existing_files\n      files.should == %W{ Rakefile }\n    end\n\n    it \"should match files in ./lib\" do\n      files = %w(Rakefile) + File.existing_files\n      handler = @handler.new(files)\n      handler.handle!\n\n      handler.tests.should == File.existing_files\n      files.should == %w{ Rakefile }\n    end\n\n    it \"should match lib tests in the test root as well\" do\n      File.existing_files = %W(#{type}/1_#{type}.rb #{type}/2_#{type}.rb)\n\n      files = %W{ Rakefile lib/1.rb lib/namespace/2.rb }\n      handler = @handler.new(files)\n      handler.handle!\n\n      handler.tests.should == %W{ #{type}/1_#{type}.rb #{type}/2_#{type}.rb }\n      files.should == %W{ Rakefile }\n    end\n\n    it \"should check if a different test case root\" do\n      @handler.test_cases_root = 'test/cases'\n\n      files = %W{ Rakefile test/cases/1_#{type}.rb test/cases/namespace/2_#{type}.rb }\n      handler = @handler.new(files)\n      handler.handle!\n\n      handler.tests.should == %W{ test/cases/1_#{type}.rb test/cases/namespace/2_#{type}.rb }\n      files.should == %W{ Rakefile }\n    end\n  end\nend\n\ndescribe \"The Ruby Bundler handler\" do\n  before do\n    # We assume the Ruby Bundler handler is in the chain after the Ruby handler\n    # because it's defined in the same recipe\n    @handler = Kicker.process_chain[Kicker.process_chain.index(Kicker::Recipes::Ruby) + 1]\n  end\n\n  it \"runs `bundle install` whenever the Gemfile changes\" do\n    Kicker::Utils.expects(:execute).with('bundle install')\n    @handler.call(%w{ Gemfile })\n  end\n\n  it \"does not run `bundle install` when another file is changed\" do\n    Kicker::Utils.expects(:execute).never\n    @handler.call(%w{ Rakefile })\n  end\nend\n"
  },
  {
    "path": "spec/recipes_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\nrequire 'fakefs/safe'\n\nmodule ReloadDotKick; end\n\ndescribe \"Kicker::Recipes\" do\n  RECIPES_PATH = Pathname.new('../../lib/kicker/recipes/').expand_path(__FILE__)\n\n  def recipe_files\n    Kicker::Recipes.recipe_files\n  end\n\n  before do\n    Kicker::Recipes.reset!\n  end\n\n  before do\n    FakeFS.activate!\n    FakeFS::FileSystem.clone(RECIPES_PATH)\n    Dir.chdir(File.absolute_path('../../', __FILE__))\n  end\n\n  after do\n    FakeFS.deactivate!\n    FakeFS::FileSystem.clear\n  end\n\n  it \"returns a list of recipes\" do\n    Pathname.glob(RECIPES_PATH.join('**/*.rb')) do |path|\n      recipe_files.should.include?(path.expand_path)\n    end\n  end\n\n  it \"loads local recipes\" do\n    local = Pathname.new('~/.kick').expand_path\n    local.mkpath\n    recipe = local.join('some-random-recipe.rb')\n    FileUtils.touch(recipe)\n\n    recipe_files.should.include?(recipe.expand_path)\n  end\n\n  it \"loads recipes in current working dir\" do\n    pwd = Pathname.pwd.join('.kick')\n    pwd.mkpath\n    recipe = pwd.expand_path.join('cwd-recipe.rb')\n    FileUtils.touch(recipe)\n\n    recipe_files.should.include(recipe.expand_path)\n  end\n\n  it \"returns a list of recipe names\" do\n    expected = Set.new(%w(could_not_handle_file dot_kick execute_cli_command ignore jstest rails ruby).map { |n| n.to_sym })\n    actual = Set.new(Kicker::Recipes.recipe_names)\n    actual.should == expected\n  end\n\n  # TODO ~/.kick is no longer added to the load path, but files are looked up\n  # in lib/kicker/recipes.rb recipe_filename\n  #\n  #if File.exist?(File.expand_path('~/.kick'))\n    #it \"should add ~/.kick to the load path\" do\n      #$:.should.include File.expand_path('~/.kick')\n    #end\n  #else\n    #puts \"[!] ~/.kick does not exist, not testing the Kicker directory support.\"\n  #end\n\n  it \"should load a recipe\" do\n    should.not.raise { recipe :ruby }\n  end\n\n  it \"does not break when a recipe is loaded twice\" do\n    should.not.raise do\n      recipe :ruby\n      recipe :ruby\n    end\n  end\n\n  it \"should define a recipe load callback\" do\n    called = false\n    recipe('new_recipe') { called = true }\n    called.should == false\n    recipe(:new_recipe)\n    called.should == true\n  end\n\n  it \"should raise if a recipe does not exist\" do\n    begin\n      recipe :foobar\n    rescue LoadError => e\n      e.message.should.start_with \"Can't load recipe `foobar', it doesn't exist on disk.\"\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "require 'bacon'\nrequire 'mocha-on-bacon'\n\nBacon.summary_at_exit\n\nrequire 'set'\n\n$:.unshift File.expand_path('../../lib', __FILE__)\nrequire 'kicker'\n\nclass File\n  class << self\n    attr_accessor :existing_files\n    attr_accessor :use_original_exist\n\n    alias exist_without_stubbing? exist?\n    def exist?(file)\n      if use_original_exist\n        exist_without_stubbing?(file)\n      else\n        if existing_files\n          existing_files.include?(file)\n        else\n          raise \"Please stub the files you want to exist by setting File.existing_files\"\n        end\n      end\n    end\n  end\nend\n\nFile.use_original_exist = true\n"
  },
  {
    "path": "spec/utils_spec.rb",
    "content": "require File.expand_path('../spec_helper', __FILE__)\n\nclass Kicker\n  module Utils\n    public :will_execute_command, :did_execute_command\n  end\nend\n\ndescribe \"A Kicker instance, concerning its utility methods\" do\n  def utils\n    Kicker::Utils\n  end\n\n  before do\n    utils.stubs(:puts)\n    Kicker::Notification.use = false\n    Kicker::Notification.stubs(:`)\n  end\n\n  after do\n    Kicker.silent = false\n    Kicker::Notification.use = true\n  end\n\n  it \"should print a log entry with timestamp\" do\n    now = Time.now\n    Time.stubs(:now).returns(now)\n\n    utils.expects(:puts).with(\"#{now.strftime('%H:%M:%S')}.#{now.usec.to_s[0,2]} | the message\")\n    utils.send(:log, 'the message')\n  end\n\n  it 'should print a log entry with no timestamp in quiet mode' do\n    before = Kicker.quiet\n\n    utils.expects(:puts).with('the message')\n\n    Kicker.quiet = true\n    utils.send(:log, 'the message')\n\n    Kicker.quiet = before\n  end\n\n  it \"logs that the command succeeded\" do\n    utils.stubs(:_execute).with do |job|\n      job.output = \"line 1\\nline 2\"\n      job.exit_code = 0\n    end\n    utils.expects(:log).with('Executing: ls')\n    utils.expects(:log).with('Success')\n    utils.execute('ls')\n  end\n\n  it \"logs that the command failed\" do\n    utils.stubs(:_execute).with do |job|\n      job.output = \"line 1\\nline 2\"\n      job.exit_code = 123\n    end\n    utils.expects(:log).with('Executing: ls')\n    utils.expects(:log).with('Failed (123)')\n    utils.execute('ls')\n  end\n\n  it \"calls the block given to execute and yields the job so the user can transform the output\" do\n    Kicker.silent = true\n\n    utils.stubs(:_execute).with do |job|\n      job.output = \"line 1\\nline 2\"\n      job.exit_code = 123\n    end\n\n    utils.expects(:log).with('Executing: ls -l')\n    utils.expects(:puts).with(\"\\nOhnoes!\\n\\n\")\n    utils.expects(:log).with('Failed (123)')\n\n    utils.execute('ls -l') do |job|\n      job.output = job.success? ? 'Done!' : 'Ohnoes!'\n    end\n  end\n\n  before do\n    Kicker::Notification.use = true\n  end\n\n  it \"notifies that a change occurred and shows the command and then the output\" do\n    utils.stubs(:log)\n    utils.stubs(:_execute).with do |job|\n      job.output = \"line 1\\nline 2\"\n    end\n    Kicker::Notification.expects(:notify).with(:title => 'Kicker: Executing', :message => \"ls\")\n    Kicker::Notification.expects(:notify).with(:title => 'Kicker: Success', :message => \"line 1\\nline 2\")\n    utils.execute('ls')\n  end\n\n  it \"does not notify that a change occured in silent mode\" do\n    Kicker.silent = true\n    utils.stubs(:did_execute_command)\n\n    utils.expects(:log)\n    Kicker::Notification.expects(:change_occured).never\n    utils.execute('ls')\n  end\n\n  it \"only logs that it has succeeded in silent mode\" do\n    Kicker.silent = true\n    Kicker::Notification.expects(:notify).with(:title => \"Kicker: Success\", :message => \"\")\n\n    job = Kicker::Job.new(:command => 'ls -l', :exit_code => 0, :output => \"line 1\\nline 2\")\n\n    utils.expects(:log).with(\"Success\")\n    utils.did_execute_command(job)\n  end\n\n  it \"fully logs that it has failed in silent mode\" do\n    Kicker.silent = true\n    Kicker::Notification.expects(:notify).with(:title => \"Kicker: Failed (123)\", :message => \"\")\n\n    utils.expects(:puts).with(\"\\nline 1\\nline 2\\n\\n\")\n    utils.expects(:log).with('Failed (123)')\n\n    job = Kicker::Job.new(:command => 'ls -l', :exit_code => 123, :output => \"line 1\\nline 2\")\n    utils.did_execute_command(job)\n  end\nend\n\ndescribe \"Kernel utility methods\" do\n  def utils\n    Kicker::Utils\n  end\n\n  it \"should forward log calls to the Kicker::Utils module\" do\n    utils.expects(:log).with('the message')\n    log 'the message'\n  end\n\n  it \"should forward execute calls to the Kicker::Utils module\" do\n    utils.expects(:execute).with('ls')\n    execute 'ls'\n  end\nend\n"
  }
]