joshbuddy-guard 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/CHANGELOG.md +370 -0
  2. data/LICENSE +20 -0
  3. data/README.md +470 -0
  4. data/bin/fsevent_watch_guard +0 -0
  5. data/bin/guard +6 -0
  6. data/images/failed.png +0 -0
  7. data/images/pending.png +0 -0
  8. data/images/success.png +0 -0
  9. data/lib/guard.rb +463 -0
  10. data/lib/guard/cli.rb +125 -0
  11. data/lib/guard/dsl.rb +370 -0
  12. data/lib/guard/dsl_describer.rb +150 -0
  13. data/lib/guard/group.rb +37 -0
  14. data/lib/guard/guard.rb +129 -0
  15. data/lib/guard/hook.rb +118 -0
  16. data/lib/guard/interactor.rb +116 -0
  17. data/lib/guard/listener.rb +351 -0
  18. data/lib/guard/listeners/darwin.rb +60 -0
  19. data/lib/guard/listeners/linux.rb +91 -0
  20. data/lib/guard/listeners/polling.rb +55 -0
  21. data/lib/guard/listeners/windows.rb +61 -0
  22. data/lib/guard/notifier.rb +290 -0
  23. data/lib/guard/templates/Guardfile +2 -0
  24. data/lib/guard/ui.rb +193 -0
  25. data/lib/guard/version.rb +6 -0
  26. data/lib/guard/watcher.rb +114 -0
  27. data/lib/vendor/darwin/Gemfile +6 -0
  28. data/lib/vendor/darwin/Guardfile +8 -0
  29. data/lib/vendor/darwin/LICENSE +20 -0
  30. data/lib/vendor/darwin/README.rdoc +254 -0
  31. data/lib/vendor/darwin/Rakefile +21 -0
  32. data/lib/vendor/darwin/ext/extconf.rb +61 -0
  33. data/lib/vendor/darwin/ext/fsevent/fsevent_watch.c +226 -0
  34. data/lib/vendor/darwin/lib/rb-fsevent.rb +2 -0
  35. data/lib/vendor/darwin/lib/rb-fsevent/fsevent.rb +105 -0
  36. data/lib/vendor/darwin/lib/rb-fsevent/version.rb +3 -0
  37. data/lib/vendor/darwin/rb-fsevent.gemspec +24 -0
  38. data/lib/vendor/darwin/spec/fixtures/folder1/file1.txt +0 -0
  39. data/lib/vendor/darwin/spec/fixtures/folder1/folder2/file2.txt +0 -0
  40. data/lib/vendor/darwin/spec/rb-fsevent/fsevent_spec.rb +75 -0
  41. data/lib/vendor/darwin/spec/spec_helper.rb +24 -0
  42. data/lib/vendor/linux/MIT-LICENSE +20 -0
  43. data/lib/vendor/linux/README.md +66 -0
  44. data/lib/vendor/linux/Rakefile +54 -0
  45. data/lib/vendor/linux/VERSION +1 -0
  46. data/lib/vendor/linux/lib/rb-inotify.rb +17 -0
  47. data/lib/vendor/linux/lib/rb-inotify/event.rb +139 -0
  48. data/lib/vendor/linux/lib/rb-inotify/native.rb +31 -0
  49. data/lib/vendor/linux/lib/rb-inotify/native/flags.rb +89 -0
  50. data/lib/vendor/linux/lib/rb-inotify/notifier.rb +308 -0
  51. data/lib/vendor/linux/lib/rb-inotify/watcher.rb +83 -0
  52. data/lib/vendor/linux/rb-inotify.gemspec +53 -0
  53. data/lib/vendor/windows/Gemfile +4 -0
  54. data/lib/vendor/windows/README.md +34 -0
  55. data/lib/vendor/windows/Rakefile +18 -0
  56. data/lib/vendor/windows/lib/rb-fchange.rb +14 -0
  57. data/lib/vendor/windows/lib/rb-fchange/event.rb +29 -0
  58. data/lib/vendor/windows/lib/rb-fchange/native.rb +45 -0
  59. data/lib/vendor/windows/lib/rb-fchange/native/flags.rb +78 -0
  60. data/lib/vendor/windows/lib/rb-fchange/notifier.rb +149 -0
  61. data/lib/vendor/windows/lib/rb-fchange/version.rb +3 -0
  62. data/lib/vendor/windows/lib/rb-fchange/watcher.rb +99 -0
  63. data/lib/vendor/windows/rb-fchange.gemspec +34 -0
  64. data/lib/vendor/windows/spec/fixtures/folder1/file1.txt +0 -0
  65. data/lib/vendor/windows/spec/fixtures/folder1/folder2/file2.txt +0 -0
  66. data/lib/vendor/windows/spec/rb-fchange/fchange_spec.rb +119 -0
  67. data/lib/vendor/windows/spec/spec_helper.rb +21 -0
  68. data/man/guard.1 +96 -0
  69. data/man/guard.1.html +181 -0
  70. metadata +193 -0
@@ -0,0 +1,150 @@
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
@@ -0,0 +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
@@ -0,0 +1,129 @@
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
@@ -0,0 +1,118 @@
1
+ module Guard
2
+
3
+ # Guard has a hook mechanism that allows you to insert callbacks for individual Guards.
4
+ # By default, each of the Guard instance methods has a "_begin" and an "_end" hook.
5
+ # For example, the Guard::Guard#start method has a :start_begin hook that is runs immediately
6
+ # before Guard::Guard#start, and a :start_end hook that runs immediately after Guard::Guard#start.
7
+ #
8
+ # Read more about [hooks and callbacks on the wiki](https://github.com/guard/guard/wiki/Hooks-and-callbacks).
9
+ #
10
+ module Hook
11
+
12
+ # The Hook module gets included.
13
+ #
14
+ # @param [Class] base the class that includes the module
15
+ #
16
+ def self.included(base)
17
+ base.send :include, InstanceMethods
18
+ end
19
+
20
+ # Instance methods that gets included in the base class.
21
+ #
22
+ module InstanceMethods
23
+
24
+ # When event is a Symbol, {#hook} will generate a hook name
25
+ # by concatenating the method name from where {#hook} is called
26
+ # with the given Symbol.
27
+ #
28
+ # @example Add a hook with a Symbol
29
+ #
30
+ # def run_all
31
+ # hook :foo
32
+ # end
33
+ #
34
+ # Here, when {Guard::Guard#run_all} is called, {#hook} will notify callbacks
35
+ # registered for the "run_all_foo" event.
36
+ #
37
+ # When event is a String, {#hook} will directly turn the String
38
+ # into a Symbol.
39
+ #
40
+ # @example Add a hook with a String
41
+ #
42
+ # def run_all
43
+ # hook "foo_bar"
44
+ # end
45
+ #
46
+ # When {Guard::Guard#run_all} is called, {#hook} will notify callbacks
47
+ # registered for the "foo_bar" event.
48
+ #
49
+ # @param [Symbol, String] event the name of the Guard event
50
+ # @param [Array] args the parameters are passed as is to the callbacks registered for the given event.
51
+ #
52
+ def hook(event, *args)
53
+ hook_name = if event.is_a? Symbol
54
+ calling_method = caller[0][/`([^']*)'/, 1]
55
+ "#{ calling_method }_#{ event }"
56
+ else
57
+ event
58
+ end.to_sym
59
+
60
+ UI.debug "Hook :#{ hook_name } executed for #{ self.class }"
61
+
62
+ Hook.notify(self.class, hook_name, *args)
63
+ end
64
+ end
65
+
66
+ class << self
67
+
68
+ # Get all callbacks.
69
+ #
70
+ def callbacks
71
+ @callbacks ||= Hash.new { |hash, key| hash[key] = [] }
72
+ end
73
+
74
+ # Add a callback.
75
+ #
76
+ # @param [Block] listener the listener to notify
77
+ # @param [Guard::Guard] guard_class the Guard class to add the callback
78
+ # @param [Array<Symbol>] events the events to register
79
+ #
80
+ def add_callback(listener, guard_class, events)
81
+ _events = events.is_a?(Array) ? events : [events]
82
+ _events.each do |event|
83
+ callbacks[[guard_class, event]] << listener
84
+ end
85
+ end
86
+
87
+ # Checks if a callback has been registered.
88
+ #
89
+ # @param [Block] listener the listener to notify
90
+ # @param [Guard::Guard] guard_class the Guard class to add the callback
91
+ # @param [Symbol] event the event to look for
92
+ #
93
+ def has_callback?(listener, guard_class, event)
94
+ callbacks[[guard_class, event]].include?(listener)
95
+ end
96
+
97
+ # Notify a callback.
98
+ #
99
+ # @param [Guard::Guard] guard_class the Guard class to add the callback
100
+ # @param [Symbol] event the event to trigger
101
+ # @param [Array] args the arguments for the listener
102
+ #
103
+ def notify(guard_class, event, *args)
104
+ callbacks[[guard_class, event]].each do |listener|
105
+ listener.call(guard_class, event, *args)
106
+ end
107
+ end
108
+
109
+ # Reset all callbacks.
110
+ #
111
+ def reset_callbacks!
112
+ @callbacks = nil
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,116 @@
1
+ module Guard
2
+
3
+ # The interactor reads user input and triggers
4
+ # specific action upon them unless its locked.
5
+ #
6
+ # Currently the following actions are implemented:
7
+ #
8
+ # - stop, quit, exit, s, q, e => Exit Guard
9
+ # - reload, r, z => Reload Guard
10
+ # - pause, p => Pause Guard
11
+ # - Everything else => Run all
12
+ #
13
+ # It's also possible to scope `reload` and `run all` actions to only a specified group or a guard.
14
+ #
15
+ # @example `backend reload` will only reload backend group
16
+ # @example `spork reload` will only reload rspec guard
17
+ # @example `jasmine` will only run all jasmine specs
18
+ #
19
+ class Interactor
20
+
21
+ STOP_ACTIONS = %w[stop quit exit s q e]
22
+ RELOAD_ACTIONS = %w[reload r z]
23
+ PAUSE_ACTIONS = %w[pause p]
24
+
25
+ # Start the interactor in its own thread.
26
+ #
27
+ def start
28
+ return if ENV["GUARD_ENV"] == 'test'
29
+
30
+ if !@thread || !@thread.alive?
31
+ @thread = Thread.new do
32
+ while entry = $stdin.gets.chomp
33
+ scopes, action = extract_scopes_and_action(entry)
34
+ case action
35
+ when :stop
36
+ ::Guard.stop
37
+ when :pause
38
+ ::Guard.pause
39
+ when :reload
40
+ ::Guard::Dsl.reevaluate_guardfile if scopes.empty?
41
+ ::Guard.reload(scopes)
42
+ when :run_all
43
+ ::Guard.run_all(scopes)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ # Kill interactor thread if not current
51
+ #
52
+ def stop
53
+ unless Thread.current == @thread
54
+ @thread.kill
55
+ end
56
+ end
57
+
58
+ # Extract guard or group scope and action from Interactor entry
59
+ #
60
+ # @example `spork reload` will only reload rspec
61
+ # @example `jasmine` will only run all jasmine specs
62
+ #
63
+ # @param [String] Interactor entry gets from $stdin
64
+ # @return [Array] entry group or guard scope hash and action
65
+ #
66
+ def extract_scopes_and_action(entry)
67
+ scopes = {}
68
+ entries = entry.split(' ')
69
+ case entries.length
70
+ when 1
71
+ unless action = action_from_entry(entries[0])
72
+ scopes = scopes_from_entry(entries[0])
73
+ end
74
+ when 2
75
+ scopes = scopes_from_entry(entries[0])
76
+ action = action_from_entry(entries[1])
77
+ end
78
+ action ||= :run_all
79
+
80
+ [scopes, action]
81
+ end
82
+
83
+ # Extract guard or group scope from entry if valid
84
+ #
85
+ # @param [String] Interactor entry gets from $stdin
86
+ # @return [Hash] An hash with a guard or a group scope
87
+ #
88
+ def scopes_from_entry(entry)
89
+ scopes = {}
90
+ if guard = ::Guard.guards(entry)
91
+ scopes[:guard] = guard
92
+ end
93
+ if group = ::Guard.groups(entry)
94
+ scopes[:group] = group
95
+ end
96
+
97
+ scopes
98
+ end
99
+
100
+ # Extract action from entry if an existing action is present
101
+ #
102
+ # @param [String] Interactor entry gets from $stdin
103
+ # @return [Symbol] A guard action
104
+ #
105
+ def action_from_entry(entry)
106
+ if STOP_ACTIONS.include?(entry)
107
+ :stop
108
+ elsif RELOAD_ACTIONS.include?(entry)
109
+ :reload
110
+ elsif PAUSE_ACTIONS.include?(entry)
111
+ :pause
112
+ end
113
+ end
114
+
115
+ end
116
+ end