guard 0.8.4 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.md +348 -330
- data/LICENSE +19 -19
- data/README.md +464 -431
- data/bin/guard +6 -6
- data/lib/guard.rb +452 -414
- data/lib/guard/cli.rb +119 -178
- data/lib/guard/dsl.rb +370 -370
- data/lib/guard/dsl_describer.rb +150 -60
- data/lib/guard/group.rb +37 -37
- data/lib/guard/guard.rb +129 -113
- data/lib/guard/hook.rb +118 -118
- data/lib/guard/interactor.rb +110 -44
- data/lib/guard/listener.rb +350 -350
- data/lib/guard/listeners/darwin.rb +66 -66
- data/lib/guard/listeners/linux.rb +97 -97
- data/lib/guard/listeners/polling.rb +55 -55
- data/lib/guard/listeners/windows.rb +61 -61
- data/lib/guard/notifier.rb +290 -211
- data/lib/guard/templates/Guardfile +2 -2
- data/lib/guard/ui.rb +193 -188
- data/lib/guard/version.rb +6 -6
- data/lib/guard/watcher.rb +114 -110
- data/man/guard.1 +93 -93
- data/man/guard.1.html +176 -176
- metadata +107 -59
data/lib/guard/dsl_describer.rb
CHANGED
@@ -1,60 +1,150 @@
|
|
1
|
-
require 'guard/dsl'
|
2
|
-
|
3
|
-
module Guard
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
class << self
|
17
|
-
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# @
|
21
|
-
#
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
1
|
+
require 'guard/dsl'
|
2
|
+
|
3
|
+
module Guard
|
4
|
+
|
5
|
+
autoload :UI, 'guard/ui'
|
6
|
+
|
7
|
+
# The DslDescriber overrides methods to create an internal structure
|
8
|
+
# of the Guardfile that is used in some inspection utility methods
|
9
|
+
# like the CLI commands `show` and `list`.
|
10
|
+
#
|
11
|
+
# @see Guard::Dsl
|
12
|
+
# @see Guard::CLI
|
13
|
+
#
|
14
|
+
class DslDescriber < Dsl
|
15
|
+
|
16
|
+
class << self
|
17
|
+
|
18
|
+
# Evaluate the DSL methods in the `Guardfile`.
|
19
|
+
#
|
20
|
+
# @option options [Array<Symbol,String>] groups the groups to evaluate
|
21
|
+
# @option options [String] guardfile the path to a valid Guardfile
|
22
|
+
# @option options [String] guardfile_contents a string representing the content of a valid Guardfile
|
23
|
+
# @raise [ArgumentError] when options are not a Hash
|
24
|
+
#
|
25
|
+
def evaluate_guardfile(options = {})
|
26
|
+
@@guardfile_structure = [{ :guards => [] }]
|
27
|
+
super options
|
28
|
+
end
|
29
|
+
|
30
|
+
# List the Guards that are available for use in your system and marks
|
31
|
+
# those that are currently used in your `Guardfile`.
|
32
|
+
#
|
33
|
+
# @example Guard list output
|
34
|
+
#
|
35
|
+
# Available guards:
|
36
|
+
# bundler *
|
37
|
+
# livereload
|
38
|
+
# ronn
|
39
|
+
# rspec *
|
40
|
+
# spork
|
41
|
+
#
|
42
|
+
# See also https://github.com/guard/guard/wiki/List-of-available-Guards
|
43
|
+
# * denotes ones already in your Guardfile
|
44
|
+
#
|
45
|
+
# @param [Hash] options the Guard options
|
46
|
+
#
|
47
|
+
def list(options)
|
48
|
+
evaluate_guardfile(options)
|
49
|
+
|
50
|
+
installed = guardfile_structure.inject([]) do |installed, group|
|
51
|
+
group[:guards].each { |guard| installed << guard[:name] } if group[:guards]
|
52
|
+
installed
|
53
|
+
end
|
54
|
+
|
55
|
+
UI.info 'Available guards:'
|
56
|
+
|
57
|
+
::Guard.guard_gem_names.sort.uniq.each do |name|
|
58
|
+
UI.info " #{ name }#{ installed.include?(name) ? '*' : '' }"
|
59
|
+
end
|
60
|
+
|
61
|
+
UI.info ''
|
62
|
+
UI.info 'See also https://github.com/guard/guard/wiki/List-of-available-Guards'
|
63
|
+
UI.info '* denotes ones already in your Guardfile'
|
64
|
+
end
|
65
|
+
|
66
|
+
# Shows all Guards and their options that are defined in
|
67
|
+
# the `Guardfile`.
|
68
|
+
#
|
69
|
+
# @example guard show output
|
70
|
+
#
|
71
|
+
# (global):
|
72
|
+
# bundler
|
73
|
+
# coffeescript: input => "app/assets/javascripts", noop => true
|
74
|
+
# jasmine
|
75
|
+
# rspec: cli => "--fail-fast --format Fuubar
|
76
|
+
#
|
77
|
+
# @param [Hash] options the Guard options
|
78
|
+
#
|
79
|
+
def show(options)
|
80
|
+
evaluate_guardfile(options)
|
81
|
+
|
82
|
+
guardfile_structure.each do |group|
|
83
|
+
unless group[:guards].empty?
|
84
|
+
if group[:group]
|
85
|
+
UI.info "Group #{ group[:group] }:"
|
86
|
+
else
|
87
|
+
UI.info '(global):'
|
88
|
+
end
|
89
|
+
|
90
|
+
group[:guards].each do |guard|
|
91
|
+
line = " #{ guard[:name] }"
|
92
|
+
|
93
|
+
unless guard[:options].empty?
|
94
|
+
line += ": #{ guard[:options].sort.collect { |k, v| "#{ k } => #{ v.inspect }" }.join(', ') }"
|
95
|
+
end
|
96
|
+
|
97
|
+
UI.info line
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
UI.info ''
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
|
107
|
+
# Get the Guardfile structure.
|
108
|
+
#
|
109
|
+
# @return [Array<Hash>] the structure
|
110
|
+
#
|
111
|
+
def guardfile_structure
|
112
|
+
@@guardfile_structure
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
# Declares a group of guards.
|
120
|
+
#
|
121
|
+
# @param [String] name the group's name called from the CLI
|
122
|
+
# @yield a block where you can declare several guards
|
123
|
+
#
|
124
|
+
# @see Guard::Dsl#group
|
125
|
+
#
|
126
|
+
def group(name)
|
127
|
+
@@guardfile_structure << { :group => name.to_sym, :guards => [] }
|
128
|
+
@group = true
|
129
|
+
|
130
|
+
yield if block_given?
|
131
|
+
|
132
|
+
@group = false
|
133
|
+
end
|
134
|
+
|
135
|
+
# Declares a Guard.
|
136
|
+
#
|
137
|
+
# @param [String] name the Guard name
|
138
|
+
# @param [Hash] options the options accepted by the Guard
|
139
|
+
# @yield a block where you can declare several watch patterns and actions
|
140
|
+
#
|
141
|
+
# @see Guard::Dsl#guard
|
142
|
+
#
|
143
|
+
def guard(name, options = { })
|
144
|
+
node = (@group ? @@guardfile_structure.last : @@guardfile_structure.first)
|
145
|
+
|
146
|
+
node[:guards] << { :name => name, :options => options }
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
data/lib/guard/group.rb
CHANGED
@@ -1,37 +1,37 @@
|
|
1
|
-
module Guard
|
2
|
-
|
3
|
-
# A group of Guards. There are two reasons why you want to group your guards:
|
4
|
-
#
|
5
|
-
# - You can start only certain Groups from the command line by passing the `--group` option.
|
6
|
-
# - Abort task execution chain on failure within a group.
|
7
|
-
#
|
8
|
-
# @example Group that aborts on failure
|
9
|
-
#
|
10
|
-
# group :frontend, :halt_on_fail => true do
|
11
|
-
# guard 'coffeescript', :input => 'spec/coffeescripts', :output => 'spec/javascripts'
|
12
|
-
# guard 'jasmine-headless-webkit' do
|
13
|
-
# watch(%r{^spec/javascripts/(.*)\..*}) { |m| newest_js_file("spec/javascripts/#{m[1]}_spec") }
|
14
|
-
# end
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# @see Guard::CLI
|
18
|
-
#
|
19
|
-
class Group
|
20
|
-
|
21
|
-
attr_accessor :name, :options
|
22
|
-
|
23
|
-
# Initialize a Group.
|
24
|
-
#
|
25
|
-
# @param [String] name the name of the group
|
26
|
-
# @param [Hash] options the group options
|
27
|
-
# @option options [Boolean] halt_on_fail if a task execution
|
28
|
-
# should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
29
|
-
#
|
30
|
-
def initialize(name, options = {})
|
31
|
-
@name = name.to_sym
|
32
|
-
@options = options
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|
1
|
+
module Guard
|
2
|
+
|
3
|
+
# A group of Guards. There are two reasons why you want to group your guards:
|
4
|
+
#
|
5
|
+
# - You can start only certain Groups from the command line by passing the `--group` option.
|
6
|
+
# - Abort task execution chain on failure within a group.
|
7
|
+
#
|
8
|
+
# @example Group that aborts on failure
|
9
|
+
#
|
10
|
+
# group :frontend, :halt_on_fail => true do
|
11
|
+
# guard 'coffeescript', :input => 'spec/coffeescripts', :output => 'spec/javascripts'
|
12
|
+
# guard 'jasmine-headless-webkit' do
|
13
|
+
# watch(%r{^spec/javascripts/(.*)\..*}) { |m| newest_js_file("spec/javascripts/#{m[1]}_spec") }
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# @see Guard::CLI
|
18
|
+
#
|
19
|
+
class Group
|
20
|
+
|
21
|
+
attr_accessor :name, :options
|
22
|
+
|
23
|
+
# Initialize a Group.
|
24
|
+
#
|
25
|
+
# @param [String] name the name of the group
|
26
|
+
# @param [Hash] options the group options
|
27
|
+
# @option options [Boolean] halt_on_fail if a task execution
|
28
|
+
# should be halted for all Guards in this group if one Guard throws `:task_has_failed`
|
29
|
+
#
|
30
|
+
def initialize(name, options = {})
|
31
|
+
@name = name.to_sym
|
32
|
+
@options = options
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/lib/guard/guard.rb
CHANGED
@@ -1,113 +1,129 @@
|
|
1
|
-
module Guard
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# Guard will trigger the `start`, `stop`, `reload`, `run_all`, `run_on_change` and
|
6
|
-
# `run_on_deletion` methods depending on user interaction and file modification.
|
7
|
-
#
|
8
|
-
# In each of these Guard methods you have to implement some work when you want to
|
9
|
-
# support this kind of task. The return value of each Guard method is
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# @
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
#
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
#
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
#
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
#
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
#
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
#
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
1
|
+
module Guard
|
2
|
+
|
3
|
+
# Base class that every Guard implementation must inherit from.
|
4
|
+
#
|
5
|
+
# Guard will trigger the `start`, `stop`, `reload`, `run_all`, `run_on_change` and
|
6
|
+
# `run_on_deletion` task methods depending on user interaction and file modification.
|
7
|
+
#
|
8
|
+
# In each of these Guard task methods you have to implement some work when you want to
|
9
|
+
# support this kind of task. The return value of each Guard task method is not evaluated
|
10
|
+
# by Guard, but I'll be passed to the "_end" hook for further evaluation. You can
|
11
|
+
# throw `:task_has_failed` to indicate that your Guard method was not successful,
|
12
|
+
# and successive guard tasks will be aborted when the group has set the `:halt_on_fail`
|
13
|
+
# option.
|
14
|
+
#
|
15
|
+
# @see Guard::Hook
|
16
|
+
# @see Guard::Group
|
17
|
+
#
|
18
|
+
# @example Throw :task_has_failed
|
19
|
+
#
|
20
|
+
# def run_all
|
21
|
+
# if !runner.run(['all'])
|
22
|
+
# throw :task_has_failed
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# Each Guard should provide a template Guardfile located within the Gem
|
27
|
+
# at `lib/guard/guard-name/templates/Guardfile`.
|
28
|
+
#
|
29
|
+
# By default all watchers for a Guard are returning strings of paths to the
|
30
|
+
# Guard, but if your Guard want to allow any return value from a watcher,
|
31
|
+
# you can set the `any_return` option to true.
|
32
|
+
#
|
33
|
+
# If one of those methods raise an exception other than `:task_has_failed`,
|
34
|
+
# the Guard::GuardName instance will be removed from the active guards.
|
35
|
+
#
|
36
|
+
class Guard
|
37
|
+
include Hook
|
38
|
+
|
39
|
+
attr_accessor :watchers, :options, :group
|
40
|
+
|
41
|
+
# Initialize a Guard.
|
42
|
+
#
|
43
|
+
# @param [Array<Guard::Watcher>] watchers the Guard file watchers
|
44
|
+
# @param [Hash] options the custom Guard options
|
45
|
+
# @options [Symbol] group the group this Guard belongs to
|
46
|
+
# @options [Boolean] any_return allow any object to be returned from a watcher
|
47
|
+
#
|
48
|
+
def initialize(watchers = [], options = {})
|
49
|
+
@group = options[:group] ? options.delete(:group).to_sym : :default
|
50
|
+
@watchers, @options = watchers, options
|
51
|
+
end
|
52
|
+
|
53
|
+
# Initialize the Guard. This will copy the Guardfile template inside the Guard gem.
|
54
|
+
# The template Guardfile must be located within the Gem at `lib/guard/guard-name/templates/Guardfile`.
|
55
|
+
#
|
56
|
+
# @param [String] name the name of the Guard
|
57
|
+
#
|
58
|
+
def self.init(name)
|
59
|
+
if ::Guard::Dsl.guardfile_include?(name)
|
60
|
+
::Guard::UI.info "Guardfile already includes #{ name } guard"
|
61
|
+
else
|
62
|
+
content = File.read('Guardfile')
|
63
|
+
guard = File.read("#{ ::Guard.locate_guard(name) }/lib/guard/#{ name }/templates/Guardfile")
|
64
|
+
|
65
|
+
File.open('Guardfile', 'wb') do |f|
|
66
|
+
f.puts(content)
|
67
|
+
f.puts("")
|
68
|
+
f.puts(guard)
|
69
|
+
end
|
70
|
+
|
71
|
+
::Guard::UI.info "#{ name } guard added to Guardfile, feel free to edit it"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Call once when Guard starts. Please override initialize method to init stuff.
|
76
|
+
#
|
77
|
+
# @raise [:task_has_failed] when start has failed
|
78
|
+
# @return [Object] the task result
|
79
|
+
#
|
80
|
+
def start
|
81
|
+
end
|
82
|
+
|
83
|
+
# Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits).
|
84
|
+
#
|
85
|
+
# @raise [:task_has_failed] when stop has failed
|
86
|
+
# @return [Object] the task result
|
87
|
+
#
|
88
|
+
def stop
|
89
|
+
end
|
90
|
+
|
91
|
+
# Called when `reload|r|z + enter` is pressed.
|
92
|
+
# This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
|
93
|
+
#
|
94
|
+
# @raise [:task_has_failed] when reload has failed
|
95
|
+
# @return [Object] the task result
|
96
|
+
#
|
97
|
+
def reload
|
98
|
+
end
|
99
|
+
|
100
|
+
# Called when just `enter` is pressed
|
101
|
+
# This method should be principally used for long action like running all specs/tests/...
|
102
|
+
#
|
103
|
+
# @raise [:task_has_failed] when run_all has failed
|
104
|
+
# @return [Object] the task result
|
105
|
+
#
|
106
|
+
def run_all
|
107
|
+
end
|
108
|
+
|
109
|
+
# Called on file(s) modifications that the Guard watches.
|
110
|
+
#
|
111
|
+
# @param [Array<String>] paths the changes files or paths
|
112
|
+
# @raise [:task_has_failed] when run_on_change has failed
|
113
|
+
# @return [Object] the task result
|
114
|
+
#
|
115
|
+
def run_on_change(paths)
|
116
|
+
end
|
117
|
+
|
118
|
+
# Called on file(s) deletions that the Guard watches.
|
119
|
+
#
|
120
|
+
# @param [Array<String>] paths the deleted files or paths
|
121
|
+
# @raise [:task_has_failed] when run_on_change has failed
|
122
|
+
# @return [Object] the task result
|
123
|
+
#
|
124
|
+
def run_on_deletion(paths)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|