fssm 0.0.9 → 0.1.0
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.
- data/.gitignore +4 -2
- data/VERSION.yml +2 -2
- data/example.rb +3 -3
- data/fssm.gemspec +3 -2
- data/lib/fssm.rb +2 -2
- data/lib/fssm/backends/fsevents.rb +5 -5
- data/lib/fssm/backends/inotify.rb +25 -0
- data/lib/fssm/backends/polling.rb +2 -2
- data/lib/fssm/{fsevents.rb → backends/rubycocoa/fsevents.rb} +22 -20
- data/lib/fssm/pathname.rb +310 -132
- data/lib/fssm/support.rb +32 -3
- data/lib/fssm/tree.rb +43 -42
- data/profile/prof-cache.rb +2 -2
- data/profile/prof-fssm-pathname.html +1224 -1112
- data/profile/prof-pathname.rb +2 -2
- data/profile/prof-plain-pathname.html +981 -902
- data/profile/prof.html +2372 -2156
- data/spec/path_spec.rb +3 -3
- metadata +3 -2
data/.gitignore
CHANGED
data/VERSION.yml
CHANGED
data/example.rb
CHANGED
@@ -3,7 +3,7 @@ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
3
3
|
require 'fssm'
|
4
4
|
|
5
5
|
FSSM.monitor('.', '**/*') do
|
6
|
-
update {|b,r| puts "Update in #{b} to #{r}"}
|
7
|
-
delete {|b,r| puts "Delete in #{b} to #{r}"}
|
8
|
-
create {|b,r| puts "Create in #{b} to #{r}"}
|
6
|
+
update {|b, r| puts "Update in #{b} to #{r}"}
|
7
|
+
delete {|b, r| puts "Delete in #{b} to #{r}"}
|
8
|
+
create {|b, r| puts "Create in #{b} to #{r}"}
|
9
9
|
end
|
data/fssm.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{fssm}
|
8
|
-
s.version = "0.0
|
8
|
+
s.version = "0.1.0"
|
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"]
|
@@ -27,8 +27,9 @@ Gem::Specification.new do |s|
|
|
27
27
|
"fssm.gemspec",
|
28
28
|
"lib/fssm.rb",
|
29
29
|
"lib/fssm/backends/fsevents.rb",
|
30
|
+
"lib/fssm/backends/inotify.rb",
|
30
31
|
"lib/fssm/backends/polling.rb",
|
31
|
-
"lib/fssm/fsevents.rb",
|
32
|
+
"lib/fssm/backends/rubycocoa/fsevents.rb",
|
32
33
|
"lib/fssm/monitor.rb",
|
33
34
|
"lib/fssm/path.rb",
|
34
35
|
"lib/fssm/pathname.rb",
|
data/lib/fssm.rb
CHANGED
@@ -4,13 +4,13 @@ $LOAD_PATH.unshift dir unless $LOAD_PATH.include?(dir)
|
|
4
4
|
module FSSM
|
5
5
|
FileNotFoundError = Class.new(StandardError)
|
6
6
|
CallbackError = Class.new(StandardError)
|
7
|
-
|
7
|
+
|
8
8
|
class << self
|
9
9
|
def dbg(msg=nil)
|
10
10
|
STDERR.puts(msg)
|
11
11
|
end
|
12
12
|
|
13
|
-
def monitor(*args, &block)
|
13
|
+
def monitor(*args, &block)
|
14
14
|
monitor = FSSM::Monitor.new
|
15
15
|
context = args.empty? ? monitor : monitor.path(*args)
|
16
16
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require File.join(File.dirname(__FILE__), 'rubycocoa/fsevents')
|
2
2
|
|
3
3
|
module FSSM::Backends
|
4
4
|
class FSEvents
|
@@ -6,23 +6,23 @@ module FSSM::Backends
|
|
6
6
|
@handlers = {}
|
7
7
|
@fsevents = []
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
def add_path(path, preload=true)
|
11
11
|
handler = FSSM::State.new(path)
|
12
12
|
@handlers["#{path}"] = handler
|
13
|
-
|
13
|
+
|
14
14
|
fsevent = Rucola::FSEvents.new("#{path}", {:latency => 0.5}) do |events|
|
15
15
|
events.each do |event|
|
16
16
|
handler.refresh(event.path)
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
fsevent.create_stream
|
21
21
|
handler.refresh(path.to_pathname, true) if preload
|
22
22
|
fsevent.start
|
23
23
|
@fsevents << fsevent
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def run
|
27
27
|
begin
|
28
28
|
OSX.CFRunLoopRun
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module FSSM::Backends
|
2
|
+
class Inotify
|
3
|
+
def initialize
|
4
|
+
@notifier = INotify::Notifier.new
|
5
|
+
end
|
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)
|
12
|
+
end
|
13
|
+
|
14
|
+
handler.refresh(path.to_pathname, true) if preload
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
begin
|
19
|
+
@notifier.run
|
20
|
+
rescue Interrupt
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -6,33 +6,35 @@ module Rucola
|
|
6
6
|
attr_reader :fsevents_object
|
7
7
|
attr_reader :id
|
8
8
|
attr_reader :path
|
9
|
+
|
9
10
|
def initialize(fsevents_object, id, path)
|
10
11
|
@fsevents_object, @id, @path = fsevents_object, id, path
|
11
12
|
end
|
12
|
-
|
13
|
+
|
13
14
|
# Returns an array of the files/dirs in the path that the event occurred in.
|
14
15
|
# The files are sorted by the modification time, the first entry is the last modified file.
|
15
16
|
def files
|
16
17
|
Dir.glob("#{File.expand_path(path)}/*").sort_by {|f| File.mtime(f) }.reverse
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
# Returns the last modified file in the path that the event occurred in.
|
20
21
|
def last_modified_file
|
21
22
|
files.first
|
22
23
|
end
|
23
24
|
end
|
24
|
-
|
25
|
-
class StreamError < StandardError;
|
26
|
-
|
25
|
+
|
26
|
+
class StreamError < StandardError;
|
27
|
+
end
|
28
|
+
|
27
29
|
attr_reader :paths
|
28
30
|
attr_reader :stream
|
29
|
-
|
31
|
+
|
30
32
|
attr_accessor :allocator
|
31
33
|
attr_accessor :context
|
32
34
|
attr_accessor :since
|
33
35
|
attr_accessor :latency
|
34
36
|
attr_accessor :flags
|
35
|
-
|
37
|
+
|
36
38
|
# Initializes a new FSEvents `watchdog` object and starts watching the directories you specify for events. The
|
37
39
|
# block is used as a handler for events, which are passed as the block's argument. This method is the easiest
|
38
40
|
# way to start watching some directories if you don't care about the details of setting up the event stream.
|
@@ -57,7 +59,7 @@ module Rucola
|
|
57
59
|
fsevents.start
|
58
60
|
fsevents
|
59
61
|
end
|
60
|
-
|
62
|
+
|
61
63
|
# Creates a new FSEvents `watchdog` object. You can specify a list of paths to watch and options to control the
|
62
64
|
# behaviour of the watchdog. The block you pass serves as a callback when an event is generated on one of the
|
63
65
|
# specified paths.
|
@@ -84,19 +86,19 @@ module Rucola
|
|
84
86
|
# Please refer to the Cocoa documentation for the rest of the options.
|
85
87
|
def initialize(*params, &block)
|
86
88
|
raise ArgumentError, 'No callback block was specified.' unless block_given?
|
87
|
-
|
89
|
+
|
88
90
|
options = params.last.kind_of?(Hash) ? params.pop : {}
|
89
91
|
@paths = params.flatten
|
90
|
-
|
92
|
+
|
91
93
|
paths.each { |path| raise ArgumentError, "The specified path (#{path}) does not exist." unless File.exist?(path) }
|
92
|
-
|
94
|
+
|
93
95
|
@allocator = options[:allocator] || OSX::KCFAllocatorDefault
|
94
|
-
@context
|
95
|
-
@since
|
96
|
-
@latency
|
97
|
-
@flags
|
98
|
-
@stream
|
99
|
-
|
96
|
+
@context = options[:context] || nil
|
97
|
+
@since = options[:since] || OSX::KFSEventStreamEventIdSinceNow
|
98
|
+
@latency = options[:latency] || 0.0
|
99
|
+
@flags = options[:flags] || 0
|
100
|
+
@stream = options[:stream] || nil
|
101
|
+
|
100
102
|
@user_callback = block
|
101
103
|
@callback = Proc.new do |stream, client_callback_info, number_of_events, paths_pointer, event_flags, event_ids|
|
102
104
|
paths_pointer.regard_as('*')
|
@@ -105,7 +107,7 @@ module Rucola
|
|
105
107
|
@user_callback.call(events)
|
106
108
|
end
|
107
109
|
end
|
108
|
-
|
110
|
+
|
109
111
|
# Create the stream.
|
110
112
|
# Raises a Rucola::FSEvents::StreamError if the stream could not be created.
|
111
113
|
def create_stream
|
@@ -113,13 +115,13 @@ module Rucola
|
|
113
115
|
raise(StreamError, 'Unable to create FSEvents stream.') unless @stream
|
114
116
|
OSX.FSEventStreamScheduleWithRunLoop(@stream, OSX.CFRunLoopGetCurrent, OSX::KCFRunLoopDefaultMode)
|
115
117
|
end
|
116
|
-
|
118
|
+
|
117
119
|
# Start the stream.
|
118
120
|
# Raises a Rucola::FSEvents::StreamError if the stream could not be started.
|
119
121
|
def start
|
120
122
|
raise(StreamError, 'Unable to start FSEvents stream.') unless OSX.FSEventStreamStart(@stream)
|
121
123
|
end
|
122
|
-
|
124
|
+
|
123
125
|
# Stop the stream.
|
124
126
|
# You can resume it by calling `start` again.
|
125
127
|
def stop
|
data/lib/fssm/pathname.rb
CHANGED
@@ -3,16 +3,16 @@
|
|
3
3
|
|
4
4
|
module FSSM
|
5
5
|
class Pathname < String
|
6
|
-
|
6
|
+
|
7
7
|
SEPARATOR = Regexp.quote(File::SEPARATOR)
|
8
|
-
|
8
|
+
|
9
9
|
if File::ALT_SEPARATOR
|
10
10
|
ALT_SEPARATOR = Regexp.quote(File::ALT_SEPARATOR)
|
11
11
|
SEPARATOR_PAT = Regexp.compile("[#{SEPARATOR}#{ALT_SEPARATOR}]")
|
12
12
|
else
|
13
13
|
SEPARATOR_PAT = Regexp.compile(SEPARATOR)
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
if RUBY_PLATFORM =~ /(:?mswin|mingw|bccwin)/
|
17
17
|
PREFIX_PAT = Regexp.compile("^([A-Za-z]:#{SEPARATOR_PAT})")
|
18
18
|
else
|
@@ -26,27 +26,28 @@ module FSSM
|
|
26
26
|
path
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
def initialize(path)
|
31
31
|
if path =~ %r{\0}
|
32
32
|
raise ArgumentError, "path cannot contain ASCII NULLs"
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
dememo
|
36
|
-
|
36
|
+
|
37
37
|
super(path)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
def to_path
|
41
41
|
self
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
def to_s
|
45
45
|
"#{self}"
|
46
46
|
end
|
47
|
+
|
47
48
|
alias to_str to_s
|
48
|
-
|
49
|
-
def to_a
|
49
|
+
|
50
|
+
def to_a
|
50
51
|
return @segments if @segments
|
51
52
|
set_prefix_and_names
|
52
53
|
@segments = @names.dup
|
@@ -54,136 +55,142 @@ module FSSM
|
|
54
55
|
@segments.unshift(@prefix) unless @prefix.empty?
|
55
56
|
@segments
|
56
57
|
end
|
58
|
+
|
57
59
|
alias segments to_a
|
58
|
-
|
60
|
+
|
59
61
|
def each_filename(&block)
|
60
62
|
to_a.each(&block)
|
61
63
|
end
|
62
|
-
|
64
|
+
|
63
65
|
def ascend
|
64
66
|
parts = to_a
|
65
67
|
parts.length.downto(1) do |i|
|
66
68
|
yield self.class.join(parts[0, i])
|
67
69
|
end
|
68
70
|
end
|
69
|
-
|
71
|
+
|
70
72
|
def descend
|
71
73
|
parts = to_a
|
72
74
|
1.upto(parts.length) do |i|
|
73
75
|
yield self.class.join(parts[0, i])
|
74
76
|
end
|
75
77
|
end
|
76
|
-
|
78
|
+
|
77
79
|
def root?
|
78
80
|
set_prefix_and_names
|
79
81
|
@names.empty? && !@prefix.empty?
|
80
82
|
end
|
81
|
-
|
83
|
+
|
82
84
|
def parent
|
83
85
|
self + '..'
|
84
86
|
end
|
85
|
-
|
87
|
+
|
86
88
|
def relative?
|
87
89
|
set_prefix_and_names
|
88
90
|
@prefix.empty?
|
89
91
|
end
|
90
|
-
|
92
|
+
|
91
93
|
def absolute?
|
92
94
|
!relative?
|
93
95
|
end
|
94
|
-
|
96
|
+
|
95
97
|
def +(path)
|
96
98
|
dup << path
|
97
99
|
end
|
98
|
-
|
100
|
+
|
99
101
|
def <<(path)
|
100
102
|
replace(join(path).cleanpath!)
|
101
103
|
end
|
102
|
-
|
104
|
+
|
103
105
|
def cleanpath!
|
104
106
|
parts = to_a
|
105
107
|
final = []
|
106
108
|
|
107
109
|
parts.each do |part|
|
108
110
|
case part
|
109
|
-
when '.'
|
110
|
-
|
111
|
+
when '.' then
|
112
|
+
next
|
113
|
+
when '..' then
|
111
114
|
case final.last
|
112
|
-
when '..'
|
113
|
-
|
114
|
-
|
115
|
+
when '..' then
|
116
|
+
final.push('..')
|
117
|
+
when nil then
|
118
|
+
final.push('..')
|
119
|
+
else
|
120
|
+
final.pop
|
115
121
|
end
|
116
|
-
else
|
122
|
+
else
|
123
|
+
final.push(part)
|
117
124
|
end
|
118
125
|
end
|
119
126
|
|
120
127
|
replace(final.empty? ? Dir.pwd : File.join(*final))
|
121
128
|
end
|
122
|
-
|
129
|
+
|
123
130
|
def cleanpath
|
124
131
|
dup.cleanpath!
|
125
132
|
end
|
126
|
-
|
133
|
+
|
127
134
|
def realpath
|
128
|
-
|
135
|
+
raise unless self.exist?
|
129
136
|
|
130
|
-
|
131
|
-
|
137
|
+
if File.symlink?(self)
|
138
|
+
file = self.dup
|
132
139
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
140
|
+
while true
|
141
|
+
file = File.join(File.dirname(file), File.readlink(file))
|
142
|
+
break unless File.symlink?(file)
|
143
|
+
end
|
137
144
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
145
|
+
self.class.new(file).clean
|
146
|
+
else
|
147
|
+
self.class.new(Dir.pwd) + self
|
148
|
+
end
|
142
149
|
end
|
143
|
-
|
150
|
+
|
144
151
|
def relative_path_from(base)
|
145
152
|
base = self.class.for(base)
|
146
|
-
|
153
|
+
|
147
154
|
if self.absolute? != base.absolute?
|
148
155
|
raise ArgumentError, 'no relative path between a relative and absolute'
|
149
156
|
end
|
150
|
-
|
157
|
+
|
151
158
|
if self.prefix != base.prefix
|
152
159
|
raise ArgumentError, "different prefix: #{@prefix.inspect} and #{base.prefix.inspect}"
|
153
160
|
end
|
154
|
-
|
161
|
+
|
155
162
|
base = base.cleanpath!.segments
|
156
163
|
dest = dup.cleanpath!.segments
|
157
|
-
|
164
|
+
|
158
165
|
while !dest.empty? && !base.empty? && dest[0] == base[0]
|
159
166
|
base.shift
|
160
167
|
dest.shift
|
161
168
|
end
|
162
|
-
|
169
|
+
|
163
170
|
base.shift if base[0] == '.'
|
164
171
|
dest.shift if dest[0] == '.'
|
165
|
-
|
172
|
+
|
166
173
|
if base.include?('..')
|
167
174
|
raise ArgumentError, "base directory may not contain '..'"
|
168
175
|
end
|
169
|
-
|
176
|
+
|
170
177
|
path = base.fill('..') + dest
|
171
178
|
path = self.class.join(*path)
|
172
179
|
path = self.class.new('.') if path.empty?
|
173
|
-
|
180
|
+
|
174
181
|
path
|
175
182
|
end
|
176
|
-
|
177
|
-
def replace(path)
|
183
|
+
|
184
|
+
def replace(path)
|
178
185
|
if path =~ %r{\0}
|
179
186
|
raise ArgumentError, "path cannot contain ASCII NULLs"
|
180
187
|
end
|
181
|
-
|
188
|
+
|
182
189
|
dememo
|
183
|
-
|
190
|
+
|
184
191
|
super(path)
|
185
192
|
end
|
186
|
-
|
193
|
+
|
187
194
|
def unlink
|
188
195
|
Dir.unlink(self)
|
189
196
|
true
|
@@ -191,31 +198,31 @@ module FSSM
|
|
191
198
|
File.unlink(self)
|
192
199
|
true
|
193
200
|
end
|
194
|
-
|
201
|
+
|
195
202
|
def prefix
|
196
203
|
set_prefix_and_names
|
197
204
|
@prefix
|
198
205
|
end
|
199
|
-
|
206
|
+
|
200
207
|
def names
|
201
208
|
set_prefix_and_names
|
202
209
|
@names
|
203
210
|
end
|
204
|
-
|
211
|
+
|
205
212
|
def dememo
|
206
|
-
@set
|
207
|
-
@segments
|
208
|
-
@prefix
|
209
|
-
@names
|
213
|
+
@set = nil
|
214
|
+
@segments = nil
|
215
|
+
@prefix = nil
|
216
|
+
@names = nil
|
210
217
|
end
|
211
|
-
|
218
|
+
|
212
219
|
private
|
213
|
-
|
220
|
+
|
214
221
|
def set_prefix_and_names
|
215
222
|
return if @set
|
216
|
-
|
223
|
+
|
217
224
|
@names = []
|
218
|
-
|
225
|
+
|
219
226
|
if (match = PREFIX_PAT.match(self))
|
220
227
|
@prefix = match[0].to_s
|
221
228
|
@names += match.post_match.split(SEPARATOR_PAT)
|
@@ -223,10 +230,10 @@ module FSSM
|
|
223
230
|
@prefix = ''
|
224
231
|
@names += self.split(SEPARATOR_PAT)
|
225
232
|
end
|
226
|
-
|
233
|
+
|
227
234
|
@names.compact!
|
228
235
|
@names.delete('')
|
229
|
-
|
236
|
+
|
230
237
|
@set = true
|
231
238
|
end
|
232
239
|
|
@@ -237,7 +244,7 @@ module FSSM
|
|
237
244
|
def glob(pattern, flags=0)
|
238
245
|
dirs = Dir.glob(pattern, flags)
|
239
246
|
dirs.map! {|path| new(path)}
|
240
|
-
|
247
|
+
|
241
248
|
if block_given?
|
242
249
|
dirs.each {|dir| yield dir}
|
243
250
|
nil
|
@@ -245,62 +252,158 @@ module FSSM
|
|
245
252
|
dirs
|
246
253
|
end
|
247
254
|
end
|
248
|
-
|
255
|
+
|
249
256
|
def [](pattern)
|
250
257
|
Dir[pattern].map! {|path| new(path)}
|
251
258
|
end
|
252
|
-
|
259
|
+
|
253
260
|
def pwd
|
254
261
|
new(Dir.pwd)
|
255
262
|
end
|
256
263
|
end
|
257
|
-
|
258
|
-
def entries; Dir.entries(self).map! {|e| FSSM::Pathname.new(e) }; end
|
259
|
-
def mkdir(mode = 0777); Dir.mkdir(self, mode); end
|
260
|
-
def opendir(&blk); Dir.open(self, &blk); end
|
261
|
-
def rmdir; Dir.rmdir(self); end
|
262
264
|
|
263
|
-
def
|
265
|
+
def entries
|
266
|
+
Dir.entries(self).map! {|e| FSSM::Pathname.new(e) }
|
267
|
+
end
|
268
|
+
|
269
|
+
def mkdir(mode = 0777)
|
270
|
+
Dir.mkdir(self, mode)
|
271
|
+
end
|
272
|
+
|
273
|
+
def opendir(&blk)
|
274
|
+
Dir.open(self, &blk)
|
275
|
+
end
|
276
|
+
|
277
|
+
def rmdir
|
278
|
+
Dir.rmdir(self)
|
279
|
+
end
|
280
|
+
|
281
|
+
def chdir
|
264
282
|
blk = lambda { yield self } if block_given?
|
265
283
|
Dir.chdir(self, &blk)
|
266
284
|
end
|
267
285
|
end
|
268
286
|
|
269
287
|
class Pathname
|
270
|
-
def blockdev
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
def
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
def
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
def
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
def
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
def
|
291
|
-
|
292
|
-
|
288
|
+
def blockdev?
|
289
|
+
FileTest.blockdev?(self)
|
290
|
+
end
|
291
|
+
|
292
|
+
def chardev?
|
293
|
+
FileTest.chardev?(self)
|
294
|
+
end
|
295
|
+
|
296
|
+
def directory?
|
297
|
+
FileTest.directory?(self)
|
298
|
+
end
|
299
|
+
|
300
|
+
def executable?
|
301
|
+
FileTest.executable?(self)
|
302
|
+
end
|
303
|
+
|
304
|
+
def executable_real?
|
305
|
+
FileTest.executable_real?(self)
|
306
|
+
end
|
307
|
+
|
308
|
+
def exists?
|
309
|
+
FileTest.exists?(self)
|
310
|
+
end
|
311
|
+
|
312
|
+
def file?
|
313
|
+
FileTest.file?(self)
|
314
|
+
end
|
315
|
+
|
316
|
+
def grpowned?
|
317
|
+
FileTest.grpowned?(self)
|
318
|
+
end
|
319
|
+
|
320
|
+
def owned?
|
321
|
+
FileTest.owned?(self)
|
322
|
+
end
|
323
|
+
|
324
|
+
def pipe?
|
325
|
+
FileTest.pipe?(self)
|
326
|
+
end
|
327
|
+
|
328
|
+
def readable?
|
329
|
+
FileTest.readable?(self)
|
330
|
+
end
|
331
|
+
|
332
|
+
def readable_real?
|
333
|
+
FileTest.readable_real?(self)
|
334
|
+
end
|
335
|
+
|
336
|
+
def setgid?
|
337
|
+
FileTest.setgit?(self)
|
338
|
+
end
|
339
|
+
|
340
|
+
def setuid?
|
341
|
+
FileTest.setuid?(self)
|
342
|
+
end
|
343
|
+
|
344
|
+
def socket?
|
345
|
+
FileTest.socket?(self)
|
346
|
+
end
|
347
|
+
|
348
|
+
def sticky?
|
349
|
+
FileTest.sticky?(self)
|
350
|
+
end
|
351
|
+
|
352
|
+
def symlink?
|
353
|
+
FileTest.symlink?(self)
|
354
|
+
end
|
355
|
+
|
356
|
+
def world_readable?
|
357
|
+
FileTest.world_readable?(self)
|
358
|
+
end
|
359
|
+
|
360
|
+
def world_writable?
|
361
|
+
FileTest.world_writable?(self)
|
362
|
+
end
|
363
|
+
|
364
|
+
def writable?
|
365
|
+
FileTest.writable?(self)
|
366
|
+
end
|
367
|
+
|
368
|
+
def writable_real?
|
369
|
+
FileTest.writable_real?(self)
|
370
|
+
end
|
371
|
+
|
372
|
+
def zero?
|
373
|
+
FileTest.zero?(self)
|
374
|
+
end
|
375
|
+
|
293
376
|
alias exist? exists?
|
294
377
|
end
|
295
378
|
|
296
379
|
class Pathname
|
297
|
-
def atime
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
def
|
302
|
-
|
303
|
-
|
380
|
+
def atime
|
381
|
+
File.atime(self)
|
382
|
+
end
|
383
|
+
|
384
|
+
def ctime
|
385
|
+
File.ctime(self)
|
386
|
+
end
|
387
|
+
|
388
|
+
def ftype
|
389
|
+
File.ftype(self)
|
390
|
+
end
|
391
|
+
|
392
|
+
def lstat
|
393
|
+
File.lstat(self)
|
394
|
+
end
|
395
|
+
|
396
|
+
def mtime
|
397
|
+
File.mtime(self)
|
398
|
+
end
|
399
|
+
|
400
|
+
def stat
|
401
|
+
File.stat(self)
|
402
|
+
end
|
403
|
+
|
404
|
+
def utime(atime, mtime)
|
405
|
+
File.utime(self, atime, mtime)
|
406
|
+
end
|
304
407
|
end
|
305
408
|
|
306
409
|
class Pathname
|
@@ -309,42 +412,117 @@ module FSSM
|
|
309
412
|
new(File.join(*parts.reject {|p| p.empty? }))
|
310
413
|
end
|
311
414
|
end
|
312
|
-
|
313
|
-
def basename
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
def
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
def
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
def
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
def
|
330
|
-
|
415
|
+
|
416
|
+
def basename
|
417
|
+
self.class.new(File.basename(self))
|
418
|
+
end
|
419
|
+
|
420
|
+
def chmod(mode)
|
421
|
+
File.chmod(mode, self)
|
422
|
+
end
|
423
|
+
|
424
|
+
def chown(owner, group)
|
425
|
+
File.chown(owner, group, self)
|
426
|
+
end
|
427
|
+
|
428
|
+
def dirname
|
429
|
+
self.class.new(File.dirname(self))
|
430
|
+
end
|
431
|
+
|
432
|
+
def expand_path(from = nil)
|
433
|
+
self.class.new(File.expand_path(self, from))
|
434
|
+
end
|
435
|
+
|
436
|
+
def extname
|
437
|
+
File.extname(self)
|
438
|
+
end
|
439
|
+
|
440
|
+
def fnmatch?(pat, flags = 0)
|
441
|
+
File.fnmatch(pat, self, flags)
|
442
|
+
end
|
443
|
+
|
444
|
+
def join(*parts)
|
445
|
+
self.class.join(self, *parts)
|
446
|
+
end
|
447
|
+
|
448
|
+
def lchmod(mode)
|
449
|
+
File.lchmod(mode, self)
|
450
|
+
end
|
451
|
+
|
452
|
+
def lchown(owner, group)
|
453
|
+
File.lchown(owner, group, self)
|
454
|
+
end
|
455
|
+
|
456
|
+
def link(to)
|
457
|
+
File.link(self, to)
|
458
|
+
end
|
459
|
+
|
460
|
+
def open(mode = 'r', perm = nil, &blk)
|
461
|
+
File.open(self, mode, perm, &blk)
|
462
|
+
end
|
463
|
+
|
464
|
+
def readlink
|
465
|
+
self.class.new(File.readlink(self))
|
466
|
+
end
|
467
|
+
|
468
|
+
def rename(to)
|
469
|
+
File.rename(self, to)
|
470
|
+
replace(to)
|
471
|
+
end
|
472
|
+
|
473
|
+
def size
|
474
|
+
File.size(self)
|
475
|
+
end
|
476
|
+
|
477
|
+
def size?
|
478
|
+
File.size?(self)
|
479
|
+
end
|
480
|
+
|
481
|
+
def symlink(to)
|
482
|
+
File.symlink(self, to)
|
483
|
+
end
|
484
|
+
|
485
|
+
def truncate
|
486
|
+
File.truncate(self)
|
487
|
+
end
|
331
488
|
end
|
332
489
|
|
333
490
|
class Pathname
|
334
|
-
def mkpath
|
335
|
-
|
336
|
-
|
491
|
+
def mkpath
|
492
|
+
self.class.new(FileUtils.mkpath(self))
|
493
|
+
end
|
494
|
+
|
495
|
+
def rmtree
|
496
|
+
self.class.new(FileUtils.rmtree(self).first)
|
497
|
+
end
|
498
|
+
|
499
|
+
def touch
|
500
|
+
self.class.new(FileUtils.touch(self).first)
|
501
|
+
end
|
337
502
|
end
|
338
503
|
|
339
504
|
class Pathname
|
340
|
-
def each_line(sep = $/, &blk)
|
341
|
-
|
342
|
-
|
343
|
-
|
505
|
+
def each_line(sep = $/, &blk)
|
506
|
+
IO.foreach(self, sep, &blk)
|
507
|
+
end
|
508
|
+
|
509
|
+
def read(len = nil, off = 0)
|
510
|
+
IO.read(self, len, off)
|
511
|
+
end
|
512
|
+
|
513
|
+
def readlines(sep = $/)
|
514
|
+
IO.readlines(self, sep)
|
515
|
+
end
|
516
|
+
|
517
|
+
def sysopen(mode = 'r', perm = nil)
|
518
|
+
IO.sysopen(self, mode, perm)
|
519
|
+
end
|
344
520
|
end
|
345
521
|
|
346
522
|
class Pathname
|
347
|
-
def find
|
523
|
+
def find
|
524
|
+
Find.find(self) {|path| yield FSSM::Pathname.new(path) }
|
525
|
+
end
|
348
526
|
end
|
349
527
|
|
350
528
|
end
|