fun_with_files 0.0.14 → 0.0.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.markdown +15 -3
- data/Gemfile +17 -7
- data/{README.rdoc → README.markdown} +12 -11
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/lib/fun_with/files/bootstrapper.rb +87 -0
- data/lib/fun_with/files/core_extensions/file.rb +15 -3
- data/lib/fun_with/files/core_extensions/set.rb +12 -0
- data/lib/fun_with/files/core_extensions/true_class.rb +11 -0
- data/lib/fun_with/files/digest_methods.rb +50 -17
- data/lib/fun_with/files/directory_builder.rb +9 -4
- data/lib/fun_with/files/downloader.rb +29 -16
- data/lib/fun_with/files/errors.rb +9 -1
- data/lib/fun_with/files/file_manipulation_methods.rb +25 -15
- data/lib/fun_with/files/file_orderer.rb +2 -0
- data/lib/fun_with/files/file_path.rb +242 -156
- data/lib/fun_with/files/file_path_class_methods.rb +23 -2
- data/lib/fun_with/files/file_permission_methods.rb +18 -7
- data/lib/fun_with/files/file_requirements.rb +63 -7
- data/lib/fun_with/files/requirements/manager.rb +104 -0
- data/lib/fun_with/files/root_path.rb +3 -3
- data/lib/fun_with/files/stat_methods.rb +33 -0
- data/lib/fun_with/files/string_behavior.rb +6 -2
- data/lib/fun_with/files/utils/byte_size.rb +143 -0
- data/lib/fun_with/files/utils/opts.rb +26 -0
- data/lib/fun_with/files/utils/succession.rb +47 -0
- data/lib/fun_with/files/utils/timestamp.rb +47 -0
- data/lib/fun_with/files/utils/timestamp_format.rb +31 -0
- data/lib/fun_with/files/watcher.rb +157 -0
- data/lib/fun_with/files/watchers/directory_watcher.rb +67 -0
- data/lib/fun_with/files/watchers/file_watcher.rb +45 -0
- data/lib/fun_with/files/watchers/missing_watcher.rb +23 -0
- data/lib/fun_with/files/watchers/node_watcher.rb +44 -0
- data/lib/fun_with/testing/assertions/fun_with_files.rb +91 -0
- data/lib/fun_with/testing/test_case_extensions.rb +12 -0
- data/lib/fun_with_files.rb +5 -31
- data/test/helper.rb +13 -5
- data/test/test_core_extensions.rb +6 -0
- data/test/test_descent.rb +2 -2
- data/test/test_directory_builder.rb +29 -10
- data/test/test_extension_methods.rb +62 -0
- data/test/test_file_manipulation.rb +4 -4
- data/test/test_file_path.rb +83 -56
- data/test/test_file_requirements.rb +36 -0
- data/test/test_fun_with_files.rb +1 -1
- data/test/test_fwf_assertions.rb +62 -0
- data/test/test_moving_files.rb +111 -0
- data/test/test_permission_methods.rb +22 -0
- data/test/test_root_path.rb +9 -0
- data/test/test_stat_methods.rb +17 -0
- data/test/test_timestamping.rb +74 -0
- data/test/test_utils_bytesize.rb +71 -0
- data/test/test_utils_succession.rb +30 -0
- data/test/test_watchers.rb +196 -0
- metadata +59 -13
- /data/lib/fun_with/files/core_extensions/{false.rb → false_class.rb} +0 -0
- /data/lib/fun_with/files/core_extensions/{nil.rb → nil_class.rb} +0 -0
@@ -0,0 +1,157 @@
|
|
1
|
+
# You want to watch a list of files or directories for changes
|
2
|
+
# (files created, deleted, or modified), and then return a... list?
|
3
|
+
# of changes.
|
4
|
+
#
|
5
|
+
# Tricky part is, what constitutes a "change" for a directory.
|
6
|
+
# or a file, for that matter.
|
7
|
+
#
|
8
|
+
# Cool expansion: customize the sorts of changes that trigger actions.
|
9
|
+
# You can already do that to some extent with the user-code that the
|
10
|
+
# change list is delivered to
|
11
|
+
#
|
12
|
+
# usr/ (modified, watched)
|
13
|
+
# bin/ (modified)
|
14
|
+
# new_directory/ (created)
|
15
|
+
# README.txt (created)
|
16
|
+
# bash (unchanged)
|
17
|
+
#
|
18
|
+
# lib/ (modified)
|
19
|
+
# libgpg.so (unchanged)
|
20
|
+
# libmysql.so (deleted)
|
21
|
+
# libzip.so (modified)
|
22
|
+
# libjpeg.so (file_created)
|
23
|
+
# you_have_been_hacked_by_chinese.txt (file_created)
|
24
|
+
# cache/ (deleted)
|
25
|
+
# firefox/ (deleted)
|
26
|
+
# cached_item.jpg (deleted)
|
27
|
+
# cached_folder/ (deleted)
|
28
|
+
# cache_file.csv (deleted)
|
29
|
+
#
|
30
|
+
# When you find a change in a subdirector/file, the :modified status
|
31
|
+
# propagates up the tree.
|
32
|
+
# Feels like a job for a visitor.
|
33
|
+
#
|
34
|
+
# If you create the top-level watcher, it could create any sub-watchers
|
35
|
+
# for the files and folders. It asks its watchers to update their
|
36
|
+
# statuses and report back.
|
37
|
+
#
|
38
|
+
# But the top-level one should know that it's the top level, so it
|
39
|
+
# shouldn't be deleting its watchers that might be, for example,
|
40
|
+
# waiting for a file to come into being.
|
41
|
+
#
|
42
|
+
# Hence, anyone using this code probably ought to stick to using the main Watcher
|
43
|
+
# class, and not worry about the ones it uses in the background
|
44
|
+
#
|
45
|
+
# Filters can be added
|
46
|
+
module FunWith
|
47
|
+
module Files
|
48
|
+
class Watcher
|
49
|
+
def self.watch( *paths, interval: 1.0, notice: [], ignore: [], &block )
|
50
|
+
watcher = self.new( paths ).sleep_interval( interval ).filter( notice: notice, ignore: ignore )
|
51
|
+
|
52
|
+
if block_given?
|
53
|
+
watcher.watch( &block )
|
54
|
+
else
|
55
|
+
watcher
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.factory( path )
|
60
|
+
path = path.fwf_filepath
|
61
|
+
|
62
|
+
if path.exist?
|
63
|
+
if path.directory?
|
64
|
+
Watchers::DirectoryWatcher.new( path )
|
65
|
+
elsif path.file?
|
66
|
+
Watchers::FileWatcher.new( path )
|
67
|
+
end
|
68
|
+
else
|
69
|
+
Watchers::MissingWatcher.new( path )
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize( paths )
|
74
|
+
@sleep_interval = 1.0
|
75
|
+
@notice_filters = []
|
76
|
+
@ignore_filters = []
|
77
|
+
|
78
|
+
# Create a watcher for every single thing that we're
|
79
|
+
# asking it to watch
|
80
|
+
@watchers = paths.inject({}) do |watchers, path|
|
81
|
+
watchers[path.fwf_filepath] = self.class.factory( path )
|
82
|
+
watchers
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def sleep_interval( i )
|
87
|
+
@sleep_interval = i
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
def watch( &block )
|
92
|
+
while true
|
93
|
+
sleep( @sleep_interval )
|
94
|
+
yield self.update
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def filter( notice: [], ignore: [] )
|
99
|
+
@notice_filters += [notice].flatten
|
100
|
+
@ignore_filters += [ignore].flatten
|
101
|
+
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
# returns a hash of the changes that have happened in the file system being monitored,
|
106
|
+
def update
|
107
|
+
{}.tap do |changes|
|
108
|
+
for path, watcher in @watchers
|
109
|
+
changes.merge!( watcher.update )
|
110
|
+
replace_watcher( path, changes[path] ) # a DirectoryWatcher might need to be replaced with a MissingWatcher, for example, or vice-versa
|
111
|
+
|
112
|
+
# corner case: if a directory is created, everything created under the directory
|
113
|
+
# is deemed to have also been created at the same time
|
114
|
+
if path.directory? && changes[path] == :created
|
115
|
+
changes.merge!( path.glob(:all).inject({}){ |memo,path| memo[path] = :created ; memo } )
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
apply_filters( changes )
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def replace_watcher( path, change )
|
124
|
+
case change
|
125
|
+
when nil
|
126
|
+
# didn't change
|
127
|
+
when :deleted, :created
|
128
|
+
@watchers[path] = self.class.factory( path )
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
def apply_filters( changes )
|
134
|
+
apply_notice_filters( changes )
|
135
|
+
apply_ignore_filters( changes )
|
136
|
+
changes
|
137
|
+
end
|
138
|
+
|
139
|
+
def apply_notice_filters( changes )
|
140
|
+
for filter in @notice_filters
|
141
|
+
for path in changes.keys
|
142
|
+
changes.delete( path ) if path !~ filter
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def apply_ignore_filters( changes )
|
148
|
+
for filter in @ignore_filters
|
149
|
+
for path in changes.keys
|
150
|
+
changes.delete( path ) if path =~ filter
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Files
|
3
|
+
module Watchers
|
4
|
+
class DirectoryWatcher < NodeWatcher
|
5
|
+
def initialize( path )
|
6
|
+
set_path( path )
|
7
|
+
@watchers = create_watchers( self.path.entries )
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
# returns a hash of changes
|
12
|
+
def update
|
13
|
+
new_changeset do
|
14
|
+
if self.path.exist?
|
15
|
+
update_existing_files
|
16
|
+
find_new_files
|
17
|
+
else
|
18
|
+
# If the directory is gone, you can assume the same is true
|
19
|
+
# for all the files it held.
|
20
|
+
report_files( self.all_paths, :deleted )
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def update_existing_files
|
26
|
+
# first, check on the files we're supposed to be keeping track of
|
27
|
+
for path, watcher in @watchers
|
28
|
+
@changes[path] = :deleted unless path.exist?
|
29
|
+
@changes.merge!( watcher.update )
|
30
|
+
|
31
|
+
# While the main Watcher will continue to monitor the places it's
|
32
|
+
# been told, even if they're missing, the subwatchers just disappear
|
33
|
+
# when the files they're watching do.
|
34
|
+
@watchers.delete( path ) unless path.exist?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_new_files
|
39
|
+
# next, get the updated list of files/folders beneath this directory
|
40
|
+
current_paths = self.path.entries
|
41
|
+
|
42
|
+
for path in current_paths
|
43
|
+
unless @watchers.has_key?( path )
|
44
|
+
w = Watcher.factory( path )
|
45
|
+
|
46
|
+
report_files( w.all_paths, :created )
|
47
|
+
|
48
|
+
@watchers[path] = w
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# modify the current list of changes by adding "deleted" for
|
54
|
+
# every file/folder below this one.
|
55
|
+
def report_files( paths, status )
|
56
|
+
for path in paths
|
57
|
+
@changes[path] = status
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def all_paths
|
62
|
+
@watchers.map{|path, watcher| watcher.all_paths }.flatten + [self.path]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module FunWith
|
3
|
+
module Files
|
4
|
+
module Watchers
|
5
|
+
class FileWatcher < NodeWatcher
|
6
|
+
attr_accessor :last_modified
|
7
|
+
|
8
|
+
def initialize( path )
|
9
|
+
set_path( path )
|
10
|
+
refresh_last_modified
|
11
|
+
end
|
12
|
+
|
13
|
+
def refresh_last_modified
|
14
|
+
self.last_modified = self.path.stat.mtime if self.path.exist?
|
15
|
+
end
|
16
|
+
|
17
|
+
def modified?
|
18
|
+
self.path.exist? && self.last_modified < self.path.stat.mtime
|
19
|
+
end
|
20
|
+
|
21
|
+
def deleted?
|
22
|
+
! self.path.exist?
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
if deleted?
|
27
|
+
{ self.path => :deleted }
|
28
|
+
elsif modified?
|
29
|
+
refresh_last_modified
|
30
|
+
{ self.path => :modified }
|
31
|
+
else
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# returns all paths below it in the hierarchy, including
|
37
|
+
# the path of the node itself. In this case, there's
|
38
|
+
# only one path to return.
|
39
|
+
def all_paths
|
40
|
+
[self.path]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Files
|
3
|
+
module Watchers
|
4
|
+
# Watches a path where nothing currently exists, and reports a change if
|
5
|
+
# something appears there.
|
6
|
+
class MissingWatcher < NodeWatcher
|
7
|
+
def initialize( path )
|
8
|
+
set_path( path )
|
9
|
+
end
|
10
|
+
|
11
|
+
# The fact that the watcher now needs to be replaced with a File/DirectoryWatcher
|
12
|
+
# must be handled elsewhere.
|
13
|
+
def update
|
14
|
+
self.path.exist? ? {self.path => :created } : {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def all_paths
|
18
|
+
[]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
module FunWith
|
14
|
+
module Files
|
15
|
+
module Watchers
|
16
|
+
class NodeWatcher
|
17
|
+
attr_accessor :path
|
18
|
+
|
19
|
+
def set_path( path )
|
20
|
+
self.path = path.fwf_filepath
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_watchers( paths )
|
24
|
+
{}.tap do |watchers|
|
25
|
+
for path in paths
|
26
|
+
watchers[path.fwf_filepath] = Watcher.factory( path )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# sets up an object variable for changes, then clears it and returns
|
32
|
+
# the changes. I got sick of passing the changes hash around.
|
33
|
+
def new_changeset( &block )
|
34
|
+
@changes = {}
|
35
|
+
yield
|
36
|
+
|
37
|
+
changes = @changes
|
38
|
+
@changes = {}
|
39
|
+
changes
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module FunWith
|
2
|
+
module Testing
|
3
|
+
module Assertions
|
4
|
+
module FunWithFiles
|
5
|
+
# The object given must be an instance of class FilePath
|
6
|
+
def assert_fwf_filepath( file, msg = nil )
|
7
|
+
msg = message(msg){ "File <#{file}> should be a FunWith::Files::FilePath" }
|
8
|
+
assert_kind_of FunWith::Files::FilePath, file, msg
|
9
|
+
end
|
10
|
+
|
11
|
+
# The object given is an instance of class FilePath, and points to
|
12
|
+
# a file that exists.
|
13
|
+
def assert_file( file, msg = nil )
|
14
|
+
assert_fwf_filepath( file, message(nil){ "...is not a file." } )
|
15
|
+
|
16
|
+
msg = message(msg){ "File should exist at <#{file}>." }
|
17
|
+
assert file.file?, msg
|
18
|
+
end
|
19
|
+
|
20
|
+
# The object given is a filepath, but doesn't point to
|
21
|
+
# an existing file or directory.
|
22
|
+
def assert_no_file( file, msg = nil )
|
23
|
+
assert_fwf_filepath( file, message )
|
24
|
+
msg = message(msg){ "No file/directory should exist at <#{file}>." }
|
25
|
+
refute file.file?, msg
|
26
|
+
end
|
27
|
+
|
28
|
+
# The object given is a filepath, and points to a directory
|
29
|
+
def assert_directory( file, msg = nil )
|
30
|
+
assert_fwf_filepath( file, msg )
|
31
|
+
msg = message(msg){ "<#{file}> should be a directory." }
|
32
|
+
assert file.directory?, msg
|
33
|
+
end
|
34
|
+
|
35
|
+
# The object given is a filepath, but doesn't point to a directory.
|
36
|
+
def assert_not_directory( file, msg = nil )
|
37
|
+
assert_fwf_filepath( file, message )
|
38
|
+
msg = message(msg){ "<#{file}> shouldn't be a directory." }
|
39
|
+
refute file.directory?
|
40
|
+
end
|
41
|
+
|
42
|
+
# The object given is a filepath.
|
43
|
+
# It points to a file that exists.
|
44
|
+
# That file is empty.
|
45
|
+
def assert_empty_file( file, msg = nil )
|
46
|
+
assert_fwf_filepath( file )
|
47
|
+
msg = message(msg){ "Empty file should exist at <#{file}>." }
|
48
|
+
assert file.file? && file.empty?, msg
|
49
|
+
end
|
50
|
+
|
51
|
+
# The object given is a filepath.
|
52
|
+
# It points to a directory that exists.
|
53
|
+
# That directory is empty.
|
54
|
+
def assert_empty_directory( file, msg = nil )
|
55
|
+
assert_fwf_filepath( file )
|
56
|
+
msg = message(msg){ "Empty directory should exist at <#{file}>." }
|
57
|
+
assert file.directory? && file.empty?, msg
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# The object given is a filepath.
|
62
|
+
# It points to a file that exists.
|
63
|
+
# That file contains content.
|
64
|
+
def assert_file_has_content( file, msg = nil )
|
65
|
+
assert_fwf_filepath( file, message )
|
66
|
+
msg = message(msg){ "File should exist at <#{file}>, and have content." }
|
67
|
+
assert file.exist?, msg.call + "(file does not exist)"
|
68
|
+
assert file.file?, msg.call + "(not a file)"
|
69
|
+
refute file.empty?, msg.call + "(file is not empty)"
|
70
|
+
end
|
71
|
+
|
72
|
+
alias :assert_file_not_empty :assert_file_has_content
|
73
|
+
|
74
|
+
|
75
|
+
def assert_file_contents( file, content, msg = nil )
|
76
|
+
assert_file( file )
|
77
|
+
|
78
|
+
case content
|
79
|
+
when String
|
80
|
+
# message = build_message( message, "File <#{file}> contents should be #{content[0..99].inspect}#{'...(truncated)' if content.length > 100}" )
|
81
|
+
assert_equal( content, file.read, msg )
|
82
|
+
when Regexp
|
83
|
+
assert_match( content, file.read, msg )
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# The bulk of FunWith::Testing::TestCase can be found in the fun_with_testing gem.
|
2
|
+
|
3
|
+
module FunWith
|
4
|
+
module Testing
|
5
|
+
module TestCaseExtensions
|
6
|
+
def install_fun_with_files_assertions
|
7
|
+
include FunWith::Testing::Assertions::Basics # some of the FWF assertions rely on these
|
8
|
+
include FunWith::Testing::Assertions::FunWithFiles
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/fun_with_files.rb
CHANGED
@@ -1,38 +1,12 @@
|
|
1
1
|
require 'xdg'
|
2
2
|
require 'digest' # stdlib
|
3
3
|
require 'pathname' # stdlib
|
4
|
+
require 'set'
|
4
5
|
require 'tmpdir' # Dir.tmpdir
|
5
6
|
|
7
|
+
require 'debug'
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
|
9
|
+
require_relative 'fun_with/files/bootstrapper'
|
10
|
+
# sets up everything needed to load .requir(), which loads everything else
|
11
|
+
FunWith::Files::Bootstrapper.bootstrap
|
10
12
|
|
11
|
-
for klass in ["String", "Object", "NilClass", "Hash", "FalseClass", "Array"]
|
12
|
-
Kernel.const_get(klass).send( :include, FunWith::Files::CoreExtensions.const_get(klass))
|
13
|
-
end
|
14
|
-
|
15
|
-
|
16
|
-
for fil in ["file_path", "string_behavior", "file_manipulation_methods", "file_permission_methods", "digest_methods", "file_requirements"]
|
17
|
-
require_relative File.join( "fun_with", "files", fil )
|
18
|
-
end
|
19
|
-
|
20
|
-
|
21
|
-
# These have some FilePath methods required by .requir()
|
22
|
-
for mod in [ FunWith::Files::StringBehavior,
|
23
|
-
FunWith::Files::FileManipulationMethods,
|
24
|
-
FunWith::Files::FilePermissionMethods,
|
25
|
-
FunWith::Files::DigestMethods,
|
26
|
-
FunWith::Files::FileRequirements ]
|
27
|
-
FunWith::Files::FilePath.send( :include, mod )
|
28
|
-
end
|
29
|
-
|
30
|
-
lib_dir = File.dirname(__FILE__).fwf_filepath( "fun_with" )
|
31
|
-
|
32
|
-
# And requir() everything else
|
33
|
-
lib_dir.requir
|
34
|
-
|
35
|
-
FunWith::Files::RootPath.rootify( FunWith::Files, __FILE__.fwf_filepath.dirname.up )
|
36
|
-
FunWith::Files::FilePath.extend( FunWith::Files::FilePathClassMethods )
|
37
|
-
|
38
|
-
FunWith::Files.extend( FunWith::Files::GemAPI )
|
data/test/helper.rb
CHANGED
@@ -21,13 +21,21 @@ require 'fun_with_files'
|
|
21
21
|
|
22
22
|
class FunWith::Files::TestCase < FunWith::Testing::TestCase
|
23
23
|
include FunWith::Files
|
24
|
-
include FunWith::
|
25
|
-
|
24
|
+
include FunWith::Files::Errors
|
25
|
+
|
26
|
+
|
27
|
+
self.install_fun_with_files_assertions
|
28
|
+
# include FunWith::Testing::Assertions::FunWithFiles
|
29
|
+
# include FunWith::Testing::Assertions::Basics
|
26
30
|
|
27
31
|
def tmpdir( &block )
|
28
|
-
|
29
|
-
|
30
|
-
|
32
|
+
if block_given?
|
33
|
+
FilePath.tmpdir do |d|
|
34
|
+
@tmpdir = d
|
35
|
+
yield
|
36
|
+
end
|
37
|
+
else
|
38
|
+
@tmpdir = FilePath.tmpdir # remember to remove the directory when you're done
|
31
39
|
end
|
32
40
|
end
|
33
41
|
|
@@ -26,6 +26,12 @@ class TestCoreExtensions < FunWith::Files::TestCase
|
|
26
26
|
should "fwf_blank? nicely." do
|
27
27
|
assert_equal false, { 1 => 2 }.fwf_blank?
|
28
28
|
assert_equal true, {}.fwf_blank?
|
29
|
+
assert_equal true, true.fwf_present?
|
30
|
+
end
|
31
|
+
|
32
|
+
should "respond to fwf_filepath" do
|
33
|
+
assert_respond_to ".", :fwf_filepath
|
34
|
+
assert_respond_to ".".fwf_filepath, :fwf_filepath
|
29
35
|
end
|
30
36
|
end
|
31
37
|
end
|
data/test/test_descent.rb
CHANGED
@@ -7,11 +7,11 @@ class TestDescent < FunWith::Files::TestCase
|
|
7
7
|
ascent = []
|
8
8
|
descent = []
|
9
9
|
|
10
|
-
|
10
|
+
root.ascend do |path|
|
11
11
|
ascent << path
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
root.descend do |path|
|
15
15
|
descent << path
|
16
16
|
end
|
17
17
|
|
@@ -54,7 +54,7 @@ class TestDirectoryBuilder < FunWith::Files::TestCase
|
|
54
54
|
gemfile = b.current_path.join("Gemfile")
|
55
55
|
assert gemfile.exist?
|
56
56
|
assert !gemfile.zero?
|
57
|
-
assert_equal 1, gemfile.grep( /
|
57
|
+
assert_equal 1, gemfile.grep( /fun_with_testing/ ).length
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
@@ -70,18 +70,37 @@ class TestDirectoryBuilder < FunWith::Files::TestCase
|
|
70
70
|
should "download random crap from all over the Internet" do
|
71
71
|
if_internet_works do
|
72
72
|
DirectoryBuilder.tmpdir do |b|
|
73
|
-
|
74
|
-
|
75
|
-
|
73
|
+
# The file Bryce uses on Github to prove to Keybase that he owns this Github account
|
74
|
+
# I used to host a test file on my own site, but apparently if you stop paying DigitalOcean
|
75
|
+
# for a few measly months your website goes away. Github will probably provide a more
|
76
|
+
# stable target.
|
77
|
+
url = "https://gist.githubusercontent.com/darthschmoo/ac3ca60338ed41e87b94448f9e851fd3/raw" +
|
78
|
+
"/3cba6b60b552266f4d5aa92d307ef2cda0cf228b/fun_with_files.download.txt"
|
79
|
+
|
80
|
+
dest_file = "download.01.txt"
|
81
|
+
dest_file2 = "download.02.txt"
|
82
|
+
|
83
|
+
downloaded_text = "You have successfully downloaded a file. Huzzah!"
|
84
|
+
downloaded_text_md5 = "2e9d3a924ea36c860c3dd491166ec1ce"
|
85
|
+
downloaded_text_sha1 = "d9be1d5b5c8bd1de6b1dcb99e02cab8e35ed9659"
|
86
|
+
downloaded_text_sha256 = "dc9a6e5d571b39b9754b9592a3b586db8186121d37ec72f7fcbf45241cc43aa6"
|
87
|
+
|
88
|
+
b.download( url, dest_file,
|
89
|
+
:md5 => downloaded_text_md5,
|
90
|
+
:sha1 => downloaded_text_sha1,
|
91
|
+
:sha256 => downloaded_text_sha256
|
92
|
+
)
|
93
|
+
|
76
94
|
|
77
|
-
b.file(
|
78
|
-
b.download(
|
95
|
+
b.file( dest_file2 ) do
|
96
|
+
b.download( url )
|
79
97
|
end
|
80
98
|
|
81
99
|
assert b.current_file.nil?
|
82
|
-
assert b.current_path.join(
|
83
|
-
assert b.current_path.join(
|
84
|
-
assert_equal
|
100
|
+
assert b.current_path.join( dest_file ).exist?
|
101
|
+
assert b.current_path.join( dest_file2 ).exist?
|
102
|
+
assert_equal downloaded_text, b.current_path.join( dest_file ).read
|
103
|
+
assert_equal downloaded_text, b.current_path.join( dest_file2 ).read
|
85
104
|
end
|
86
105
|
end
|
87
106
|
end
|
@@ -112,7 +131,7 @@ class TestDirectoryBuilder < FunWith::Files::TestCase
|
|
112
131
|
end
|
113
132
|
end
|
114
133
|
|
115
|
-
|
134
|
+
assert_equal "Hello", b.current_path.join("earth", "air", "fire", "water", "hello.txt").read
|
116
135
|
|
117
136
|
b.dir( "fire", "water", "earth", "air" ) do
|
118
137
|
assert b.current_path.exist?
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestExtensionMethods < FunWith::Files::TestCase
|
4
|
+
context "Testing extension methods" do
|
5
|
+
setup do
|
6
|
+
@bash = "/bin/bash".fwf_filepath
|
7
|
+
@log = "/var/log/apache/access.log".fwf_filepath
|
8
|
+
@older_log = "/var/log/apache/access.log.9"
|
9
|
+
end
|
10
|
+
|
11
|
+
context "Testing ext?()" do
|
12
|
+
should "correctly identify the extension" do
|
13
|
+
assert_true @bash.ext?("")
|
14
|
+
|
15
|
+
assert_true @log.ext?(".log")
|
16
|
+
assert_true @log.ext?(:log)
|
17
|
+
assert_false @log.ext?(".blog")
|
18
|
+
assert_true @log.ext?(:blog, :flog, :frog, :log)
|
19
|
+
end
|
20
|
+
|
21
|
+
should "run a block if the extension matches" do
|
22
|
+
var = 5
|
23
|
+
|
24
|
+
@log.ext?(:log) do |f|
|
25
|
+
assert_equal @log, f
|
26
|
+
var = 6
|
27
|
+
end
|
28
|
+
|
29
|
+
assert_equal 6, var
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context "Testing file.ext()" do
|
34
|
+
|
35
|
+
should "draw a blank on bash file" do
|
36
|
+
assert_blank @bash.ext
|
37
|
+
assert_equal "", @bash.ext
|
38
|
+
end
|
39
|
+
|
40
|
+
should "add an extension when an extension is given as an argument" do
|
41
|
+
bash2 = @bash.ext( 12 )
|
42
|
+
|
43
|
+
assert_fwf_filepath bash2
|
44
|
+
assert_equal "12", bash2.ext
|
45
|
+
|
46
|
+
for ext in [:exe, "exe"]
|
47
|
+
bash2 = @bash.ext( ext )
|
48
|
+
assert_fwf_filepath bash2
|
49
|
+
assert_equal "exe", bash2.ext
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
should "add multiple extensions when multiple extensions are given" do
|
54
|
+
for args in [ [:tar, :gz], ["tar", "gz"], [".tar", ".gz"] ]
|
55
|
+
bash2 = @bash.ext( *args )
|
56
|
+
assert_equal "gz", bash2.ext
|
57
|
+
assert_equal "/bin/bash.tar.gz", bash2.path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|