feather_watch 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c365a117cc400f3b83860aabf245dbdd24a87d0e
4
+ data.tar.gz: e37efc790a575ed9c9beb2f2699d6e4eff745fbd
5
+ SHA512:
6
+ metadata.gz: 54894b9dc54e207f0afc675e75ceddcfb036bfa502d55bbef66fdfcc25b647e5ab85e86807c9a6783d04f8aeaea2868cf61ee4994043ebcbef77372b767f144d
7
+ data.tar.gz: 5ccbdba157e5c9cab6cfd23e4033a837259975a81e1cefa0cf6e6900f1543e637f822f90db76cbe0bf8b15bb8b6309521350953484406650548bcec5b0484ef0
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,18 @@
1
+ gemfile:
2
+ - Gemfile
3
+ language: ruby
4
+ rvm:
5
+ - 2.0.0
6
+ - 2.1.0
7
+ - 2.1.1
8
+ - 2.1.2
9
+ - 2.1.3
10
+ matrix:
11
+ allow_failures:
12
+ - rvm: 1.8.7
13
+ - rvm: 1.9.2
14
+ - rvm: 1.9.3
15
+ - rvm: jruby-head
16
+ - rvm: ruby-head
17
+ - rvm: rbx
18
+ fast_finish: true
Binary file
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in feather_watch.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Stephan Nordnes Eriksen
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,67 @@
1
+ ![Feather Watch](/Feather Watch.png?raw=true)
2
+
3
+ Light weight, cross platform, file system watcher.
4
+
5
+
6
+ ### Should work windows, but not yet tested becase I do not have access to a windows machine now. If you do, I would love for you to run the specs and see if it works :)
7
+
8
+ [![Build Status](https://travis-ci.org/stephan-nordnes-eriksen/feather_watch.svg?branch=master)](https://travis-ci.org/stephan-nordnes-eriksen/feather_watch)
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'feather_watch'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install feather_watch
23
+
24
+ ## Usage
25
+
26
+ require "feather_watch"
27
+ callback = lambda{|e| puts "Event #{e[:status]} on file #{e[:file]}"}
28
+ paths_to_watch = "/" #can be a string or array of string, eg: ["/home/data", "/home/pictures"]
29
+ watcher = FeatherWatch.new(paths_to_watch, callback)
30
+ watcher.start #non-blocking
31
+
32
+ #To stop:
33
+ watcher.stop
34
+
35
+ ### Received statuses
36
+
37
+ - :added
38
+ - :modified
39
+ - :removed
40
+
41
+
42
+ # Important Notes!
43
+ Events on OSx, also known as darwin, is currenty an approximation as the underlying libraries does not currently support actual events. Thus on OSx, you get `:removed` if the file recieved does not exist by checking File.file?(the_file). If it does exist you get `:modified`. So you will **not** get any `:added` events on OSx.
44
+
45
+ Feather Watch will recieve very many file events, even for temp files. Care should be taken when handling the events. Make sure to only process what you need. For instance, you should check against temp-files, and skip those events. Example:
46
+
47
+ #black list approach
48
+ un_accepted_file_types = ["tmp", "cache", "db"]
49
+ callback = lambda{|e| use_event(e) unless un_accepted_file_types.include?(e[:file].split(".")[-1])}
50
+
51
+ #white list approach
52
+ accepted_file_types = ["png", "jpg", "jpeg", "gif"]
53
+ callback = lambda{|e| use_event(e) if accepted_file_types.include?(e[:file].split(".")[-1])}
54
+
55
+ You need to take care to filter out what you do not need for each target platform.
56
+
57
+
58
+
59
+
60
+
61
+ ## Contributing
62
+
63
+ 1. Fork it ( https://github.com/[my-github-username]/feather_watch/fork )
64
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
65
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
66
+ 4. Push to the branch (`git push origin my-new-feature`)
67
+ 5. Create a new Pull Request
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+ require "rubygems"
3
+ Bundler::GemHelper.install_tasks
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
7
+ task :test => :spec
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'feather_watch/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "feather_watch"
8
+ spec.version = FeatherWatch::VERSION
9
+ spec.authors = ["Stephan Nordnes Eriksen"]
10
+ spec.email = ["stephanruler@gmail.com"]
11
+ spec.summary = %q{Barebones, simple, and fast file system watcher}
12
+ spec.description = %q{A barebones file system watcher which uses native file system events for Linux, OSx, and Windows.}
13
+ spec.homepage = "https://github.com/stephan-nordnes-eriksen/feather_watch"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'rb-fsevent', '~> 0.9'
22
+ spec.add_dependency 'rb-inotify', '~> 0.9'
23
+ spec.add_dependency 'wdm', '~> 0.1'
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.6"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "simplecov"
28
+ spec.add_development_dependency "rake"
29
+ end
@@ -0,0 +1,17 @@
1
+ require "feather_watch/version"
2
+ require "feather_watch/os"
3
+ require "feather_watch/watcher"
4
+ require "feather_watch/core/darwin_watcher"
5
+ require "feather_watch/core/linux_watcher"
6
+ require "feather_watch/core/windows_watcher"
7
+
8
+
9
+ require 'rb-fsevent' if FeatherWatch::OS.mac?
10
+ require 'rb-inotify' if FeatherWatch::OS.linux?
11
+ require 'wdm' if FeatherWatch::OS.windows?
12
+
13
+ module FeatherWatch
14
+ def self.new(*args)
15
+ FeatherWatch::Watcher.new(*args)
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ module FeatherWatch::Core
2
+ class DarwinWatcher
3
+ def initialize(directories, callback, verbose= false)
4
+ @verbose = verbose
5
+ puts "Initializing mac watcher" if @verbose
6
+ @fs_event = FSEvent.new
7
+ options = { :no_defer => true,
8
+ :file_events => true }
9
+
10
+ @fs_event.watch directories, options do |changed_files|
11
+ changed_files.each do |f|
12
+ if File.file?(f)
13
+ puts "Change on file: #{f}" if @verbose
14
+ callback.call({status: :modified, file: f})
15
+ else
16
+ puts "Removed file: #{f}" if @verbose
17
+ callback.call({status: :removed, file: f})
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ def start
24
+ puts "Starting mac watcher" if @verbose
25
+ Thread.new do
26
+ @fs_event.run
27
+ end
28
+ end
29
+
30
+ def stop
31
+ puts "Stopping mac watcher" if @verbose
32
+ @fs_event.stop
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,52 @@
1
+ module FeatherWatch::Core
2
+ class LinuxWatcher
3
+ def initialize(directories, callback, verbose= false)
4
+ @verbose = verbose
5
+ puts "Initializing linux watcher" if @verbose
6
+ @notifiers = []
7
+ directories.each do |dir|
8
+ notifier = INotify::Notifier.new
9
+ @notifiers << notifier
10
+ #Avaliable events: :access, :attrib, :close_write, :close_nowrite, :create, :delete, :delete_self, :ignored, :modify, :move_self, :moved_from, :moved_to, :open
11
+ notifier.watch(dir, :create, :attrib, :delete, :close_write, :delete_self, :modify, :move_self, :moved_from, :moved_to) do |event|
12
+ #TODO: This information is probably in the event, but I'm on a mac now, so I can't test it properly
13
+
14
+ if !([:attrib, :close_write, :modify] & event.flags ).empty?
15
+ puts "Change on file: #{event.absolute_name}" if @verbose
16
+ callback.call({status: :modified, file: event.absolute_name})
17
+ elsif !([:moved_to] & event.flags ).empty?
18
+ puts "File added: #{event.absolute_name}" if @verbose
19
+ callback.call({status: :added, file: event.absolute_name})
20
+ elsif !([:moved_from] & event.flags ).empty?
21
+ puts "File removed: #{event.absolute_name}" if @verbose
22
+ callback.call({status: :removed, file: event.absolute_name})
23
+ elsif !([:create] & event.flags ).empty?
24
+ puts "File added: #{event.absolute_name}" if @verbose
25
+ callback.call({status: :added, file: event.absolute_name})
26
+ elsif !([:delete, :delete_self] & event.flags ).empty?
27
+ puts "File removed: #{event.absolute_name}" if @verbose
28
+ callback.call({status: :removed, file: event.absolute_name})
29
+ else
30
+ puts "Unhandled status flags: #{event.flags} for file #{event.absolute_name}" if @verbose
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def start
37
+ puts "Starting linux watcher" if @verbose
38
+ @notifiers.each do |notifier|
39
+ Thread.new do
40
+ notifier.run
41
+ end
42
+ end
43
+ end
44
+
45
+ def stop
46
+ puts "Stopping linux watcher" if @verbose
47
+ @notifiers.each do |notifier|
48
+ notifier.stop
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,46 @@
1
+ module FeatherWatch::Core
2
+ class WindowsWatcher
3
+ def initialize(directories, callback, verbose= false)
4
+ @verbose = verbose
5
+ puts "Initializing windows watcher" if @verbose
6
+ @monitors = []
7
+ directories.each do |dir|
8
+ monitor = WDM::Monitor.new
9
+ @monitors << monitor
10
+ monitor.watch_recursively(dir, :files) do |change|
11
+ #TODO: Have not tested this. It should work
12
+
13
+ case change.type
14
+ when :added, :renamed_new_file
15
+ puts "File added: #{change.path}" if @verbose
16
+ callback.call({status: :added, file: change.path})
17
+ when :removed, :renamed_old_file
18
+ puts "Removed file: #{change.path}" if @verbose
19
+ callback.call({status: :removed, file: change.path})
20
+ when :modified, :attrib
21
+ puts "File modified: #{change.path}" if @verbose
22
+ callback.call({status: :modified, file: change.path})
23
+ else
24
+ puts "Unhandled status type: #{change.type} for file #{change.path}" if @verbose
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ def start
31
+ puts "Starting windows watcher" if @verbose
32
+ @monitors.each do |monitor|
33
+ Thread.new do
34
+ monitor.run!
35
+ end
36
+ end
37
+ end
38
+
39
+ def stop
40
+ puts "Stopping windows watcher" if @verbose
41
+ @monitors.each do |monitor|
42
+ monitor.stop
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,17 @@
1
+ module FeatherWatch::OS
2
+ def self.windows?
3
+ (/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM) != nil
4
+ end
5
+
6
+ def self.mac?
7
+ (/darwin/ =~ RUBY_PLATFORM) != nil
8
+ end
9
+
10
+ def self.unix?
11
+ !self.windows?
12
+ end
13
+
14
+ def self.linux?
15
+ self.unix? and not self.mac?
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module FeatherWatch
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,50 @@
1
+ module FeatherWatch
2
+ class Watcher
3
+
4
+ # Public: Initialize the file system watcher.
5
+ #
6
+ # directories - An array of directories to watch.
7
+ # callback - A callback that will receive events. Recieved objects on form: {status: [:modified, :removed].sample, file: "path/to/file"}. ":modified" means everything except deleted.
8
+ # verbose=false - Enable verbose mode. Warning: Can produce very much output
9
+ #
10
+ # Examples
11
+ #
12
+ # FeatherWatch::Watcher.new([File.join(Dir.home, 'Desktop')], lambda{|e| puts "got event with status: #{e[:status]} on file #{e[:file]}"})
13
+ #
14
+ # Returns a Watcher object.
15
+ def initialize(directories, callback, verbose= false)
16
+ @verbose = verbose
17
+ dir = directories
18
+ dir = [directories] if directories.is_a?(String)
19
+ raise "Unknown datatype for directories. Was: #{dir}" unless dir.is_a?(Array)
20
+
21
+ @listener = FeatherWatch::Core::DarwinWatcher.new(dir, callback, verbose) if FeatherWatch::OS.mac?
22
+ @listener = FeatherWatch::Core::LinuxWatcher.new(dir, callback, verbose) if FeatherWatch::OS.linux?
23
+ @listener = FeatherWatch::Core::WindowsWatcher.new(dir, callback, verbose) if FeatherWatch::OS.windows?
24
+ end
25
+
26
+ # Public: Starts the watcher.
27
+ #
28
+ # Examples
29
+ #
30
+ # watcher.start
31
+ # # => nil
32
+ #
33
+ # Returns nil
34
+ def start
35
+ @listener.start if @listener
36
+ end
37
+
38
+ # Public: Stops the watcher.
39
+ #
40
+ # Examples
41
+ #
42
+ # watcher.start
43
+ # # => nil
44
+ #
45
+ # Returns nil
46
+ def stop
47
+ @listener.stop if @listener
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,159 @@
1
+ # encoding: UTF-8
2
+ require 'spec_helper'
3
+
4
+
5
+ describe FeatherWatch::Watcher do
6
+ describe ".initialize" do
7
+ it "does not crash" do
8
+ expect{FeatherWatch::Watcher.new("/",lambda { |e| })}.to_not raise_error
9
+ expect{FeatherWatch::Watcher.new("/",lambda { |e| }, false)}.to_not raise_error
10
+ end
11
+ it "calls DarwinWatcher.new on darwin" do
12
+ allow(Kernel).to receive(:require).with('rb-fsevent')
13
+ allow(FeatherWatch::OS).to receive(:mac?) {true}
14
+ allow(FeatherWatch::OS).to receive(:linux?) {false}
15
+ allow(FeatherWatch::OS).to receive(:windows?) {false}
16
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
17
+
18
+ path = "/"
19
+ callback = lambda { |e| }
20
+ verbose = false
21
+
22
+ expect(FeatherWatch::Core::DarwinWatcher).to receive(:new).with([path],callback,verbose)
23
+
24
+ FeatherWatch::Watcher.new(path,callback,verbose)
25
+ end
26
+ it "calls LinuxWatcher.new on linux" do
27
+ allow(Kernel).to receive(:require).with('rb-inotify')
28
+ allow(FeatherWatch::OS).to receive(:mac?) {false}
29
+ allow(FeatherWatch::OS).to receive(:linux?) {true}
30
+ allow(FeatherWatch::OS).to receive(:windows?) {false}
31
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
32
+
33
+ path = "/"
34
+ callback = lambda { |e| }
35
+ verbose = false
36
+
37
+ expect(FeatherWatch::Core::LinuxWatcher).to receive(:new).with([path],callback,verbose)
38
+
39
+ FeatherWatch::Watcher.new(path,callback,verbose)
40
+ end
41
+ it "calls WindowsWatcher.new on windows" do
42
+ allow(Kernel).to receive(:require).with('wdm')
43
+ allow(FeatherWatch::OS).to receive(:mac?) {false}
44
+ allow(FeatherWatch::OS).to receive(:linux?) {false}
45
+ allow(FeatherWatch::OS).to receive(:windows?) {true}
46
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
47
+
48
+ path = "/"
49
+ callback = lambda { |e| }
50
+ verbose = false
51
+
52
+ expect(FeatherWatch::Core::WindowsWatcher).to receive(:new).with([path],callback,verbose)
53
+
54
+ FeatherWatch::Watcher.new(path,callback,verbose)
55
+ end
56
+ end
57
+
58
+ describe ".start" do
59
+ it "calls start on a DarwinWatcher on darwin" do
60
+ allow(Kernel).to receive(:require).with('rb-fsevent')
61
+ allow(FeatherWatch::OS).to receive(:mac?) {true}
62
+ allow(FeatherWatch::OS).to receive(:linux?) {false}
63
+ allow(FeatherWatch::OS).to receive(:windows?) {false}
64
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
65
+
66
+ path = "/"
67
+ callback = lambda { |e| }
68
+ verbose = false
69
+
70
+ darwin_spy = spy "DarwinWatcher"
71
+ expect(FeatherWatch::Core::DarwinWatcher).to receive(:new).with([path],callback,verbose) {darwin_spy}
72
+ expect(darwin_spy).to receive(:start)
73
+ FeatherWatch::Watcher.new(path,callback,verbose).start
74
+ end
75
+ it "calls start on a LinuxWatcher on linux" do
76
+ allow(Kernel).to receive(:require).with('rb-inotify')
77
+ allow(FeatherWatch::OS).to receive(:mac?) {false}
78
+ allow(FeatherWatch::OS).to receive(:linux?) {true}
79
+ allow(FeatherWatch::OS).to receive(:windows?) {false}
80
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
81
+
82
+ path = "/"
83
+ callback = lambda { |e| }
84
+ verbose = false
85
+
86
+ linux_spy = spy "LinuxWatcher"
87
+ expect(FeatherWatch::Core::LinuxWatcher).to receive(:new).with([path],callback,verbose) {linux_spy}
88
+ expect(linux_spy).to receive(:start)
89
+ FeatherWatch::Watcher.new(path,callback,verbose).start
90
+ end
91
+ it "calls start on a WindowsWatcher on windows" do
92
+ allow(Kernel).to receive(:require).with('wdm')
93
+ allow(FeatherWatch::OS).to receive(:mac?) {false}
94
+ allow(FeatherWatch::OS).to receive(:linux?) {false}
95
+ allow(FeatherWatch::OS).to receive(:windows?) {true}
96
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
97
+
98
+ path = "/"
99
+ callback = lambda { |e| }
100
+ verbose = false
101
+
102
+ windows_spy = spy "WindowsWatcher"
103
+ expect(FeatherWatch::Core::WindowsWatcher).to receive(:new).with([path],callback,verbose) {windows_spy}
104
+ expect(windows_spy).to receive(:start)
105
+ FeatherWatch::Watcher.new(path,callback,verbose).start
106
+ end
107
+ end
108
+
109
+ describe ".stop" do
110
+ it "calls stop on a DarwinWatcher on darwin" do
111
+ allow(Kernel).to receive(:require).with('rb-fsevent')
112
+ allow(FeatherWatch::OS).to receive(:mac?) {true}
113
+ allow(FeatherWatch::OS).to receive(:linux?) {false}
114
+ allow(FeatherWatch::OS).to receive(:windows?) {false}
115
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
116
+
117
+ path = "/"
118
+ callback = lambda { |e| }
119
+ verbose = false
120
+
121
+ darwin_spy = spy "DarwinWatcher"
122
+ expect(FeatherWatch::Core::DarwinWatcher).to receive(:new).with([path],callback,verbose) {darwin_spy}
123
+ expect(darwin_spy).to receive(:stop)
124
+ FeatherWatch::Watcher.new(path,callback,verbose).stop
125
+ end
126
+ it "calls stop on a LinuxWatcher on linux" do
127
+ allow(Kernel).to receive(:require).with('rb-inotify')
128
+ allow(FeatherWatch::OS).to receive(:mac?) {false}
129
+ allow(FeatherWatch::OS).to receive(:linux?) {true}
130
+ allow(FeatherWatch::OS).to receive(:windows?) {false}
131
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
132
+
133
+ path = "/"
134
+ callback = lambda { |e| }
135
+ verbose = false
136
+
137
+ linux_spy = spy "LinuxWatcher"
138
+ expect(FeatherWatch::Core::LinuxWatcher).to receive(:new).with([path],callback,verbose) {linux_spy}
139
+ expect(linux_spy).to receive(:stop)
140
+ FeatherWatch::Watcher.new(path,callback,verbose).stop
141
+ end
142
+ it "calls stop on a WindowsWatcher on windows" do
143
+ allow(Kernel).to receive(:require).with('wdm')
144
+ allow(FeatherWatch::OS).to receive(:mac?) {false}
145
+ allow(FeatherWatch::OS).to receive(:linux?) {false}
146
+ allow(FeatherWatch::OS).to receive(:windows?) {true}
147
+ allow(FeatherWatch::OS).to receive(:unix?) {false}
148
+
149
+ path = "/"
150
+ callback = lambda { |e| }
151
+ verbose = false
152
+
153
+ windows_spy = spy "WindowsWatcher"
154
+ expect(FeatherWatch::Core::WindowsWatcher).to receive(:new).with([path],callback,verbose) {windows_spy}
155
+ expect(windows_spy).to receive(:stop)
156
+ FeatherWatch::Watcher.new(path,callback,verbose).stop
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,81 @@
1
+ describe FeatherWatch do
2
+ before(:each) do
3
+ FileUtils.mkdir(File.join(Dir.pwd, "test_folder"))
4
+ end
5
+ after(:each) do
6
+ FileUtils.rm_rf(File.join(Dir.pwd, "test_folder"))
7
+ end
8
+
9
+ it "passen self.new on to FeatherWatch::Watcher" do
10
+ args = ["/",lambda { |e| }, false]
11
+ expect(FeatherWatch::Watcher).to receive(:new).with(*args)
12
+ FeatherWatch.new(*args)
13
+ end
14
+ #These tests are platform dependent and should be run once on windows, darwin, and linux
15
+ #This test is also prone to sporadic failures.
16
+ it "returns correct file path and status when file is added" do
17
+ path = File.join(Dir.pwd, "test_folder")
18
+ callback_spy = spy("Callback Spy")
19
+ verbose = false
20
+
21
+ file_path = File.join(Dir.pwd, "test_folder", "new_file")
22
+
23
+ if FeatherWatch::OS.mac?
24
+ expect(callback_spy).to receive(:call).with({status: :modified ,file: file_path})
25
+ else
26
+ expect(callback_spy).to receive(:call).with({status: :added ,file: file_path})
27
+ end
28
+
29
+ watcher = FeatherWatch::Watcher.new(path,callback_spy,verbose)
30
+ watcher.start
31
+ sleep 0.1 #need to wait for watcher to properly start
32
+ FileUtils.touch(file_path)
33
+ sleep 0.1 #need to wait for file event to propegate.
34
+ watcher.stop
35
+ end
36
+
37
+ it "returns correct file path and status when file is removed" do
38
+ path = File.join(Dir.pwd, "test_folder")
39
+ callback_spy = spy("Callback Spy")
40
+ verbose = false
41
+
42
+ file_path = File.join(Dir.pwd, "test_folder", "new_file")
43
+ FileUtils.touch(file_path)
44
+ sleep 0.1
45
+ expect(callback_spy).to receive(:call).with({status: :removed ,file: file_path})
46
+
47
+ watcher = FeatherWatch::Watcher.new(path,callback_spy,verbose)
48
+ watcher.start
49
+ sleep 0.1 #need to wait for watcher to properly start
50
+ FileUtils.rm(file_path)
51
+ sleep 0.1 #need to wait for file event to propegate.
52
+ watcher.stop
53
+ end
54
+
55
+ it "returns correct file path and status when file is moved" do
56
+ path = File.join(Dir.pwd, "test_folder")
57
+ callback_spy = spy("Callback Spy")
58
+ verbose = false
59
+
60
+ file_path = File.join(Dir.pwd, "test_folder", "new_file")
61
+ file_path_new = File.join(Dir.pwd, "test_folder", "new_file_new")
62
+
63
+ FileUtils.touch(file_path)
64
+ sleep 0.1
65
+
66
+ expect(callback_spy).to receive(:call).with({status: :removed ,file: file_path})
67
+ if FeatherWatch::OS.mac?
68
+ expect(callback_spy).to receive(:call).with({status: :modified ,file: file_path_new})
69
+ else
70
+ expect(callback_spy).to receive(:call).with({status: :added ,file: file_path_new})
71
+ end
72
+
73
+ watcher = FeatherWatch::Watcher.new(path,callback_spy,verbose)
74
+ watcher.start
75
+ sleep 0.1 #need to wait for watcher to properly start
76
+ FileUtils.mv(file_path, file_path_new)
77
+ sleep 0.1 #need to wait for file event to propegate.
78
+ watcher.stop
79
+ end
80
+ end
81
+
@@ -0,0 +1,110 @@
1
+ #START: HACK TO GET TRAVIS TO FAIL CORRECTLY WHEN SPECS FAIL:
2
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
3
+ module Kernel
4
+ alias :__at_exit :at_exit
5
+ def at_exit(&block)
6
+ __at_exit do
7
+ exit_status = $!.status if $!.is_a?(SystemExit)
8
+ block.call
9
+ exit exit_status if exit_status
10
+ end
11
+ end
12
+ end
13
+ end
14
+ #END
15
+
16
+ require 'simplecov'
17
+ SimpleCov.start
18
+
19
+ require "feather_watch"
20
+ require "fileutils"
21
+
22
+ # This file was generated by the `rspec --init` command. Conventionally, all
23
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
24
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
25
+ # file to always be loaded, without a need to explicitly require it in any files.
26
+ #
27
+ # Given that it is always loaded, you are encouraged to keep this file as
28
+ # light-weight as possible. Requiring heavyweight dependencies from this file
29
+ # will add to the boot time of your test suite on EVERY test run, even for an
30
+ # individual file that may not need all of that loaded. Instead, consider making
31
+ # a separate helper file that requires the additional dependencies and performs
32
+ # the additional setup, and require it from the spec files that actually need it.
33
+ #
34
+ # The `.rspec` file also contains a few flags that are not defaults but that
35
+ # users commonly want.
36
+ #
37
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
38
+ RSpec.configure do |config|
39
+ # rspec-expectations config goes here. You can use an alternate
40
+ # assertion/expectation library such as wrong or the stdlib/minitest
41
+ # assertions if you prefer.
42
+ config.expect_with :rspec do |expectations|
43
+ # This option will default to `true` in RSpec 4. It makes the `description`
44
+ # and `failure_message` of custom matchers include text for helper methods
45
+ # defined using `chain`, e.g.:
46
+ # be_bigger_than(2).and_smaller_than(4).description
47
+ # # => "be bigger than 2 and smaller than 4"
48
+ # ...rather than:
49
+ # # => "be bigger than 2"
50
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
51
+ end
52
+
53
+ # rspec-mocks config goes here. You can use an alternate test double
54
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
55
+ config.mock_with :rspec do |mocks|
56
+ # Prevents you from mocking or stubbing a method that does not exist on
57
+ # a real object. This is generally recommended, and will default to
58
+ # `true` in RSpec 4.
59
+ mocks.verify_partial_doubles = true
60
+ end
61
+
62
+ # The settings below are suggested to provide a good initial experience
63
+ # with RSpec, but feel free to customize to your heart's content.
64
+ =begin
65
+ # These two settings work together to allow you to limit a spec run
66
+ # to individual examples or groups you care about by tagging them with
67
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
68
+ # get run.
69
+ config.filter_run :focus
70
+ config.run_all_when_everything_filtered = true
71
+
72
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
73
+ # For more details, see:
74
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
75
+ # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
76
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
77
+ config.disable_monkey_patching!
78
+
79
+ # This setting enables warnings. It's recommended, but in some cases may
80
+ # be too noisy due to issues in dependencies.
81
+ config.warnings = true
82
+
83
+ # Many RSpec users commonly either run the entire suite or an individual
84
+ # file, and it's useful to allow more verbose output when running an
85
+ # individual spec file.
86
+ if config.files_to_run.one?
87
+ # Use the documentation formatter for detailed output,
88
+ # unless a formatter has already been configured
89
+ # (e.g. via a command-line flag).
90
+ config.default_formatter = 'doc'
91
+ end
92
+
93
+ # Print the 10 slowest examples and example groups at the
94
+ # end of the spec run, to help surface which specs are running
95
+ # particularly slow.
96
+ config.profile_examples = 10
97
+
98
+ # Run specs in random order to surface order dependencies. If you find an
99
+ # order dependency and want to debug it, you can fix the order by providing
100
+ # the seed, which is printed after each run.
101
+ # --seed 1234
102
+ config.order = :random
103
+
104
+ # Seed global randomization in this process using the `--seed` CLI option.
105
+ # Setting this allows you to use `--seed` to deterministically reproduce
106
+ # test failures related to randomization by passing the same `--seed` value
107
+ # as the one that triggered the failure.
108
+ Kernel.srand config.seed
109
+ =end
110
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feather_watch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephan Nordnes Eriksen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rb-fsevent
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rb-inotify
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.9'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.9'
41
+ - !ruby/object:Gem::Dependency
42
+ name: wdm
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.6'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.6'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: simplecov
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: A barebones file system watcher which uses native file system events
112
+ for Linux, OSx, and Windows.
113
+ email:
114
+ - stephanruler@gmail.com
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - ".rspec"
121
+ - ".travis.yml"
122
+ - Feather Watch.png
123
+ - Gemfile
124
+ - LICENSE.txt
125
+ - README.md
126
+ - Rakefile
127
+ - feather_watch.gemspec
128
+ - lib/feather_watch.rb
129
+ - lib/feather_watch/core/darwin_watcher.rb
130
+ - lib/feather_watch/core/linux_watcher.rb
131
+ - lib/feather_watch/core/windows_watcher.rb
132
+ - lib/feather_watch/os.rb
133
+ - lib/feather_watch/version.rb
134
+ - lib/feather_watch/watcher.rb
135
+ - spec/lib/feather_watch/core/watcher_spec.rb
136
+ - spec/lib/feather_watch/feather_watch_spec.rb
137
+ - spec/spec_helper.rb
138
+ homepage: https://github.com/stephan-nordnes-eriksen/feather_watch
139
+ licenses:
140
+ - MIT
141
+ metadata: {}
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ version: '0'
151
+ required_rubygems_version: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - ">="
154
+ - !ruby/object:Gem::Version
155
+ version: '0'
156
+ requirements: []
157
+ rubyforge_project:
158
+ rubygems_version: 2.2.2
159
+ signing_key:
160
+ specification_version: 4
161
+ summary: Barebones, simple, and fast file system watcher
162
+ test_files:
163
+ - spec/lib/feather_watch/core/watcher_spec.rb
164
+ - spec/lib/feather_watch/feather_watch_spec.rb
165
+ - spec/spec_helper.rb
166
+ has_rdoc: