file-monitor 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,142 @@
1
+ Ruby File Monitor
2
+ =================
3
+
4
+ Ruby File Monitor is a easy way to watch the directories and files, do anything when them changed. It's base on [rb-inotify](https://github.com/nex3/rb-inotify), So it only works in inotify supported system such as Linux.
5
+
6
+ Requirements
7
+ ------------
8
+
9
+ Ruby >= 1.8.7
10
+
11
+ Linux Kernel >= 2.6.13
12
+
13
+ Features
14
+ --------
15
+
16
+ 1. Auto watching recursively:
17
+
18
+ If make a new directory in the watched directory, the new directory will be watched automatically.
19
+
20
+ 2. Support Ignore Dirs:
21
+
22
+ Any directory matched Regexp pattern ignored_dirs will not be watched.
23
+
24
+ 3. Support Ignore Files:
25
+
26
+ Any files matched Regexp pattern ignored_files will not be recorded.
27
+
28
+ 4. Events Buffer Mechanism:
29
+
30
+ To avoid run the check methods too quickly, for example, when delete 20 files at the same time, if without Events Buffer will run the check methods 20 times. the frequency of file-monitor is 0.2 second
31
+
32
+
33
+ Installation
34
+ ------------
35
+ Install from source
36
+
37
+ git clone https://github.com/jiangmiao/ruby-file-monitor
38
+ cd ruby-file-monitor
39
+ gem build file-monitor.gemspec
40
+ gem install file-monitor-0.1.0.gem --user-install
41
+
42
+ Install from gem server
43
+
44
+ gem install file-monitor
45
+
46
+ Usage
47
+ -----
48
+ ### Using block
49
+
50
+ #!/usr/bin/env ruby
51
+ # coding: utf-8
52
+ # File: examples/use-block.rb
53
+
54
+ require 'file-monitor'
55
+
56
+ dir = ARGV[0] || '.'
57
+ m = FileMonitor.new(dir)
58
+
59
+ # ignore any dirs contains .git on .svn
60
+ m.ignored_dirs = /\.git|\.svn/
61
+
62
+ # ignore any files contains .swp or ~
63
+ m.ignored_files = /\.swp|~/
64
+
65
+ # the block's events contains all file modified infomation in last 0.2 second
66
+ m.run do|events|
67
+ puts "#{events.size} events"
68
+ puts "do something"
69
+ end
70
+
71
+ ### Using inherit
72
+
73
+ #!/usr/bin/env ruby
74
+ # coding: utf-8
75
+ # File: examples/use-inherit.rb
76
+
77
+ require 'file-monitor'
78
+
79
+ class MyFileMonitor < FileMonitor
80
+ def check(events)
81
+ puts "#{events.size} events"
82
+ puts "do something"
83
+ end
84
+ end
85
+
86
+ dir = ARGV[0] || '.'
87
+ m = MyFileMonitor.new(dir)
88
+ m.ignored_dirs = /\.git|\.svn/
89
+ m.ignored_files = /\.swp|~/
90
+ m.run
91
+
92
+ If block exists, the check method will be ignored.
93
+
94
+ Examples
95
+ --------
96
+ ### Auto F5
97
+
98
+ Auto F5 will auto refresh the webpage in browser when any watched files changed. It's simple but very useful.
99
+
100
+ f5.rb requires sinatra.
101
+
102
+ #### Limitation:
103
+
104
+ 1. The watched page MUST have </body> tag.
105
+ f5.rb will insert script before </body> to refresh the page
106
+ when physical file changed.
107
+
108
+ 2. Only support GET requests.
109
+
110
+ #### Usage
111
+
112
+ Environment:
113
+ the website physical path is /var/www/foo
114
+ the host is www.foo.com
115
+ homepage is www.foo.com/index.html
116
+
117
+ start watching the directory
118
+ ruby examples/f5.rb /var/www/foo
119
+
120
+ open www.foo.com:4567/index.html in browser
121
+ you will see the page same as www.foo.com/index.html
122
+ do some changes on /var/www/foo/index.html then save the file.
123
+ or create or modify any file in /var/www/foo
124
+ www.foo.com/index.html will refresh automatically.
125
+
126
+ ### examples/use-block.rb
127
+
128
+ $ ruby examples/use-block.rb
129
+ watching .
130
+ watching ./lib/
131
+ ignore ./.git/
132
+ watching ./examples/
133
+
134
+ Edit and save README.md by gvim, examples/use-block outputs
135
+
136
+ + ./4913
137
+ - ./4913
138
+ - ./README.md
139
+ + ./README.md
140
+ # ./README.md
141
+ 5 events
142
+ do something
data/examples/f5.rb ADDED
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'rubygems'
5
+
6
+ lib_dir = File.join File.dirname(__FILE__), '../lib'
7
+ $:.unshift lib_dir unless $:.include? lib_dir
8
+
9
+ require 'file-monitor'
10
+ require 'sinatra'
11
+ require 'getoptlong'
12
+
13
+ class AjaxF5 < FileMonitor
14
+ attr_reader :updated_at, :js
15
+ def initialize(dir)
16
+ super dir
17
+ @updated_at = Time.now.to_f
18
+ # ajax library from http://code.google.com/p/miniajax/
19
+ @js = <<EOT
20
+ (function() {
21
+ var ajax;
22
+ function $(e){if(typeof e=='string')e=document.getElementById(e);return e};
23
+ function collect(a,f){var n=[];for(var i=0;i<a.length;i++){var v=f(a[i]);if(v!=null)n.push(v)}return n};
24
+
25
+ ajax={};
26
+ ajax.x=function(){try{return new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{return new ActiveXObject('Microsoft.XMLHTTP')}catch(e){return new XMLHttpRequest()}}};
27
+ ajax.serialize=function(f){var g=function(n){return f.getElementsByTagName(n)};var nv=function(e){if(e.name)return encodeURIComponent(e.name)+'='+encodeURIComponent(e.value);else return ''};var i=collect(g('input'),function(i){if((i.type!='radio'&&i.type!='checkbox')||i.checked)return nv(i)});var s=collect(g('select'),nv);var t=collect(g('textarea'),nv);return i.concat(s).concat(t).join('&');};
28
+ ajax.send=function(u,f,m,a){var x=ajax.x();x.open(m,u,true);x.onreadystatechange=function(){if(x.readyState==4)f(x.responseText)};if(m=='POST')x.setRequestHeader('Content-type','application/x-www-form-urlencoded');x.send(a)};
29
+ ajax.get=function(url,func){ajax.send(url,func,'GET')};
30
+ var now = Date.now();
31
+ function checkStatus() {
32
+ ajax.get("/f5_status", function(rt) {
33
+ if (now < parseFloat(rt)) {
34
+ location.reload(true);
35
+ }
36
+ setTimeout(checkStatus, 500);
37
+ });
38
+ }
39
+ checkStatus();
40
+ })();
41
+ EOT
42
+ end
43
+
44
+ # simple mark the last updated time
45
+ def check(events)
46
+ @updated_at = Time.now.to_f
47
+ puts "updated at #{@updated_at}"
48
+ end
49
+
50
+ def run
51
+ # use new thread to monitor the file
52
+ Thread.new do
53
+ begin
54
+ super
55
+ rescue
56
+ puts $!.message
57
+ end
58
+ end
59
+
60
+ f5 = self
61
+ set :logging, false
62
+ get '/f5_status' do
63
+ (f5.updated_at*1000).to_s
64
+ end
65
+
66
+ get '/f5.js' do
67
+ f5.js
68
+ end
69
+
70
+ get '*' do
71
+ host = env['SERVER_NAME']
72
+ path = env['REQUEST_PATH']
73
+ begin
74
+ data = open('http://' + host + path) {|f|
75
+ content_type f.meta['content-type']
76
+ f.read
77
+ }
78
+ data.gsub Regexp.new('</body>', Regexp::IGNORECASE), '<script type="text/javascript" src="/f5.js"></script></body>'
79
+ rescue
80
+ $!.message.match /\d+/
81
+ [$&.to_i, {}, '']
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ dir = ARGV[0] || '.'
88
+
89
+ opts = GetoptLong.new(
90
+ [ '--help', '-h', GetoptLong::NO_ARGUMENT]
91
+ )
92
+
93
+ opts.each do|opt, arg|
94
+ case opt
95
+ when '--help'
96
+ puts 'ruby f5.rb [project-directory]'
97
+ exit
98
+ end
99
+ end
100
+
101
+ require 'sinatra'
102
+ require 'open-uri'
103
+ f5 = AjaxF5.new dir
104
+ f5.ignored_dirs = /\.git|\.svn/
105
+ f5.ignored_files = /\.sw.*|\~/
106
+ f5.run
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+ # File: examples/use-block.rb
4
+
5
+ require 'rubygems'
6
+
7
+ lib_dir = File.join File.dirname(__FILE__), '../lib'
8
+ $:.unshift lib_dir unless $:.include? lib_dir
9
+
10
+ require 'file-monitor'
11
+
12
+ dir = ARGV[0] || '.'
13
+ m = FileMonitor.new(dir)
14
+ # ignore any dirs end with .git on .svn
15
+ m.ignored_dirs = /\.git|\.svn/
16
+
17
+ # ignore any files end with .swp or ~
18
+ m.ignored_files = /\.swp|~/
19
+
20
+ # the block's events contains all file modified infomation in last 0.2 second
21
+ m.run do|events|
22
+ puts "#{events.size} events"
23
+ puts "do something"
24
+ end
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+ # File: examples/use-inherit.rb
4
+
5
+ require 'rubygems'
6
+
7
+ lib_dir = File.join File.dirname(__FILE__), '../lib'
8
+ $:.unshift lib_dir unless $:.include? lib_dir
9
+
10
+ require 'file-monitor.rb'
11
+
12
+ class MyFileMonitor < FileMonitor
13
+ def check(events)
14
+ puts "#{events.size} events"
15
+ puts "do something"
16
+ end
17
+ end
18
+
19
+ dir = ARGV[0] || '.'
20
+ m = MyFileMonitor.new(dir)
21
+ # ignore any dirs end with .git on .svn
22
+ m.ignored_dirs = /\.git|\.svn/
23
+
24
+ # ignore any files end with .swp or ~
25
+ m.ignored_files = /\.swp|~/
26
+
27
+ m.run
@@ -0,0 +1,146 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ require 'rb-inotify'
5
+
6
+ class FileMonitor
7
+ # the ignored list
8
+ attr_accessor :ignored_dirs, :ignored_files
9
+
10
+ # do the action every @frequency second, to avoid check too frequently
11
+ attr_accessor :frequency
12
+
13
+ def initialize(project_dir)
14
+ @notifier = INotify::Notifier.new
15
+ @project_dir = project_dir
16
+
17
+ @events = []
18
+ @ignores = []
19
+ @frequency = 0.2
20
+ end
21
+
22
+ def ignored?(path, pattern)
23
+ for ignore in Array(pattern)
24
+ if path =~ ignore
25
+ return true
26
+ end
27
+ end
28
+ return false
29
+ end
30
+
31
+ def ignored_dir?(path)
32
+ ignored? path, @ignored_dirs
33
+ end
34
+
35
+ def ignored_file?(path)
36
+ ignored? path, @ignored_files
37
+ end
38
+
39
+ # TODO combine events maybe it's not nesscary
40
+ # moved_from + moved_to = rename
41
+ # create + delete = delete
42
+ # delete + create = modify
43
+ # rename + delete = delete
44
+ def push_event event
45
+ @events << event
46
+ end
47
+
48
+ # Watch a directory
49
+ def watch(dir)
50
+ if ignored_dir?(dir)
51
+ puts "ignore #{dir}"
52
+ return false
53
+ else
54
+ puts "watching #{dir}"
55
+ end
56
+
57
+ @notifier.watch dir, :modify, :create, :move, :delete, :onlydir do|event|
58
+ flags = event.flags
59
+
60
+ # display event info
61
+ # + created or moved_to
62
+ # - deleted or moved_from
63
+ # # modified
64
+ info = ''
65
+ if flags.include? :moved_from
66
+ info += '-'
67
+ elsif flags.include? :moved_to
68
+ info += '+'
69
+ else
70
+ case flags[0]
71
+ when :create
72
+ info += '+'
73
+ when :modify
74
+ info += '#'
75
+ when :delete
76
+ info += '-'
77
+ when :ignored
78
+ info += 'stop watching'
79
+ end
80
+ end
81
+
82
+ if ignored_file?(event.absolute_name)
83
+ # the ignored info will not put currently
84
+ info += "i #{event.absolute_name}"
85
+ next
86
+ else
87
+ info += " #{event.absolute_name}"
88
+ puts info
89
+ end
90
+
91
+ if flags.include? :isdir
92
+ if flags.include? :ignore?
93
+ @notifier.watchers.delete watcher.id
94
+ elsif flags.include? :create or flags.include? :move
95
+ watch_recursive event.absolute_name
96
+ else
97
+ push_event event
98
+ end
99
+ else
100
+ push_event event
101
+ end
102
+ end
103
+
104
+ return true
105
+ end
106
+
107
+ # Watch directory recursive
108
+ # use our recursive instead rb-inotify's :recursive to filter the directory
109
+ def watch_recursive(dir)
110
+ if watch dir
111
+ # if watch current directory succeeded, then continue watching the sub-directories
112
+ Dir.glob(File.join(dir, "*/"), File::FNM_DOTMATCH).each do|subdir|
113
+ name = File.basename(subdir)
114
+ next if name == ".." or name == "."
115
+ watch_recursive subdir
116
+ end
117
+ end
118
+ end
119
+
120
+ # check the events received
121
+ def check(events)
122
+ if !@check_warning_notified
123
+ puts "[NOTICE] Inherit from FileMonitor and override method check(events) or\n use file_monitor_instance.run do|events| end to do anything when any file changes"
124
+ @check_warning_notified = true
125
+ end
126
+ end
127
+
128
+ # start watching
129
+ # if block given, check method will be ignored
130
+ def run(&block)
131
+ watch_recursive @project_dir
132
+
133
+ while true
134
+ if IO.select([@notifier.to_io], [], [], @frequency)
135
+ @notifier.process
136
+ elsif @events.size > 0
137
+ if block_given?
138
+ yield @events
139
+ else
140
+ check @events
141
+ end
142
+ @events = []
143
+ end
144
+ end
145
+ end
146
+ end
metadata ADDED
@@ -0,0 +1,99 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: file-monitor
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - JiangMiao
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-10-13 00:00:00 +08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rb-inotify
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 8
31
+ - 8
32
+ version: 0.8.8
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rb-inotify
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 0
45
+ - 8
46
+ - 8
47
+ version: 0.8.8
48
+ type: :development
49
+ version_requirements: *id002
50
+ description: Ruby File Monitor is a easy way to watch the directories and files, do anything when them changed.
51
+ email: jiangfriend@gmail.com
52
+ executables: []
53
+
54
+ extensions: []
55
+
56
+ extra_rdoc_files: []
57
+
58
+ files:
59
+ - lib/file-monitor.rb
60
+ - examples/use-block.rb
61
+ - examples/use-inherit.rb
62
+ - examples/f5.rb
63
+ - README.md
64
+ has_rdoc: true
65
+ homepage: https://github.com/jiangmiao/ruby-file-monitor
66
+ licenses: []
67
+
68
+ post_install_message:
69
+ rdoc_options: []
70
+
71
+ require_paths:
72
+ - lib
73
+ required_ruby_version: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ segments:
79
+ - 1
80
+ - 8
81
+ - 7
82
+ version: 1.8.7
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ requirements: []
92
+
93
+ rubyforge_project: file-monitor
94
+ rubygems_version: 1.3.7
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: File Monitor Library
98
+ test_files: []
99
+