guard 0.1.0.beta.1

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Thibaud Guillaume-Gentil
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = Guard
2
+
3
+ Documentation is coming.
data/bin/guard ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'guard'
4
+ require 'guard/cli'
5
+
6
+ Guard::CLI.start
data/bin/inotify_watch ADDED
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'rb-inotify'
4
+
5
+ folders = Array.new
6
+ notifier = INotify::Notifier.new
7
+
8
+ notifier.watch(ARGV.first || '.', :modify, :recursive) do |event|
9
+ dir = File.expand_path(File.dirname(event.absolute_name)) + '/'
10
+ if !folders.include?(dir)
11
+ folders << dir
12
+ end
13
+ end
14
+
15
+ while true do
16
+ notifier.process
17
+
18
+ if !folders.empty?
19
+ $stdout.puts folders.join(' ')
20
+ $stdout.flush
21
+ folders.clear
22
+ end
23
+
24
+ sleep(0.1)
25
+ end
data/ext/extconf.rb ADDED
@@ -0,0 +1,18 @@
1
+ # Workaround to make Rubygems believe it builds a native gem
2
+ require 'mkmf'
3
+ create_makefile('none')
4
+
5
+ if `uname -s`.chomp == 'Darwin'
6
+ gem_root = File.expand_path(File.join('..'))
7
+ darwin_verion = `uname -r`.to_i
8
+ sdk_verion = { 9 => '10.5', 10 => '10.6', 11 => '10.7' }[darwin_verion]
9
+
10
+ raise "Darwin #{darwin_verion} is not supported" unless sdk_verion
11
+
12
+ # Compile the actual fsevent_watch binary
13
+ system("CFLAGS='-isysroot /Developer/SDKs/MacOSX#{sdk_verion}.sdk -mmacosx-version-min=#{sdk_verion}' /usr/bin/gcc -framework CoreServices -o '#{gem_root}/bin/fsevent_watch' fsevent/fsevent_watch.c")
14
+
15
+ unless File.executable?("#{gem_root}/bin/fsevent_watch")
16
+ raise "Compilation of fsevent_watch failed (see README)"
17
+ end
18
+ end
@@ -0,0 +1,44 @@
1
+ #include <CoreServices/CoreServices.h>
2
+
3
+ void callback(ConstFSEventStreamRef streamRef,
4
+ void *clientCallBackInfo,
5
+ size_t numEvents,
6
+ void *eventPaths,
7
+ const FSEventStreamEventFlags eventFlags[],
8
+ const FSEventStreamEventId eventIds[]
9
+ ) {
10
+ // Print modified dirs
11
+ int i;
12
+ char **paths = eventPaths;
13
+ for (i = 0; i < numEvents; i++) {
14
+ printf("%s", paths[i]);
15
+ printf(" ");
16
+ }
17
+ printf("\n");
18
+ fflush(stdout);
19
+ }
20
+
21
+ int main (int argc, const char * argv[]) {
22
+ // Create event stream
23
+ CFStringRef pathToWatch = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingUTF8);
24
+ CFArrayRef pathsToWatch = CFArrayCreate(NULL, (const void **)&pathToWatch, 1, NULL);
25
+ void *callbackInfo = NULL;
26
+ FSEventStreamRef stream;
27
+ CFAbsoluteTime latency = 0.1;
28
+ stream = FSEventStreamCreate(
29
+ kCFAllocatorDefault,
30
+ callback,
31
+ callbackInfo,
32
+ pathsToWatch,
33
+ kFSEventStreamEventIdSinceNow,
34
+ latency,
35
+ kFSEventStreamCreateFlagNone
36
+ );
37
+
38
+ // Add stream to run loop
39
+ FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
40
+ FSEventStreamStart(stream);
41
+ CFRunLoopRun();
42
+
43
+ return 2;
44
+ }
data/images/failed.png ADDED
Binary file
Binary file
Binary file
data/lib/guard.rb ADDED
@@ -0,0 +1,49 @@
1
+ module Guard
2
+
3
+ autoload :UI, 'guard/ui'
4
+ autoload :Dsl, 'guard/dsl'
5
+ autoload :Interactor, 'guard/interactor'
6
+ autoload :Listener, 'guard/listener'
7
+ autoload :Watcher, 'guard/watcher'
8
+ autoload :Notifier, 'guard/notifier'
9
+
10
+ class << self
11
+ attr_accessor :options, :guards, :listener
12
+
13
+ def start(options = {})
14
+ @options = options
15
+ @listener = Listener.new
16
+ @guards = []
17
+
18
+ Dsl.evaluate_guardfile
19
+ Interactor.init_signal_traps
20
+
21
+ listener.on_change do |files|
22
+ run do
23
+ guards.each do |guard|
24
+ paths = Watcher.match_files(guard, files)
25
+ guard.run_on_change(paths) unless paths.empty?
26
+ end
27
+ end
28
+ end
29
+
30
+ UI.info "Guard is now watching at '#{Dir.pwd}'"
31
+ guards.each(&:start)
32
+ listener.start
33
+ end
34
+
35
+ def add_guard(name, watchers = [], options = {})
36
+ require "guard/#{name.downcase}"
37
+ guard_class = ObjectSpace.each_object(Class).detect { |c| c.to_s.downcase.match "^guard::#{name.downcase}" }
38
+ @guards << guard_class.new(watchers, options)
39
+ end
40
+
41
+ def run
42
+ listener.stop
43
+ yield
44
+ listener.start
45
+ end
46
+
47
+ end
48
+
49
+ end
data/lib/guard/cli.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'thor'
2
+ require 'guard/version'
3
+
4
+ module Guard
5
+ class CLI < Thor
6
+ default_task :start
7
+
8
+ desc "start", "Starts guard"
9
+ method_option :clear, :type => :boolean, :default => false, :aliases => '-c', :banner => "Auto clear shell after each change"
10
+ def start
11
+ Guard.start(options)
12
+ end
13
+
14
+ desc "version", "Prints the guard's version information"
15
+ def version
16
+ Guard::UI.info "Guard version #{Guard::VERSION}"
17
+ end
18
+ map %w(-v --version) => :version
19
+ end
20
+ end
data/lib/guard/dsl.rb ADDED
@@ -0,0 +1,24 @@
1
+ module Guard
2
+ class Dsl
3
+
4
+ def self.evaluate_guardfile
5
+ guardfile = "#{Dir.pwd}/Guardfile"
6
+ dsl = new
7
+ dsl.instance_eval(File.read(guardfile.to_s), guardfile.to_s, 1)
8
+ rescue
9
+ UI.error "Guardfile not found or invalid"
10
+ exit 1
11
+ end
12
+
13
+ def guard(name, options = {}, &definition)
14
+ @watchers = []
15
+ definition.call
16
+ Guard.add_guard(name, @watchers, options)
17
+ end
18
+
19
+ def watch(pattern, &action)
20
+ @watchers << Guard::Watcher.new(pattern, action)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ module Guard
2
+ class Guard
3
+ attr_accessor :watchers, :options
4
+
5
+ def initialize(watchers = [], options = {})
6
+ @watchers, @options = watchers, options
7
+ end
8
+
9
+ # ================
10
+ # = Guard method =
11
+ # ================
12
+
13
+ def start
14
+ true
15
+ end
16
+
17
+ def stop
18
+ true
19
+ end
20
+
21
+ def reload
22
+ true
23
+ end
24
+
25
+ def run_all
26
+ true
27
+ end
28
+
29
+ def run_on_change(paths)
30
+ true
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ module Guard
2
+ module Interactor
3
+
4
+ def self.init_signal_traps
5
+ # Run all (Ctrl-\)
6
+ Signal.trap('QUIT') do
7
+ ::Guard.run do
8
+ ::Guard.guards.each(&:run_all)
9
+ end
10
+ end
11
+
12
+ # Stop (Ctrl-C)
13
+ Signal.trap('INT') do
14
+ ::Guard.listener.stop
15
+ if ::Guard.guards.all?(&:stop)
16
+ UI.info "Bye bye...", :reset => true, :clear => false
17
+ abort("\n")
18
+ else
19
+ ::Guard.listener.start
20
+ end
21
+ end
22
+
23
+ # Reload (Ctrl-Z)
24
+ Signal.trap('TSTP') do
25
+ ::Guard.run do
26
+ ::Guard.guards.each(&:reload)
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,64 @@
1
+ require 'sys/uname'
2
+
3
+ module Guard
4
+ class Listener
5
+ attr_reader :last_event, :callback, :pipe
6
+
7
+ def initialize
8
+ update_last_event
9
+ end
10
+
11
+ def on_change(&block)
12
+ @callback = block
13
+ end
14
+
15
+ def start
16
+ @pipe = case Sys::Uname.sysname
17
+ when 'Darwin'
18
+ IO.popen("#{bin_path}/fsevent_watch .")
19
+ when 'Linux'
20
+ IO.popen("#{bin_path}/inotify_watch .")
21
+ end
22
+ watch_change
23
+ end
24
+
25
+ def stop
26
+ Process.kill("HUP", pipe.pid) if pipe
27
+ end
28
+
29
+ private
30
+
31
+ def watch_change
32
+ while !pipe.eof?
33
+ if line = pipe.readline
34
+ modified_dirs = line.split(" ")
35
+ files = modified_files(modified_dirs)
36
+ update_last_event
37
+ callback.call(files)
38
+ end
39
+ end
40
+ end
41
+
42
+ def modified_files(dirs)
43
+ files = potentially_modified_files(dirs).select { |file| recent_file?(file) }
44
+ files.map! { |file| file.gsub("#{Dir.pwd}/", '') }
45
+ end
46
+
47
+ def potentially_modified_files(dirs)
48
+ Dir.glob(dirs.map { |dir| "#{dir}*" })
49
+ end
50
+
51
+ def recent_file?(file)
52
+ File.mtime(file) >= last_event
53
+ end
54
+
55
+ def update_last_event
56
+ @last_event = Time.now
57
+ end
58
+
59
+ def bin_path
60
+ File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin'))
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,45 @@
1
+ require 'sys/uname'
2
+ require 'pathname'
3
+
4
+ case Sys::Uname.sysname
5
+ when 'Darwin'
6
+ require 'growl'
7
+ when 'Linux'
8
+ require 'libnotify'
9
+ end
10
+
11
+ module Guard
12
+ module Notifier
13
+
14
+ def self.notify(message, options = {})
15
+ unless ENV["GUARD_ENV"] == "test"
16
+ image = options[:image] || :success
17
+ title = options[:title] || "Guard"
18
+ case Sys::Uname.sysname
19
+ when 'Darwin'
20
+ Growl.notify message, :title => title, :icon => image_path(image), :name => "Guard"
21
+ when 'Linux'
22
+ Libnotify.show :body => message, :summary => title, :icon_path => image_path(image)
23
+ end
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def self.image_path(image)
30
+ images_path = Pathname.new(File.dirname(__FILE__)).join('../../images')
31
+ case image
32
+ when :failed
33
+ images_path.join("failed.png").to_s
34
+ when :pending
35
+ images_path.join("pending.png").to_s
36
+ when :success
37
+ images_path.join("success.png").to_s
38
+ else
39
+ # path given
40
+ image
41
+ end
42
+ end
43
+
44
+ end
45
+ end
data/lib/guard/ui.rb ADDED
@@ -0,0 +1,37 @@
1
+ module Guard
2
+ module UI
3
+ class << self
4
+
5
+ def info(message, options = {})
6
+ unless ENV["GUARD_ENV"] == "test"
7
+ reset_line if options[:reset]
8
+ clear if options.key?(:clear) ? options[:clear] : ::Guard.options[:clear]
9
+ puts reset_color(message) if message != ''
10
+ end
11
+ end
12
+
13
+ def error(message)
14
+ puts "ERROR: #{message}"
15
+ end
16
+
17
+ def reset_line
18
+ print "\r\e "
19
+ end
20
+
21
+ private
22
+
23
+ def clear
24
+ system("clear;")
25
+ end
26
+
27
+ def reset_color(text)
28
+ color(text, "\e[0m")
29
+ end
30
+
31
+ def color(text, color_code)
32
+ "#{color_code}#{text}\e[0m"
33
+ end
34
+
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,3 @@
1
+ module Guard
2
+ VERSION = "0.1.0.beta.1"
3
+ end
@@ -0,0 +1,35 @@
1
+ module Guard
2
+ class Watcher
3
+ attr_accessor :pattern, :action
4
+
5
+ def initialize(pattern, action = nil)
6
+ @pattern, @action = pattern, action
7
+ end
8
+
9
+ def self.match_files(guard, files)
10
+ guard.watchers.inject([]) do |paths, watcher|
11
+ files.each do |file|
12
+ if matches = file.match(watcher.pattern)
13
+ if watcher.action
14
+ begin
15
+ case watcher.action.arity
16
+ when -1
17
+ result = watcher.action.call
18
+ when 1
19
+ result = watcher.action.call(matches)
20
+ end
21
+ rescue
22
+ UI.info "Problem with watch action"
23
+ end
24
+ paths << result if result.is_a?(String) && result != ''
25
+ else
26
+ paths << matches[0]
27
+ end
28
+ end
29
+ end
30
+ paths
31
+ end
32
+ end
33
+
34
+ end
35
+ end
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: guard
3
+ version: !ruby/object:Gem::Version
4
+ hash: 62196401
5
+ prerelease: true
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ - beta
11
+ - 1
12
+ version: 0.1.0.beta.1
13
+ platform: ruby
14
+ authors:
15
+ - Thibaud Guillaume-Gentil
16
+ autorequire:
17
+ bindir: bin
18
+ cert_chain: []
19
+
20
+ date: 2010-10-03 00:00:00 +02:00
21
+ default_executable:
22
+ dependencies:
23
+ - !ruby/object:Gem::Dependency
24
+ name: bundler
25
+ prerelease: false
26
+ requirement: &id001 !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ hash: 21
32
+ segments:
33
+ - 1
34
+ - 0
35
+ - 1
36
+ version: 1.0.1
37
+ type: :development
38
+ version_requirements: *id001
39
+ - !ruby/object:Gem::Dependency
40
+ name: rspec
41
+ prerelease: false
42
+ requirement: &id002 !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ hash: 62196431
48
+ segments:
49
+ - 2
50
+ - 0
51
+ - 0
52
+ - beta
53
+ - 22
54
+ version: 2.0.0.beta.22
55
+ type: :development
56
+ version_requirements: *id002
57
+ - !ruby/object:Gem::Dependency
58
+ name: thor
59
+ prerelease: false
60
+ requirement: &id003 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ hash: 35
66
+ segments:
67
+ - 0
68
+ - 14
69
+ - 2
70
+ version: 0.14.2
71
+ type: :runtime
72
+ version_requirements: *id003
73
+ - !ruby/object:Gem::Dependency
74
+ name: sys-uname
75
+ prerelease: false
76
+ requirement: &id004 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ hash: 55
82
+ segments:
83
+ - 0
84
+ - 8
85
+ - 4
86
+ version: 0.8.4
87
+ type: :runtime
88
+ version_requirements: *id004
89
+ - !ruby/object:Gem::Dependency
90
+ name: growl
91
+ prerelease: false
92
+ requirement: &id005 !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ~>
96
+ - !ruby/object:Gem::Version
97
+ hash: 17
98
+ segments:
99
+ - 1
100
+ - 0
101
+ - 3
102
+ version: 1.0.3
103
+ type: :runtime
104
+ version_requirements: *id005
105
+ - !ruby/object:Gem::Dependency
106
+ name: rb-inotify
107
+ prerelease: false
108
+ requirement: &id006 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ hash: 3
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ type: :runtime
118
+ version_requirements: *id006
119
+ - !ruby/object:Gem::Dependency
120
+ name: libnotify
121
+ prerelease: false
122
+ requirement: &id007 !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ~>
126
+ - !ruby/object:Gem::Version
127
+ hash: 29
128
+ segments:
129
+ - 0
130
+ - 1
131
+ - 3
132
+ version: 0.1.3
133
+ type: :runtime
134
+ version_requirements: *id007
135
+ description: Guard is a command line tool to easly manage script launch when your files change
136
+ email:
137
+ - thibaud@thibaud.me
138
+ executables:
139
+ - guard
140
+ extensions:
141
+ - ext/extconf.rb
142
+ extra_rdoc_files: []
143
+
144
+ files:
145
+ - bin/guard
146
+ - bin/inotify_watch
147
+ - images/failed.png
148
+ - images/pending.png
149
+ - images/success.png
150
+ - lib/guard/cli.rb
151
+ - lib/guard/dsl.rb
152
+ - lib/guard/guard.rb
153
+ - lib/guard/interactor.rb
154
+ - lib/guard/listener.rb
155
+ - lib/guard/notifier.rb
156
+ - lib/guard/ui.rb
157
+ - lib/guard/version.rb
158
+ - lib/guard/watcher.rb
159
+ - lib/guard.rb
160
+ - ext/extconf.rb
161
+ - ext/fsevent/fsevent_watch.c
162
+ - LICENSE
163
+ - README.rdoc
164
+ has_rdoc: true
165
+ homepage: http://rubygems.org/gems/guard
166
+ licenses: []
167
+
168
+ post_install_message:
169
+ rdoc_options: []
170
+
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ none: false
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ hash: 3
179
+ segments:
180
+ - 0
181
+ version: "0"
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ">"
186
+ - !ruby/object:Gem::Version
187
+ hash: 25
188
+ segments:
189
+ - 1
190
+ - 3
191
+ - 1
192
+ version: 1.3.1
193
+ requirements: []
194
+
195
+ rubyforge_project: guard
196
+ rubygems_version: 1.3.7
197
+ signing_key:
198
+ specification_version: 3
199
+ summary: Guard keep an eye on your files event
200
+ test_files: []
201
+