lib/rb-fsevent/fsevent.rb in rb-fsevent-0.3.10 vs lib/rb-fsevent/fsevent.rb in rb-fsevent-0.4.0

- old
+ new

@@ -1,65 +1,102 @@ class FSEvent - attr_reader :paths, :callback, :pipe + class << self + class_eval <<-END + def root_path + "#{File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))}" + end + END + class_eval <<-END + def watcher_path + "#{File.join(FSEvent.root_path, 'bin', 'fsevent_watch')}" + end + END + end - def watch(paths, &callback) - @paths = paths.kind_of?(Enumerable) ? paths : [paths] - @callback = callback + attr_reader :paths, :callback + + def watch(watch_paths, options=nil, &block) + @paths = watch_paths.kind_of?(Array) ? watch_paths : [watch_paths] + @callback = block + + if options.kind_of?(Hash) + @options = parse_options(options) + elsif options.kind_of?(Array) + @options = options + else + @options = [] + end end def run - launch_bin - listen + while !pipe.eof? + if line = pipe.readline + modified_dir_paths = line.split(":").select { |dir| dir != "\n" } + callback.call(modified_dir_paths) + end + end + rescue Interrupt, IOError + ensure + stop end def stop if pipe Process.kill("KILL", pipe.pid) pipe.close end rescue IOError + ensure + @pipe = false end -private + if RUBY_VERSION < '1.9' + def pipe + @pipe ||= IO.popen("#{self.class.watcher_path} #{options_string} #{shellescaped_paths}") + end - def bin_path - File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'bin')) - end + private - def launch_bin - @pipe = IO.popen("#{bin_path}/fsevent_watch #{shellescaped_paths}") - end + def options_string + @options.join(' ') + end - def listen - while !pipe.eof? - if line = pipe.readline - modified_dir_paths = line.split(":").select { |dir| dir != "\n" } - callback.call(modified_dir_paths) - end + def shellescaped_paths + @paths.map {|path| shellescape(path)}.join(' ') end - rescue Interrupt, IOError - stop - end - def shellescaped_paths - @paths.map {|path| shellescape(path)}.join(' ') - end + # for Ruby 1.8.6 support + def shellescape(str) + # An empty argument will be skipped, so return empty quotes. + return "''" if str.empty? - # for Ruby 1.8.6 support - def shellescape(str) - # An empty argument will be skipped, so return empty quotes. - return "''" if str.empty? + str = str.dup - str = str.dup + # Process as a single byte sequence because not all shell + # implementations are multibyte aware. + str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1") - # Process as a single byte sequence because not all shell - # implementations are multibyte aware. - str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1") + # A LF cannot be escaped with a backslash because a backslash + LF + # combo is regarded as line continuation and simply ignored. + str.gsub!(/\n/, "'\n'") - # A LF cannot be escaped with a backslash because a backslash + LF - # combo is regarded as line continuation and simply ignored. - str.gsub!(/\n/, "'\n'") + return str + end + else + def pipe + @pipe ||= IO.popen([self.class.watcher_path] + @options + @paths) + end + end - return str + private + + def parse_options(options={}) + opts = [] + opts.concat(['--since-when', options[:since_when]]) if options[:since_when] + opts.concat(['--latency', options[:latency]]) if options[:latency] + opts.push('--no-defer') if options[:no_defer] + opts.push('--watch-root') if options[:watch_root] + # ruby 1.9's IO.popen(array-of-stuff) syntax requires all items to be strings + opts.map {|opt| "#{opt}"} end -end \ No newline at end of file +end