fssm 0.1.2 → 0.1.3

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.
@@ -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