fun_with_files 0.0.14 → 0.0.18
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.
- 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
|