joshbuddy-guard 0.10.0

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