guard 0.8.4 → 0.8.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,60 +1,150 @@
1
- require 'guard/dsl'
2
-
3
- module Guard
4
-
5
- # The DslDescriber overrides methods to create an internal structure
6
- # of the Guardfile that is used in some inspection utility methods
7
- # like the CLI commands `show` and `list`.
8
- #
9
- # @see Guard::Dsl
10
- # @see Guard::CLI
11
- #
12
- class DslDescriber < Dsl
13
-
14
- @@guardfile_structure = [ { :guards => [] } ]
15
-
16
- class << self
17
-
18
- # Get the Guardfile structure.
19
- #
20
- # @return [Array<Hash>] the structure
21
- #
22
- def guardfile_structure
23
- @@guardfile_structure
24
- end
25
- end
26
-
27
- private
28
-
29
- # Declares a group of guards.
30
- #
31
- # @param [String] name the group's name called from the CLI
32
- # @yield a block where you can declare several guards
33
- #
34
- # @see Guard::Dsl#group
35
- #
36
- def group(name)
37
- @@guardfile_structure << { :group => name.to_sym, :guards => [] }
38
- @group = true
39
-
40
- yield if block_given?
41
-
42
- @group = false
43
- end
44
-
45
- # Declares a Guard.
46
- #
47
- # @param [String] name the Guard name
48
- # @param [Hash] options the options accepted by the Guard
49
- # @yield a block where you can declare several watch patterns and actions
50
- #
51
- # @see Guard::Dsl#guard
52
- #
53
- def guard(name, options = {})
54
- node = (@group ? @@guardfile_structure.last : @@guardfile_structure.first)
55
-
56
- node[:guards] << { :name => name, :options => options }
57
- end
58
-
59
- end
60
- end
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
- # Main class that every Guard implementation must subclass.
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 ignored, but
10
- # you can throw `:task_has_failed` to indicate that your Guard method was
11
- # not successful. When `:task_has_failed` is thrown, successive guard tasks
12
- # can be aborted when the group has set the `:halt_on_fail` option.
13
- #
14
- # @see Guard::Group
15
- #
16
- # @example Throw :task_has_failed
17
- #
18
- # def run_all
19
- # if !runner.run(['all'])
20
- # throw :task_has_failed
21
- # end
22
- # end
23
- #
24
- # Each Guard should provide a template Guardfile located within the Gem
25
- # at `lib/guard/guard-name/templates/Guardfile`.
26
- #
27
- # If one of those methods raise an exception other than `:task_has_failed`,
28
- # the Guard::GuardName instance will be removed from the active guards.
29
- #
30
- class Guard
31
- include Hook
32
-
33
- attr_accessor :watchers, :options, :group
34
-
35
- # Initialize a Guard.
36
- #
37
- # @param [Array<Guard::Watcher>] watchers the Guard file watchers
38
- # @param [Hash] options the custom Guard options
39
- #
40
- def initialize(watchers = [], options = {})
41
- @group = options[:group] ? options.delete(:group).to_sym : :default
42
- @watchers, @options = watchers, options
43
- end
44
-
45
- # Initialize the Guard. This will copy the Guardfile template inside the Guard gem.
46
- # The template Guardfile must be located within the Gem at `lib/guard/guard-name/templates/Guardfile`.
47
- #
48
- # @param [String] name the name of the Guard
49
- #
50
- def self.init(name)
51
- if ::Guard::Dsl.guardfile_include?(name)
52
- ::Guard::UI.info "Guardfile already includes #{ name } guard"
53
- else
54
- content = File.read('Guardfile')
55
- guard = File.read("#{ ::Guard.locate_guard(name) }/lib/guard/#{ name }/templates/Guardfile")
56
- File.open('Guardfile', 'wb') do |f|
57
- f.puts(content)
58
- f.puts("")
59
- f.puts(guard)
60
- end
61
- ::Guard::UI.info "#{name} guard added to Guardfile, feel free to edit it"
62
- end
63
- end
64
-
65
- # Call once when Guard starts. Please override initialize method to init stuff.
66
- #
67
- # @raise [:task_has_failed] when start has failed
68
- #
69
- def start
70
- end
71
-
72
- # Called when `stop|quit|exit|s|q|e + enter` is pressed (when Guard quits).
73
- #
74
- # @raise [:task_has_failed] when stop has failed
75
- #
76
- def stop
77
- end
78
-
79
- # Called when `reload|r|z + enter` is pressed.
80
- # This method should be mainly used for "reload" (really!) actions like reloading passenger/spork/bundler/...
81
- #
82
- # @raise [:task_has_failed] when reload has failed
83
- #
84
- def reload
85
- end
86
-
87
- # Called when just `enter` is pressed
88
- # This method should be principally used for long action like running all specs/tests/...
89
- #
90
- # @raise [:task_has_failed] when run_all has failed
91
- #
92
- def run_all
93
- end
94
-
95
- # Called on file(s) modifications that the Guard watches.
96
- #
97
- # @param [Array<String>] paths the changes files or paths
98
- # @raise [:task_has_failed] when run_on_change has failed
99
- #
100
- def run_on_change(paths)
101
- end
102
-
103
- # Called on file(s) deletions that the Guard watches.
104
- #
105
- # @param [Array<String>] paths the deleted files or paths
106
- # @raise [:task_has_failed] when run_on_change has failed
107
- #
108
- def run_on_deletion(paths)
109
- end
110
-
111
- end
112
-
113
- end
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