fssm 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  ---
2
- :build:
3
- :minor: 1
4
- :patch: 2
5
2
  :major: 0
3
+ :minor: 1
4
+ :patch: 3
5
+ :build:
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{fssm}
8
- s.version = "0.1.2"
8
+ s.version = "0.1.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Travis Tilley"]
12
- s.date = %q{2009-12-26}
12
+ s.date = %q{2010-02-27}
13
13
  s.description = %q{file system state monitor}
14
14
  s.email = %q{ttilley@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -33,7 +33,8 @@ Gem::Specification.new do |s|
33
33
  "lib/fssm/monitor.rb",
34
34
  "lib/fssm/path.rb",
35
35
  "lib/fssm/pathname.rb",
36
- "lib/fssm/state.rb",
36
+ "lib/fssm/state/directory.rb",
37
+ "lib/fssm/state/file.rb",
37
38
  "lib/fssm/support.rb",
38
39
  "lib/fssm/tree.rb",
39
40
  "profile/prof-cache.rb",
@@ -52,12 +53,12 @@ Gem::Specification.new do |s|
52
53
  s.homepage = %q{http://github.com/ttilley/fssm}
53
54
  s.rdoc_options = ["--charset=UTF-8"]
54
55
  s.require_paths = ["lib"]
55
- s.rubygems_version = %q{1.3.5}
56
+ s.rubygems_version = %q{1.3.6}
56
57
  s.summary = %q{file system state monitor}
57
58
  s.test_files = [
58
59
  "spec/path_spec.rb",
59
- "spec/root/file.rb",
60
- "spec/spec_helper.rb"
60
+ "spec/spec_helper.rb",
61
+ "spec/root/file.rb"
61
62
  ]
62
63
 
63
64
  if s.respond_to? :specification_version then
@@ -12,15 +12,7 @@ module FSSM
12
12
 
13
13
  def monitor(*args, &block)
14
14
  monitor = FSSM::Monitor.new
15
- context = args.empty? ? monitor : monitor.path(*args)
16
-
17
- if block_given?
18
- if block.arity == 1
19
- block.call(context)
20
- else
21
- context.instance_eval(&block)
22
- end
23
- end
15
+ FSSM::Support.use_block(args.empty? ? monitor : monitor.path(*args), block)
24
16
 
25
17
  monitor.run
26
18
  end
@@ -33,7 +25,8 @@ require 'fssm/pathname'
33
25
  require 'fssm/support'
34
26
  require 'fssm/tree'
35
27
  require 'fssm/path'
36
- require 'fssm/state'
28
+ require 'fssm/state/directory'
29
+ require 'fssm/state/file'
37
30
  require 'fssm/monitor'
38
31
 
39
32
  require "fssm/backends/#{FSSM::Support.backend.downcase}"
@@ -7,18 +7,17 @@ module FSSM::Backends
7
7
  @fsevents = []
8
8
  end
9
9
 
10
- def add_path(path, preload=true)
11
- handler = FSSM::State.new(path)
12
- @handlers["#{path}"] = handler
10
+ def add_handler(handler, preload=true)
11
+ @handlers[handler.path.to_s] = handler
13
12
 
14
- fsevent = Rucola::FSEvents.new("#{path}", {:latency => 0.5}) do |events|
13
+ fsevent = Rucola::FSEvents.new(handler.path.to_s, {:latency => 0.5}) do |events|
15
14
  events.each do |event|
16
15
  handler.refresh(event.path)
17
16
  end
18
17
  end
19
18
 
20
19
  fsevent.create_stream
21
- handler.refresh(path.to_pathname, true) if preload
20
+ handler.refresh(nil, true) if preload
22
21
  fsevent.start
23
22
  @fsevents << fsevent
24
23
  end
@@ -4,14 +4,15 @@ module FSSM::Backends
4
4
  @notifier = INotify::Notifier.new
5
5
  end
6
6
 
7
- def add_path(path, preload=true)
8
- handler = FSSM::State.new(path)
9
-
10
- @notifier.watch(path.to_s, :all_events) do |event|
11
- handler.refresh(event.name)
7
+ def add_handler(handler, preload=true)
8
+ @notifier.watch(handler.path.to_s, :recursive, :attrib, :modify, :create,
9
+ :delete, :delete_self, :moved_from, :moved_to, :move_self) do |event|
10
+ path = FSSM::Pathname.for(event.absolute_name)
11
+ path = path.dirname unless event.name == "" # Event on root directory
12
+ handler.refresh(path)
12
13
  end
13
14
 
14
- handler.refresh(path.to_pathname, true) if preload
15
+ handler.refresh(nil, true) if preload
15
16
  end
16
17
 
17
18
  def run
@@ -5,9 +5,8 @@ module FSSM::Backends
5
5
  @latency = options[:latency] || 1.5
6
6
  end
7
7
 
8
- def add_path(path, preload=true)
9
- handler = FSSM::State.new(path)
10
- handler.refresh(path.to_pathname, true) if preload
8
+ def add_handler(handler, preload=true)
9
+ handler.refresh(nil, true) if preload
11
10
  @handlers << handler
12
11
  end
13
12
 
@@ -6,16 +6,17 @@ class FSSM::Monitor
6
6
 
7
7
  def path(*args, &block)
8
8
  path = FSSM::Path.new(*args)
9
+ FSSM::Support.use_block(path, block)
9
10
 
10
- if block_given?
11
- if block.arity == 1
12
- block.call(path)
13
- else
14
- path.instance_eval(&block)
15
- end
16
- end
11
+ @backend.add_handler(FSSM::State::Directory.new(path))
12
+ path
13
+ end
14
+
15
+ def file(*args, &block)
16
+ path = FSSM::Path.new(*args)
17
+ FSSM::Support.use_block(path, block)
17
18
 
18
- @backend.add_path(path)
19
+ @backend.add_handler(FSSM::State::File.new(path))
19
20
  path
20
21
  end
21
22
 
@@ -81,7 +81,7 @@ class FSSM::Path
81
81
 
82
82
  def set_path(path)
83
83
  path = FSSM::Pathname.for(path)
84
- raise FSSM::FileNotFoundError, "#{path}" unless path.exist?
84
+ raise FSSM::FileNotFoundError, "No such file or directory - #{path}" unless path.exist?
85
85
  @path = path.expand_path
86
86
  end
87
87
 
@@ -1,65 +1,50 @@
1
- # The bundled ruby pathname library is a slow and hideous beast.
2
- # There. I said it. This version is based on pathname3.
1
+ require 'fileutils'
2
+ require 'find'
3
3
 
4
4
  module FSSM
5
5
  class Pathname < String
6
+ SYMLOOP_MAX = 8
6
7
 
7
- SEPARATOR = Regexp.quote(File::SEPARATOR)
8
-
9
- if File::ALT_SEPARATOR
10
- ALT_SEPARATOR = Regexp.quote(File::ALT_SEPARATOR)
11
- SEPARATOR_PAT = Regexp.compile("[#{SEPARATOR}#{ALT_SEPARATOR}]")
12
- else
13
- SEPARATOR_PAT = Regexp.compile(SEPARATOR)
14
- end
15
-
16
- if RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/
17
- PREFIX_PAT = Regexp.compile("^([A-Za-z]:#{SEPARATOR_PAT})")
18
- else
19
- PREFIX_PAT = Regexp.compile("^(#{SEPARATOR_PAT})")
20
- end
8
+ ROOT = '/'.freeze
9
+ DOT = '.'.freeze
10
+ DOT_DOT = '..'.freeze
21
11
 
22
12
  class << self
23
13
  def for(path)
24
- path = path.is_a?(::FSSM::Pathname) ? path : new(path)
25
- path.dememo
26
- path
14
+ path.is_a?(::FSSM::Pathname) ? path : new("#{path}")
27
15
  end
28
16
  end
29
17
 
30
18
  def initialize(path)
31
- if path =~ %r{\0}
32
- raise ArgumentError, "path cannot contain ASCII NULLs"
33
- end
34
-
35
- dememo
36
-
19
+ raise ArgumentError, "path cannot contain ASCII NULLs" if path =~ %r{\0}
37
20
  super(path)
38
21
  end
39
22
 
40
- def to_path
41
- self
23
+ def <=>(other)
24
+ self.tr('/', "\0").to_s <=> other.to_str.tr('/', "\0")
25
+ rescue NoMethodError
26
+ nil
42
27
  end
43
28
 
44
- def to_s
45
- "#{self}"
46
- end
29
+ def ==(other)
30
+ left = self.cleanpath.tr('/', "\0").to_s
31
+ right = self.class.for(other).cleanpath.tr('/', "\0").to_s
47
32
 
48
- alias to_str to_s
33
+ left == right
34
+ rescue NoMethodError
35
+ false
36
+ end
49
37
 
50
- def to_a
51
- return @segments if @segments
52
- set_prefix_and_names
53
- @segments = @names.dup
54
- @segments.delete('.')
55
- @segments.unshift(@prefix) unless @prefix.empty?
56
- @segments
38
+ def +(path)
39
+ dup << path
57
40
  end
58
41
 
59
- alias segments to_a
42
+ def <<(path)
43
+ replace( join(path).cleanpath! )
44
+ end
60
45
 
61
- def each_filename(&block)
62
- to_a.each(&block)
46
+ def absolute?
47
+ self[0, 1].to_s == ROOT
63
48
  end
64
49
 
65
50
  def ascend
@@ -69,37 +54,8 @@ module FSSM
69
54
  end
70
55
  end
71
56
 
72
- def descend
73
- parts = to_a
74
- 1.upto(parts.length) do |i|
75
- yield self.class.join(parts[0, i])
76
- end
77
- end
78
-
79
- def root?
80
- set_prefix_and_names
81
- @names.empty? && !@prefix.empty?
82
- end
83
-
84
- def parent
85
- self + '..'
86
- end
87
-
88
- def relative?
89
- set_prefix_and_names
90
- @prefix.empty?
91
- end
92
-
93
- def absolute?
94
- !relative?
95
- end
96
-
97
- def +(path)
98
- dup << path
99
- end
100
-
101
- def <<(path)
102
- replace(join(path).cleanpath!)
57
+ def children
58
+ entries[2..-1]
103
59
  end
104
60
 
105
61
  def cleanpath!
@@ -108,14 +64,16 @@ module FSSM
108
64
 
109
65
  parts.each do |part|
110
66
  case part
111
- when '.' then
67
+ when DOT then
112
68
  next
113
- when '..' then
69
+ when DOT_DOT then
114
70
  case final.last
115
- when '..' then
116
- final.push('..')
117
- when nil then
118
- final.push('..')
71
+ when ROOT then
72
+ next
73
+ when DOT_DOT then
74
+ final.push(DOT_DOT)
75
+ when nil then
76
+ final.push(DOT_DOT)
119
77
  else
120
78
  final.pop
121
79
  end
@@ -124,142 +82,128 @@ module FSSM
124
82
  end
125
83
  end
126
84
 
127
- replace(final.empty? ? Dir.pwd : File.join(*final))
85
+ replace(final.empty? ? DOT : self.class.join(*final))
128
86
  end
129
87
 
130
88
  def cleanpath
131
89
  dup.cleanpath!
132
90
  end
133
91
 
134
- def realpath
135
- raise unless self.exist?
92
+ def descend
93
+ parts = to_a
94
+ 1.upto(parts.length) { |i| yield self.class.join(parts[0, i]) }
95
+ end
136
96
 
137
- if File.symlink?(self)
138
- file = self.dup
97
+ def dot?
98
+ self == DOT
99
+ end
139
100
 
140
- while true
141
- file = File.join(File.dirname(file), File.readlink(file))
142
- break unless File.symlink?(file)
143
- end
101
+ def dot_dot?
102
+ self == DOT_DOT
103
+ end
144
104
 
145
- self.class.new(file).clean
146
- else
147
- self.class.new(Dir.pwd) + self
105
+ def each_filename(&blk)
106
+ to_a.each(&blk)
107
+ end
108
+
109
+ def mountpoint?
110
+ stat1 = self.lstat
111
+ stat2 = self.parent.lstat
112
+
113
+ stat1.dev != stat2.dev || stat1.ino == stat2.ino
114
+ rescue Errno::ENOENT
115
+ false
116
+ end
117
+
118
+ def parent
119
+ self + '..'
120
+ end
121
+
122
+ def realpath
123
+ path = self
124
+
125
+ SYMLOOP_MAX.times do
126
+ link = path.readlink
127
+ link = path.dirname + link if link.relative?
128
+ path = link
148
129
  end
130
+
131
+ raise Errno::ELOOP, self
132
+ rescue Errno::EINVAL
133
+ path.expand_path
134
+ end
135
+
136
+ def relative?
137
+ !absolute?
149
138
  end
150
139
 
151
140
  def relative_path_from(base)
152
141
  base = self.class.for(base)
153
142
 
154
- if self.absolute? != base.absolute?
155
- raise ArgumentError, 'no relative path between a relative and absolute'
156
- end
143
+ raise ArgumentError, 'no relative path between a relative and absolute' if self.absolute? != base.absolute?
157
144
 
158
- if self.prefix != base.prefix
159
- raise ArgumentError, "different prefix: #{@prefix.inspect} and #{base.prefix.inspect}"
160
- end
145
+ return self if base.dot?
146
+ return self.class.new(DOT) if self == base
161
147
 
162
- base = base.cleanpath!.segments
163
- dest = dup.cleanpath!.segments
148
+ base = base.cleanpath.to_a
149
+ dest = self.cleanpath.to_a
164
150
 
165
151
  while !dest.empty? && !base.empty? && dest[0] == base[0]
166
152
  base.shift
167
153
  dest.shift
168
154
  end
169
155
 
170
- base.shift if base[0] == '.'
171
- dest.shift if dest[0] == '.'
156
+ base.shift if base[0] == DOT
157
+ dest.shift if dest[0] == DOT
172
158
 
173
- if base.include?('..')
174
- raise ArgumentError, "base directory may not contain '..'"
175
- end
159
+ raise ArgumentError, "base directory may not contain '#{DOT_DOT}'" if base.include?(DOT_DOT)
176
160
 
177
- path = base.fill('..') + dest
161
+ path = base.fill(DOT_DOT) + dest
178
162
  path = self.class.join(*path)
179
- path = self.class.new('.') if path.empty?
163
+ path = self.class.new(DOT) if path.empty?
180
164
 
181
165
  path
182
166
  end
183
167
 
184
- def replace(path)
185
- if path =~ %r{\0}
186
- raise ArgumentError, "path cannot contain ASCII NULLs"
187
- end
188
-
189
- dememo
190
-
191
- super(path)
168
+ def root?
169
+ !!(self =~ %r{^#{ROOT}+$})
192
170
  end
193
171
 
194
- def unlink
195
- Dir.unlink(self)
196
- true
197
- rescue Errno::ENOTDIR
198
- File.unlink(self)
199
- true
172
+ def to_a
173
+ array = to_s.split(File::SEPARATOR)
174
+ array.delete('')
175
+ array.insert(0, ROOT) if absolute?
176
+ array
200
177
  end
201
178
 
202
- def prefix
203
- set_prefix_and_names
204
- @prefix
205
- end
179
+ alias segments to_a
206
180
 
207
- def names
208
- set_prefix_and_names
209
- @names
181
+ def to_path
182
+ self
210
183
  end
211
184
 
212
- def dememo
213
- @set = nil
214
- @segments = nil
215
- @prefix = nil
216
- @names = nil
185
+ def to_s
186
+ "#{self}"
217
187
  end
218
188
 
219
- private
220
-
221
- def set_prefix_and_names
222
- return if @set
223
-
224
- @names = []
225
-
226
- if (match = PREFIX_PAT.match(self))
227
- @prefix = match[0].to_s
228
- @names += match.post_match.split(SEPARATOR_PAT)
229
- else
230
- @prefix = ''
231
- @names += self.split(SEPARATOR_PAT)
232
- end
233
-
234
- @names.compact!
235
- @names.delete('')
189
+ alias to_str to_s
236
190
 
237
- @set = true
191
+ def unlink
192
+ Dir.unlink(self)
193
+ true
194
+ rescue Errno::ENOTDIR
195
+ File.unlink(self)
196
+ true
238
197
  end
239
-
240
198
  end
241
199
 
242
200
  class Pathname
243
- class << self
244
- def glob(pattern, flags=0)
245
- dirs = Dir.glob(pattern, flags)
246
- dirs.map! {|path| new(path)}
247
-
248
- if block_given?
249
- dirs.each {|dir| yield dir}
250
- nil
251
- else
252
- dirs
253
- end
254
- end
255
-
256
- def [](pattern)
257
- Dir[pattern].map! {|path| new(path)}
258
- end
201
+ def self.[](pattern)
202
+ Dir[pattern].map! {|d| FSSM::Pathname.new(d) }
203
+ end
259
204
 
260
- def pwd
261
- new(Dir.pwd)
262
- end
205
+ def self.pwd
206
+ FSSM::Pathname.new(Dir.pwd)
263
207
  end
264
208
 
265
209
  def entries
@@ -278,6 +222,24 @@ module FSSM
278
222
  Dir.rmdir(self)
279
223
  end
280
224
 
225
+ def self.glob(pattern, flags = 0)
226
+ dirs = Dir.glob(pattern, flags)
227
+ dirs.map! {|path| FSSM::Pathname.new(path) }
228
+
229
+ if block_given?
230
+ dirs.each {|dir| yield dir }
231
+ nil
232
+ else
233
+ dirs
234
+ end
235
+ end
236
+
237
+ def glob(pattern, flags = 0, &block)
238
+ patterns = [pattern].flatten
239
+ patterns.map! {|p| self.class.glob(self.to_s + p, flags, &block) }
240
+ patterns.flatten
241
+ end
242
+
281
243
  def chdir
282
244
  blk = lambda { yield self } if block_given?
283
245
  Dir.chdir(self, &blk)
@@ -372,8 +334,6 @@ module FSSM
372
334
  def zero?
373
335
  FileTest.zero?(self)
374
336
  end
375
-
376
- alias exist? exists?
377
337
  end
378
338
 
379
339
  class Pathname
@@ -407,10 +367,10 @@ module FSSM
407
367
  end
408
368
 
409
369
  class Pathname
410
- class << self
411
- def join(*parts)
412
- new(File.join(*parts.reject {|p| p.empty? }))
413
- end
370
+ def self.join(*parts)
371
+ last_part = FSSM::Pathname.new(parts.last)
372
+ return last_part if last_part.absolute?
373
+ FSSM::Pathname.new(File.join(*parts.reject {|p| p.empty? }))
414
374
  end
415
375
 
416
376
  def basename
@@ -478,6 +438,10 @@ module FSSM
478
438
  File.size?(self)
479
439
  end
480
440
 
441
+ def split
442
+ File.split(self).map {|part| FSSM::Pathname.new(part) }
443
+ end
444
+
481
445
  def symlink(to)
482
446
  File.symlink(self, to)
483
447
  end
@@ -525,4 +489,14 @@ module FSSM
525
489
  end
526
490
  end
527
491
 
492
+ class Pathname
493
+ class << self
494
+ alias getwd pwd
495
+ end
496
+
497
+ alias absolute expand_path
498
+ alias delete unlink
499
+ alias exist? exists?
500
+ alias fnmatch fnmatch?
501
+ end
528
502
  end
@@ -0,0 +1,57 @@
1
+ module FSSM::State
2
+ class Directory
3
+ attr_reader :path
4
+
5
+ def initialize(path)
6
+ @path = path
7
+ @cache = FSSM::Tree::Cache.new
8
+ end
9
+
10
+ def refresh(base=nil, skip_callbacks=false)
11
+ previous, current = recache(base || @path.to_pathname)
12
+
13
+ unless skip_callbacks
14
+ deleted(previous, current)
15
+ created(previous, current)
16
+ modified(previous, current)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def created(previous, current)
23
+ (current.keys - previous.keys).each {|created| @path.create(created)}
24
+ end
25
+
26
+ def deleted(previous, current)
27
+ (previous.keys - current.keys).each {|deleted| @path.delete(deleted)}
28
+ end
29
+
30
+ def modified(previous, current)
31
+ (current.keys & previous.keys).each do |file|
32
+ @path.update(file) if (current[file] <=> previous[file]) != 0
33
+ end
34
+ end
35
+
36
+ def recache(base)
37
+ base = FSSM::Pathname.for(base)
38
+ previous = @cache.files
39
+ snapshot(base)
40
+ current = @cache.files
41
+ [previous, current]
42
+ end
43
+
44
+ def snapshot(base)
45
+ base = FSSM::Pathname.for(base)
46
+ @cache.unset(base)
47
+ @path.glob.each {|glob| add_glob(base, glob)}
48
+ end
49
+
50
+ def add_glob(base, glob)
51
+ FSSM::Pathname.glob(base.join(glob).to_s).each do |fn|
52
+ @cache.set(fn)
53
+ end
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,24 @@
1
+ module FSSM::State
2
+ class File
3
+ attr_reader :path
4
+
5
+ def initialize(path)
6
+ @path = path
7
+ end
8
+
9
+ def refresh(base=nil, skip_callbacks=false)
10
+ base ||= @path.to_pathname
11
+ used_to_exist, @exists = @exists, base.exists?
12
+ # this handles bad symlinks without failing. why handle bad symlinks at
13
+ # all? well, we could still be interested in their creation and deletion.
14
+ old_mtime, @mtime = @mtime, base.symlink? ? Time.at(0) : base.mtime if @exists
15
+
16
+ unless skip_callbacks
17
+ @path.delete(@path.to_s) if used_to_exist && !@exists
18
+ @path.create(@path.to_s) if !used_to_exist && @exists
19
+ @path.update(@path.to_s) if used_to_exist && @exists && old_mtime != @mtime
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -37,15 +37,26 @@ module FSSM::Support
37
37
  end
38
38
 
39
39
  def rb_inotify?
40
- begin
41
- require 'rubygems'
42
- gem 'rb-inotify', '>= 0.3.0'
40
+ found = begin
43
41
  require 'rb-inotify'
44
- true
45
- rescue LoadError, Gem::LoadError
46
- STDERR.puts("Warning: Unable to load rb-inotify >= 0.3.0. Inotify will be unavailable.")
42
+ if defined?(INotify::VERSION)
43
+ version = INotify::VERSION
44
+ version[0] > 0 || version[1] >= 6
45
+ end
46
+ rescue LoadError
47
47
  false
48
48
  end
49
+ STDERR.puts("Warning: Unable to load rb-inotify >= 0.5.1. Inotify will be unavailable.") unless found
50
+ found
51
+ end
52
+
53
+ def use_block(context, block)
54
+ return if block.nil?
55
+ if block.arity == 1
56
+ block.call(context)
57
+ else
58
+ context.instance_eval(&block)
59
+ end
49
60
  end
50
61
 
51
62
  end
metadata CHANGED
@@ -1,27 +1,34 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fssm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 3
9
+ version: 0.1.3
5
10
  platform: ruby
6
11
  authors:
7
- - Travis Tilley
12
+ - Travis Tilley
8
13
  autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2009-12-26 00:00:00 -05:00
17
+ date: 2010-02-27 00:00:00 -05:00
13
18
  default_executable:
14
19
  dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: rspec
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- version:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
25
32
  description: file system state monitor
26
33
  email: ttilley@gmail.com
27
34
  executables: []
@@ -29,69 +36,72 @@ executables: []
29
36
  extensions: []
30
37
 
31
38
  extra_rdoc_files:
32
- - LICENSE
33
- - README.markdown
39
+ - LICENSE
40
+ - README.markdown
34
41
  files:
35
- - .document
36
- - .gitignore
37
- - LICENSE
38
- - README.markdown
39
- - Rakefile
40
- - VERSION.yml
41
- - example.rb
42
- - fssm.gemspec
43
- - lib/fssm.rb
44
- - lib/fssm/backends/fsevents.rb
45
- - lib/fssm/backends/inotify.rb
46
- - lib/fssm/backends/polling.rb
47
- - lib/fssm/backends/rubycocoa/fsevents.rb
48
- - lib/fssm/monitor.rb
49
- - lib/fssm/path.rb
50
- - lib/fssm/pathname.rb
51
- - lib/fssm/state.rb
52
- - lib/fssm/support.rb
53
- - lib/fssm/tree.rb
54
- - profile/prof-cache.rb
55
- - profile/prof-fssm-pathname.html
56
- - profile/prof-pathname.rb
57
- - profile/prof-plain-pathname.html
58
- - profile/prof.html
59
- - spec/path_spec.rb
60
- - spec/root/duck/quack.txt
61
- - spec/root/file.css
62
- - spec/root/file.rb
63
- - spec/root/file.yml
64
- - spec/root/moo/cow.txt
65
- - spec/spec_helper.rb
42
+ - .document
43
+ - .gitignore
44
+ - LICENSE
45
+ - README.markdown
46
+ - Rakefile
47
+ - VERSION.yml
48
+ - example.rb
49
+ - fssm.gemspec
50
+ - lib/fssm.rb
51
+ - lib/fssm/backends/fsevents.rb
52
+ - lib/fssm/backends/inotify.rb
53
+ - lib/fssm/backends/polling.rb
54
+ - lib/fssm/backends/rubycocoa/fsevents.rb
55
+ - lib/fssm/monitor.rb
56
+ - lib/fssm/path.rb
57
+ - lib/fssm/pathname.rb
58
+ - lib/fssm/state/directory.rb
59
+ - lib/fssm/state/file.rb
60
+ - lib/fssm/support.rb
61
+ - lib/fssm/tree.rb
62
+ - profile/prof-cache.rb
63
+ - profile/prof-fssm-pathname.html
64
+ - profile/prof-pathname.rb
65
+ - profile/prof-plain-pathname.html
66
+ - profile/prof.html
67
+ - spec/path_spec.rb
68
+ - spec/root/duck/quack.txt
69
+ - spec/root/file.css
70
+ - spec/root/file.rb
71
+ - spec/root/file.yml
72
+ - spec/root/moo/cow.txt
73
+ - spec/spec_helper.rb
66
74
  has_rdoc: true
67
75
  homepage: http://github.com/ttilley/fssm
68
76
  licenses: []
69
77
 
70
78
  post_install_message:
71
79
  rdoc_options:
72
- - --charset=UTF-8
80
+ - --charset=UTF-8
73
81
  require_paths:
74
- - lib
82
+ - lib
75
83
  required_ruby_version: !ruby/object:Gem::Requirement
76
84
  requirements:
77
- - - ">="
78
- - !ruby/object:Gem::Version
79
- version: "0"
80
- version:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ segments:
88
+ - 0
89
+ version: "0"
81
90
  required_rubygems_version: !ruby/object:Gem::Requirement
82
91
  requirements:
83
- - - ">="
84
- - !ruby/object:Gem::Version
85
- version: "0"
86
- version:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ version: "0"
87
97
  requirements: []
88
98
 
89
99
  rubyforge_project:
90
- rubygems_version: 1.3.5
100
+ rubygems_version: 1.3.6
91
101
  signing_key:
92
102
  specification_version: 3
93
103
  summary: file system state monitor
94
104
  test_files:
95
- - spec/path_spec.rb
96
- - spec/root/file.rb
97
- - spec/spec_helper.rb
105
+ - spec/path_spec.rb
106
+ - spec/spec_helper.rb
107
+ - spec/root/file.rb
@@ -1,54 +0,0 @@
1
- require 'yaml'
2
- class FSSM::State
3
- def initialize(path)
4
- @path = path
5
- @cache = FSSM::Tree::Cache.new
6
- end
7
-
8
- def refresh(base=nil, skip_callbacks=false)
9
- previous, current = recache(base || @path.to_pathname)
10
-
11
- unless skip_callbacks
12
- deleted(previous, current)
13
- created(previous, current)
14
- modified(previous, current)
15
- end
16
- end
17
-
18
- private
19
-
20
- def created(previous, current)
21
- (current.keys - previous.keys).each {|created| @path.create(created)}
22
- end
23
-
24
- def deleted(previous, current)
25
- (previous.keys - current.keys).each {|deleted| @path.delete(deleted)}
26
- end
27
-
28
- def modified(previous, current)
29
- (current.keys & previous.keys).each do |file|
30
- @path.update(file) if (current[file] <=> previous[file]) != 0
31
- end
32
- end
33
-
34
- def recache(base)
35
- base = FSSM::Pathname.for(base)
36
- previous = @cache.files
37
- snapshot(base)
38
- current = @cache.files
39
- [previous, current]
40
- end
41
-
42
- def snapshot(base)
43
- base = FSSM::Pathname.for(base)
44
- @cache.unset(base)
45
- @path.glob.each {|glob| add_glob(base, glob)}
46
- end
47
-
48
- def add_glob(base, glob)
49
- FSSM::Pathname.glob(base.join(glob).to_s).each do |fn|
50
- @cache.set(fn)
51
- end
52
- end
53
-
54
- end